216 lines
7.5 KiB
C++
216 lines
7.5 KiB
C++
#ifndef epicsPV_h
|
|
#define epicsPV_h
|
|
|
|
#include <cadef.h>
|
|
#include <alarm.h>
|
|
#include <iostream>
|
|
#include <stdexcept>
|
|
|
|
// How epicsPVs work:
|
|
// A PV is a container for a remote named value provided via a so
|
|
// called EPICS "channel". It is "linked" to the channel in the
|
|
// constructor or later via the link() call.
|
|
// Because the original value is remote, the PV can only contain
|
|
// a copy of the original value.
|
|
// With the get() call, the PV is updated from the remote value.
|
|
// With the put() call, the remote value is updated from the PV.
|
|
|
|
|
|
// Channel Access datatypes (plus caTypeNative as default value)
|
|
// depending on the datatype of a PV, exporting the value
|
|
// to double, long or const char* may give different results
|
|
typedef enum {
|
|
caTypeString,
|
|
caTypeShort,
|
|
caTypeFloat,
|
|
caTypeEnum,
|
|
caTypeChar,
|
|
caTypeLong,
|
|
caTypeDouble,
|
|
caTypeNoAccess,
|
|
caTypeNative
|
|
} caDatatype;
|
|
|
|
class epicsExceptionOutOfMemory {};
|
|
class epicsExceptionNoData {};
|
|
class epicsExceptionOutOfBounds {};
|
|
class epicsExceptionInvalidConversion {};
|
|
|
|
class epicsPV
|
|
{
|
|
public:
|
|
// create PV and optionally link it to an EPICS channel
|
|
// normally, you call the constructor with channelName but without
|
|
// preferredDatatype to use the native datatype of the channel
|
|
// you may read back datatype later
|
|
epicsPV(const char* channelName=NULL, caDatatype preferredDatatype=caTypeNative);
|
|
|
|
// destroy PV and free all resources
|
|
virtual ~epicsPV();
|
|
|
|
// explititely (re-)link PV to a (different) EPICS channel
|
|
// it is normally called by the constructor and destructor.
|
|
// note: linking does not yet send a search request to the
|
|
// network until waitForConnect is called (probably implicitely)
|
|
void link(const char* channelName, caDatatype preferredDatatype=caTypeNative);
|
|
void unlink();
|
|
|
|
// wait until all (or one) PVs are connected
|
|
// timeoutSec = 0.0 just sends connect requests but does not wait
|
|
// timeoutSec < 0.0 means wait forever
|
|
// returns remaining seconds
|
|
// calling this function is optional because it will be called
|
|
// implicitely before the first get or put on an unconnected PV
|
|
static double waitForConnect(double timeoutSec=5.0, epicsPV* pv=NULL);
|
|
|
|
// these functions are called when the connection state changes
|
|
// the default implementation does nothing
|
|
// overwrite them if you want
|
|
// connectionUpEvent is called after all data is initialized
|
|
// connectionDownEvent is called before any data is deleted
|
|
virtual void connectionUpEvent();
|
|
virtual void connectionDownEvent();
|
|
|
|
// get and put data
|
|
epicsPV& get(double timeoutSec=2.0);
|
|
static int getPVs(double timeoutSec, epicsPV* pv1, ...);
|
|
|
|
epicsPV& put(const void* value, unsigned long elements, caDatatype datatype, double timeoutSec=0.0);
|
|
epicsPV& put(long value, double timeoutSec=0.0)
|
|
{ return put(&value, 1, caTypeLong, timeoutSec); }
|
|
epicsPV& put(double value, double timeoutSec=0.0)
|
|
{ return put(&value, 1, caTypeDouble, timeoutSec); }
|
|
epicsPV& put(const char* value, double timeoutSec=0.0)
|
|
{ return put(value, 1, caTypeString, timeoutSec); }
|
|
|
|
// read back channel name (what you provided to link or constuctor)
|
|
const char* name() const
|
|
{ return channel ? ca_name(channel) : ""; }
|
|
|
|
// find out connection state
|
|
// see $(EPICS_BASE)/include/cadef.h for valid values
|
|
channel_state connectionState() const
|
|
{ return channel ? ca_state(channel) : cs_never_conn; }
|
|
const char* connectionStateStr() const
|
|
{ return connectionStateStrings[connectionState()]; }
|
|
static const char* connectionStateStr(channel_state state)
|
|
{ return connectionStateStrings[state]; }
|
|
|
|
// The following methods return information which is available
|
|
// as soon as the PV is connected.
|
|
|
|
// return currently used data type
|
|
caDatatype datatype() const
|
|
{ return usedDatatype; }
|
|
const char* datatypeStr() const
|
|
{ return dataTypeStrings[datatype()+1]; }
|
|
|
|
// return number of elements (for array data)
|
|
unsigned long elements() const
|
|
{ return channel ? 0 : ca_element_count(channel); }
|
|
|
|
// return units and precision (.EGU and .PREC fields)
|
|
const char* units() const;
|
|
int precision() const;
|
|
|
|
// return access rights (might change at run-time)
|
|
bool hasReadAccess() const
|
|
{ return channel ? ca_read_access(channel) : false; }
|
|
bool hasWriteAccess() const
|
|
{ return channel ? ca_write_access(channel) : false; }
|
|
|
|
// The following methods return information which is available
|
|
// after a successful get().
|
|
|
|
// return alarm severity and status (.SEVR and .STAT fields)
|
|
// see $(EPICS_BASE)/include/alarm.h for valid values
|
|
// not conencted PV returns epicsSevInvalid/epicsAlarmNone
|
|
epicsAlarmSeverity alarmSeverity() const
|
|
{ if (data)
|
|
{ epicsUInt16 sevr = static_cast<dbr_time_string*>(data)->severity;
|
|
if (sevr <= lastEpicsAlarmSev)
|
|
return static_cast<epicsAlarmSeverity>(sevr);
|
|
}
|
|
return epicsSevInvalid;
|
|
}
|
|
const char* alarmSeverityStr() const
|
|
{ return epicsAlarmSeverityStrings[alarmSeverity()]; }
|
|
static const char* alarmSeverityStr(epicsAlarmSeverity severity)
|
|
{ return epicsAlarmSeverityStrings[severity]; }
|
|
epicsAlarmCondition alarmStatus() const
|
|
{ if (data)
|
|
{ epicsUInt16 stat = static_cast<dbr_time_string*>(data)->status;
|
|
if (stat <= lastEpicsAlarmCond)
|
|
return static_cast<epicsAlarmCondition>(stat);
|
|
}
|
|
return epicsAlarmNone;
|
|
}
|
|
const char* alarmStatusStr() const
|
|
{ return epicsAlarmConditionStrings[alarmStatus()]; }
|
|
static const char* alarmStatusStr(epicsAlarmCondition status)
|
|
{ return epicsAlarmConditionStrings[status]; }
|
|
|
|
// return time of record processing
|
|
// see $(EPICS_BASE)/include/epicsTime.h for class epicsTime
|
|
epicsTime timestamp() const
|
|
{ if (data)
|
|
{ return epicsTime(static_cast<dbr_time_string*>(data)->stamp);
|
|
}
|
|
return epicsTime();
|
|
}
|
|
|
|
// return value of pv
|
|
|
|
long toLong(unsigned long index = 0) const;
|
|
double toDouble(unsigned long index = 0) const;
|
|
enum { withUnits = 1 }; // flags for toStr()
|
|
const char* toStr(int flags = 0, unsigned long index = 0);
|
|
|
|
// conversion operators for convenience
|
|
// We try not to be ambigous and define ops for all types.
|
|
operator double() const
|
|
{ return toDouble(); }
|
|
double operator [] (unsigned long index) const
|
|
{ return toDouble(index); }
|
|
|
|
static const char* dataTypeStrings[9];
|
|
static const char* connectionStateStrings[4];
|
|
private:
|
|
chid channel;
|
|
void* data;
|
|
void* info;
|
|
caDatatype usedDatatype;
|
|
caDatatype requestedDatatype;
|
|
int status;
|
|
static unsigned long nconnecting;
|
|
char stringrep[40];
|
|
|
|
static void connectCallback(connection_handler_args);
|
|
void connectionUp();
|
|
void connectionDown();
|
|
};
|
|
|
|
inline std::ostream& operator << (std::ostream& o, epicsPV& pv)
|
|
{
|
|
return o << pv.toStr(epicsPV::withUnits);
|
|
}
|
|
|
|
inline std::ostream& operator << (std::ostream& o, epicsAlarmSeverity sevr)
|
|
{
|
|
return o << epicsAlarmSeverityStrings[sevr];
|
|
}
|
|
|
|
inline std::ostream& operator << (std::ostream& o, epicsAlarmCondition stat)
|
|
{
|
|
return o << epicsAlarmConditionStrings[stat];
|
|
}
|
|
|
|
inline std::ostream& operator << (std::ostream& o, caDatatype type)
|
|
{
|
|
return o << epicsPV::dataTypeStrings[type];
|
|
}
|
|
|
|
#define caget(pvs...) epicsPV::getPVs(2.0, pvs, NULL)
|
|
|
|
#endif
|