diff --git a/.hgignore b/.hgignore index edb9c72..721dbf6 100644 --- a/.hgignore +++ b/.hgignore @@ -1,11 +1,12 @@ -^QtC- -^bin/ -^lib/ -^doc/ -^include/ -^db/ -^dbd/ -^documentation/html +QtC- +bin/ +lib/ +doc/ +include/ +db/ +dbd/ +documentation/html +documentation/*.tag envPaths configure/.*\.local /O\..* diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md new file mode 100644 index 0000000..0e0311c --- /dev/null +++ b/documentation/RELEASE_NOTES.md @@ -0,0 +1,47 @@ +Release release/3.1 IN DEVELOPMENT +=========== + +The main changes since release 3.0.2 are: + +* array semantics now enforce Copy On Write. +* union is new type. +* copy is new. +* monitorPlugin is new. + +New Semantics for Arrays +-------- + +PVScalarArray, PVStructureArray, and PVUnionArray all enforce COW (Copy On Write) Semantics. +In order to limit memory usage the storage for raw data is managed via a new shared_vector facility. +This allows multiple instances of array data to use the shared raw data. +COW is implemented via shared_vectors of const data, i. e. data that can not be modified. + +union is a new basic type. +------------ + +There are two new basic types: union_t and unionArray. + +A union is like a structure that has a single subfield. +There are two flavors: + +* varient union The field can have any type. +* union The field can any of specified set of types. + +The field type can be dynamically changed. + +copy +---- + +This consists of createRequest and pvCopy. +createRequest was moved from pvAccess to here. +pvCopy is moved from pvDatabaseCPP and now depends +only on pvData, i. e. it no longer has any knowledge of PVRecord. + +monitorPlugin +------------- + +This is for is for use by code that implements pvAccess monitors. + +Release 3.0.2 +========== +This was the starting point for RELEASE_NOTES diff --git a/documentation/TODO.md b/documentation/TODO.md new file mode 100644 index 0000000..268a561 --- /dev/null +++ b/documentation/TODO.md @@ -0,0 +1,54 @@ +TODO +=========== + +toString, dumpValue, printer, and streams +------------ + +The way to print introspection and data instances is not consistent. +This needs work. +Some items that need work are: + +* Introspection has no support for streams. Only for toString. +* data has problems. toString is implemented by calling Convert::getString. +It look like this was intended to use printer but that did nor properly indent fields of structures. + +The current implementation is: + + void Convert::getString(StringBuilder buf,PVField const *pvField,int /*indentLevel*/) + { + // TODO indextLevel ignored + std::ostringstream strm; + strm << pvField->dumpValue(strm) << std::endl; + // PrinterPlain p; + // p.setStream(strm); + // p.print(*pvField); + strm.str().swap(*buf); + } + +Thus it just uses dumpValue. +What should it do? +If printer is used it must do proper indentation. + +doxygen +------- + +There is a lot of public code that does not have doxygen tags. + + +monitorPlugin +------------- + +A debate is on-going about what semantics should be. + +PVFieldConstPtr etc +------------------- + +In pvDataCPP.html look at the monoitorPlugin example. +It has a discussion of a possible need for shared pointers that can not be used to modify data. +This in addition to PVFieldPtr should PVFieldConstPtr exist. +But this means that all methods defined in pvDataCPP must be checked. +This is a BIG job. + +Release 3.0.2 +========== +This was the starting point for RELEASE_NOTES 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);
+ }
+}
+
+
+
+PVData is a computer software package for the efficient -storage, access, and communication, of structured data. +
EPICS Version 4 provides efficient
+storage, access, and communication, of memory resident structured data.
+pvData is the storage compoment.
pvDataCPP is the C++ implementation of pvData.
It is one part of the set of related products in the EPICS
V4 control system programming environment:
@@ -77,22 +78,13 @@ V4 control system programming environment:
This is the 28-Oct-2013 version of the C++ implementation of pvData. -This version describes the changes since the 4.3.0 release of Epics Version 4. +
This is the 01-May-2014 version of the C++ implementation of pvData.
-The text describes software which is a complete implementation of pvData as -currently planned by the EPICS V4 Working Group.
+RELEASE_NOTES.md provides changes since the last release. +TODO.md describes things to do before the next release. +
-The major changes since the 4.3.0 release are:
-The implementation of PVValueArray and PVStructureArray now inforce Copy On Write (COW) - and use shared_vector for the raw array.
-pvData is one of a set of related projects. It describes and implements the +
pvData is one of a set of related projects. It describes and implements data that the other projects support. Thus it is not useful by itself but understanding pvData is required in order to understand the other projects. The reader should also become familar with project pvAccess, which is @@ -110,8 +102,8 @@ located via the same sourceforge site as this project.
The Java and C++ implementation of pvData implement the same data model but differ in implementation because of the differences between Java and C++.
-It is a good idea to read all of pvDataJava.html but read at least the -first two chapters:
+It is a good idea to read all of pvDataJava.html but read at least the +first two chapters:
Doxygen documentation is available at doxygenDoc
+The next section provides some examples of creating and accessing data. +
+This document discusses the following:
+This section provides some examples of creating and accessing both introspection and +data interfaces. The first time reader may not understand them but hopefully will get an +idea of how pvData works. After reading the rest of this document the examples will +be much easier to understand. +
+The documentation directory for this project has a file examples.zip. +It has the code for the examples. +After it is unzipped just edit configure/RELEASE.local and then execute make. + +The examples assume that the following statements have been issued:
++String builder; +FieldCreatePtr fieldCreate = getFieldCreate(); +PVDataCreatePtr pvDataCreate = getPVDataCreate(); +StandardFieldPtr standardField = getStandardField(); +StandardPVFieldPtr standardPVField = getStandardPVField(); +StructureConstPtr alarm = getStandardField()->alarm(); +StructureConstPtr timeStamp = getStandardField()->timeStamp(); ++
These provide access to most of pvData:
+The examples all produce a top level structure. +The reason is that top level structures are what pvAccess passes between client and server +and what pvDatabaseCPP supports.
+The following is the hardest way to create structure that has a double value field and a time stamp field: +It uses only createField. +
+
+ size_t n = 3;
+ StringArray names;
+ names.reserve(n);
+ FieldConstPtrArray fields;
+ fields.reserve(n);
+ names.push_back("secsPastEpoch");
+ fields.push_back(fieldCreate->createScalar(pvLong));
+ names.push_back("nanoseconds");
+ fields.push_back(fieldCreate->createScalar(pvInt));
+ names.push_back("userTag");
+ fields.push_back(fieldCreate->createScalar(pvInt));
+ StructureConstPtr timeStamp = fieldCreate->createStructure(names,fields);
+ size_t ntop = 2;
+ StringArray topnames;
+ topnames.reserve(ntop);
+ FieldConstPtrArray topfields;
+ topfields.reserve(ntop);
+ topnames.push_back("value");
+ topfields.push_back(fieldCreate->createScalar(pvDouble));
+ topnames.push_back("timeStamp");
+ topfields.push_back(timeStamp);
+ StructureConstPtr doubleScalar = fieldCreate->createStructure(topnames,topfields);
+ builder.clear();
+ doubleScalar->toString(&builder);
+ cout << builder << "\n\n";
+
+Using FieldBuilder the same can be done via:
+
+ StructureConstPtr doubleScalarHard =
+ getFieldCreate()->createFieldBuilder()->
+ add("value",pvDouble) ->
+ addNestedStructure("timeStamp")->
+ setId("time_t")->
+ add("secsPastEpoch", pvLong)->
+ add("nanoseconds", pvInt)->
+ add("userTag", pvInt)->
+ endNested()->
+ createStructure();
+ builder.clear();
+ doubleScalarHard->toString(&builder);
+ cout << builder << endl;
+
+Both produce:
++structure + double value + time_t timeStamp + long secsPastEpoch + int nanoseconds ++
An easy way to create a structure with a string array value field and an alarm and time stamp is +via standardField:
++ StructureConstPtr stringArrayEasy = + getStandardField()->scalarArray(pvString,"alarm,timeStamp"); + builder.clear(); + stringArrayEasy->toString(&builder); + cout << builder << endl; ++It produces : +
+uri:ev4:nt/2012/pwd:NTScalarArray + string[] value + alarm_t alarm + int severity + int status + string message + time_t timeStamp + long secondsPastEpoch + int nanoSeconds + int userTag ++
An enumerated structure is a structure with two sub-fields: +index, which is an int, and choices, which is an array of string. +The following examples create a structure which has a field names value, which +is an enumerated structure and additional fields. +A hard way to create an structure with an enumerated value field and a time stamp is:
+
+ StructureConstPtr enum_t =
+ getFieldCreate()->createFieldBuilder()->
+ setId("enum_t")->
+ add("index", pvInt)->
+ addArray("choices", pvString)->
+ createStructure();
+
+ StructureConstPtr ntEnumHard =
+ getFieldCreate()->createFieldBuilder()->
+ setId("uri:ev4:nt/2012/pwd/NTEnum")->
+ add("value", enum_t)->
+ addNestedStructure("timeStamp")->
+ setId("time_t")->
+ add("secsPastEpoch", pvLong)->
+ add("nanoseconds", pvInt)->
+ add("userTag", pvInt)->
+ endNested()->
+ createStructure();
+ builder.clear();
+ ntEnumHard->toString(&builder);
+ cout << builder << endl;
+
+It produces:
++uri:ev4:nt/2012/pwd/NTEnum + enum_t value + int index + string[] choices + time_t timeStamp + long secsPastEpoch + int nanoseconds + int userTag ++
The following is an easy way. Note that it has two additional +fields: alarm and timeStamp:
+
+ StructureConstPtr ntEnumEasy = getStandardField()->enumerated("alarm,timeStamp");
+ builder.clear();
+ ntEnumEasy->toString(&builder);
+ cout << builder << endl;
+
+It produces:
++uri:ev4:nt/2012/pwd:NTEnum + enum_t value + int index + string[] choices + alarm_t alarm + int severity + int status + string message + time_t timeStamp + long secondsPastEpoch + int nanoSeconds + int userTag ++ +
The following creates a union and a structure with a union value field:
+ +
+ UnionConstPtr ntunion =
+ getFieldCreate()->createFieldBuilder()->
+ add("doubleValue", pvDouble)->
+ add("intValue", pvInt)->
+ add("timeStamp",timeStamp)->
+ createUnion();
+ builder.clear();
+ ntunion->toString(&builder);
+ cout << builder << endl;
+
+ StructureConstPtr unionValue = getStandardField()->regUnion(punion,"alarm,timeStamp");
+ builder.clear();
+ ntunion->toString(&builder);
+ cout << builder << endl;
+
+It produces:
++union + double doubleValue + int intValue + time_t timeStamp + long secondsPastEpoch + int nanoSeconds + int userTag + +structure with value field being a union +uri:ev4:nt/2012/pwd:NTUnion + union value + double doubleValue + int intValue + time_t timeStamp + long secondsPastEpoch + int nanoSeconds + int userTag + alarm_t alarm + int severity + int status + string message + time_t timeStamp + long secondsPastEpoch + int nanoSeconds + int userTag ++
The following creates a more complex structure:
+
+ StructureConstPtr powerSupply =
+ getFieldCreate()->createFieldBuilder()->
+ add("alarm_t",alarm) ->
+ add("timestamp_t",timeStamp) ->
+ addNestedStructure("power") ->
+ add("value",pvDouble) ->
+ add("alarm",alarm) ->
+ endNested()->
+ addNestedStructure("voltage") ->
+ add("value",pvDouble) ->
+ add("alarm",alarm) ->
+ endNested()->
+ addNestedStructure("current") ->
+ add("value",pvDouble) ->
+ add("alarm",alarm) ->
+ endNested()->
+ createStructure();
+ builder.clear();
+ powerSupply->toString(&builder);
+ cout << builder << endl;
+
+It produces:
++structure + alarm_t alarm_t + int severity + int status + string message + time_t timestamp_t + long secondsPastEpoch + int nanoSeconds + int userTag + structure power + double value + alarm_t alarm + int severity + int status + string message + structure voltage + double value + alarm_t alarm + int severity + int status + string message + structure current + double value + alarm_t alarm + int severity + int status + string message ++
The examples all produce a top level structure.
+
+ PVStructurePtr doubleValue = getPVDataCreate()->createPVStructure(
+ getStandardField()->scalar(pvDouble,"alarm,timeStamp"));
+ PVDoublePtr pvdouble =
+ doubleValue->getSubField<PVDouble>("value");
+ pvdouble->put(1e5);
+ cout << doubleValue->dumpValue(cout) << endl;
+
+This produces:
++uri:ev4:nt/2012/pwd:NTScalar + double value 100000 + alarm_t alarm + int severity 0 + int status 0 + string message + time_t timeStamp + long secondsPastEpoch 0 + int nanoSeconds 0 + int userTag 0 +0x607268 ++
+ PVStructurePtr doubleArrayValue = getPVDataCreate()->createPVStructure(
+ getStandardField()->scalarArray(pvDouble,"alarm,timeStamp"));
+ PVDoubleArrayPtr pvDoubleArray =s
+ doubleArrayValue->getSubField<PVDoubleArray>("value");
+ size_t len = 10;
+ shared_vector<double> xxx(len);
+ for(size_t i=0; i< len; ++i) xxx[i] = i;
+ shared_vector<const double> data(freeze(xxx));
+ pvDoubleArray->replace(data);
+ cout << doubleArrayValue->dumpValue(cout) << endl;
+
+ shared_vector<const double> getData = pvDoubleArray->view();
+ cout << "via getData";
+ for (size_t i=0; i< len; ++i) cout << " " << getData[i];
+ cout << endl;
+
+This produces:
++uri:ev4:nt/2012/pwd:NTScalarArray + double[] value [0,1,2,3,4,5,6,7,8,9] + alarm_t alarm + int severity 0 + int status 0 + string message + time_t timeStamp + long secondsPastEpoch 0 + int nanoSeconds 0 + int userTag 0 +0x607268 +via getData 0 1 2 3 4 5 6 7 8 9 ++
+ PVStructurePtr pvntenum = getPVDataCreate()->createPVStructure(
+ getStandardField()->enumerated("alarm,timeStamp"));
+ cout << pvntenum->dumpValue(cout) << "\n\n";
+
+This produces:
++uri:ev4:nt/2012/pwd:NTEnum + enum_t value + int index 0 + string[] choices [] + alarm_t alarm + int severity 0 + int status 0 + string message + time_t timeStamp + long secondsPastEpoch 0 + int nanoSeconds 0 + int userTag 0 +0x607268 ++
+ StructureConstPtr powerSupply =
+ getFieldCreate()->createFieldBuilder()->
+ add("alarm_t",alarm) ->
+ add("timestamp_t",timeStamp) ->
+ addNestedStructure("power") ->
+ add("value",pvDouble) ->
+ add("alarm",alarm) ->
+ endNested()->
+ addNestedStructure("voltage") ->
+ add("value",pvDouble) ->
+ add("alarm",alarm) ->
+ endNested()->
+ addNestedStructure("current") ->
+ add("value",pvDouble) ->
+ add("alarm",alarm) ->
+ endNested()->
+ createStructure();
+ PVStructurePtr pvpowerSupply = getPVDataCreate()->createPVStructure(powerSupply);
+ cout << pvpowerSupply->dumpValue(cout) << endl;
+
+This produces:
++structure + alarm_t alarm_t + int severity 0 + int status 0 + string message + time_t timestamp_t + long secondsPastEpoch 0 + int nanoSeconds 0 + int userTag 0 + structure power + double value 0 + alarm_t alarm + int severity 0 + int status 0 + string message + structure voltage + double value 0 + alarm_t alarm + int severity 0 + int status 0 + string message + structure current + double value 0 + alarm_t alarm + int severity 0 + int status 0 + string message +0x607268 ++
+ PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
+ standardField->regUnion(
+ getFieldCreate()->createFieldBuilder()->
+ add("doubleValue", pvDouble)->
+ add("intValue", pvInt)->
+ add("timeStamp",timeStamp)->
+ createUnion(),
+ "alarm,timeStamp"));
+ PVStructurePtr pvTimeStamp =
+ pvStructure->getSubField<PVUnion>("value")->select<PVStructure>(2);
+ pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000);
+ cout << pvStructure->dumpValue(cout) << "\n";
+ pvStructure->getSubField<PVUnion>("value")->select<PVDouble>(0)->put(1e5);
+ cout << pvStructure->dumpValue(cout) << "\n\n";
+
+This produces:
++uri:ev4:nt/2012/pwd:NTUnion + union value + time_t + long secondsPastEpoch 1000 + int nanoSeconds 0 + int userTag 0 + alarm_t alarm + int severity 0 + int status 0 + string message + time_t timeStamp + long secondsPastEpoch 0 + int nanoSeconds 0 + int userTag 0 +0x60a2c8 +uri:ev4:nt/2012/pwd:NTUnion + union value + double 100000 + alarm_t alarm + int severity 0 + int status 0 + string message + time_t timeStamp + long secondsPastEpoch 0 + int nanoSeconds 0 + int userTag 0 +0x60a2c8 ++ +
+ PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
+ standardField->variantUnion("alarm,timeStamp"));
+ PVStructurePtr pvTimeStamp =
+ pvDataCreate->createPVStructure(standardField->timeStamp());
+ pvStructure->getSubField<PVUnion>("value")->set(pvTimeStamp);
+ pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000);
+ cout << pvStructure->dumpValue(cout) << "\n";
+ pvStructure->getSubField<PVUnion>("value")->set(
+ pvDataCreate->createPVScalar(pvDouble));
+ PVDoublePtr pvValue = static_pointer_cast<PVDouble>(
+ pvStructure->getSubField<PVUnion>("value")->get());
+ pvValue->put(1e5);
+ cout << pvStructure->dumpValue(cout) << "\n\n";
+
+This produces:
++uri:ev4:nt/2012/pwd:NTUnion + any value + time_t + long secondsPastEpoch 1000 + int nanoSeconds 0 + int userTag 0 + alarm_t alarm + int severity 0 + int status 0 + string message + time_t timeStamp + long secondsPastEpoch 0 + int nanoSeconds 0 + int userTag 0 +0x60a2c8 +uri:ev4:nt/2012/pwd:NTUnion + any value + double 100000 + alarm_t alarm + int severity 0 + int status 0 + string message + time_t timeStamp + long secondsPastEpoch 0 + int nanoSeconds 0 + int userTag 0 +0x60a2c8 ++ +
+ PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
+ standardField->regUnion(
+ getFieldCreate()->createFieldBuilder()->
+ add("doubleValue", pvDouble)->
+ addArray("doubleArrayValue",pvDouble)->
+ addNestedUnion("unionValue") ->
+ add("doubleValue", pvDouble)->
+ add("alarm",standardField->alarm()) ->
+ endNested() ->
+ addNestedStructure("structValue") ->
+ add("doubleValue", pvDouble)->
+ addArray("doubleArrayValue",pvDouble)->
+ endNested() ->
+ addNestedUnionArray("unionArrayValue") ->
+ add("doubleValue", pvDouble)->
+ add("alarm",standardField->alarm()) ->
+ endNested() ->
+ addNestedStructureArray("structArrayValue") ->
+ add("doubleValue", pvDouble)->
+ addArray("doubleArrayValue",pvDouble)->
+ endNested() ->
+ createUnion(),
+ "alarm,timeStamp"));
+ builder.clear();
+ pvStructure->getStructure()->toString(&builder);
+ cout << "introspection\n";
+ cout << builder << endl;
+ cout << "data\n";
+ cout << pvStructure->dumpValue(cout) << "\n";
+ PVUnionPtr pvUnion = pvStructure->getSubField<PVUnion>("value");;
+ pvUnion->select("doubleValue");
+ PVDoublePtr pvDouble = pvUnion->get<PVDouble>();
+ pvDouble->put(1.55);
+ cout << "select valueDouble\n";
+ cout << pvStructure->dumpValue(cout) << "\n";
+ cout << "value = " << pvDouble->get() << "\n";
+ pvUnion->select("structValue");
+ pvDouble = pvUnion->get<PVStructure>()->getSubField<PVDouble>("doubleValue");
+ pvDouble->put(1.65);
+ cout << "select structValue\n";
+ cout << pvStructure->dumpValue(cout) << "\n";
+ cout << "value = " << pvDouble->get() << "\n";
+
+This produces:
++introspection +uri:ev4:nt/2012/pwd:NTUnion + union value + double doubleValue + double[] doubleArrayValue + union unionValue + double doubleValue + alarm_t alarm + int severity + int status + string message + structure structValue + double doubleValue + double[] doubleArrayValue + union[] unionArrayValue + union[] + union + double doubleValue + alarm_t alarm + int severity + int status + string message + structure[] structArrayValue + structure[] + structure + double doubleValue + double[] doubleArrayValue + alarm_t alarm + int severity + int status + string message + time_t timeStamp + long secondsPastEpoch + int nanoSeconds + int userTag +data +uri:ev4:nt/2012/pwd:NTUnion + union value + (none) + alarm_t alarm + int severity 0 + int status 0 + string message + time_t timeStamp + long secondsPastEpoch 0 + int nanoSeconds 0 + int userTag 0 +0x60a2c8 +select valueDouble +uri:ev4:nt/2012/pwd:NTUnion + union value + double 1.55 + alarm_t alarm + int severity 0 + int status 0 + string message + time_t timeStamp + long secondsPastEpoch 0 + int nanoSeconds 0 + int userTag 0 +0x60a2c8 +value = 1.55 +select structValue +uri:ev4:nt/2012/pwd:NTUnion + union value + structure + double doubleValue 1.65 + double[] doubleArrayValue [] + alarm_t alarm + int severity 0 + int status 0 + string message + time_t timeStamp + long secondsPastEpoch 0 + int nanoSeconds 0 + int userTag 0 +0x60a2c8 +value = 1.65 +
pvDataCPP introspection and data objects are designed to be shared. They are -made availiable via std::tr1::shared_ptr. In addition arrays are -implemented via shared_vector. The following naming conventions are used +
Many pvDataCPP introspection and data objects are designed to be shared. They are +made availiable via std::tr1::shared_ptr. +The following naming convention is used in typedefs:
As an example pvType.h includes the following definitions:
-typedef std::vector<double> DoubleArray;
-typedef std::tr1::shared_ptr<DoubleArray> DoubleArrayPtr;
-inline double * get(DoubleArray &value)
-{
- return &value[0];
-}
-inline const double * get(const DoubleArray &value)
-{
- return static_cast<const double *>(&value[0]);
-}
-typedef std::vector<double>::iterator DoubleArray_iterator;
-typedef std::vector<double>::const_iterator DoubleArray_const_iterator;
-
-where
-For example:
++typedef PVScalarValue<boolean> PVBoolean; +typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr; +
Directory pvDataApp/pv has header files that completely describe pvData. The implementation is provided in directory pvDataApp/factory. Test programs appears in testApp/pv.
@@ -186,9 +808,9 @@ Test programs appears in testApp/pv.NOTES:
A PVStructure is a field that contains an array of subfields. Each field has code for accessing the field. The interface for each field is an interface that extends PVField. Each field also has an introspection interface, which an -extension of Field. This section describes the complete set of C++ +extension of Field. The next few sections describes the complete set of C++ introspection and data interfaces for pvData.
Class FieldCreate creates introspection objects. Class PVDataCreate creates @@ -217,15 +839,22 @@ copying data between fields.
This provides C/C++ definitions for the pvData primitive types: boolean, byte, short, int, long, ubyte,ushort, uint,u long,float, double, and string. @@ -234,11 +863,9 @@ proper semantics for the primitive types.
pvType.h provides the proper semantics.
-It has the definitions:
+It includes the definitions:
-typedef detail::pick_type<int8_t, signed char, - detail::pick_type<uint8_t, char, unsigned char>::type - >::type boolean; +typedef /*lots of stuff*/ boolean typedef int8_t int8; typedef int16_t int16; @@ -251,30 +878,19 @@ typedef uint64_t uint64; // float and double are types typedef std::string String; -/** - * A boolean array. - */ -typedef std::vector<uint8> BooleanArray; -typedef std::tr1::shared_ptr<BooleanArray> BooleanArrayPtr; -/* get is same is ubyte*/ -typedef std::vector<uint8>::iterator BooleanArray_iterator; -typedef std::vector<uint8>::const_iterator BooleanArray_const_iterator; +typedef std::vectorStringArray; +typedef std::tr1::shared_ptr StringArrayPtr; +inline String * get(StringArray &value); +inline String const * get(StringArray const &value); +inline String * get(StringArrayPtr &value); +inline String const * get(StringArrayPtr const &value); +} +inline StringArray & getVector(StringArrayPtr &value); +inline StringArray const & getVector(StringArrayPtr const &value); +typedef std::vector ::iterator StringArray_iterator; +typedef std::vector ::const_iterator StringArray_const_iterator; -/** - * A byte array. - */ -typedef std::vector<int8> ByteArray; -typedef std::tr1::shared_ptr<ByteArray> ByteArrayPtr; -inline int8 * get(ByteArray &value); -inline int8 const * get(ByteArray const &value); -inline int8 * get(ByteArrayPtr &value); -inline int8 const * get(ByteArrayPtr const &value); -inline ByteArray & getVector(ByteArrayPtr &value); -inline ByteArray const & getVector(ByteArrayPtr const &value); -typedef std::vector<int8>::iterator ByteArray_iterator; -typedef std::vector<int8>::const_iterator ByteArray_const_iterator; - -/* similar definitions are present for ALL the primitive types */ +typedef String * StringBuilder;
where
@@ -295,14 +911,16 @@ typedef std::vector<int8>::const_iterator ByteArray_const_iterator; copy on write semantics, it can be used for support for immutable strings. It can also be serialized/deserialized as a UTF8 encoded string. Because it is not a C++ primitive the first letter is capitalized. This - is the same convention the Java implementation uses. + is the same convention the Java implementation uses. + Note that string is treated like a primitive type. +TBD
This subsection describes pvIntrospect.h This file is quite big so rather than showing the entire file, it will be described in parts.
-A primary reason for pvData is to support network access to structured data. +
The primary purpose for pvData is to support network access to structured data. pvAccess transports top level pvStructures. In addition a pvAccess server holds -a set of pvnames, where each pvname if a unique name in the local network.
+a set of pvnames, where each name is a unique name in the local network. +This is also refered to as the channel name. + -Given a pvname PV), it is possible to introspect the field without requiring +
Given a pvname , it is possible to introspect the types of the associated data access to data. The reflection and data interfaces are separate because the -data may not be available. For example when a pvAccess client connects to a PV, +data may not be available. For example when a pvAccess client connects to a pvname, the client library can obtain the reflection information without obtaining any data. Only when a client issues an I/O request will data be available. This separation is especially important for arrays and structures so that a client can discover the type without requiring that a large data array or structure be transported over the network.
-Types are defined as:
enum Type {
scalar,
scalarArray,
structure,
- structureArray;
+ structureArray,
+ union_,
+ unionArray
};
class TypeFunc {
@@ -384,6 +1011,15 @@ public:
ScalarType is one of the following:
@@ -443,20 +1079,8 @@ public:TBD -
-String toString(ScalarType scalarType); --
This section describes the reflection interfaces which provide the following:
@@ -481,20 +1105,40 @@ following: Structure interspection interface. A pvAccess client can only get/put entire PVStructure elements NOT subfields of array elements.class Field;
class Scalar;
class ScalarArray;
class Structure;
class StructureArray;
+class Union;
+class UnionArray;
typedef std::tr1::shared_ptr<const Field> FieldConstPtr;
typedef std::vector<FieldConstPtr> FieldConstPtrArray;
@@ -502,6 +1146,8 @@ typedef std::tr1::shared_ptr<const Scalar> ScalarConstPtr;
typedef std::tr1::shared_ptr<const ScalarArray> ScalarArrayConstPtr;
typedef std::tr1::shared_ptr<const Structure> StructureConstPtr;
typedef std::tr1::shared_ptr<const StructureArray> StructureArrayConstPtr;
+typedef std::tr1::shared_ptr<const Union> UnionConstPtr;
+typedef std::tr1::shared_ptr<const UnionArray> UnionArrayConstPtr;
class Field :
@@ -584,28 +1230,51 @@ public:
...
};
-class FieldCreate {
+class epicsShareClass Union : public Field {
public:
- static FieldCreatePtr getFieldCreate();
- ScalarConstPtr createScalar(ScalarType scalarType) const
- ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
- StructureArrayConstPtr createStructureArray(StructureConstPtr const & structure) const;
- StructureConstPtr createStructure (
- StringArray const & fieldNames,
- FieldConstPtrArray const & fields) const;
- StructureConstPtr createStructure (
- String const &id,
- StringArray const & fieldNames,
- FieldConstPtrArray const & fields) const;
- FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
- ...
+ POINTER_DEFINITIONS(Union);
+ static epics::pvData::String DEFAULT_ID;
+ static epics::pvData::String ANY_ID;
+ virtual ~Union();
+ typedef Union& reference;
+ typedef const Union& const_reference;
+
+ std::size_t getNumberFields() const;
+ FieldConstPtr getField(String const &fieldName) const;
+ FieldConstPtr getField(std::size_t index);
+ std::size_t getFieldIndex(String const &fieldName) const;
+ FieldConstPtrArray const & getFields() const;
+ StringArray const & getFieldNames() const;
+ String getFieldName(std::size_t fieldIndex) const;
+ bool isVariant() const;
+ virtual void toString(StringBuilder buf) const;
+ virtual void toString(StringBuilder buf,int indentLevel) const;
+ virtual String getID() const;
+ virtual void serialize(
+ ByteBuffer *buffer, SerializableControl *control) const;
+ virtual void deserialize(
+ ByteBuffer *buffer, DeserializableControl *control);
+
};
-extern FieldCreatePtr getFieldCreate();
+class epicsShareClass UnionArray : public Field{
+public:
+ POINTER_DEFINITIONS(UnionArray);
+ typedef UnionArray& reference;
+ typedef const UnionArray& const_reference;
+ UnionConstPtr getUnion() const {return punion;}
+ virtual void toString(StringBuilder buf,int indentLevel=0) const;
+
+ virtual String getID() const;
+
+ virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+ virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
+};
+
+class epicsShareClass FieldBuilder :
+ public std::tr1::enable_shared_from_this<FieldBuilder>
+{
+public:
+ FieldBuilderPtr setId(std::string const & id);
+ FieldBuilderPtr add(std::string const & name, ScalarType scalarType);
+ FieldBuilderPtr add(std::string const & name, FieldConstPtr const & field);
+ FieldBuilderPtr addArray(std::string const & name, ScalarType scalarType);
+ FieldBuilderPtr addArray(std::string const & name, FieldConstPtr const & element);
+ StructureConstPtr createStructure();
+ UnionConstPtr createUnion();
+ FieldBuilderPtr addNestedStructure(std::string const & name);
+ FieldBuilderPtr addNestedUnion(std::string const & name);
+ FieldBuilderPtr addNestedStructureArray(std::string const & name);
+ FieldBuilderPtr addNestedUnionArray(std::string const & name);
+ FieldBuilderPtr endNested();
+};
-FieldCreate
+class epicsShareClass FieldCreate {
+public:
+ static FieldCreatePtr getFieldCreate();
+ FieldBuilderPtr createFieldBuilder() const;
+ ScalarConstPtr createScalar(ScalarType scalarType) const;
+ ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
+ StructureArrayConstPtr createStructureArray(StructureConstPtr const & structure) const;
+ StructureConstPtr createStructure () const;
+ StructureConstPtr createStructure (
+ StringArray const & fieldNames,
+ FieldConstPtrArray const & fields) const;
+ StructureConstPtr createStructure (
+ String const & id,
+ StringArray const & fieldNames,
+ FieldConstPtrArray const & fields) const;
+ UnionConstPtr createUnion (
+ StringArray const & fieldNames,
+ FieldConstPtrArray const & fields) const;
+ UnionConstPtr createUnion (
+ String const & id,
+ StringArray const & fieldNames,
+ FieldConstPtrArray const & fields) const;
+ UnionConstPtr createVariantUnion() const;
+ UnionArrayConstPtr createVariantUnionArray() const;
+ UnionArrayConstPtr createUnionArray(UnionConstPtr const & punion) const;
+ StructureConstPtr appendField(
+ StructureConstPtr const & structure,
+ String const & fieldName, FieldConstPtr const & field) const;
+ StructureConstPtr appendFields(
+ StructureConstPtr const & structure,
+ StringArray const & fieldNames,
+ FieldConstPtrArray const & fields) const;
+ FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
+
+};
+
+epicsShareExtern FieldCreatePtr getFieldCreate();
+
+
+This is a class that makes it easier to create introspection interfaces. +It is meant to be used via stream input syntax. See the examples that follow the +description of the methods. +
+A simple example is:
+
+StructureConstPtr structure =
+ getFieldCreate()->createFieldBuilder()->
+ setId("enum_t")->
+ add("index", pvDouble)->
+ addArray("choices", pvString)->
+ createStructure();
+String builder;
+structure->toString(&builder);
+cout << builder << endl;
+
+This produces:
++enum_t + double index + string[] choices ++
Another example is:
+
+StructureConstPtr enum_t =
+getFieldCreate()->createFieldBuilder()->
+ setId("enum_t")->
+ add("index", pvInt)->
+ addArray("choices", pvString)->
+ createStructure();
+
+StructureConstPtr ntEnum =
+getFieldCreate()->createFieldBuilder()->
+ setId("uri:ev4:nt/2012/pwd/NTEnum")->
+ add("value", enum_t)->
+ addNestedStructure("timeStamp")->
+ setId("time_t")->
+ add("secsPastEpoch", pvLong)->
+ add("nanoseconds", pvInt)->
+ add("userTag", pvInt)->
+ endNested()->
+ createStructure();
+builder.clear();
+ntEnum->toString(&builder);
+cout << builder << endl;
+
+This produces:
++uri:ev4:nt/2012/pwd/NTEnum + enum_t value + int index + string[] choices + time_t timeStamp + long secsPastEpoch + int nanoseconds + int userTag ++
The following example:
+
+ UnionConstPtr ntunion =
+ getFieldCreate()->createFieldBuilder()->
+ add("doubleValue", pvDouble)->
+ add("intValue", pvInt)->
+ addNestedStructure("timeStamp")->
+ setId("time_t")->
+ add("secsPastEpoch", pvLong)->
+ add("nanoseconds", pvInt)->
+ add("userTag", pvInt)->
+ endNested()->
+ createUnion();
+ builder.clear();
+ ntunion->toString(&builder);
+ cout << builder << endl;
+
+produces:
++union + double doubleValue + int intValue + time_t timeStamp + long secsPastEpoch + int nanoseconds + int userTag ++
A powerSupply structure can be created as follows:
+
+StructureConstPtr alarm = getStandardField()->alarm();
+StructureConstPtr timeStamp = getStandardField()->timeStamp();
+
+StructureConstPtr powerSupply =
+getFieldCreate()->createFieldBuilder()->
+ add("alarm_t",alarm) ->
+ add("timestamp_t",timeStamp) ->
+ addNestedStructure("power") ->
+ add("value",pvDouble) ->
+ add("alarm",alarm) ->
+ endNested()->
+ addNestedStructure("voltage") ->
+ add("value",pvDouble) ->
+ add("alarm",alarm) ->
+ endNested()->
+ addNestedStructure("current") ->
+ add("value",pvDouble) ->
+ add("alarm",alarm) ->
+ endNested()->
+ createStructure();
+builder.clear();
+powerSupply->toString(&builder);
+cout << builder << endl;
+
+produces:
++structure + alarm_t alarm_t + int severity + int status + string message + time_t timestamp_t + long secondsPastEpoch + int nanoSeconds + int userTag + structure power + double value + alarm_t alarm + int severity + int status + string message + structure voltage + double value + alarm_t alarm + int severity + int status + string message + structure current + double value + alarm_t alarm + int severity + int status + string message ++
TBD
The file standardField.h has a class description for creating or sharing Field objects for standard fields. For each type of field a method is provided. @@ -735,10 +1699,15 @@ public: static StandardFieldPtr getStandardField(); ~StandardField(); StructureConstPtr scalar(ScalarType type,String const &properties); + StructureConstPtr regUnion( + UnionConstPtr const & punion, + String const & properties); + StructureConstPtr variantUnion(String const & properties); StructureConstPtr scalarArray( ScalarType elementType, String const &properties); StructureConstPtr structureArray( StructureConstPtr const & structure,String const &properties); + StructureConstPtr unionArray(UnionConstPtr const & punion,String const & properties); StructureConstPtr enumerated(); StructureConstPtr enumerated(String const &properties); StructureConstPtr alarm(); @@ -765,6 +1734,16 @@ public: will be created with the first element being a scalar with the specified scalar type and name value. The other fields in the structure will be the corresponding property structures. +
TBD -
This subsection describes pvData.h This file is quite big so rather than +
This section describes pvData.h This file is quite big so rather than showing the entire file, it will be described in parts.
-These are typedefs for Array and Ptr for the various pvData class definitions, i.e. typdefs for "std::vector" and "std::tr1::shared_ptr".
@@ -846,6 +1823,20 @@ typedef std::tr1::shared_ptr<PVStructureArray> PVStructureArrayPtr; typedef std::vector<PVStructureArrayPtr> PVStructureArrayPtrArray; typedef std::tr1::shared_ptr<PVStructureArrayPtrArray> PVStructureArrayPtrArrayPtr; +typedef std::tr1::shared_ptr<PVUnion> PVUnionPtr; +typedef std::vector<PVUnionPtr> PVUnionPtrArray; +typedef std::vector<PVUnionPtr>::iterator PVUnionPtrArray_iterator; +typedef std::vector<PVUnionPtr>::const_iterator PVUnionPtrArray_const__iterator; + +typedef PVValueArray<PVUnionPtr> PVUnionArray; +typedef std::tr1::shared_ptr<PVUnionArray> PVUnionArrayPtr; +typedef std::vector<PVUnionArrayPtr> PVUnionArrayPtrArray; +typedef std::tr1::shared_ptr<PVUnionArrayPtrArray> PVUnionArrayPtrArrayPtr; + +class PVDataCreate; +typedef std::tr1::shared_ptr<PVDataCreate> PVDataCreatePtr; + + /** * typedefs for the various possible scalar types. */ @@ -902,18 +1893,9 @@ typedef std::tr1::shared_ptr<PVULongArray> PVULongArrayPtr; typedef std::tr1::shared_ptr<PVFloatArray> PVFloatArrayPtr; typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr; typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr; - -TBD -
PVField is the base interface for accessing data. A data structure consists of a top level PVStructure. Every field of every structure of every top level @@ -935,6 +1917,7 @@ public: POINTER_DEFINITIONS(PVField); virtual ~PVField(); String getFieldName() const ; + String getFullName() const; std::size_t getFieldOffset() const; std::size_t getNextFieldOffset() const; std::size_t getNumberFields() const; @@ -949,7 +1932,9 @@ public: virtual void toString(StringBuilder buf,int indentLevel); std::ostream& dumpValue(std::ostream& o) const; ... -} +} +std::ostream& operator<<(std::ostream& o, const PVField& f); +
The public methods for PVField are:
TBD
-virtual String toString() const; -virtual std::ostream& operator<<(std::ostream& o) const = 0; -+
This is the base class for all scalar data.
class PVScalar : public PVField {
@@ -1057,7 +2035,7 @@ uint32 val = pv->getAs();
The interfaces for primitive data types are:
template<typename T>
@@ -1082,12 +2060,39 @@ public:
...
}
+typedef PVScalarValue<boolean> PVBoolean;
+typedef PVScalarValue<int8> PVByte;
+typedef PVScalarValue<int16> PVShort;
+typedef PVScalarValue<int32> PVInt;
+typedef PVScalarValue<int64> PVLong;
+typedef PVScalarValue<uint8> PVUByte;
+typedef PVScalarValue<uint16> PVUShort;
+typedef PVScalarValue<uint32> PVUInt;
+typedef PVScalarValue<uint64> PVULong;
+typedef PVScalarValue<float> PVFloat;
+typedef PVScalarValue<double> PVDouble;
+typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
+typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
+typedef std::tr1::shared_ptr<PVShort> PVShortPtr;
+typedef std::tr1::shared_ptr<PVInt> PVIntPtr;
+typedef std::tr1::shared_ptr<PVLong> PVLongPtr;
+typedef std::tr1::shared_ptr<PVUByte> PVUBytePtr;
+typedef std::tr1::shared_ptr<PVUShort> PVUShortPtr;
+typedef std::tr1::shared_ptr<PVUInt> PVUIntPtr;
+typedef std::tr1::shared_ptr<PVULong> PVULongPtr;
+typedef std::tr1::shared_ptr<PVFloat> PVFloatPtr;
+typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;
+
+
// PVString is special case, since it implements SerializableArray
class PVString : public PVScalarValue<String>, SerializableArray {
public:
virtual ~PVString() {}
...
-};
+};
+
+
+
where
A PVUnion has a single subfield. +The Union introspection interface determines the possible +field types for the subfield. +If it is a varient union then any type is allowed and the +subfield name is normally any. +If it is not a varient union that the Union interface determines +the possible field types and names.
+
+class PVUnion : public PVField
+{
+public:
+ POINTER_DEFINITIONS(PVUnion);
+ virtual ~PVUnion();
+ UnionConstPtr getUnion() const;
+ PVFieldPtr get() const;
+
+ template<typename PVT>
+ std::tr1::shared_ptr<PVT> get() const {
+ return std::tr1::dynamic_pointer_cast<PVT>(get());
+ }
+
+ PVFieldPtr select(int32 index);
+
+ template<typename PVT>
+ std::tr1::shared_ptr<PVT> select(int32 index) {
+ return std::tr1::dynamic_pointer_cast<PVT>(select(index));
+ }
+
+ PVFieldPtr select(String const & fieldName);
+
+ template<typename PVT>
+ std::tr1::shared_ptr<PVT> select(String const & fieldName) {
+ return std::tr1::dynamic_pointer_cast<PVT>(select(fieldName));
+ }
+
+ int32 getSelectedIndex() const;
+ String getSelectedFieldName() const;
+ void set(PVFieldPtr const & value);
+ void set(int32 index, PVFieldPtr const & value);
+ void set(String const & fieldName, PVFieldPtr const & value);
+ virtual void serialize(
+ ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
+ PVUnion(UnionConstPtr const & punion);
+};
+
+PVArray is the base interface for all the other PV Array interfaces. It extends PVField and provides the additional methods:
@@ -1188,15 +2263,10 @@ public:TBD -
PVScalarArray is the base class for scalar array data. PVValueArray is a templete for the various scalar array data classes. There is a class for each @@ -1210,10 +2280,13 @@ public: typedef const PVScalarArray& const_reference; const ScalarArrayConstPtr getScalarArray() const ; + template<typename T> void getAs(shared_vector<const T>& out) const + template<typename T> void putFrom(const shared_vector<const T>& inp) + void assign(PVScalarArray& pv); ... } @@ -1242,7 +2315,77 @@ public: -
The interface for a structure is:
+class PVStructure : public PVField,public BitSetSerializable {
+public:
+ POINTER_DEFINITIONS(PVStructure);
+ virtual ~PVStructure();
+ typedef PVStructure & reference;
+ typedef const PVStructure & const_reference;
+
+ virtual void setImmutable();
+ StructureConstPtr getStructure() const;
+ const PVFieldPtrArray & getPVFields() const;
+ PVFieldPtr getSubField(String const &fieldName) const;
+
+ template<typename PVT>
+ std::tr1::shared_ptr<PVT> getSubField(String const &fieldName) const
+
+ PVFieldPtr getSubField(std::size_t fieldOffset) const;
+
+ template<typename PVT>
+ std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const
+
+ virtual void serialize(
+ ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
+ virtual void deserialize(
+ ByteBuffer *pbuffer,DeserializableControl *pflusher);
+ virtual void serialize(ByteBuffer *pbuffer,
+ SerializableControl *pflusher,BitSet *pbitSet) const;
+ virtual void deserialize(ByteBuffer *pbuffer,
+ DeserializableControl*pflusher,BitSet *pbitSet);
+ PVStructure(StructureConstPtr const & structure);
+ PVStructure(StructureConstPtr const & structure,PVFieldPtrArray const & pvFields);
+ virtual std::ostream& dumpValue(std::ostream& o) const;
+};
+
+where
+TBD +
This is a template class plus instances for PVBooleanArray, ..., PVStringArray.
@@ -1296,129 +2439,7 @@ public: -The interface for a structure is:
-class PVStructure : public PVField,public BitSetSerializable {
-public:
- POINTER_DEFINITIONS(PVStructure);
- virtual ~PVStructure();
- typedef PVStructure & reference;
- typedef const PVStructure & const_reference;
-
- virtual void setImmutable();
- StructureConstPtr getStructure() const;
- const PVFieldPtrArray & getPVFields() const;
- PVFieldPtr getSubField(String const &fieldName) const;
- PVFieldPtr getSubField(std::size_t fieldOffset) const;
- PVBooleanPtr getBooleanField(String const &fieldName) ;
- PVBytePtr getByteField(String const &fieldName) ;
- PVShortPtr getShortField(String const &fieldName) ;
- PVIntPtr getIntField(String const &fieldName) ;
- PVLongPtr getLongField(String const &fieldName) ;
- PVUBytePtr getUByteField(String const &fieldName) ;
- PVUShortPtr getUShortField(String const &fieldName) ;
- PVUIntPtr getUIntField(String const &fieldName) ;
- PVULongPtr getULongField(String const &fieldName) ;
- PVFloatPtr getFloatField(String const &fieldName) ;
- PVDoublePtr getDoubleField(String const &fieldName) ;
- PVStringPtr getStringField(String const &fieldName) ;
- PVStructurePtr getStructureField(String const &fieldName) ;
- PVScalarArrayPtr getScalarArrayField(
- String const &fieldName,ScalarType elementType) ;
- PVStructureArrayPtr getStructureArrayField(String const &fieldName) ;
- virtual void serialize(
- ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
- virtual void deserialize(
- ByteBuffer *pbuffer,DeserializableControl *pflusher);
- virtual void serialize(ByteBuffer *pbuffer,
- SerializableControl *pflusher,BitSet *pbitSet) const;
- virtual void deserialize(ByteBuffer *pbuffer,
- DeserializableControl*pflusher,BitSet *pbitSet);
- PVStructure(StructureConstPtr const & structure);
- PVStructure(StructureConstPtr const & structure,PVFieldPtrArray const & pvFields);
- virtual std::ostream& dumpValue(std::ostream& o) const;
-};
-
-where
-TBD -
The interface for an array of structures is:
@@ -1481,28 +2502,110 @@ public:
done there are no null elements.
-The other methods are similar to the methods for other array types.
+The other methods are similar to the methods for other array types.
+ See PVArray above for details.
-PVDataCreate
+PVUnionArray
+The interface for an array of unions is:
+
+template&ly;>
+class epicsShareClass PVValueArray&ly;PVUnionPtr> : public detail::PVVectorStorage&ly;PVUnionPtr,PVArray>
+{
+ typedef detail::PVVectorStorage&ly;PVUnionPtr,PVArray> base_t;
+public:
+ POINTER_DEFINITIONS(PVUnionArray);
+ typedef PVUnionPtr value_type;
+ typedef PVUnionPtr* pointer;
+ typedef const PVUnionPtr* const_pointer;
+ typedef PVUnionArray &reference;
+ typedef const PVUnionArray& const_reference;
+
+ //TODO: full namespace can be removed along with local typedef 'shared_vector'
+ typedef ::epics::pvData::shared_vector&ly;PVUnionPtr> svector;
+ typedef ::epics::pvData::shared_vector&ly;const PVUnionPtr> const_svector;
+
+ virtual ~PVValueArray() {}
+
+ virtual size_t getLength() const;
+ virtual size_t getCapacity() const;
+ virtual void setCapacity(size_t capacity);
+ virtual void setLength(std::size_t length);
+ UnionArrayConstPtr getUnionArray() const;
+ virtual std::size_t append(std::size_t number);
+ virtual bool remove(std::size_t offset,std::size_t number);
+ virtual void compress();
+ virtual const_svector view() const;
+ virtual void swap(const_svector &other);
+ virtual void replace(const const_svector &other);
+ virtual void serialize(ByteBuffer *pbuffer,
+ SerializableControl *pflusher) const;
+ virtual void deserialize(ByteBuffer *buffer,
+ DeserializableControl *pflusher);
+ virtual void serialize(ByteBuffer *pbuffer,
+ SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
+ virtual std::ostream& dumpValue(std::ostream& o) const;
+ virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
+};
+
+where
+The other methods are similar to the methods for other array types. + See PVArray above for details.
+ +PVDataCreate is an interface that provides methods that create PVField interfaces. A factory is provided that creates PVDataCreate.
class PVDataCreate {
public:
static PVDataCreatePtr getPVDataCreate();
+
PVFieldPtr createPVField(FieldConstPtr const & field);
PVFieldPtr createPVField(PVFieldPtr const & fieldToClone);
+
PVScalarPtr createPVScalar(ScalarConstPtr const & scalar);
PVScalarPtr createPVScalar(ScalarType scalarType);
PVScalarPtr createPVScalar(PVScalarPtr const & scalarToClone);
+ template<typename PVT>
+ std::tr1::shared_ptr<PVT> createPVScalar();
+
+ PVStructurePtr createPVStructure(
+ StringArray const & fieldNames,PVFieldPtrArray const & pvFields);
+ PVStructurePtr createPVStructure(PVStructurePtr const & structToClone);
+ PVStructurePtr createPVStructure(StructureConstPtr const & structure);
+
+ PVUnionPtr createPVUnion(UnionConstPtr const & punion);
+ PVUnionPtr createPVUnion(PVUnionPtr const & unionToClone);
+ PVUnionPtr createPVVariantUnion();
+
PVScalarArrayPtr createPVScalarArray(ScalarArrayConstPtr const & scalarArray);
PVScalarArrayPtr createPVScalarArray(ScalarType elementType);
PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const & scalarArrayToClone);
+ template<typename PVAT>
+ std::tr1::shared_ptr<PVAT> createPVScalarArray();
+
PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const & structureArray);
- PVStructurePtr createPVStructure(StructureConstPtr const & structure);
- PVStructurePtr createPVStructure(
- StringArray const & fieldNames,PVFieldPtrArray const & pvFields);
- PVStructurePtr createPVStructure(PVStructurePtr const & structToClone);
+ PVStructureArrayPtr createPVStructureArray(StructureConstPtr const ∓ structure);
+
+ PVUnionArrayPtr createPVUnionArray(UnionArrayConstPtr const & unionArray);
+ PVUnionArrayPtr createPVUnionArray(UnionConstPtr const & punion);
+ PVUnionArrayPtr createPVVariantUnionArray();
...
};
@@ -1510,37 +2613,73 @@ extern PVDataCreatePtr getPVDataCreate();
where
+PVDoublePtr pvDouble = getPVDataCreate()->createPVScalar<PVDouble>(); ++
+PVDoubleArrayPtr pvDoubleArray = getPVDataCreate()->createPVScalarArray<PVDoubleArray>(); ++
A class StandardPVField has methods for creating standard data fields. Like class StandardField it has two forms of the methods which create a field, one @@ -1558,6 +2697,7 @@ public: PVStructurePtr scalar(ScalarType type,String const &properties); PVStructurePtr scalarArray(ScalarType elementType, String const &properties); PVStructurePtr structureArray(StructureConstPtr const &structure,String const &properties); + PVStructurePtr unionArray(UnionConstPtr const &punion,String const &properties); PVStructurePtr enumerated(StringArray const &choices); PVStructurePtr enumerated(StringArray const &choices, String const &properties); ... @@ -1566,7 +2706,7 @@ public: extern StandardPVFieldPtr getStandardPVField(); -
There are two facilities for converting between two different PVData objects:
NOTE about copying immutable array fields. If an entire immutable array field is copied to another array that has the same elementType, both offsets @@ -1599,13 +2739,11 @@ Thus the source and target share the same primitive array.
newLine is a convenience method for code that implements toString It generates a newline and inserts blanks at the beginning of the newline.
-
template<typename T>
void copy(
@@ -2497,77 +3641,6 @@ public:
structure.
-Examples
-
-Accessing PVData
-
-Assume that code wants to print two fields from a PVStructure:
-The following code uses introspection to get the desired information.
-void getValueAndTimeStamp(PVStructurePtr pvStructure,StringBuilder buf) {
- PVFieldPtr valuePV = pvStructure->getSubField(String("value"));
- if(valuePV.get()==NULL) {
- buf += "value field not found";
- return;
- }
- buf += "value ";
- valuePV->toString(&buf);
- PVFieldPtr timeStampPV = pvStructure->getSubField(String("timeStamp"));
- if(timeStampPV.get()==NULL) {
- buf += "timeStamp field not found";
- return;
- }
- buf += " timeStamp ";
- timeStampPV->toString(&buf);
-}
-
-Example of creating a scalar field.
-PVDataCreatePtr pvDataCreate = getPVDataCreate(); - PVDoublePtr pvValue = static_pointer_cast<PVDouble>( - pvDataCreate->createPVScalar(pvDouble));- -
Create a structure with a value and an alarm the hard way
-FieldCreatePtr fieldCreate = getFieldCreate(); - PVDataCreatePtr pvDataCreate = getPVDataCreate(); - FieldConstPtrArray fields; - StringArray names; - fields.resize(3); - names.resize(3); - fields[0] = fieldCreate->createScalar(pvInt); - fields[1] = fieldCreate->createScalar(pvInt); - fields[2] = fieldCreate->createScalar(pvString); - names[0] = "severity"; - names[0] = "status"; - names[0] = "message"; - StructureConstPtr alarmField = - fieldCreate->createStructure(names,fields); - fields.resize(2); - names.resize(2); - fields[0] = fieldCreate->createScalar(pvDouble); - fields[1] = alarmField; - names[0] = "value"; - names[0] = "alarm"; - StructureConstPtr structure = - fieldCreate->createStructure(names,fields); - PVStructurePtr pv = pvDataCreate->createPVStructure(structure);- -
Create an alarm structure the easy way.
-StandardPVFieldPtr standardPVField = getStandardPVField(); - PVStructurePtr pv = standardPVField->scalar(pvDouble,"alarm");- -
Create a PVStructure with field name example that has a double value field , -timeStamp, alarm, and display. Do it the easy way.
-StandardPVFieldPtr standardPVField = getStandardPVField(); - PVStructurePtr pvStructure = standardPVField->scalar( - pvDouble,"timeStamp,alarm.display");
TBD
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);
+ }
+}
+
+
+