diff --git a/documentation/copyandmonitor.html b/documentation/copyandmonitor.html new file mode 100644 index 0000000..e4901a0 --- /dev/null +++ b/documentation/copyandmonitor.html @@ -0,0 +1,679 @@ + + + +
+ +copy and monitor are not used in this project. +They are intended for use by pvAccess and by pvAccess servers. +They are provided with this project because the code depends only on +pvData itself. +
+This document describes C++ specific code. + +pvRequest.html +provides a language independent overview of copy and monitor. +
++NOTE:pvRequest.html must be updated since it is based on an earlier version of pvCopy that +had knowlege of PVRecord. The C++ version was implemented in pvDatabaseCPP +and the Java version on pvIOCJava. +At present only the C++ version of the new API for pvCopy is implemented. +
+Copy provides: +
copy provides the ability to create a structure that has +a copy of an arbitrary subset of the fields in an existing top level +structure. In addition it allows global options and field specific options. +It has two main components: createRequest and pvCopy. +Given a string createRequest creates a pvRequest, which is a PVStructure +that has the format expected by pvCopy. +
+ +This is mainly used by pvAccess clients. Given a request string it creates +a pvRequest structure that can be passed to the pvAccess create methods. +In turn pvAccess passes the pvRequest to a local channel provider which +then passes it to pvCopy. +
+The definition of the public members is:
+
+class CreateRequest {
+...
+ static CreateRequestPtr create();
+ virtual PVStructurePtr createRequest(String const &request);
+ String getMessage();
+};
+
+An example of how it is used is:
+
+CreateRequestPtr createRequest = CreateRequest::create();
+PVStructurePtr pvRequest = createRequest->createRequest(request);
+if(pvRequest==NULL) {
+ String error = createRequest->getMessage();
+ // take some action
+} else {
+ //success do something
+}
+
+The definition of the public members is:
+
+class epicsShareClass PVCopyTraverseMasterCallback
+{
+...
+ virtual void nextMasterPVField(PVFieldPtr const &pvField);
+};
+
+class class epicsShareClass PVCopy
+{
+...
+ static PVCopyPtr create(
+ PVStructurePtr const &pvMaster,
+ PVStructurePtr const &pvRequest,
+ String const & structureName);
+ PVStructurePtr getPVMaster();
+ void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback);
+ StructureConstPtr getStructure();
+ PVStructurePtr createPVStructure();
+ size_t getCopyOffset(PVFieldPtr const &masterPVField);
+ size_t getCopyOffset(
+ PVStructurePtr const &masterPVStructure,
+ PVFieldPtr const &masterPVField);
+ PVFieldPtr getMasterPVField(std::size_t structureOffset);
+ void initCopy(
+ PVStructurePtr const ©PVStructure,
+ BitSetPtr const &bitSet);
+ void updateCopySetBitSet(
+ PVStructurePtr const ©PVStructure,
+ BitSetPtr const &bitSet);
+ void updateCopyFromBitSet(
+ PVStructurePtr const ©PVStructure,
+ BitSetPtr const &bitSet);
+ void updateMaster(
+ PVStructurePtr const ©PVStructure,
+ BitSetPtr const &bitSet);
+ PVStructurePtr getOptions(std::size_t fieldOffset);
+...
+};
+
+where
+This consists of two components: +
+class MonitorElement {
+ MonitorElement(PVStructurePtr const & pvStructurePtr);
+ PVStructurePtr pvStructurePtr;
+ BitSetPtr changedBitSet;
+ BitSetPtr overrunBitSet;
+};
+
+class Monitor {
+ virtual Status start() = 0;
+ virtual Status stop() = 0;
+ virtual MonitorElementPtr poll() = 0;
+ virtual void release(MonitorElementPtr const & monitorElement) = 0;
+};
+
+class MonitorRequester : public virtual Requester {
+ virtual void monitorConnect(Status const & status,
+ MonitorPtr const & monitor, StructureConstPtr const & structure) = 0;
+ virtual void monitorEvent(MonitorPtr const & monitor) = 0;
+ virtual void unlisten(MonitorPtr const & monitor) = 0;
+};
+
+MonitorElement holds the data for one element of a monitor queue. +It has the fields: +
+A queue of monitor elements must be implemented by any channel provider that implements +Channel::createMonitor. +For an example implementation look at pvDatabaseCPP. +It has the following: +
+typedef Queue<MonitorElement> MonitorElementQueue;
+typedef std::tr1::shared_ptr<MonitorElementQueue> MonitorElementQueuePtr;
+
+class MultipleElementQueue :
+ public ElementQueue
+{
+public:
+ POINTER_DEFINITIONS(MultipleElementQueue);
+ virtual ~MultipleElementQueue(){}
+ MultipleElementQueue(
+ MonitorLocalPtr const &monitorLocal,
+ MonitorElementQueuePtr const &queue,
+ size_t nfields);
+ virtual void destroy(){}
+ virtual Status start();
+ virtual Status stop();
+ virtual bool dataChanged();
+ virtual MonitorElementPtr poll();
+ virtual void release(MonitorElementPtr const &monitorElement);
+...
+};
+
+Monitor must be implemented by any channel provider that implements +Channel::createMonitor. +Remote PVAccess also implements Monitor on the client side. +Note that each client has it's own queue that is not shared with other client. +
+Monitor has the following methods:
+This must be implemented by a pvAccess client. +It has the methods:
+
+class MonitorPlugin
+{
+ virtual String const & getName() = 0;
+ virtual bool causeMonitor(
+ PVFieldPtr const &pvField,
+ PVStructurePtr const &pvTop,
+ MonitorElementPtr const &monitorElement) = 0;
+ virtual void monitorDone(
+ MonitorElementPtr const &monitorElement);
+ virtual void startMonitoring();
+ virtual void stopMonitoring();
+ virtual void beginGroupPut();
+ virtual void endGroupPut();
+};
+
+class MonitorPluginCreator
+{
+ virtual MonitorPluginPtr create(
+ FieldConstPtr const &field,
+ StructureConstPtr const &top,
+ PVStructurePtr const &pvFieldOptions) = 0;
+ virtual String const & getName() = 0;
+}
+
+class MonitorPluginManager
+{
+ static MonitorPluginManagerPtr get();
+ bool addPlugin(
+ String const &pluginName,
+ MonitorPluginCreatorPtr const &creator);
+ MonitorPluginCreatorPtr findPlugin(String const &pluginName);
+ void showNames();
+};
+
+
+MonitorPlugin must be implemented by the plugin implementation. +It has methods:
+MonitorPluginCreator must also be implemented by the plugin implementation. +It is called for each field instance that has options of the from +[plugin=name...] where name is the name of the plugin. +Note that a plugin instance will belong to a single client. +It has methods:
+MonitorPluginManager has the methods:
+NOTE: +Should the method causeMonitor +have arguments pvField and pvTop +be defined so that they can not be modfied. +This would be posssible if the following was defined: +
+typedef std::tr1::shared_ptr<const PVField> PVFieldConstPtr; +typedef std::tr1::shared_ptr<const PVStructure> PVStructureConstPtr; ++then the definition for causeMonitor could be: +
+virtual bool causeMonitor( + PVFieldConstPtr const &pvField, + PVStructureConstPtr const &pvTop, + MonitorElementPtr const &monitorElement) = 0; ++But just adding these definitions is not sufficent. +In addition all methods defined in pvDataCPP must be checked. +In particular many of the methods in Convert must have +their arguments modified. +Big job. + +
This section describes an example plugin that:
+As an example assume that a channel provided by pvAccess has a top level structure +that represents a power supply.
++structure powerSupply + structure alarm + structure timeStamp + structure power + double value + structure alarm + struvture display + structure voltage + double value + structure alarm + struvture display + structure current + double value + structure alarm + struvture display ++
A pvAccess client wants to create a monitor on the powerSupply as follows: +The client wants a top level structure that looks like: +
+structure powerSupply + structure alarm + structure timeStamp + structure power + double value + structure voltage + double value + structure current + double value ++In addition the client wants monitors to occur only when one of the monitored +fields changes value but not just because a put occured. +Also if only the timeStamp changes value then that should not cause a monitor. + +
The example monitor plugin implements the semantics the +client wants. It can be attached to any field via the following options: +
+[plugin=onChange,raiseMonitor=value] ++This plugin will trigger a monitor for the field only if the field changes +value. In addition value equals false means do not raise a monotor +for changes to this field. +But if a change to another field does cause a monitor the change to this field +will be passed to the client. + +
+Assume that the client has already connected to the channel. +The client can then issue the commands:
+
+String request("field(alarm[plugin=onChange]");
+request += ",timeStamp[plugin=onChange,raiseMonitor=false]";
+request += ",power.value[plugin=onChange";
+request += ",voltage.value[plugin=onChange";
+request += ",current.value[plugin=onChange";
+
+PVStructurePtr pvRequest = createRequest->createRequest(request);
+
+MonitorPtr monitor = channel->createMonitor(monitorRequester,pvRequest);
+
+The header file to create the example has the definition:
+
+class ExampleMonitorPlugin{
+public:
+ static void create();
+};
+
+The implementation is:
+
+class OnChangePlugin : public MonitorPlugin
+{
+public:
+ virtual ~OnChangePlugin(){}
+ OnChangePlugin() {}
+ bool init(
+ FieldConstPtr const &field,
+ StructureConstPtr const &top,
+ PVStructurePtr const &pvFieldOptions)
+ {
+ pvField = getPVDataCreate()->createPVField(field);
+ raiseMonitor = true;
+ if(pvFieldOptions!=NULL) {
+ PVStringPtr pvString =
+ pvFieldOptions->getSubField<PVString>("raiseMonitor");
+ if(pvString!=NULL) {
+ String value = pvString->get();
+ if(value.compare("false")==0) raiseMonitor = false;
+ }
+ }
+ return true;
+ }
+ virtual String &getName(){return pluginName;}
+ virtual bool causeMonitor(
+ PVFieldPtr const &pvNew,
+ PVStructurePtr const &pvTop,
+ MonitorElementPtr const &monitorElement)
+ {
+ bool isSame = convert->equals(pvNew,pvField);
+ if(isSame) return false;
+ convert->copy(pvNew,pvField);
+ return raiseMonitor;
+ }
+private:
+ PVFieldPtr pvField;
+ bool raiseMonitor;
+};
+class OnChangePluginCreator : public MonitorPluginCreator
+{
+public:
+ virtual String &getName(){return pluginName;}
+ virtual MonitorPluginPtr create(
+ FieldConstPtr const &field,
+ StructureConstPtr const &top,
+ PVStructurePtr const &pvFieldOptions)
+ {
+ OnChangePluginPtr plugin(new OnChangePlugin());
+ bool result = plugin->init(field,top,pvFieldOptions);
+ if(!result) return MonitorPluginPtr();
+ return plugin;
+ }
+
+};
+
+void ExampleMonitorPlugin::create()
+{
+ static OnChangePluginCreatorPtr plugin;
+ static Mutex mutex;
+ Lock xx(mutex);
+ if(plugin==NULL) {
+ plugin = OnChangePluginCreatorPtr(new OnChangePluginCreator());
+ MonitorPluginManager::get()->addPlugin(pluginName,plugin);
+ }
+}
+
+
+
+