Files
pvAccess/src/client/pv/monitor.h
2018-06-05 09:32:22 -07:00

224 lines
6.0 KiB
C++

/* monitor.h */
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
*/
#ifndef MONITOR_H
#define MONITOR_H
#ifdef epicsExportSharedSymbols
# define monitorEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <pv/status.h>
#include <pv/pvData.h>
#include <pv/sharedPtr.h>
#include <pv/bitSet.h>
#ifdef monitorEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef monitorEpicsExportSharedSymbols
#endif
#include <pv/requester.h>
#include <pv/destroyable.h>
#include <shareLib.h>
namespace epics { namespace pvAccess {
class MonitorRequester;
class MonitorElement;
typedef std::tr1::shared_ptr<MonitorElement> MonitorElementPtr;
typedef std::vector<MonitorElementPtr> MonitorElementPtrArray;
class Monitor;
typedef std::tr1::shared_ptr<Monitor> MonitorPtr;
/**
* @brief An element for a monitorQueue.
*
* Class instance representing monitor element.
* @author mrk
*/
class epicsShareClass MonitorElement {
public:
POINTER_DEFINITIONS(MonitorElement);
MonitorElement(epics::pvData::PVStructurePtr const & pvStructurePtr);
const epics::pvData::PVStructurePtr pvStructurePtr;
const epics::pvData::BitSet::shared_pointer changedBitSet;
const epics::pvData::BitSet::shared_pointer overrunBitSet;
class Ref;
};
/** Access to Monitor subscription and queue
*
* Downstream interface to access a monitor queue (via poll() and release() )
*/
class epicsShareClass Monitor : public virtual Destroyable{
public:
POINTER_DEFINITIONS(Monitor);
typedef MonitorRequester requester_type;
virtual ~Monitor(){}
/**
* Start monitoring.
* @return completion status.
*/
virtual epics::pvData::Status start() = 0;
/**
* Stop Monitoring.
* @return completion status.
*/
virtual epics::pvData::Status stop() = 0;
/**
* If monitor has occurred return data.
* @return monitorElement for modified data.
* Must call get to determine if data is available.
*
* May recursively call MonitorRequester::unlisten()
*/
virtual MonitorElementPtr poll() = 0;
/**
* Release a MonitorElement that was returned by poll.
* A poll() must be called after the release() to check the presence of any modified data.
* @param monitorElement
*/
virtual void release(MonitorElementPtr const & monitorElement) = 0;
struct Stats {
size_t nfilled; //!< # of elements ready to be poll()d
size_t noutstanding; //!< # of elements poll()d but not released()d
size_t nempty; //!< # of elements available for new remote data
};
virtual void getStats(Stats& s) const {
s.nfilled = s.noutstanding = s.nempty = 0;
}
/**
* Report remote queue status.
* @param freeElements number of free elements.
*/
virtual void reportRemoteQueueStatus(epics::pvData::int32 freeElements) {}
};
/** A (single ownership) smart pointer to extract a MonitorElement from a Monitor queue
*
* To fetch a single element
@code
epics::pvAccess::Monitor::shared_pointer mon(....);
epics::pvAccess::MonitorElement::Ref elem(mon);
if(elem) {
// do something with element
assert(elem->pvStructurePtr->getSubField("foo"));
} else {
// queue was empty
}
@endcode
* To fetch all available elements (c++11)
@code
epics::pvAccess::Monitor::shared_pointer mon(....);
for(auto& elem : *mon) {
assert(elem.pvStructurePtr->getSubField("foo"));
}
@endcode
* To fetch all available elements (c++98)
@code
epics::pvAccess::Monitor::shared_pointer mon(....);
for(epics::pvAccess::MonitorElement::Ref it(mon); it; ++it) {
MonitorElement& elem(*it);
assert(elem.pvStructurePtr->getSubField("foo"));
}
@endcode
*/
class MonitorElement::Ref
{
Monitor* mon;
MonitorElementPtr elem;
public:
Ref() :mon(0), elem() {}
Ref(Monitor& M) :mon(&M), elem(mon->poll()) {}
Ref(const Monitor::shared_pointer& M) :mon(M.get()), elem(mon->poll()) {}
~Ref() { reset(); }
#if __cplusplus>=201103L
Ref(Ref&& o) :mon(o.mon), elem(o.elem) {
o.mon = 0;
o.elem.reset();
}
#endif
void swap(Ref& o) {
std::swap(mon , o.mon);
std::swap(elem, o.elem);
}
//! analogous to auto_ptr<>::release() but given a different name
//! to avoid being confused with Monitor::release()
MonitorElementPtr letGo() {
MonitorElementPtr ret;
elem.swap(ret);
return ret;
}
void attach(Monitor& M) {
reset();
mon = &M;
}
void attach(const Monitor::shared_pointer& M) {
reset();
mon = M.get();
}
bool next() {
if(elem) mon->release(elem);
elem = mon->poll();
return !!elem;
}
void reset() {
if(elem && mon) mon->release(elem);
elem.reset();
}
Ref& operator++() {// prefix increment. aka "++(*this)"
next();
return *this;
}
#if __cplusplus>=201103L
inline explicit operator bool() const { return elem.get(); }
#else
private:
typedef const Monitor* const * hidden_bool_type;
public:
operator hidden_bool_type() const { return elem.get() ? &mon : 0; }
#endif
inline MonitorElement* operator->() { return elem.get(); }
inline MonitorElement& operator*() { return *elem; }
inline MonitorElement* get() { return elem.get(); }
inline bool operator==(const Ref& o) const { return elem==o.elem; }
inline bool operator!=(const Ref& o) const { return !(*this==o); }
EPICS_NOT_COPYABLE(Ref)
};
#if __cplusplus>=201103L
// used by c++11 for-range
inline MonitorElement::Ref begin(Monitor& mon) { return MonitorElement::Ref(mon); }
inline MonitorElement::Ref end(Monitor& mon) { return MonitorElement::Ref(); }
#endif // __cplusplus<201103L
}}
namespace epics { namespace pvData {
using epics::pvAccess::MonitorElement;
using epics::pvAccess::MonitorElementPtr;
using epics::pvAccess::MonitorElementPtrArray;
using epics::pvAccess::Monitor;
using epics::pvAccess::MonitorPtr;
}}
#endif /* MONITOR_H */