Files
caClientLessons/caLesson6/caClientWrapperC++/epicsPV.h
T

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