diff --git a/documentation/pvDataCPP.html b/documentation/pvDataCPP.html index c430a2c..dc7e2ea 100644 --- a/documentation/pvDataCPP.html +++ b/documentation/pvDataCPP.html @@ -37,7 +37,7 @@
This is the 08-Oct-2014 version of the C++ implementation of pvData. +
This is the 10-Nov-2014 version of the C++ implementation of pvData.
RELEASE_NOTES.md provides changes since the last release. diff --git a/documentation/pvDataCPP_20141110.html b/documentation/pvDataCPP_20141110.html new file mode 100644 index 0000000..dc7e2ea --- /dev/null +++ b/documentation/pvDataCPP_20141110.html @@ -0,0 +1,5478 @@ + + + +
+ +This product is made available subject to acceptance of the EPICS open source +license.
+EPICS Version 4 provides efficient
+storage, access, and communication, of memory resident structured data.
+pvData is the storage component.
+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:
+relatedDocumentsV4.html
+
This is the 10-Nov-2014 version of the C++ implementation of pvData. +
+ +RELEASE_NOTES.md provides changes since the last release. +TODO.md describes things to do before the next release. +
+ + + +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 familiar with project pvAccess, which is +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:
+The material in these two chapters is NOT repeated in this documentation.
+ +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:
++cd examples/configure +cp ExampleRELEASE.local RELEASE.local +#edit RELEASE.local +cd .. +make ++Now you are ready to run the examples: +
+bin/linux-x86_64/introspectMain +bin/linux-x86_64/dataMain ++
The examples assume that the following statements have been issued:
++using std::cout; +using std::endl; +FieldCreatePtr fieldCreate = getFieldCreate(); +PVDataCreatePtr pvDataCreate = getPVDataCreate(); +StandardFieldPtr standardField = getStandardField(); +StandardPVFieldPtr standardPVField = getStandardPVField(); ++
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("secondsPastEpoch");
+ 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);
+ cout << *doubleScalar << endl;
+
+Using FieldBuilder the same can be done via:
+
+ StructureConstPtr doubleScalarHard =
+ getFieldCreate()->createFieldBuilder()->
+ add("value",pvDouble) ->
+ addNestedStructure("timeStamp")->
+ setId("time_t")->
+ add("secondsPastEpoch", pvLong)->
+ add("nanoseconds", pvInt)->
+ add("userTag", pvInt)->
+ endNested()->
+ createStructure();
+ cout << *doubleScalarHard << endl;
+
+The easiest way to produce the structure is:
++ StructureConstPtr stringArrayEasy = + getStandardField()->scalarArray(pvString,"alarm,timeStamp"); + cout << *stringArrayEasy << "\n\n"; ++These three ways produce: +
+hardest way +structure + double value + structure timeStamp + long secsPastEpoch + int nanoseconds + int userTag + +hard way +structure + double value + time_t timeStamp + long secsPastEpoch + int nanoseconds + int userTag + +easy way +epics:nt/NTScalarArray:1.0 + string[] value + alarm_t alarm + int severity + int status + string message + time_t timeStamp + long secondsPastEpoch + int nanoseconds + int userTag ++
An easy way to create a structure with a string array value field and an alarm and time stamp is +via standardField:
++ StructureConstPtr stringArrayEasy = + standardField->scalarArray(pvString,"alarm,timeStamp"); + cout << *stringArrayEasy << endl; ++It produces : +
+epics:nt/NTScalarArray:1.0 + string[] value + alarm_t alarm + int severity + int status + string message + time_t timeStamp + long secondsPastEpoch + int nanoseconds + int userTag +0x607188 ++
An enumerated structure is a structure with two subfields: +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 =
+ fieldCreate->createFieldBuilder()->
+ setId("enum_t")->
+ add("index", pvInt)->
+ addArray("choices", pvString)->
+ createStructure();
+
+ StructureConstPtr ntEnumHard =
+ fieldCreate->createFieldBuilder()->
+ setId("epics:nt/NTEnum:1.0")->
+ add("value", enum_t)->
+ addNestedStructure("timeStamp")->
+ setId("time_t")->
+ add("secondsPastEpoch", pvLong)->
+ add("nanoseconds", pvInt)->
+ add("userTag", pvInt)->
+ endNested()->
+ createStructure();
+ cout << *ntEnumHard << endl;
+
+It produces:
++epics:nt/NTEnum:1.0 + enum_t value + int index + string[] choices + time_t timeStamp + long secondsPastEpoch + 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");
+ cout << *ntEnumEasy << endl;
+
+It produces:
++epics:nt/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 =
+ fieldCreate->createFieldBuilder()->
+ add("doubleValue", pvDouble)->
+ add("intValue", pvInt)->
+ add("timeStamp",standardField->timeStamp())->
+ createUnion();
+ cout << *ntunion << endl;
+
+ StructureConstPtr unionValue = standardField->regUnion(punion,"alarm,timeStamp");
+ cout << *unionValue << endl;
+
+It produces:
++union + double doubleValue + int intValue + time_t timeStamp + long secondsPastEpoch + int nanoseconds + int userTag + +structure with value field being a union +epics:nt/NTUnion:1.0 + 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:
++ UnionArrayConstPtr unionArray = fieldCreate->createUnionArray( + fieldCreate->createVariantUnion()); + cout << *unionArray << "\n\n"; ++
Produces
++any[] +any +0x607188 ++
The following creates a more complex structure:
+
+ StructureConstPtr powerSupply =
+ fieldCreate->createFieldBuilder()->
+ add("alarm",standardField->alarm()) ->
+ add("timestamp",standardField->timeStamp()) ->
+ addNestedStructure("power") ->
+ add("value",pvDouble) ->
+ add("alarm",standardField->alarm()) ->
+ endNested()->
+ addNestedStructure("voltage") ->
+ add("value",pvDouble) ->
+ add("alarm",standardField->alarm()) ->
+ endNested()->
+ addNestedStructure("current") ->
+ add("value",pvDouble) ->
+ add("alarm",standardField->alarm()) ->
+ endNested()->
+ createStructure();
+ std::cout << *powerSupply <<std::endl;
+
+It produces:
++structure + alarm_t alarm + int severity + int status + string message + time_t timestamp + 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 << endl;
+ double value = doubleValue->getSubField<PVDouble>("value")->get();
+ cout << "from get " << value << "\n\n";
+
+This produces:
++epics:nt/NTScalar:1.0 + 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 +from get 100000 ++
+ PVStructurePtr doubleArrayValue = pvDataCreate->createPVStructure(
+ standardField->scalarArray(pvDouble,"alarm,timeStamp"));
+ PVDoubleArrayPtr pvDoubleArray =
+ 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 << 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:
++epics:nt/NTScalarArray:1.0 + 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 = pvDataCreate->createPVStructure(
+ standardField->enumerated("alarm,timeStamp"));
+ cout << *pvntenum << "\n\n";
+
+This produces:
++epics:nt/NTEnum:1.0 + 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 =
+ fieldCreate->createFieldBuilder()->
+ add("alarm",alarm) ->
+ add("timestamp",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 = pvDataCreate->createPVStructure(powerSupply);
+ cout << *pvpowerSupply << 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(
+ fieldCreate->createFieldBuilder()->
+ add("doubleValue", pvDouble)->
+ add("intValue", pvInt)->
+ add("timeStamp",standardField->timeStamp())->
+ createUnion(),
+ "alarm,timeStamp"));
+ PVStructurePtr pvTimeStamp =
+ pvStructure->getSubField<PVUnion>("value")->select<PVStructure>(2);
+ pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000);
+ cout << *pvStructure) << "\n";
+ pvStructure->getSubField<PVUnion>("value")->select<PVDouble>(0)->put(1e5);
+ cout << *pvStructure << "\n\n";
+
+This produces:
++epics:nt/NTUnion:1.0 + 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 +epics:nt/NTUnion:1.0 + 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 << "\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 << "\n\n";
+
+This produces:
++epics:nt/NTUnion:1.0 + 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 +epics:nt/NTUnion:1.0 + 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(
+ fieldCreate->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"));
+ cout << "introspection\n";
+ cout << *pvStructure->getStructure() << endl;
+ cout << "data\n";
+ cout << *pvStructure << "\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 << "\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 << "\n";
+ cout << "value = " << pvDouble->get() << "\n";
+
+This produces:
++introspection +epics:nt/NTUnion:1.0 + 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 +0x60a2c8 +data +epics:nt/NTUnion:1.0 + 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 +epics:nt/NTUnion:1.0 + 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 +epics:nt/NTUnion:1.0 + 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 ++ +
All code in project pvDataCPP appears in namespace:
+namespace epics { namespace pvData {
+ // ...
+}}
+
+Many pvDataCPP introspection and data objects are designed to be shared. They are +made available via std::tr1::shared_ptr. +The following naming convention is used +in typedefs:
+For example:
++typedef PVScalarValue<boolean> PVBoolean; +typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr; ++ +
Directory src/pv has header files that completely describe pvData. +The implementation is provided in directory src/factory. +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. The next few sections describes the complete set of C++ +introspection and data interfaces for pvData.
+ +Class FieldCreate creates introspection objects. Class PVDataCreate creates +data objects. Class Convert provides a rich set of methods for converting and +copying data between fields.
+ +Directory src/pv has the following header files:
+This provides C/C++ definitions for the pvData primitive types: boolean, +byte, short, int, long, ubyte, ushort, uint, ulong, float, double, and string. +Because pvData is network data, the C++ implementation must implement the +proper semantics for the primitive types.
+ +pvType.h provides the proper semantics.
+ +It includes the definitions:
++typedef /*lots of stuff*/ boolean + +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; +// float and double are types + +typedef std::vector<std::string> StringArray; +typedef std::tr1::shared_ptr<StringArray> StringArrayPtr; +inline std::string * get(StringArray &value); +inline std::string const * get(StringArray const &value); +inline std::string * get(StringArrayPtr &value); +inline std::string const * get(StringArrayPtr const &value); +} +inline StringArray & getVector(StringArrayPtr &value); +inline StringArray const & getVector(StringArrayPtr const &value); +typedef std::vector<std::string>::iterator StringArray_iterator; +typedef std::vector<std::string>::const_iterator StringArray_const_iterator; ++ +
where
+TBD
++typedef uint8_t boolean; ++
This subsection describes pvIntrospect.h This file is quite big so rather +than showing the entire file, it will be described in parts.
+ +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 name is a unique name in the local network. +This is also referred to as the channel name. +
+ +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 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,
+ union_,
+ unionArray
+};
+
+class TypeFunc {
+public:
+ epicsShareExtern const char* name(Type type);
+};
+
+enum ScalarType {
+ pvBoolean,
+ pvByte, pvShort, pvInt, pvLong,
+ pvUByte, pvUShort, pvUInt, pvULong,
+ pvFloat,pvDouble,
+ pvString;
+};
+
+namespace ScalarTypeFunc {
+public:
+ bool isInteger(ScalarType type);
+ bool isUInteger(ScalarType type);
+ bool isNumeric(ScalarType type);
+ bool isPrimitive(ScalarType type);
+ ScalarType getScalarType(std::string const &value);
+ const char* name(ScalarType);
+ size_t elementSize(ScalarType id);
+};
+std::ostream& operator<<(std::ostream& o, const ScalarType& scalarType);
+
+
+Type is one of the following:
+ScalarType is one of the following:
+TypeFunction is a set of convenience methods for Type
+ScalarTypeFunction is a set of convenience methods for ScalarType
+This section describes the reflection interfaces which provide the +following:
+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;
+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 :
+ virtual public Serializable,
+ public std::tr1::enable_shared_from_this<Field>
+{
+public:
+ POINTER_DEFINITIONS(Field);
+ virtual ~Field();
+ Type getType() const{return m_type;}
+ virtual std::string getID() const = 0;
+ virtual std::ostream& dump(std::ostream& o) const = 0;
+ ...
+};
+std::ostream& operator<<(std::ostream& o, const Field& field);
+
+class Scalar : public Field{
+public:
+ POINTER_DEFINITIONS(Scalar);
+ virtual ~Scalar();
+ typedef Scalar& reference;
+ typedef const Scalar& const_reference;
+
+ ScalarType getScalarType() const {return scalarType;}
+ virtual std::string getID() const;
+ virtual std::ostream& dump(std::ostream& o) const;
+ virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+ virtual void deserialize(ByteBuffer *buffer, DeserializableContol *control);
+ ...
+};
+
+class BoundedString : public Scalar{
+public:
+ POINTER_DEFINITIONS(BoundedString);
+ virtual ~BoundedString();
+ typedef BoundedString& reference;
+ typedef const BoundedString& const_reference;
+
+ std::size_t getMaximumLength() const;
+ virtual std::string getID() const;
+ virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+...
+};
+
+class epicsShareClass Array : public Field{
+public:
+ POINTER_DEFINITIONS(Array);
+ virtual ~Array();
+ typedef Array& reference;
+ typedef const Array& const_reference;
+ enum ArraySizeType { variable, fixed, bounded };
+
+ virtual ArraySizeType getArraySizeType() const = 0;
+ virtual std::size_t getMaximumCapacity() const = 0;
+ ...
+};
+
+
+class ScalarArray : public Field{
+public:
+ POINTER_DEFINITIONS(ScalarArray);
+ typedef ScalarArray& reference;
+ typedef const ScalarArray& const_reference;
+
+ ScalarArray(ScalarType scalarType);
+ ScalarType getElementType() const {return elementType;}
+ virtual ArraySizeType getArraySizeType() const;
+ virtual std::size_t getMaximumCapacity() const;
+ virtual std::string getID() const;
+ virtual std::ostream& dump(std::ostream& o) const;
+ virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+ virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
+ ...
+};
+
+class epicsShareClass BoundedScalarArray : public ScalarArray{
+public:
+ POINTER_DEFINITIONS(BoundedScalarArray);
+ typedef BoundedScalarArray& reference;
+ typedef const BoundedScalarArray& const_reference;
+
+ BoundedScalarArray(ScalarType scalarType, std::size_t size);
+ virtual ArraySizeType getArraySizeType() const;
+ virtual std::size_t getMaximumCapacity() const;
+ virtual std::string getID() const;
+ virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+...
+}
+
+class epicsShareClass FixedScalarArray : public ScalarArray{
+public:
+ POINTER_DEFINITIONS(FixedScalarArray);
+ typedef FixedScalarArray& reference;
+ typedef const FixedScalarArray& const_reference;
+
+ FixedScalarArray(ScalarType scalarType, std::size_t size);
+ virtual ArraySizeType getArraySizeType() const {return Array::fixed;}
+ virtual std::size_t getMaximumCapacity() const {return size;}
+ virtual std::string getID() const;
+ virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+...
+};
+
+
+
+class StructureArray : public Field{
+public:
+ POINTER_DEFINITIONS(StructureArray);
+ typedef StructureArray& reference;
+ typedef const StructureArray& const_reference;
+
+ StructureConstPtr getStructure() const {return pstructure;}
+ virtual ArraySizeType getArraySizeType() const;
+ virtual std::size_t getMaximumCapacity() const;
+ virtual std::string getID() const;
+ virtual std::ostream& dump(std::ostream& o) const;
+ virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+ virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
+ ...
+};
+
+class epicsShareClass UnionArray : public Field{
+public:
+ POINTER_DEFINITIONS(UnionArray);
+ typedef UnionArray& reference;
+ typedef const UnionArray& const_reference;
+ UnionConstPtr getUnion() const {return punion;}
+ virtual ArraySizeType getArraySizeType() const;
+ virtual std::size_t getMaximumCapacity() const;
+ virtual std::string getID() const;
+ virtual std::ostream& dump(std::ostream& o) const;
+ virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+ virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
+};
+
+class Structure : public Field {
+public:
+ POINTER_DEFINITIONS(Structure);
+ typedef Structure& reference;
+ typedef const Structure& const_reference;
+
+ std::size_t getNumberFields() const {return numberFields;}
+ FieldConstPtr getField(std::string const & fieldName) const;
+ FieldConstPtr getField(std::size_t index) const;
+ std::size_t getFieldIndex(std::string const &fieldName) const;
+ FieldConstPtrArray const & getFields() const {return fields;}
+ StringArray const & getFieldNames() const;
+ std::string getFieldName(std::size_t fieldIndex) const;
+ virtual std::string getID() const;
+ virtual std::ostream& dump(std::ostream& o) const;
+ virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+ virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
+ ...
+};
+
+class epicsShareClass Union : public Field {
+public:
+ POINTER_DEFINITIONS(Union);
+ static std::string DEFAULT_ID;
+ static std::string ANY_ID;
+ virtual ~Union();
+ typedef Union& reference;
+ typedef const Union& const_reference;
+
+ std::size_t getNumberFields() const;
+ FieldConstPtr getField(std::string const &fieldName) const;
+ FieldConstPtr getField(std::size_t index);
+ std::size_t getFieldIndex(std::string const &fieldName) const;
+ FieldConstPtrArray const & getFields() const;
+ StringArray const & getFieldNames() const;
+ std::string getFieldName(std::size_t fieldIndex) const;
+ bool isVariant() const;
+ virtual std::string getID() const;
+ virtual std::ostream& dump(std::ostream& o) 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 addBoundedString(std::string const & name, std::size_t maxLength);
+ FieldBuilderPtr add(std::string const & name, FieldConstPtr const & field);
+ FieldBuilderPtr addArray(std::string const & name, ScalarType scalarType);
+ FieldBuilderPtr addFixedArray(
+ std::string const & name,
+ ScalarType scalarType,
+ std::size_t size);
+ FieldBuilderPtr addBoundedArray(std::string const &
+ name,ScalarType scalarType,
+ std::size_t bound);
+ 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();
+};
+
+class epicsShareClass FieldCreate {
+public:
+ static FieldCreatePtr getFieldCreate();
+ FieldBuilderPtr createFieldBuilder() const;
+ ScalarConstPtr createScalar(ScalarType scalarType) const;
+ BoundedStringConstPtr createBoundedString(std::size_t maxLength) const;
+ ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
+ ScalarArrayConstPtr createFixedScalarArray(
+ ScalarType elementType, std::size_t size) const
+ ScalarArrayConstPtr createBoundedScalarArray(
+ ScalarType elementType, std::size_t bound) const;
+ StructureArrayConstPtr createStructureArray(
+ StructureConstPtr const & structure) const;
+ StructureConstPtr createStructure () const;
+ StructureConstPtr createStructure (
+ StringArray const & fieldNames,
+ FieldConstPtrArray const & fields) const;
+ StructureConstPtr createStructure (
+ std::string const & id,
+ StringArray const & fieldNames,
+ FieldConstPtrArray const & fields) const;
+ UnionConstPtr createUnion (
+ StringArray const & fieldNames,
+ FieldConstPtrArray const & fields) const;
+ UnionConstPtr createUnion (
+ std::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,
+ std::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. +
+Examples of using fieldBuilder were given earlier in this manual.
+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. +Each creates a structure that has a field named "value" and a set of properyt +fields, The property field is a comma separated string of property names of the +following: alarm, timeStamp, display, control, and valueAlarm. An example is +"alarm,timeStamp,valueAlarm". The method with properties creates a structure +with fields named value and each of the property names. Each property field is +a structure defining the property. The details about each property is given in +the section named "Property". For example the call:
++StructureConstPtr example = standardField->scalar( + pvDouble, + "value,alarm,timeStamp" + ); ++ +
Will result in a Field definition that has the form:
+structure example + double value + alarm_t alarm + int severity + int status + string message + timeStamp_t timeStamp + long secondsPastEpoch + int nanoseconds + int userTag+ +
In addition there are methods that create each of the property structures, +i.e. the methods named: alarm, .... enumeratedAlarm."
+ +standardField.h contains:
+class StandardField;
+typedef std::tr1::shared_ptr<StandardField> StandardFieldPtr;
+
+class StandardField {
+public:
+ static StandardFieldPtr getStandardField();
+ ~StandardField();
+ StructureConstPtr scalar(ScalarType type,std::string const &properties);
+ StructureConstPtr regUnion(
+ UnionConstPtr const & punion,
+ std::string const & properties);
+ StructureConstPtr variantUnion(std::string const & properties);
+ StructureConstPtr scalarArray(
+ ScalarType elementType, std::string const &properties);
+ StructureConstPtr structureArray(
+ StructureConstPtr const & structure,std::string const &properties);
+ StructureConstPtr unionArray(UnionConstPtr const & punion,std::string const & properties);
+ StructureConstPtr enumerated();
+ StructureConstPtr enumerated(std::string const &properties);
+ StructureConstPtr alarm();
+ StructureConstPtr timeStamp();
+ StructureConstPtr display();
+ StructureConstPtr control();
+ StructureConstPtr booleanAlarm();
+ StructureConstPtr byteAlarm();
+ StructureConstPtr ubyteAlarm();
+ StructureConstPtr shortAlarm();
+ StructureConstPtr ushortAlarm();
+ StructureConstPtr intAlarm();
+ StructureConstPtr uintAlarm();
+ StructureConstPtr longAlarm();
+ StructureConstPtr ulongAlarm();
+ StructureConstPtr floatAlarm();
+ StructureConstPtr doubleAlarm();
+ StructureConstPtr enumeratedAlarm();
+ ...
+};
+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. typedefs for "std::vector" and "std::tr1::shared_ptr".
++class PVField; +class PVScalar; +class PVScalarArray; +class PVStructure; +class PVStructureArray; +class PVUnion; + +template<typename T> class PVScalarValue; +template<typename T> class PVValueArray; + +typedef PVValueArray<PVUnionPtr> PVUnionArray; +typedef std::tr1::shared_ptr<PVUnionArray> PVUnionArrayPtr; + + +typedef std::tr1::shared_ptr<PostHandler> PostHandlerPtr; + +typedef std::tr1::shared_ptr<PVField> PVFieldPtr; +typedef std::vector<PVFieldPtr> PVFieldPtrArray; +typedef std::vector<PVFieldPtr>::iterator PVFieldPtrArray_iterator; +typedef std::vector<PVFieldPtr>::const_iterator PVFieldPtrArray_const__iterator; + +typedef std::tr1::shared_ptr<PVScalar> PVScalarPtr; +typedef std::tr1::shared_ptr<PVScalarArray> PVScalarArrayPtr; + +typedef std::tr1::shared_ptr<PVStructure> PVStructurePtr; +typedef std::vector<PVStructurePtr> PVStructurePtrArray; +typedef std::vector<PVStructurePtr>::iterator PVStructurePtrArray_iterator; +typedef std::vector<PVStructurePtr>::const_iterator PVStructurePtrArray_const__iterator; + +typedef PVValueArray<PVStructurePtr> PVStructureArray; +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. + */ +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; +class PVString; +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; +typedef std::tr1::shared_ptr<PVString> PVStringPtr; + +/** + * Definitions for the various scalarArray types. + */ +typedef PVValueArray<boolean> PVBooleanArray; +typedef PVValueArray<int8> PVByteArray; +typedef PVValueArray<int16> PVShortArray; +typedef PVValueArray<int32> PVIntArray; +typedef PVValueArray<int64> PVLongArray; +typedef PVValueArray<uint8> PVUByteArray; +typedef PVValueArray<uint16> PVUShortArray; +typedef PVValueArray<uint32> PVUIntArray; +typedef PVValueArray<uint64> PVULongArray; +typedef PVValueArray<float> PVFloatArray; +typedef PVValueArray<double> PVDoubleArray; +typedef PVValueArray<std::string> PVStringArray; + +typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr; +typedef std::tr1::shared_ptr<PVByteArray> PVByteArrayPtr; +typedef std::tr1::shared_ptr<PVShortArray> PVShortArrayPtr; +typedef std::tr1::shared_ptr<PVIntArray> PVIntArrayPtr; +typedef std::tr1::shared_ptr<PVLongArray> PVLongArrayPtr; +typedef std::tr1::shared_ptr<PVUByteArray> PVUByteArrayPtr; +typedef std::tr1::shared_ptr<PVUShortArray> PVUShortArrayPtr; +typedef std::tr1::shared_ptr<PVUIntArray> PVUIntArrayPtr; +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; ++ +
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 +structure has a PVField associated with it.
+
+class PostHandler
+{
+public:
+ POINTER_DEFINITIONS(PostHandler);
+ virtual ~PostHandler(){}
+ virtual void postPut() = 0;
+};
+
+class PVField
+: virtual public Serializable,
+ public std::tr1::enable_shared_from_this<PVField>
+{
+public:
+ POINTER_DEFINITIONS(PVField);
+ virtual ~PVField();
+ std::string getFieldName() const ;
+ std::string getFullName() const;
+ std::size_t getFieldOffset() const;
+ std::size_t getNextFieldOffset() const;
+ std::size_t getNumberFields() const;
+ bool isImmutable() const;
+ virtual void setImmutable();
+ const FieldConstPtr & getField() const ;
+ PVStructure * getParent() const
+ void postPut();
+ void setPostHandler(PostHandlerPtr const &postHandler);
+ virtual bool equals(PVField &pv);
+ std::ostream& dumpValue(std::ostream& o) const;
+ ...
+}
+std::ostream& operator<<(std::ostream& o, const PVField& f);
+
+
+The public methods for PVField are:
+This is the base class for all scalar data.
+class PVScalar : public PVField {
+public:
+ POINTER_DEFINITIONS(PVScalar);
+ virtual ~PVScalar();
+ typedef PVScalar &reference;
+ typedef const PVScalar& const_reference;
+ const ScalarConstPtr getScalar() const ;
+ template<typename T>
+ T getAs() const;
+ ...
+}
+
+where
++uint32 val = pv->getAs<pvInt>(); ++
The interfaces for primitive data types are:
+template<typename T>
+class PVScalarValue : public PVScalar {
+public:
+ POINTER_DEFINITIONS(PVScalarValue);
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ static const ScalarType typeCode;
+
+ virtual ~PVScalarValue() {}
+ virtual T get() const = 0;
+ virtual void put(T value) = 0;
+ std::ostream& dumpValue(std::ostream& o) const;
+ void operator>>=(T& value) const;
+ void operator<<=(T value);
+ template<typename T1>
+ T1 getAs() const;
+ template<typename T1>
+ void putFrom(T1 val);
+ ...
+}
+
+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<std::string>, SerializableArray {
+public:
+ virtual ~PVString() {}
+ ...
+};
+
+
+
+
+where
++double value; +PVDoublePtr pvDouble; +... +pvDouble>>=value; ++
+double value; +PVDoublePtr pvDouble; +... +pvDouble<<=value; ++
+int32 val = pv->getAs<pvInt>>(); ++
+int32 val; +pv->putFrom<pvInt>(val); ++ +
A PVUnion has a single subfield. +The Union introspection interface determines the possible +field types for the subfield. +If it is a variant union then any type is allowed and the +subfield name is normally any. +If it is not a variant union that the Union interface determines +the possible field types and names.
+
+class PVUnion : public PVField
+{
+public:
+ POINTER_DEFINITIONS(PVUnion);
+ virtual ~PVUnion();
+ typedef PVUnion & reference;
+ typedef const PVUnion & const_reference;
+
+ UnionConstPtr getUnion() const;
+ PVFieldPtr get() const;
+
+ template<typename PVT>
+ std::tr1::shared_ptr<PVT> get() const;
+
+ PVFieldPtr select(int32 index);
+
+ template<typename PVT>
+ std::tr1::shared_ptr<PVT> select(int32 index);
+
+ PVFieldPtr select(std::string const & fieldName);
+
+ template<typename PVT>
+ std::tr1::shared_ptr<PVT> select(std::string const & fieldName);
+
+ int32 getSelectedIndex() const;
+ std::string getSelectedFieldName() const;
+ void set(PVFieldPtr const & value);
+ void set(int32 index, PVFieldPtr const & value);
+ void set(std::string const & fieldName, PVFieldPtr const & value);
+ virtual void serialize(
+ ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
+ PVUnion(UnionConstPtr const & punion);
+ virtual std::ostream& dumpValue(std::ostream& o) const;
+};
+
+PVArray is the base interface for all the other PV Array interfaces. It +extends PVField and provides the additional methods:
+
+class PVArray : public PVField, public SerializableArray {
+public:
+ POINTER_DEFINITIONS(PVArray);
+ virtual ~PVArray();
+ virtual ArrayConstPtr getArray() const = 0;
+ virtual void setImmutable();
+ std::size_t getLength() const;
+ virtual void setLength(std::size_t length);
+ std::size_t getCapacity() const;
+ bool isCapacityMutable() const;
+ void setCapacityMutable(bool isMutable);
+ virtual void setCapacity(std::size_t capacity) = 0;
+ virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
+ ...
+};
+PVScalarArray is the base class for scalar array data. PVValueArray is a +template for the various scalar array data classes. There is a class for each +possible scalar type, i. e. PVBooleanArray, ..., PVStringArray.
+
+class PVScalarArray : public PVArray {
+public:
+ POINTER_DEFINITIONS(PVScalarArray);
+ virtual ~PVScalarArray();
+ typedef PVScalarArray &reference;
+ 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);
+ ...
+}
+
+
+where
+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(std::string const &fieldName) const;
+
+ template<typename PVT>
+ std::tr1::shared_ptr<PVT> getSubField(std::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
+This is a template class plus instances for PVBooleanArray, ..., +PVStringArray.
+template<typename T>
+class PVValueArray : public detail::PVVectorStorage<T,PVScalarArray>
+{
+public:
+ POINTER_DEFINITIONS(PVValueArray);
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef ::epics::pvData::shared_vector<T> svector;
+ typedef ::epics::pvData::shared_vector<const T> const_svector;
+ static const ScalarType typeCode;
+
+ virtual ~PVValueArray() {}
+ virtual ArrayConstPtr getArray() const
+ std::ostream& dumpValue(std::ostream& o) const;
+ std::ostream& dumpValue(std::ostream& o, size_t index) const;
+ // inherited from PVVectorStorage
+ const_svector view();
+ void swap(const_svector& other);
+ void replace(const const_svector& next);
+ svector reuse();
+ ...
+};
+
+
+where
+TBD
+The interface for an array of structures is:
+
+template<>
+class PVValueArray<PVStructurePtr> : public detail::PVVectorStorage<PVStructurePtr,PVArray>
+{
+public:
+ POINTER_DEFINITIONS(PVStructureArray);
+ typedef PVStructurePtr value_type;
+ typedef PVStructurePtr* pointer;
+ typedef const PVStructurePtr* const_pointer;
+ typedef PVStructureArray &reference;
+ typedef const PVStructureArray& const_reference;
+ typedef ::epics::pvData::shared_vector<PVStructurePtr> svector;
+ typedef ::epics::pvData::shared_vector<const PVStructurePtr> const_svector;
+
+ virtual ~PVStructureArray() {}
+ virtual ArrayConstPtr getArray() const;
+ virtual size_t getLength();
+ virtual size_t getCapacity();
+ virtual void setCapacity(size_t capacity);
+ virtual void setLength(std::size_t length);
+ virtual StructureArrayConstPtr getStructureArray() 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 serialize(ByteBuffer *pbuffer,
+ SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
+ virtual void deserialize(ByteBuffer *buffer,
+ DeserializableControl *pflusher);
+ 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.
+ +The interface for an array of unions is:
+
+template<>
+class epicsShareClass PVValueArray<PVUnionPtr> : public detail::PVVectorStorage<PVUnionPtr,PVArray>
+{
+ typedef detail::PVVectorStorage<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<PVUnionPtr> svector;
+ typedef ::epics::pvData::shared_vector<const PVUnionPtr> const_svector;
+
+ virtual ~PVValueArray() {}
+ virtual ArrayConstPtr getArray() const;
+ 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);
+ PVStructureArrayPtr createPVStructureArray(StructureConstPtr const & structure);
+
+ PVUnionArrayPtr createPVUnionArray(UnionArrayConstPtr const & unionArray);
+ PVUnionArrayPtr createPVUnionArray(UnionConstPtr const & punion);
+ PVUnionArrayPtr createPVVariantUnionArray();
+ ...
+};
+
+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 +without properties and one with properties. Again the properties is some +combination of alarm, timeStamp, control, display, and valueAlarm. And just +like StandardField there are methods to create the standard properties. The +methods are:
+class StandardPVField;
+typedef std::tr1::shared_ptr<StandardPVField> StandardPVFieldPtr;
+
+class StandardPVField : private NoDefaultMethods {
+public:
+ static StandardPVFieldPtr getStandardPVField();
+ ~StandardPVField();
+ PVStructurePtr scalar(ScalarType type,std::string const &properties);
+ PVStructurePtr scalarArray(ScalarType elementType, std::string const &properties);
+ PVStructurePtr structureArray(StructureConstPtr const &structure,std::string const &properties);
+ PVStructurePtr unionArray(UnionConstPtr const &punion,std::string const &properties);
+ PVStructurePtr enumerated(StringArray const &choices);
+ PVStructurePtr enumerated(StringArray const &choices, std::string const &properties);
+ ...
+}
+
+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 +are 0, and the length is the length of the source array, then the shareData +method of the target array is called and the target array is set immutable. +Thus the source and target share the same primitive array.
+ +This section describes the supported conversions between data types.
+
+bool operator==(PVField&, PVField&);
+
+static bool operator!=(PVField& a, PVField& b);
+
+bool operator==(const Field&, const Field&);
+bool operator==(const Scalar&, const Scalar&);
+bool operator==(const ScalarArray&, const ScalarArray&);
+bool operator==(const Structure&, const Structure&);
+bool operator==(const StructureArray&, const StructureArray&);
+bool operator==(const Union&, const Union&);
+bool operator==(const UnionArray&, const UnionArray&);
+
+static inline bool operator!=(const Field& a, const Field& b);
+static inline bool operator!=(const Scalar& a, const Scalar& b);
+static inline bool operator!=(const ScalarArray& a, const ScalarArray& b);
+static inline bool operator!=(const Structure& a, const Structure& b);
+static inline bool operator!=(const StructureArray& a, const StructureArray& b);
+static inline bool operator!=(const Union& a, const Union& b);
+static inline bool operator!=(const UnionArray& a, const UnionArray& b);
+
+class Convert;
+typedef std::tr1::shared_ptr<Convert> ConvertPtr;
+
+class Convert {
+public:
+ static ConvertPtr getConvert();
+ ~Convert();
+ void getFullName(std::string * buf,PVFieldPtr const & pvField);
+ bool equals(PVFieldPtr const &a,PVFieldPtr const &b);
+ bool equals(PVField &a,PVField &b);
+ void getString(std::string * buf,PVFieldPtr const & pvField,int indentLevel);
+ void getString(std::string * buf,PVFieldPtr const & pvField);
+ void getString(std::string * buf,PVField const * pvField,int indentLevel);
+ void getString(std::string * buf,PVField const * pvField);
+ std::size_t fromString(
+ PVStructurePtr const &pv,
+ StringArray const & from,
+ std::size_t fromStartIndex = 0);
+ void fromString(PVScalarPtr const & pv, std::string const & from);
+ std::size_t fromString(PVScalarArrayPtr const & pv, std::string const &from);
+ std::size_t fromStringArray(
+ PVScalarArrayPtr const & pv,
+ std::size_t offset, std::size_t length,
+ StringArray const & from,
+ std::size_t fromOffset);
+ std::size_t toStringArray(PVScalarArrayPtr const & pv,
+ std::size_t offset,
+ std::size_t length,
+ StringArray & to,
+ std::size_t toOffset);
+ bool isCopyCompatible(FieldConstPtr const & from, FieldConstPtr const & to);
+ void copy(PVFieldPtr const & from, PVFieldPtr const & to);
+ bool isCopyScalarCompatible(
+ ScalarConstPtr const & from,
+ ScalarConstPtr const & to);
+ void copyScalar(PVScalarPtr const & from, PVScalarPtr const & to);
+ bool isCopyScalarArrayCompatible(
+ ScalarArrayConstPtr const & from,
+ ScalarArrayConstPtr const & to);
+ bool isCopyStructureCompatible(
+ StructureConstPtr const & from, StructureConstPtr const & to);
+ void copyStructure(PVStructurePtr const & from, PVStructurePtr const & to);
+ bool isCopyStructureArrayCompatible(
+ StructureArrayConstPtr const & from, StructureArrayConstPtr const & to);
+ void copyStructureArray(
+ PVStructureArrayPtr const & from, PVStructureArrayPtr const & to);
+ bool isCopyUnionCompatible(
+ UnionConstPtr const & from, UnionConstPtr const & to);
+ void copyUnion(
+ PVUnionPtr const & from, PVUnionPtr const & to);
+ bool isCopyUnionArrayCompatible(
+ UnionArrayConstPtr const & from, UnionArrayConstPtr const & to);
+ void copyUnionArray(
+ PVUnionArrayPtr const & from, PVUnionArrayPtr const & to);
+ int8 toByte(PVScalarPtr const & pv);
+ int16 toShort(PVScalarPtr const & pv);
+ int32 toInt(PVScalarPtr const & pv);
+ int64 toLong(PVScalarPtr const & pv);
+ uint8 toUByte(PVScalarPtr const & pv);
+ uint16 toUShort(PVScalarPtr const & pv);
+ uint32 toUInt(PVScalarPtr const & pv);
+ uint64 toULong(PVScalarPtr const & pv);
+ float toFloat(PVScalarPtr const & pv);
+ double toDouble(PVScalarPtr const & pv);
+ std::string toString(PVScalarPtr const & pv);
+ void fromByte(PVScalarPtr const & pv,int8 from);
+ void fromShort(PVScalarPtr const & pv,int16 from);
+ void fromInt(PVScalarPtr const & pv, int32 from);
+ void fromLong(PVScalarPtr const & pv, int64 from);
+ void fromUByte(PVScalarPtr const & pv,uint8 from);
+ void fromUShort(PVScalarPtr const & pv,uint16 from);
+ void fromUInt(PVScalarPtr const & pv, uint32 from);
+ void fromULong(PVScalarPtr const & pv, uint64 from);
+ void fromFloat(PVScalarPtr const & pv, float from);
+ void fromDouble(PVScalarPtr const & pv, double from);
+ void newLine(std::string * buf, int indentLevel);
+ ...
+}
+
+extern ConvertPtr getConvert();
+
+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( + PVValueArray<T> & pvFrom, + size_t fromOffset, + size_t fromStride, + PVValueArray<T> & pvTo, + size_t toOffset, + size_t toStride, + size_t count); + +void copy( + PVScalarArray & from, + size_t fromOffset, + size_t fromStride, + PVScalarArray & to, + size_t toOffset, + size_t toStride, + size_t count); + +void copy( + PVStructureArray & from, + size_t fromOffset, + size_t fromStride, + PVStructureArray & to, + size_t toOffset, + size_t toStride, + size_t count); + +void copy( + PVArray & from, + size_t fromOffset, + size_t fromStride, + PVArray & to, + size_t toOffset, + size_t toStride, + size_t count); ++
The last copy is the only one most client need to call. +It either throws an error if the element types do not match or calls the +other copy functions. The arguments are:
+An exception is thrown if:
++Often a field named "value" has properties. A record can have multiple value +fields, which can appear in the top level structure of a record or in a +substructure. All other fields in the structure containing a value field are +considered properties of the value field. The fieldname is also the property +name. The value field can have any type, i.e. scalar, scalarArray, or +structure. Typical property fields are timeStamp, alarm, display, control, and +history. The timeStamp is a special case. If it appears anywhere in the +structure hierarchy above a value field it is a property of the value field.
+ +For example the following top level structure has a single value field. The +value field has properties alarm, timeStamp, and display.
+structure counterOutput + double value + alarm_t + int severity 0 + int status 0 + string message + timeStamp_t + long secondsPastEpoch + int nanoseconds + int userTag + display_t + double limitLow 0.0 + double limitHigh 10.0 + string description "Sample Description" + string format "%f" + string units volts+ +
The following example has three value fields each with properties alarm and +timeStamp. Voltage, Current, and Power each have a different alarms but all +share the timeStamp.
+structure powerSupplyValue + double value + alarm_t + int severity 0 + int status 0 + string message + +structure powerSupplySimple + alarm_t + int severity 0 + int status 0 + string message + timeStamp_t + long secondsPastEpoch + int nanoseconds + int userTag + powerSupplyValue_t voltage + double value + alarm_t + int severity 0 + int status 0 + string message + powerSupplyValue_t power + double value + alarm_t + int severity 0 + int status 0 + string message + powerSupplyValue_t current + double value + alarm_t + int severity 0 + int status 0 + string message+ +
The following field names have special meaning, i.e. support properties for +general purpose clients.
+In addition a structure can have additional fields that support the value +field but are not recognized by most general purpose client tools. Typical +examples are:
+The model allows for device records. A device record has structure fields +that that support the PVData data model. For example a powerSupport record can +have fields power, voltage, current that each support the PVData data model. +
+ +Except for enumerated, each property has two files: a property.h and a +pvProperty.h . For example: timeStamp.h and pvTimeStamp.h In each case the +property.h file defined methods for manipulating the property data and the +pvProperty.h provides methods to transfer the property data to/from a pvData +structure.
+ +All methods copy data via copy by value semantics, i.e. not by pointer or by +reference. No property class calls new or delete and all allow the compiler to +generate default methods. All allow a class instance to be generated on the +stack. For example the following is permitted:
+void example(PVFieldPtr const &pvField) {
+ Alarm alarm;
+ PVAlarm pvAlarm;
+ bool result;
+ result = pvAlarm.attach(pvField);
+ assert(result);
+ Alarm al;
+ al.setMessage(std::string("testMessage"));
+ al.setSeverity(majorAlarm);
+ result = pvAlarm.set(al);
+ assert(result);
+ alarm = pvAlarm.get();
+ ...
+}
+
+A timeStamp is represented by the following structure
+structure timeStamp + long secondsPastEpoch + int nanoseconds + int userTag+ +
The Epoch is the posix epoch, i.e. Jan 1, 1970 00:00:00 UTC. Both the +seconds and nanoseconds are signed integers and thus can be negative. Since the +seconds is kept as a 64 bit integer, it allows for a time much greater than the +present age of the universe. Since the nanoseconds portion is kept as a 32 bit +integer it is subject to overflow if a value that corresponds to a value that +is greater than a little more than 2 seconds of less that about -2 seconds. The +support code always adjust seconds so that the nanoseconds part is normalized, +i. e. it has is 0<=nanoseconds<nanoSecPerSec..
+ +Two header files are provided for manipulating time stamps:
+This provides
+extern int32 milliSecPerSec;
+extern int32 microSecPerSec;
+extern int32 nanoSecPerSec;
+extern int64 posixEpochAtEpicsEpoch;
+
+class TimeStamp {
+public:
+ TimeStamp()
+ :secondsPastEpoch(0), nanoseconds(0), userTag(0) {}
+ TimeStamp(int64 secondsPastEpoch,int32 nanoseconds = 0,int32 userTag = 0);
+ //default constructors and destructor are OK
+ //This class should not be extended
+ void normalize();
+ void fromTime_t(const time_t &);
+ void toTime_t(time_t &) const;
+ int64 getSecondsPastEpoch() const {return secondsPastEpoch;}
+ int64 getEpicsSecondsPastEpoch() const {
+ return secondsPastEpoch - posixEpochAtEpicsEpoch;
+ }
+ int32 getNanoseconds() const {return nanoseconds;}
+ int32 getUserTag() const {return userTag;}
+ void setUserTag(int userTag) {this->userTag = userTag;}
+ void put(int64 secondsPastEpoch,int32 nanoseconds = 0) {
+ this->secondsPastEpoch = secondsPastEpoch;
+ this->nanoseconds = nanoseconds;
+ normalize();
+ }
+ void put(int64 milliseconds);
+ void getCurrent();
+ double toSeconds() const ;
+ bool operator==(TimeStamp const &) const;
+ bool operator!=(TimeStamp const &) const;
+ bool operator<=(TimeStamp const &) const;
+ bool operator< (TimeStamp const &) const;
+ bool operator>=(TimeStamp const &) const;
+ bool operator> (TimeStamp const &) const;
+ static double diff(TimeStamp const & a,TimeStamp const & b);
+ TimeStamp & operator+=(int64 seconds);
+ TimeStamp & operator-=(int64 seconds);
+ TimeStamp & operator+=(double seconds);
+ TimeStamp & operator-=(double seconds);
+ int64 getMilliseconds(); // milliseconds since epoch
+ ...
+}
+
+where
+The TimeStamp class provides arithmetic operations on time stamps. The +result is always kept in normalized form, which means that the nano second +portion is 0≤=nano<nanoSecPerSec. Note that it is OK to have timeStamps +for times previous to the epoch.
+ +TimeStamp acts like a primitive. It can be allocated on the stack and the +compiler is free to generate default methods, i.e. copy constructor, assignment +constructor, and destructor.
+ +One use for TimeStamp is to time how long a section of code takes to +execute. This is done as follows:
+TimeStamp startTime; + TimeStamp endTime; + ... + startTime.getCurrent(); + // code to be measured for elapsed time + endTime.getCurrent(); + double time = TimeStamp::diff(endTime,startTime);+ +
class PVTimeStamp {
+public:
+ PVTimeStamp();
+ //default constructors and destructor are OK
+ //This class should not be extended
+ //returns (false,true) if pvField(isNot, is valid timeStamp structure
+ bool attach(PVFieldPtr const &pvField);
+ void detach();
+ bool isAttached();
+ // following throw logic_error if not attached to PVField
+ // a set returns false if field is immutable
+ void get(TimeStamp &) const;
+ bool set(TimeStamp const & timeStamp);
+};
+
+where
+An alarm structure is defined as follows:
+structure alarm + int severity + int status + string message+ +
Note that neither severity or status is defined as an enumerated structure. +The reason is performance, i. e. prevent passing the array of choice strings +everywhere. The file alarm.h provides the choice strings. Thus all code that +needs to know about alarms share the exact same choice strings.
+ +Two header files are provided for manipulating alarms:
+enum AlarmSeverity {
+ noAlarm,minorAlarm,majorAlarm,invalidAlarm,undefinedAlarm
+};
+
+enum AlarmStatus {
+ noStatus,deviceStatus,driverStatus,recordStatus,
+ dbStatus,confStatus,undefinedStatus,clientStatus
+};
+
+
+class AlarmSeverityFunc {
+public:
+ static AlarmSeverity getSeverity(int value);
+ static StringArrayPtr getSeverityNames();
+};
+
+class AlarmStatusFunc {
+public:
+ static AlarmStatus getStatus(int value);
+ static StringArrayPtr getStatusNames();
+};
+
+class Alarm {
+public:
+ Alarm();
+ //default constructors and destructor are OK
+ std::string getMessage();
+ void setMessage(std::string const &value);
+ AlarmSeverity getSeverity() const;
+ void setSeverity(AlarmSeverity value);
+ AlarmStatus getStatus() const;
+ void setStatus(AlarmStatus value);
+};
+
+Alarm Severity defines the possible alarm severities:
+Alarm Status defines the possible choices for alarm status:
+Alarm has the methods:
+class PVAlarm {
+public:
+ PVAlarm() : pvSeverity(0),pvMessage(0) {}
+ //default constructors and destructor are OK
+ //returns (false,true) if pvField(isNot, is valid enumerated structure
+ //An automatic detach is issued if already attached.
+ bool attach(PVFieldPtr const &pvField);
+ void detach();
+ bool isAttached();
+ // each of the following throws logic_error is not attached to PVField
+ // set returns false if field is immutable
+ void get(Alarm & alarm) const;
+ bool set(Alarm const & alarm);
+};
+
+where
+Control information is represented by the following structure
+structure control + double limitLow + double limitHigh + double minStep+ +
Two header files are provided for manipulating control:
+class Control {
+public:
+ Control();
+ //default constructors and destructor are OK
+ double getLow() const;
+ double getHigh() const;
+ double getMinStep() const;
+ void setLow(double value);
+ void setHigh(double value);
+ void setMinStep(double value);
+};
+
+where
+class PVControl {
+public:
+ PVControl();
+ //default constructors and destructor are OK
+ //returns (false,true) if pvField(isNot, is valid enumerated structure
+ //An automatic detach is issued if already attached.
+ bool attach(PVFieldPtr const &pvField);
+ void detach();
+ bool isAttached();
+ // each of the following throws logic_error is not attached to PVField
+ // set returns false if field is immutable
+ void get(Control &) const;
+ bool set(Control const & control);
+};
+
+where
+Display information is represented by the following structure
+structure display + double limitLow + double limitHigh + string description + string format + string units+ +
Two header files are provided for manipulating display:
+class Display {
+public:
+ Display();
+ //default constructors and destructor are OK
+ double getLow() const;
+ double getHigh() const;
+ void setLow(double value);
+ void setHigh(double value);
+ std::string getDescription() const;
+ void setDescription(std::string const &value);
+ std::string getFormat() const;
+ void setFormat(std::string const &value);
+ std::string getUnits() const;
+ void setUnits(std::string const &value);
+};
+
+where
+class PVDisplay {
+public:
+ PVDisplay()
+ : pvDescription(0),pvFormat(),pvUnits(),pvLow(),pvHigh() {}
+ //default constructors and destructor are OK
+ //An automatic detach is issued if already attached.
+ bool attach(PVFieldPtr const&pvField);
+ void detach();
+ bool isAttached();
+ // each of the following throws logic_error is not attached to PVField
+ // a set returns false if field is immutable
+ void get(Display &) const;
+ bool set(Display const & display);
+};
+
+where
+An enumerated structure is a structure that has fields:
+structure + int index + string[] choices+ +
For enumerated structures a single header file pvEnumerted.h is available
+class PVEnumerated {
+public:
+ PVEnumerated();
+ //default constructors and destructor are OK
+ //This class should not be extended
+ //returns (false,true) if pvField(isNot, is valid enumerated structure
+ //An automatic detach is issued if already attached.
+ bool attach(PVFieldPtr const &pvField);
+ void detach();
+ bool isAttached();
+ // each of the following throws logic_error is not attached to PVField
+ // a set returns false if field is immutable
+ bool setIndex(int32 index);
+ int32 getIndex();
+ std::string getChoice();
+ bool choicesMutable();
+ StringArrayPtr const & getChoices();
+ int32 getNumberChoices();
+ bool setChoices(StringArray &choices);
+};
+
+where
+Directory factory has code that implements everything described by the files +in directory pv
+ +TypeFunc.cpp implements the functions for the enums defined in +pvIntrospecct.h
+ +FieldCreateFactory.cpp automatically creates a single instance of +FieldCreate and implements getFieldCreate.
+ +PVDataCreateFactory.cpp automatically creates a single instance of +PVDataCreate and implements getPVDataCreate.
+ + +Convert.cpp automatically creates a single instance of Convert and +implements getConvert.
+ +Other files implement PVData base classes
+ +This package provides utility code:
+Note that directory testApp/misc has test code for all the classes in misc. +The test code also can be used as examples.
+ +This is adapted from the java.util.BitSet. bitSet.h is:
+
+class BitSet;
+typedef std::tr1::shared_ptr<BitSet> BitSetPtr;
+
+class BitSet : public Serializable {
+public:
+ static BitSetPtr create(uint32 nbits);
+ BitSet();
+ BitSet(uint32 nbits);
+ virtual ~BitSet();
+ void flip(uint32 bitIndex);
+ void set(uint32 bitIndex);
+ void clear(uint32 bitIndex);
+ void set(uint32 bitIndex, bool value);
+ bool get(uint32 bitIndex) const;
+ void clear();
+ int32 nextSetBit(uint32 fromIndex) const;
+ int32 nextClearBit(uint32 fromIndex) const;
+ bool isEmpty() const;
+ uint32 cardinality() const;
+ uint32 size() const;
+ BitSet& operator&=(const BitSet& set);
+ BitSet& operator|=(const BitSet& set);
+ BitSet& operator^=(const BitSet& set);
+ BitSet& operator=(const BitSet &set);
+ void or_and(const BitSet& set1, const BitSet& set2);
+ bool operator==(const BitSet &set) const;
+ bool operator!=(const BitSet &set) const;
+ virtual void serialize(
+ ByteBuffer *buffer,SerializableControl *flusher) const;
+ virtual void deserialize(
+ ByteBuffer *buffer,DeserializableControl *flusher);
+private:
+};
+
+std::ostream& operator<<(std::ostream& o, const BitSet& b);
+
+
+where
+A ByteBuffer is used to serialize and deserialize primitive data. File +byteBuffer.h is:
+class ByteBuffer {
+public:
+ ByteBuffer(std::size_t size, int byteOrder = EPICS_BYTE_ORDER)
+ ~ByteBuffer();
+ void setEndianess(int byteOrder);
+ const char* getBuffer();
+ void clear();
+ void flip();
+ void rewind();
+ std::size_t getPosition();
+ void setPosition(std::size_t pos);
+ std::size_t getLimit();
+ void setLimit(std::size_t limit);
+ std::size_t getRemaining();
+ std::size_t getSize();
+ template<typename T>
+ void put(T value)
+ template<typename T>
+ void put(std::size_t index, T value);
+ template<typename T>
+ T get()
+ template<typename T>
+ T get(std::size_t index)
+ void put(const char* src, std::size_t src_offset, std::size_t count);
+ void get(char* dest, std::size_t dest_offset, std::size_t count);
+ template<typename T>
+ inline void putArray(T* values, std::size_t count)
+ template<typename T>
+ inline void getArray(T* values, std::size_t count)
+ template<typename T>
+ inline bool reverse();
+ inline void align(std::size_t size)
+ void putBoolean( bool value);
+ void putByte ( int8 value);
+ void putShort ( int16 value);
+ void putInt ( int32 value);
+ void putLong ( int64 value);
+ void putFloat ( float value);
+ void putDouble (double value);
+ void putBoolean(std::size_t index, bool value);
+ void putByte (std::size_t index, int8 value);
+ void putShort (std::size_t index, int16 value);
+ void putInt (std::size_t index, int32 value);
+ void putFloat (std::size_t index, float value);
+ void putDouble (std::size_t index, double value);
+ bool getBoolean();
+ int8 getByte ();
+ int16 getShort ();
+ int32 getInt ();
+ int64 getLong ();
+ float getFloat ();
+ double getDouble ();
+ bool getBoolean(std::size_t index);
+ int8 getByte (std::size_t index);
+ int16 getShort (std::size_t index);
+ int32 getInt (std::size_t index);
+ int64 getLong (std::size_t index);
+ float getFloat (std::size_t index);
+ double getDouble (std::size_t index);
+ const char* getArray();
+ ...
+};
+
+class Destroyable {
+public:
+ POINTER_DEFINITIONS(Destroyable);
+ virtual void destroy() = 0;
+ virtual ~Destroyable() {};
+};
+
+/*
+ * Throwing exceptions w/ file+line# and, when possibly, a stack trace
+ *
+ * THROW_EXCEPTION1( std::bad_alloc );
+ *
+ * THROW_EXCEPTION2( std::logic_error, "my message" );
+ *
+ * THROW_EXCEPTION( mySpecialException("my message", 42, "hello", ...) );
+ *
+ * Catching exceptions
+ *
+ * catch(std::logic_error& e) {
+ * fprintf(stderr, "%s happened\n", e.what());
+ * PRINT_EXCEPTION2(e, stderr);
+ * cout<<SHOW_EXCEPTION(e);
+ * }
+ *
+ * If the exception was not thrown with the above THROW_EXCEPTION*
+ * the nothing will be printed.
+ */
+
+This class provides coordinates activity between threads. One thread can +wait for the event and the other signals the event.
+class Event;
+typedef std::tr1::shared_ptr<Event> EventPtr;
+
+class Event {
+public:
+ POINTER_DEFINITIONS(Event);
+ explicit Event(bool = false);
+ ~Event();
+ void signal();
+ bool wait (); /* blocks until full */
+ bool wait ( double timeOut ); /* false if empty at time out */
+ bool tryWait (); /* false if empty */
+...
+};
+
+where
+An Executor is a thread that can execute commands. The user can request that +a single command be executed.
+
+class Command;
+class Executor;
+typedef std::tr1::shared_ptr<Command> CommandPtr;
+typedef std::tr1::shared_ptr<Executor> ExecutorPtr;
+
+class Command {
+public:
+ POINTER_DEFINITIONS(Command);
+ virtual ~Command(){}
+ virtual void command() = 0;
+private:
+ CommandPtr next;
+ friend class Executor;
+};
+
+class Executor : public Runnable{
+public:
+ POINTER_DEFINITIONS(Executor);
+ Executor(std::string threadName,ThreadPriority priority);
+ ~Executor();
+ void execute(CommandPtr const &node);
+ virtual void run();
+ ...
+};
+
+Command is a class that must be implemented by the code that calls execute. +It contains the single virtual method command, which is the command to +execute.
+ +Executor has the methods:
+
+extern epics::pvData::Mutex& getLocalStaticInitMutex();
+
+static class MutexInitializer {
+ public:
+ MutexInitializer ();
+ ~MutexInitializer ();
+} localStaticMutexInitializer; // Note object here in the header.
+
+TBD Matej will explain.
+ +
+typedef epicsMutex Mutex;
+
+class Lock : private NoDefaultMethods {
+public:
+ explicit Lock(Mutex &pm);
+ ~Lock();
+ void lock();
+ void unlock();
+ bool tryLock();
+ bool ownsLock() ;
+ ...
+};
+
+Lock is as easy to use as Java synchronize. To protect some object just +create a Mutex for the object and then in any method to be synchronized just +have code like:
+class SomeClass {
+private
+ Mutex mutex;
+ ...
+public
+ SomeClass() : mutex(Mutex()) {}
+ ...
+ void method()
+ {
+ Lock xx(mutex);
+ ...
+ }
+
+
+The method will take the lock when xx is created and release the lock when +the current code block completes.
+ +Another example of Lock is initialization code that must initialize only +once. This can be implemented as follows:
+ static void init(void) {
+ static Mutex mutex;
+ Lock guard(mutex);
+ if(alreadyInitialized) return;
+ // initialization
+ }
+Lock has a private variable:
++bool locked; ++and improves efficiency by checking the local variable before calling the +mutex methods. This is not thread safe if any methods are called by a thread other than +the thread that created the Lock. +
It is thread safe if used as follows:
+
+{
+ Lock guard(mutex);
+ ...
+ /* the following can optionally be called
+ guard.unlock();
+ guard.lock();
+ */
+}
+
+It is not thread safe if used as follows:
+
+class SomeClass
+{
+private:
+ Mutex mutex;
+ Lock lock;
+public:
+ SomeClass: lock(mutex) {}
+ ...
+ void someMethod() {
+ lock.unlock();
+ ...
+ }
+ ...
+};
+
+It is only safe if all methods of Lock, including ~Lock(), +are called by the same thread. +
+ +A messageQueue is for use by code that wants to handle messages without +blocking higher priority threads.
+class MessageNode;
+class MessageQueue;
+typedef std::tr1::shared_ptr<MessageNode> MessageNodePtr;
+typedef std::vector<MessageNodePtr> MessageNodePtrArray;
+typedef std::tr1::shared_ptr<MessageQueue> MessageQueuePtr;
+
+class MessageNode {
+public:
+ std::string getMessage() const;
+ MessageType getMessageType() const;
+ void setMessageNull();
+};
+
+class MessageQueue : public Queue<MessageNode> {
+public:
+ POINTER_DEFINITIONS(MessageQueue);
+ static MessageQueuePtr create(int size);
+ MessageQueue(MessageNodePtrArray &nodeArray);
+ virtual ~MessageQueue();
+ MessageNodePtr &get();
+ // must call release before next get
+ void release();
+ // return (false,true) if message (was not, was) put into queue
+ bool put(std::string message,MessageType messageType,bool replaceLast);
+ bool isEmpty() ;
+ bool isFull() ;
+ int getClearOverrun();
+ ...
+};
+
+A messageNode is a class with two public data members:
+A messageQueue is an interface with public methods:
+Look at miscTest/testMessageQueue.cpp for an example.
+ +If a class privately extends this class then the compiler can not create any +of the following: default constructor, default copy constructor, or default +assignment constructor.
+/* This is based on Item 6 of
+ * Effective C++, Third Edition, Scott Meyers
+ */
+ class NoDefaultMethods {
+ protected:
+ // allow by derived objects
+ NoDefaultMethods(){};
+ ~NoDefaultMethods(){}
+ private:
+ // do not implement
+ NoDefaultMethods(const NoDefaultMethods&);
+ NoDefaultMethods & operator=(const NoDefaultMethods &);
+ };
+
+This provides a bounded queue. When the queue is +full the user code is expected to keep using the current element until a new +free element becomes available.
+
+template <typename T>
+class Queue
+{
+public:
+ POINTER_DEFINITIONS(Queue);
+ typedef std::tr1::shared_ptr<T> queueElementPtr;
+ typedef std::vector<queueElementPtr> queueElementPtrArray;
+ Queue(queueElementPtrArray &);
+ virtual ~Queue();
+ void clear();
+ int capacity();
+ int getNumberFree();
+ int getNumberUsed();
+ queueElementPtr & getFree();
+ void setUsed(queueElementPtr const &element);
+ queueElementPtr & getUsed();
+ void releaseUsed(queueElementPtr const &element);
+ ...
+};
+
+testApp/misc/testQueue.cpp provides an example of how to define a queue.
+ +The queue methods are:
+A queue is created as follows:
+ class MyClass;
+ typedef MyQueueElement<MyClass> MyElement;
+ typedef MyQueue<MyClass> MyQueue;
+ int numElement = 5;
+ ...
+ MyClass *array[numElements];
+ for(int i=0; i<numElements; i++) {
+ array[i] = new MyClass();
+ }
+ MyQueue *queue = new MyQueue(array,numElements);
+
+A producer calls getFree and setUsed via code like the following:
+ MyClass *getFree() {
+ MyElement *element = queue->getFree();
+ if(element==0) return 0;
+ return element->getObject();
+ }
+
+A consumer calls getUsed and releaseUsed via code like the following:
+ while(true) {
+ MyElement *element = queue->getUsed();
+ if(element==0) break;
+ MyClass *myClass = element->getObject();
+ // do something with myClass
+ queue->releaseUsed(element);
+ }
+
+Requester is present so that when +errors are found there is someplace to send a message. +At one time PVField extended Requester but it no longer does. +Requester is, however, used by pvAccess. +
+
+class Requester;
+typedef std::tr1::shared_ptr<Requester> RequesterPtr;
+
+enum MessageType {
+ infoMessage,warningMessage,errorMessage,fatalErrorMessage
+};
+
+extern std::string getMessageTypeName(MessageType messageType);
+extern const size_t messageTypeCount;
+class Requester {
+public:
+ POINTER_DEFINITIONS(Requester);
+ virtual ~Requester(){}
+ virtual std::string getRequesterName() = 0;
+ virtual void message(std::string const & message,MessageType messageType) = 0;
+};
+
+where
+
+ class SerializableControl;
+ class DeserializableControl;
+ class Serializable;
+ class BitSetSerializable;
+ class SerializableArray;
+ class BitSet;
+ class Field;
+
+ class SerializableControl {
+ public:
+ virtual ~SerializableControl(){}
+ virtual void flushSerializeBuffer() =0;
+ virtual void ensureBuffer(std::size_t size) =0;
+ virtual void alignBuffer(std::size_t alignment) =0;
+ virtual void cachedSerialize(
+ std::tr1::shared_ptr<const Field> const & field,
+ ByteBuffer* buffer) = 0;
+ };
+
+ class DeserializableControl {
+ public:
+ virtual ~DeserializableControl(){}
+ virtual void ensureData(std::size_t size) =0;
+ virtual void alignData(std::size_t alignment) =0;
+ virtual std::tr1::shared_ptr<const Field> cachedDeserialize(
+ ByteBuffer* buffer) = 0;
+ };
+
+ class Serializable {
+ public:
+ virtual ~Serializable(){}
+ virtual void serialize(ByteBuffer *buffer,
+ SerializableControl *flusher) const = 0;
+ virtual void deserialize(ByteBuffer *buffer,
+ DeserializableControl *flusher) = 0;
+ };
+
+ class BitSetSerializable {
+ public:
+ virtual ~BitSetSerializable(){}
+ virtual void serialize(ByteBuffer *buffer,
+ SerializableControl *flusher,BitSet *bitSet) const = 0;
+ virtual void deserialize(ByteBuffer *buffer,
+ DeserializableControl *flusher,BitSet *bitSet) = 0;
+ };
+
+
+ class SerializableArray : virtual public Serializable {
+ public:
+ virtual ~SerializableArray(){}
+ virtual void serialize(ByteBuffer *buffer,
+ SerializableControl *flusher, std::size_t offset,
+ std::size_t count) const = 0;
+ };
+
+This is a helper class for serialization, which is required for sending and +receiving pvData over the network.
+class SerializeHelper : public NoDefaultMethods {
+public:
+ static void writeSize(int s, ByteBuffer* buffer,
+ SerializableControl* flusher);
+ static int readSize(ByteBuffer* buffer,
+ DeserializableControl* control);
+ static void serializeString(const std::string& value,
+ ByteBuffer* buffer,SerializableControl* flusher);
+ static void serializeSubstring(const std::string& value, int offset,
+ int count, ByteBuffer* buffer,
+ SerializableControl* flusher);
+ static std::string deserializeString(ByteBuffer* buffer,
+ DeserializableControl* control);
+ ...
+};
+
+where
++#define POINTER_DEFINITIONS(clazz) \ + typedef std::tr1::shared_ptr<clazz> shared_pointer; \ + typedef std::tr1::shared_ptr<const clazz> const_shared_pointer; \ + typedef std::tr1::weak_ptr<clazz> weak_pointer; \ + typedef std::tr1::weak_ptr<const clazz> const_weak_pointer;+ +
+shared_vector is a holder for a contiguous piece of memory. +Data is shared, but offset and length are not. +This allows one vector to have access to only a subset of a piece of memory. +
++shared_vector differs from std::vector as follows:
+
+template<typename E, class Enable = void& class shared_vector;
+
+template<typename E, class Enable&
+class shared_vector : public detail::shared_vector_base<E&
+{
+ typedef detail::shared_vector_base<E& base_t;
+ typedef typename detail::call_with<E&::type param_type;
+ typedef typename meta::strip_const<E&::type _E_non_const;
+public:
+ typedef E value_type;
+ typedef E& reference;
+ typedef typename meta::decorate_const<E&::type& const_reference;
+ typedef E* pointer;
+ typedef typename meta::decorate_const<E&::type* const_pointer;
+ typedef E* iterator;
+ typedef std::reverse_iterator<iterator& reverse_iterator;
+ typedef typename meta::decorate_const<E&::type* const_iterator;
+ typedef std::reverse_iterator<const_iterator& const_reverse_iterator;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+
+ typedef E element_type;
+ typedef std::tr1::shared_ptr<E& shared_pointer_type;
+
+ // allow specialization for all E to be friends
+ template<typename E1, class Enable1& friend class shared_vector;
+
+ shared_vector() :base_t();
+ explicit shared_vector(size_t c)
+ :base_t(new _E_non_const[c], 0, c);
+ shared_vector(size_t c, param_type e);
+ template<typename A&
+ shared_vector(A v, size_t o, size_t c) :base_t(v,o,c);
+ template<typename E1&
+ shared_vector(const std::tr1::shared_ptr<E1&& d, size_t o, size_t c);
+ template<typename A, typename B&
+ shared_vector(A d, B b, size_t o, size_t c);
+ shared_vector(const shared_vector& o) :base_t(o);
+
+ size_t max_size() const;
+ size_t capacity() const;
+ void reserve(size_t i);
+ void resize(size_t i);
+ void resize(size_t i, param_type v);
+ void make_unique();
+
+ iterator begin() const;
+ iterator end() const;
+ reverse_iterator rbegin() const;
+ reverse_iterator rend() const;
+ reference front() const;
+ reference back() const;
+
+ void push_back(param_type v);
+ void pop_back();
+ pointer data() const;
+ reference operator[](size_t i) const;
+ reference at(size_t i) const;
+ // inherited from detail
+ shared_vector_base& operator=(const shared_vector_base& o);
+ void swap(shared_vector_base& o);
+ void clear();
+ bool unique() const;
+ size_t size() const;
+ bool empty() const;
+ void slice(size_t offset, size_t length=(size_t)-1);
+ const std::tr1::shared_ptr<E&& dataPtr();
+ size_t dataOffset() const;
+ size_t dataCount() const;
+ size_t dataTotal() const;
+
+where
++shared_vector(size_t c); ++ This creates a shared_vector of the specified size/ +
TBD +Michael should decide if this is the correct set of methods to describe. +Also he should check for correct descriptions. +
+ + +Status provides a way to pass status back to client code:
+class Status : public epics::pvData::Serializable {
+ public:
+ enum StatusType {
+ /** Operation completed successfully. */
+ STATUSTYPE_OK,
+ /** Operation completed successfully, but there is a warning message. */
+ STATUSTYPE_WARNING,
+ /** Operation failed due to an error. */
+ STATUSTYPE_ERROR,
+ /** Operation failed due to an unexpected error. */
+ STATUSTYPE_FATAL
+ };
+ static const char* StatusTypeName[];
+ static Status Ok;
+ Status();
+ Status(StatusType type, std::string const & message);
+ Status(StatusType type, std::string const & message, std::string stackDump);
+ ~Status()
+ StatusType getType() const;
+ std::string getMessage() const;
+ std::string getStackDump() const;
+ bool isOK() const;
+ bool isSuccess() const;
+ void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
+ void deserialize(ByteBuffer *buffer, DeserializableControl *flusher);
+ void dump(std::ostream& o) const;
+};
+
+The Status methods are:
+The StatusCreate methods are:
+TBD Michael will explain.
+ +enum ThreadPriority {
+ lowestPriority,
+ lowerPriority,
+ lowPriority,
+ middlePriority,
+ highPriority,
+ higherPriority,
+ highestPriority
+};
+
+
+class Thread;
+typedef std::tr1::shared_ptr<Thread> ThreadPtr;
+typedef std::tr1::shared_ptr<epicsThread> EpicsThreadPtr;
+
+class Runnable {
+public:
+ virtual void run() = 0;
+};
+
+class Thread;
+
+class Thread : public epicsThread, private NoDefaultMethods {
+public:
+ Thread(
+ std::string name,
+ ThreadPriority priority,
+ Runnable *runnableReady,
+ epicsThreadStackSizeClass stkcls=epicsThreadStackSmall);
+ ~Thread();
+ ...
+};
+
+Runnable must be implement by code that wants to be run via a thread. It has +one virtual method: run. Run is the code that is run as a thread. When run +completes it can not be restarted. If code wants to delete a thread then it +MUST arrange that the run returns before the thread can be deleted. An +exception is thrown if run remains active when delete is called.
+ +Thread has the methods:
+delete pthread;+
TimeFunction is a facility that measures the average number of seconds a +function call requires. When timeCall is called, it calls function in a loop. +It starts with a loop of one iteration. If the total elapsed time is less then +.1 seconds it increases the number of iterations by a factor of 10. It keeps +repeating until the elapsed time is greater than .1 seconds. It returns the +average number of seconds per call.
+class TimeFunctionRequester;
+class TimeFunction;
+typedef std::tr1::shared_ptr<TimeFunctionRequester> TimeFunctionRequesterPtr;
+typedef std::tr1::shared_ptr<TimeFunction> TimeFunctionPtr;
+
+class TimeFunctionRequester {
+public:
+ POINTER_DEFINITIONS(TimeFunctionRequester);
+ virtual ~TimeFunctionRequester(){}
+ virtual void function() = 0;
+};
+
+
+class TimeFunction {
+public:
+ POINTER_DEFINITIONS(TimeFunction);
+ TimeFunction(TimeFunctionRequesterPtr const & requester);
+ ~TimeFunction();
+ double timeCall();
+ ...
+};
+
+TimeFunctionRequester must be implemented by code that wants to time how +long a function takes. It has the single method:
+TimeFunction has the methods:
+This provides a general purpose timer. It allows a user callback to be +called after a delay or periodically.
+class TimerCallback;
+class Timer;
+typedef std::tr1::shared_ptr<TimerCallback> TimerCallbackPtr;
+typedef std::tr1::shared_ptr<Timer> TimerPtr;
+
+
+class TimerCallback {
+public:
+ POINTER_DEFINITIONS(TimerCallback);
+ TimerCallback();
+ virtual ~TimerCallback(){}
+ virtual void callback() = 0;
+ virtual void timerStopped() = 0;
+};
+
+class Timer : private Runnable {
+public:
+ POINTER_DEFINITIONS(Timer);
+ Timer(std::string threadName, ThreadPriority priority);
+ virtual ~Timer();
+ virtual void run();
+ void scheduleAfterDelay(
+ TimerCallbackPtr const &timerCallback,
+ double delay);
+ void schedulePeriodic(
+ TimerCallbackPtr const &timerCallback,
+ double delay,
+ double period));
+ void cancel(TimerCallbackPtr const &timerCallback);
+ bool isScheduled(TimerCallbackPtr const &timerCallback);
+ void dump(std::ostream& o);
+ ...
+};
+
+TimerCallback must be implemented by the user. It has the following methods: +
+In order to schedule a callback client code must allocate a TimerNode It can +be used to schedule multiple callbacks. It has the methods:
+delete timerNode;+
Timer has the methods:
+TBD Michael will explain.
+ +The following is also provided:
+class BitSetUtil : private NoDefaultMethods {
+public:
+ static bool compress(BitSet const &bitSet,PVStructure const &pvStructure);
+};
+
+This provides functions that operate on a BitSet for a PVStructure. It +currently has only one method:
+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 knowledge 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(std::string const &request);
+ std::string getMessage();
+};
+
+An example of how it is used is:
+
+CreateRequestPtr createRequest = CreateRequest::create();
+PVStructurePtr pvRequest = createRequest->createRequest(request);
+if(pvRequest==NULL) {
+ std::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,
+ std::string const & structureName);
+ virtual void destroy();
+ 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);
+ std::string dump();
+...
+};
+
+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 std::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 std::string const & getName() = 0;
+}
+
+class MonitorPluginManager
+{
+ static MonitorPluginManagerPtr get();
+ bool addPlugin(
+ std::string const &pluginName,
+ MonitorPluginCreatorPtr const &creator);
+ MonitorPluginCreatorPtr findPlugin(std::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 modified. +This would be possible 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 sufficient. +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 + structure display + structure voltage + double value + structure alarm + structure display + structure current + double value + structure alarm + structure 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 occurred. +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 monitor +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:
+
+std::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) {
+ std::string value = pvString->get();
+ if(value.compare("false")==0) raiseMonitor = false;
+ }
+ }
+ return true;
+ }
+ virtual std::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 std::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);
+ }
+}
+
+
+
+