#ifndef epicsPV_h #define epicsPV_h #include #include #include #include // 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(data)->severity; if (sevr <= lastEpicsAlarmSev) return static_cast(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(data)->status; if (stat <= lastEpicsAlarmCond) return static_cast(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(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