From cb19940fa7600d523e7107e1e42d2e1668bc99aa Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Wed, 12 Dec 2012 15:17:44 -0500 Subject: [PATCH] I forget to do an hg add on documentation/pvDataCPP_20121212.html --- documentation/pvDataCPP_20121212.html | 3646 +++++++++++++++++++++++++ 1 file changed, 3646 insertions(+) create mode 100644 documentation/pvDataCPP_20121212.html diff --git a/documentation/pvDataCPP_20121212.html b/documentation/pvDataCPP_20121212.html new file mode 100644 index 0000000..78d053e --- /dev/null +++ b/documentation/pvDataCPP_20121212.html @@ -0,0 +1,3646 @@ + + + + + + EPICS pvDataCPP + + + + + + + + +
+

EPICS pvDataCPP

+ + +

EPICS v4 Working Group, Working Draft, 12-Dec-2012

+ +
+
Latest version:
+
pvDataCPP.html +
+
This version:
+
pvDataCPP_20121212html +
+
Previous version:
+
pvDataCPP_20121026html +
+
Editors:
+
Marty Kraimer, BNL
+
+ + +
+
+ +

Abstract

+ +

pvDataCPP is a computer software package for the efficient +storage, access, and communication, of structured data. It is specifically the +C++ implementation of pvData, which is one part of the set of related products in the EPICS +V4 control system programming environment:

+
+
pvData
+
pvData (Process Variable Data) defines and implements an efficent way + to store, access, and communicate memory resident structured data
+
pvAccess
+
pvAccess is a software library for high speed controls network communications, + optimized for pvData
+
pvIOC
+
pvIOC is a software framework for building network accessable "smart" real time + databases, suitable for interfacing devices in a distributed control system, + that can exchange pvData over pvAccess. +
+
pvService
+
A middle layer for implementing efficient data services.
+
+ +

Each of these products has a Java and a C++ implementation.

+ +

The products are all part of the V4 implementation of Experimental Physics and Industrial +Control System (EPICS).

+ +

Status of this Document

+ +

This is the 12-Dec-2012 version of the C++ implementation of pvData.

+ +

The text describes software which is a complete implementation of pvData as +currently planned by the EPICS V4 Working Group.

+ +

The following is a list of unresolved issues for pvDataCPP:

+
+
PVArray
+
The implementation of the different array types (PVBooleanArray, ..., + PVStructureArray) all store the data as a shared pointer holding a + vector. A test case should be created to make sure that vector.size() is + the same as getLength()
+
PVArray Examples
+
The following examples should be provided: 1) use all the get methods. + 2) create an example that makes data available in chunks.
+
pvType Example
+
Create an example of how to use the array typedefs
+
Convert test
+
How can this be better tested?
+
Structure and PVStructure
+
These two classes still keep data via std::vector. + Should they keep it as std::tr1::shared_ptr<std::vector<... ?
+ In particular change +
+class Structure
+...
+StringArray fieldNames;
+FieldConstPtrArray fields
+
+class PVStructure
+...
+PVFieldPtrArray pvFields;
+
+To +
+class Structure
+...
+StringArrayPtr fieldNames;
+FieldConstPtrArrayPtr fields
+
+class PVStructure
+...
+PVFieldPtrArrayPtr pvFields;
+
+If these are changed several methods also change so that raw vectors are never passed as +argument or returned from methods.
+
+ +
+

Table of Contents

+
+
+ + +

Introduction

+ +

pvData is one of a set of related projects. It describes and implements the +data that the other projects support. Thus it is not useful by itself but +understanding pvData is required in order to understand the other projects. The +reader should also become familar with projects pvAccess and pvIOC, which are +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:

+
+
Introduction
+
A brief descripton of pvData.
+
PVData Meta Language
+
A language used to describe data.
+
+ +

The material in these two chapters is NOT repeated in this documentation.

+ +

Doxygen documentation is available at doxygenDoc

+ +

Namespace and Memory Management

+ +

Namespace

+ +

All code in project pvDataCPP appears in namespace:

+
namespace epics { namespace pvData {
+     // ...
+}}
+ +

Memory Managemment

+ +

pvDataCPP introspection and data objects are designed to be shared. They are +made availiable via std::tr1::shared_ptr. In addition arrays are +implemented via std::vector. The following naming conventions are used +in typedefs:

+
+
Ptr
+
When Ptr appears it stands for std::tr1::shared_ptr.
+
Array
+
When Array appears it stands for std::vector.
+
+ +

As an example pvType.h includes the following definitions:

+
typedef std::vector<double> DoubleArray;
+typedef std::tr1::shared_ptr<DoubleArray> DoubleArrayPtr;
+inline double * get(DoubleArray &value)
+{
+    return &value[0];
+}
+inline const double * get(const DoubleArray &value)
+{
+    return static_cast<const double *>(&value[0]);
+}
+typedef std::vector<double>::iterator DoubleArray_iterator;
+typedef std::vector<double>::const_iterator DoubleArray_const_iterator;
+ +

where

+
+
DoubleArray
+
This defines a vector for an array of the primitive type "double".
+
DoubleArrayPtr
+
This devices a shared pointer to a vector for an array of the primitive + type "double".
+
get
+
This gets the raw array of doubles that the DoubleArray holds.
+
DoubleArray_iterator
+
This gets a iterator for the DoubleArray.
+
DoubleArray_const_iterator
+
This gets a constant iterator for the DoubleArray.
+
+ +

pvDataApp/pv

+ +

Overview

+ +

Directory pvDataApp/pv has header files that completely describe pvData. The +implementation is provided in directory pvDataApp/factory. Test programs +appears in testApp/pv.

+ +

NOTES:

+
+
interface
+
The documention uses the word interface. This is an analogy for + what the Java implementation implements, i. e. package pv provides Java + interfaces. C++ does not have interfaces but directory pv defines classes + with public members that are similar to the Java interfaces. Most of the + implementation is in factory.
+
Naming Convertions
+
The naming convertions for variables, methods, and classes follow the + Java convertions, i. e. class name begin with an upper case letter, + variables and methods begin with a lower case letter.
+
+ +

A PVStructure is a field that contains an array of subfields. Each field has +code for accessing the field. The interface for each field is an interface that +extends PVField. Each field also has an introspection interface, which an +extension of Field. This section describes the complete set of C++ +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 pvDataApp/pv has the following header files:

+
+
pvType.h
+
C++ definitions for primitive types.
+
pvIntrospect.h
+
A complete description of the introspection interfaces.
+
pvData.h
+
A complete description of the data interfaces.
+
convert.h
+
A facility that converts between data fields.
+
standardField.h
+
Provides access to introspection interfaces for standard structures + like timeStamp, alarm, etc.
+
standardPVField.h
+
Cteates data interfaces for standard data structures like timeStamp, + alarm, etc.
+
+ +

pvType.h

+ +

This provides C/C++ definitions for the pvData primitive types: boolean, +byte, short, int, long, ubyte,ushort, uint,u long,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 has the definitions:

+
typedef uint8_t  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::string String;
+
+/**
+ * A boolean array.
+ */
+typedef std::vector<uint8> BooleanArray;
+typedef std::tr1::shared_ptr<BooleanArray> BooleanArrayPtr;
+/* get is same is ubyte*/
+typedef std::vector<uint8>::iterator BooleanArray_iterator;
+typedef std::vector<uint8>::const_iterator BooleanArray_const_iterator;
+
+/**
+ * A byte array.
+ */
+typedef std::vector<int8> ByteArray;
+typedef std::tr1::shared_ptr<ByteArray> ByteArrayPtr;
+inline int8 * get(ByteArray &value);
+inline int8 const * get(ByteArray const &value);
+inline int8 * get(ByteArrayPtr &value);
+inline int8 const * get(ByteArrayPtr const &value);
+inline ByteArray & getVector(ByteArrayPtr &value);
+inline ByteArray const & getVector(ByteArrayPtr const &value);
+typedef std::vector<int8>::iterator ByteArray_iterator;
+typedef std::vector<int8>::const_iterator ByteArray_const_iterator;
+
+/* similar definitions are present for ALL the primitive types */
+ +

where

+
+
boolean
+
A c++ bool has the semantics required for boolean. Only the name is + different. C++ code can use either bool or boolean.
+
int8,...,uint64
+
Integers present a problem because short, int, and long are C++ + reserved words but do not have a well defined number of bits. Thus for + C++ the definitions above are used in C++ code. The above definitions + have worked on all C++ implementations tested at present. If they break + in a future implementation they should be changes via "#ifdef" + preprocessor statements.
+
String
+
pvData requires that a string be an immutable string that is transfered + over the network as a UTF8 encoded string. Since std::string implements + copy on write semantics, it can be used for support for immutable + strings. It can also be serialized/deserialized as a UTF8 encoded string. + Because it is not a C++ primitive the first letter is capitalized. This + is the same convention the Java implementation uses.
+
StringBuilder
+
This is defined here because to is used by the toString methods defined + for both introsection and data objects. The definition above acts like + the Java StringBuilder class.
+
Array definitions
+
typedefs are provided for an array of each of the primitive types. Note + that string is treated like a primitive type/
+
+ +

pvIntrospect.h

+ +

This subsection describes pvIntrospect.h This file is quite big so rather +than showing the entire file, it will be described in parts.

+ +

A primary reason for pvData is to support network access to structured data. +pvAccess transports top level pvStructures. In addition a pvAccess server holds +a set of pvnames, where each pvname if a unique name in the local network.

+ +

Given a pvname PV), it is possible to introspect the field without requiring +access to data. The reflection and data interfaces are separate because the +data may not be available. For example when a pvAccess client connects to a PV, +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.

+ +

Type Description

+ +

Types are defined as:

+
enum Type {
+    scalar,
+    scalarArray,
+    structure,
+    structureArray;
+};
+
+class TypeFunc {
+public:
+    const char* name(Type);
+    static void toString(StringBuilder buf,const 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(String const &value);
+    const char* name(ScalarType);
+    void toString(StringBuilder buf,ScalarType scalarType);
+};
+ +

Type is one of the following:

+
+
scalar
+
A scalar of one of the scalar types.
+
scalarArray
+
An array where every element has the same scalar type.
+
structure
+
A structure where each field has a name and a type. Within a structure + each field name must be unique but the types can be different.
+
structureArray
+
An array where each element is a structure. Each element has the same + structure introspection interface.
+
+ +

ScalarType is one of the following:

+
+
pvBoolean
+
Has the value false or true.
+
pvByte
+
A signed 8 bit integer.
+
pvShort
+
A signed 16 bit integer.
+
pvInt
+
A signed 32 bit integer.
+
pvLong
+
A signed 64 bit integer.
+
pvUByte
+
An unsigned 8 bit integer.
+
pvUShort
+
An unsigned 16 bit integer.
+
pvUInt
+
An unsigned 32 bit integer.
+
pvULong
+
An unsigned 64 bit integer.
+
pvFloat
+
A IEEE float.
+
pvDouble
+
A IEEE double,
+
pvString
+
An immutable string.
+
+ +

TypeFunction is a set of convenience methods for Type

+
+
name
+
Returns the name of the type.
+
toString
+
Convert the type to a string.
+
+ +

ScalarTypeFunction is a set of convenience methods for ScalarType

+
+
isInteger
+
Is the scalarType an integer type, i.e. one of pvByte,...pvULong.
+
isUInteger
+
Is the scalarType an unsigned integer type, i.e. one of + pvUByte,...pvULong
+
isNumeric
+
Is the scalarType numeric, i.e. pvByte,...,pvDouble.
+
isPrimitive
+
Is the scalarType primitive, i.e. not pvString
+
name
+
Returns the name of the scalarType.
+
getScalarType
+
Given a string of the form String("boolean"),...,String("string") + return the scalarType.
+
toString
+
Convert the scalar type to a string.
+
+ +

Introspection Description

+ +

This section describes the reflection interfaces which provide the +following:

+
+
Field
+
A field: +
    +
  • Has a Type.
  • +
  • Can be converted to a string.
  • +
  • Can be shared. A reference count is kept. When it becomes 0 the + instance is automatically deleted.
  • +
+
+
Scalar
+
A scalar has a scalarType
+
ScalarArray
+
The element type is a scalarType
+
StructureArray
+
The field holds an array of structures. Each element has the same + Structure interspection interface. A pvAccess client can only get/put + entire PVStructure elements NOT subfields of array elements.
+
Structure
+
Has fields that can be any of the supported types.
+
FieldCreate
+
This is an interface that provides methods to create introspection + interfaces. A factory is provides to create FieldCreate.
+
getFieldCreate
+
Gets a pointer to the single instance of FieldCreate.
+
+
class Field;
+class Scalar;
+class ScalarArray;
+class Structure;
+class StructureArray;
+
+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;
+
+
+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 String getID() const = 0;
+    virtual void toString(StringBuilder buf) const{toString(buf,0);}
+    virtual void toString(StringBuilder buf,int indentLevel) const;
+ ...
+};
+
+class Scalar : public Field{
+public:
+    POINTER_DEFINITIONS(Scalar);
+    virtual ~Scalar();
+    typedef Scalar& reference;
+    typedef const Scalar& const_reference;
+
+    ScalarType getScalarType() const {return scalarType;}
+    virtual void toString(StringBuilder buf) const{toString(buf,0);}
+    virtual void toString(StringBuilder buf,int indentLevel) const;
+    virtual String getID() const;
+    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+    virtual void deserialize(ByteBuffer *buffer, DeserializableContol *control);
+ ...
+};
+
+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 void toString(StringBuilder buf) const{toString(buf,0);}
+    virtual void toString(StringBuilder buf,int indentLevel) const;
+    virtual String getID() const;
+    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
+ ...
+};
+
+class StructureArray : public Field{
+public:
+    POINTER_DEFINITIONS(StructureArray);
+    typedef StructureArray& reference;
+    typedef const StructureArray& const_reference;
+
+    StructureConstPtr  getStructure() const {return pstructure;}
+    virtual void toString(StringBuilder buf,int indentLevel=0) const;
+    virtual String getID() const;
+    virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+    virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
+ ...
+};
+
+class Structure : public Field {
+public:
+    POINTER_DEFINITIONS(Structure);
+    typedef Structure& reference;
+    typedef const Structure& const_reference;
+
+   std::size_t getNumberFields() const {return numberFields;}
+   FieldConstPtr getField(String const & fieldName) const;
+   FieldConstPtr getField(std::size_t index) const;
+   std::size_t getFieldIndex(String const &fieldName) const;
+   FieldConstPtrArray const & getFields() const {return fields;}
+   StringArray const & getFieldNames() const;
+   void renameField(std::size_t fieldIndex,String const &newName);
+   String getFieldName(std::size_t fieldIndex);
+   virtual void toString(StringBuilder buf,int indentLevel) const;
+   virtual String getID() const;
+   virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
+   virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
+ ...
+};
+
+class FieldCreate  {
+public:
+    static FieldCreatePtr getFieldCreate();
+    ScalarConstPtr  createScalar(ScalarType scalarType) const
+    ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
+    StructureArrayConstPtr createStructureArray(StructureConstPtr const & structure) const;
+    StructureConstPtr createStructure (
+        StringArray const & fieldNames,
+        FieldConstPtrArray const & fields) const;
+    StructureConstPtr createStructure (
+        String const &id,
+        StringArray const & fieldNames,
+        FieldConstPtrArray const & fields) const;
+    StructureConstPtr appendField(
+        StructureConstPtr const & structure,
+        String const &fieldName, FieldConstPtr const & field) const;
+    StructureConstPtr appendFields(
+        StructureConstPtr const & structure,
+        StringArray const & fieldNames,
+        FieldConstPtrArray const & fields) const;
+    FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
+ ...
+};
+
+extern FieldCreatePtr getFieldCreate(); 
+
+
Constructor
+
Note that all constructors are protected or private. The only way to + create instances is via FieldCreate. The implementation manages all + storage via shared pointers.
+
toString
+
Many classes provide this (actually two methods). This method is called + to get a string that uses the metadata syntax described in a previous + section.
+
+ +
Field
+
+
getType
+
Get the field type.
+
getID
+
Get an ID for this introspection interface
+
+ +
Scalar
+
+
getScalarType
+
Get that scalar type.
+
getID
+
For each scalarType there is one instance of Scalar. The ID for each is + the metadata name for the type, i. e. one of "boolean" , ... , "string". +
+
+ +
ScalarArray
+
+
getElementType
+
Get the element type.
+
getID
+
For each elemnetType there is one instance of ScalarArray. The ID for + each is the metadata name for the type, i. e. one of "boolean[]" , ... , + "string[]".
+
+ +
StructureArray
+
+
getStructure
+
Get the introspection interface that each element shares,
+
getID
+
This returns the ID[] where ID is the value returned by + structure->getID().
+
+ +
Structure
+
+
getNumberFields
+
Get the number of immediate subfields.
+
getField
+
Given a name or an index get the introspection interface for the + field.
+
getFieldIndex
+
Given a name get the index, within the array returned by the next + method, of the field.
+
getFields
+
Get the array of introspection interfaces for the field,
+
getFieldNames
+
Get the array of field names for the subfields.
+
renameField
+
Rename the field.
+
getFieldName
+
Get the field name for the specified index.
+
+ +
FieldCreate
+
+
getFieldCreate
+
Get the single instance of FieldCreate.
+
createScalar
+
Create a scalar introspection instance.
+
createScalarArray
+
Create a scalar array introspection instance.
+
createStructure
+
Create a structure introspection instance. Two methods are provided + where the only difference is that one provides an ID and the other does + not. The one without will result in ID "structure".
+
createStructureArray
+
Create a structure array introspection instance.
+
appendField
+
Append a field to a structure.
+
appendFields
+
Append fields to a structure.
+
deserialize
+
Deserialize from given byte buffer.
+
+ +

standardField.h

+ +

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,String const &properties);
+    StructureConstPtr scalarArray(
+        ScalarType elementType, String const &properties);
+    StructureConstPtr structureArray(
+        StructureConstPtr const & structure,String const &properties);
+    StructureConstPtr enumerated();
+    StructureConstPtr enumerated(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();
+ ...
+};
+
+
scalar
+
Create a scalar with the specified scalar type and name. A structure + will be created with the first element being a scalar with the specified + scalar type and name value. The other fields in the structure will be the + corresponding property structures.
+
scalarArray
+
Create a scalarArray with each element having the specified scalar type + and name. A structure will be created with the first element being a + scalarArray with name value. The other fields in the structure will be + the corresponding property structures.
+
structureArray
+
Create a structureArray with the specified structure interface and + name. A structure will be created with the first element being a + structureArray with the specified structure interface and name value. The + other fields in the structure will be the corresponding property + structures.
+
structure
+
Create a structure with the specified name and fields specified by + numFields and fields. A structure will be created with the first element + being a structure with the name value and fields specified by numFields + and fields. The other fields in the structure will be the corresponding + property structures.
+
enumerated
+
Create a structure with the specified name and fields for an enumerated + structure. If properties are specified then a structure will be created + with the first element being a structure with the name value and fields + for an enumerated structure. The other fields in the structure will be + the corresponding property structures.
+
alarm
+
timeStamp
+
display
+
control
+
booleanAlarm
+
byteAlarm
+
shortAlarm
+
intAlarm
+
longAlarm
+
floatAlarm
+
doubleAlarm
+
enumeratedAlarm
+
The above provide introspection interfaces for standard properties. See + the section on Properties for a description of how these are defined.
+
+ +

pvData.h

+ +

This subsection describes pvData.h This file is quite big so rather than +showing the entire file, it will be described in parts.

+ +

typedefs

+ +

These are typedefs for Array and Ptr for the various pvData class +definitions, i.e. typdefs for "std::vector" and "std::tr1::shared_ptr".

+
class PVAuxInfo;
+class PostHandler;
+
+class PVField;
+class PVScalar;
+
+class PVScalarArray;
+
+class PVStructure;
+class PVStructureArray;
+
+typedef std::tr1::shared_ptr<PVAuxInfo> PVAuxInfoPtr;
+
+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 std::tr1::shared_ptr<PostHandler> PostHandlerPtr
+ +

PostHandler is a class that must be implemented by any code that calls +setPostHandler. It's single virtual method. postPut is called whenever +PVField::postPut is called.

+
class PostHandler 
+{
+public:
+    POINTER_DEFINITIONS(PostHandler);
+    virtual ~PostHandler(){}
+    virtual void postPut() = 0;
+};
+ +

PVField

+ +

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 PVField
+: virtual public Serializable,
+  public std::tr1::enable_shared_from_this<PVField>
+{
+public:
+   POINTER_DEFINITIONS(PVField);
+   virtual ~PVField();
+   virtual void message(String message,MessageType messageType);
+   String getFieldName() const ;
+   virtual void setRequester(RequesterPtr const &prequester);
+   std::size_t getFieldOffset() const;
+   std::size_t getNextFieldOffset() const;
+   std::size_t getNumberFields() const;
+   PVAuxInfoPtr & getPVAuxInfo()
+   bool isImmutable() const;
+   virtual void setImmutable();
+   const FieldConstPtr & getField() const ;
+   PVStructure * getParent() const 
+   void replacePVField(const PVFieldPtr&  newPVField);
+   void renameField(String const &newName);
+   void postPut() ;
+   void setPostHandler(PostHandlerPtr const &postHandler);
+   virtual bool equals(PVField &pv);
+   virtual void toString(StringBuilder buf) ;
+   virtual void toString(StringBuilder buf,int indentLevel);
+   std::ostream& dumpValue(std::ostream& o) const;
+ ...
+}
+ +

The public methods for PVField are:

+
+
~PVField
+
Destructor. Since shared pointers are used it should never be called by + user code.
+
message
+
Code attached to this field can call this method to report + problems.
+
getFieldName
+
Get the field name. If the field is a top level structure the field + name will be an empty string.
+
setRequester
+
Sets a requester to be called when message or getRequesterName are + called. This is only legal for the top level PVField.
+
getFieldOffset
+
Get offset of the PVField field within top level structure. Every field + within the PVStructure has a unique offset. The top level structure has + an offset of 0. The first field within the structure has offset equal to + 1. The other offsets are determined by recursively traversing each + structure of the tree.
+
getNextFieldOffset
+
Get the next offset. If the field is a scalar or array field then this + is just offset + 1. If the field is a structure it is the offset of the + next field after this structure. Thus (nextOffset - offset) is always + equal to the total number of fields within the field.
+
getNumberFields
+
Get the total number of fields in this field. This is nextFieldOffset - + fieldOffset.
+
getPVAuxInfo
+
Get the PVAuxInfo for this field. PVAuxInfo is described below.
+
isImmutable
+
Is the field immutable?
+
setImmutable
+
Make the field immutable. Once a field is immutable it can never be + changed since there is no method to again make it mutable. This is an + important design decision since it allows immutable array fields to share + the internal primitive data array.
+
getField
+
Get the reflection interface for the data.
+
getParent
+
Get the interface for the parent or null if this is the top level + PVStructure.
+
replacePVField
+
Replace the data implementation for the field.
+
renameField
+
Rename the field name.
+
postPut
+
If a postHandler is registered it is called otherwise no action is + taken.
+
setPostHandler
+
Set the postHandler for the record. Only a single handler can be + registered.
+
equals
+
Compare this field with another field. The result will be true only if + the fields have exactly the same field types and if the data values are + equal.
+
toString
+
Converts the field data to a string. This is mostly for debugging + purposes.
+
dumpValue
+
Method for streams I/O.
+
+ +

PVAuxInfo

+ +

AuxInfo (Auxillary Information) is information about a field that is +application specific. It will not be available outside the application that +implements the database. In particular it will not be made available to Channel +Access. It is used by the database itself to override the default +implementation of fields. The JavaIOC uses it for attaching support code. +Database Configuration and other tools can use it for configuration +information. Each Field and each PVField can have have an arbitrary number of +auxInfos. An auxInfo is a (key,PVScalar) pair where key is a string.

+
class PVAuxInfo : private NoDefaultMethods {
+public:
+    typedef std::map<String,PVScalarPtr> PVInfoMap;
+    typedef std::map<String,PVScalarPtr>::iterator PVInfoIter;
+    typedef std::pair<String,PVScalarPtr> PVInfoPair;
+
+    PVAuxInfo(PVField *pvField);
+    ~PVAuxInfo();
+    PVField * getPVField();
+    PVScalarPtr createInfo(String const &key,ScalarType scalarType);
+    PVScalarPtr getInfo(String const &key);
+    PVInfoMap & getInfoMap();
+    void toString(StringBuilder buf);
+    void toString(StringBuilder buf,int indentLevel);
+ ...
+};
+ +

where

+
+
getPVField
+
Get the PVField to which this PVAuxInfo is attached.
+
createInfo
+
Create a new PVScalar of type scalarType.
+
getInfo
+
Get the PVScalar with the specified key.
+
getInfoMap
+
Get the map of all the PVScalars that hold the info.
+
toString
+
Print all the auxInfos
+
+ +

PVScalar

+ +

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 ;
+ ...
+}
+ +

where

+
+
getScalar
+
Get the introspection interface for the PVScalar.
+
+ +

PVScalarValue

+ +

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;
+    virtual ~PVScalarValue() {}
+    virtual T get() const = 0;
+    virtual void put(T value) = 0;
+ ...
+}
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+};
+ +

where

+
+
get
+
Get the value stored in the object.
+
put
+
Change the value stored in the object.
+
+ +

PVArray

+ +

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 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;
+ ...
+};
+
+
setImmutable
+
Set the data immutable. Note that this is permanent since there is no + methods to make it mutable.
+
getLength
+
Get the current length. This is less than or equal to the capacity.
+
setLength
+
Set the length. If the PVField is not mutable then an exception is + thrown. If this is greater than the capacity setCapacity is called.
+
getCapacity
+
Get the capacity, i.e. this is the size of the underlying data + array.
+
setCapacity
+
Set the capacity. The semantics are implementation dependent but + typical semantics are as follows: If the capacity is not mutable an + exception is thrown. A new data array is created and data is copied from + the old array to the new array.
+
isCapacityMutable
+
Is the capacity mutable
+
setCapacityMutable
+
Specify if the capacity can be changed.
+
setCapacity
+
Set the capaciity.
+
+ +

PVArrayData

+ +

This is the argument to one of the get methods of PVValueArray.

+
template<typename T>
+class PVArrayData {
+private:
+    std::vector<T> init;
+public:
+    POINTER_DEFINITIONS(PVArrayData);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    std::vector<T> & data;
+    std::size_t offset;
+    PVArrayData()
+    : data(init)
+    {}
+};
+ +

PVScalarArray

+ +

PVScalarArray is the base class for scalar array data. PVValueArray is a +templete for the various scalar array data classes. There is a class for each +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 ;
+    virtual std::ostream& dumpValue(std::ostream& o, size_t index) const = 0;
+ ...
+}
+ +

where

+
+
getScalarArray
+
Get the introspection interface.
+
dumpValue
+
Method for streams I/O.
+
+ +

PVValueArray

+ +

This is a template class plus instances for PVBooleanArray, ..., +PVStringArray.

+
template<typename T>
+class PVValueArray : public PVScalarArray {
+public:
+    POINTER_DEFINITIONS(PVValueArray);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    typedef PVArrayData<T> ArrayDataType;
+    typedef std::vector<T> vector;
+    typedef const std::vector<T> const_vector;
+    typedef std::tr1::shared_ptr<vector> shared_vector;
+    typedef PVValueArray & reference;
+    typedef const PVValueArray & const_reference;
+
+    virtual ~PVValueArray() {}
+    virtual std::size_t get(
+         std::size_t offset, std::size_t length, ArrayDataType &data) = 0;
+    virtual std::size_t put(std::size_t offset,
+        std::size_t length, const_pointer from, std::size_t fromOffset) = 0;
+    virtual std::size_t put(std::size_t offset,
+        std::size_t length, const_vector &from, std::size_t fromOffset);
+    virtual void shareData(
+         shared_vector const & value,
+         std::size_t capacity,
+         std::size_t length) = 0;
+    virtual pointer get() = 0;
+    virtual pointer get() const = 0;
+    virtual vector const & getVector() = 0;
+    virtual shared_vector const & getSharedVector() = 0;
+    std::ostream& dumpValue(std::ostream& o) const;
+    std::ostream& dumpValue(std::ostream& o, size_t index) const;
+protected:
+    PVValueArray(ScalarArrayConstPtr const & scalar)
+    : PVScalarArray(scalar) {}
+    friend class PVDataCreate;
+};
+
+template<typename T>
+std::size_t PVValueArray<T>::put(
+    std::size_t offset,
+    std::size_t length,
+    const_vector &from,
+    std::size_t fromOffset)
+{ return put(offset,length, &from[0], fromOffset); }
+
+/**
+ * Definitions for the various scalarArray types.
+ */
+typedef PVArrayData<uint8> BooleanArrayData;
+typedef PVValueArray<uint8> PVBooleanArray;
+typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
+
+typedef PVArrayData<int8> ByteArrayData;
+typedef PVValueArray<int8> PVByteArray;
+typedef std::tr1::shared_ptr<PVByteArray> PVByteArrayPtr;
+
+typedef PVArrayData<int16> ShortArrayData;
+typedef PVValueArray<int16> PVShortArray;
+typedef std::tr1::shared_ptr<PVShortArray> PVShortArrayPtr;
+
+typedef PVArrayData<int32> IntArrayData;
+typedef PVValueArray<int32> PVIntArray;
+typedef std::tr1::shared_ptr<PVIntArray> PVIntArrayPtr;
+
+typedef PVArrayData<int64> LongArrayData;
+typedef PVValueArray<int64> PVLongArray;
+typedef std::tr1::shared_ptr<PVLongArray> PVLongArrayPtr;
+
+typedef PVArrayData<uint8> UByteArrayData;
+typedef PVValueArray<uint8> PVUByteArray;
+typedef std::tr1::shared_ptr<PVUByteArray> PVUByteArrayPtr;
+
+typedef PVArrayData<uint16> UShortArrayData;
+typedef PVValueArray<uint16> PVUShortArray;
+typedef std::tr1::shared_ptr<PVUShortArray> PVUShortArrayPtr;
+
+typedef PVArrayData<uint32> UIntArrayData;
+typedef PVValueArray<uint32> PVUIntArray;
+typedef std::tr1::shared_ptr<PVUIntArray> PVUIntArrayPtr;
+
+typedef PVArrayData<uint64> ULongArrayData;
+typedef PVValueArray<uint64> PVULongArray;
+typedef std::tr1::shared_ptr<PVULongArray> PVULongArrayPtr;
+
+typedef PVArrayData<float> FloatArrayData;
+typedef PVValueArray<float> PVFloatArray;
+typedef std::tr1::shared_ptr<PVFloatArray> PVFloatArrayPtr;
+
+typedef PVArrayData<double> DoubleArrayData;
+typedef PVValueArray<double> PVDoubleArray;
+typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr;
+
+typedef PVArrayData<String> StringArrayData;
+typedef PVValueArray<String> PVStringArray;
+typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
+ +

where

+
+
get( std::size_t offset, std::size_t length, ArrayDataType &data) +
+
This method "exposes" it's internal array by setting data.data and + data.offset. The caller is responsible for copying the array elements. + This violates the principle that objects should not expose their internal + data but is done for efficency. For example it makes it possible to copy + between arrays with identical element types without requiring an + intermediate array.
+
put(std::size_t offset, std::size_t length, const_pointer from, + std::size_t fromOffset)
+
Put data into the array. from is a raw array.
+
put(std::size_t offset, std::size_t length, const_vector &from, + std::size_t fromOffset)
+
Put data into the array from a vector holding the raw array.
+
shareData( shared_vector const & value, std::size_t capacity, + std::size_t length)
+
Make the instance share the raw data from value.
+ One use is + for immutable arrays. In this case the caller must set the PVArray to be + immutable. In the PVArray is not immutable then it is the applications + responsibility to coordinate access to the array. Again this violates the + principle that objects should not expose their internal data but is + important for immutable arrays. For example pvData and the javaIOC define + many enumerated structures where an enumerated structure has two fields: + index and choices. Choices is a PVStringArray that holds the enumerated + choices. Index is a PVInt that is the index of the currently selected + choice. For many enumerated structures choices is immutable. Allowing the + choices internal String[] to be shared between all the instances of an + enumerated structure saves on storage.
+ Another use for shared data is an application which processes an + array via multiple modules. Each accesses the internal data array of a + PVArray. In this case it is the applications responsibility + to coordinate access to the array.
+
get()
+
Get the raw array.
+
getVector()
+
Get the vector holding the raw array.
+
getSharedVector()
+
Get the shared vector holding the data.
+
dumpValue
+
Method for streams I/O.
+
+ +

Both get and put return the number of elements actually transfered. The +arguments are:

+
+
offset
+
The offset in the PV array.
+
len
+
The maximum number of elements to transfer. The number actually + transfered will be less than or equal to this value.
+
data
+
Get sets data.data to it's internal array and data.offset to the offset + into the array. The caller is responsible for the actual data + transfer.
+
from
+
The array from which the data is taken. This array is supplied by the + caller
+
fromOffset
+
The offset in from
+
+ +

The caller must be prepared to make multiple calls to retrieve or put an +entire array. A caller should accept or put partial arrays. For example the +following reads an entire array:

+
void getArray(PVDoubleArrayPtr & pv,DoubleArray const & to)
+{
+    size_t len = pv->getLength();
+    if(to.size()<len) to.resize(len);
+    DoubleArrayData data;
+    size_t offset = 0;
+    while(offset<len) {
+        size_t num = pv->get(offset,(len-offset),data);
+        DoubleArray &from = data.data;
+        size_t fromOffset = data.offset;
+        for(size_t i=0; i<num; i++) to[i+offset] = from[i + fromOffset];
+        offset += num;
+    }
+} 
+ +

+ +

PVStructure

+ +

The interface for a structure is:

+
class PVStructure : public PVField,public BitSetSerializable {
+public:
+    POINTER_DEFINITIONS(PVStructure);
+    virtual ~PVStructure();
+    typedef PVStructure & reference;
+    typedef const PVStructure & const_reference;
+    virtual void setImmutable();
+    StructureConstPtr getStructure() const;
+    const PVFieldPtrArray & getPVFields() const;
+    PVFieldPtr getSubField(String const &fieldName) const;
+    PVFieldPtr getSubField(std::size_t fieldOffset) const;
+    void appendPVField(
+        String const &fieldName,
+        PVFieldPtr const & pvField);
+    void appendPVFields(
+        StringArray const & fieldNames,
+        PVFieldPtrArray const & pvFields);
+    void removePVField(String const &fieldName);
+    PVBooleanPtr getBooleanField(String const &fieldName) ;
+    PVBytePtr getByteField(String const &fieldName) ;
+    PVShortPtr getShortField(String const &fieldName) ;
+    PVIntPtr getIntField(String const &fieldName) ;
+    PVLongPtr getLongField(String const &fieldName) ;
+    PVUBytePtr getUByteField(String const &fieldName) ;
+    PVUShortPtr getUShortField(String const &fieldName) ;
+    PVUIntPtr getUIntField(String const &fieldName) ;
+    PVULongPtr getULongField(String const &fieldName) ;
+    PVFloatPtr getFloatField(String const &fieldName) ;
+    PVDoublePtr getDoubleField(String const &fieldName) ;
+    PVStringPtr getStringField(String const &fieldName) ;
+    PVStructurePtr getStructureField(String const &fieldName) ;
+    PVScalarArrayPtr getScalarArrayField(
+        String const &fieldName,ScalarType elementType) ;
+    PVStructureArrayPtr getStructureArrayField(String const &fieldName) ;
+    String getExtendsStructureName() const;
+    bool putExtendsStructureName(
+        String const &extendsStructureName);
+    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);
+};
+ +

where

+
+
getStructure
+
Get the introspection interface for the structure.
+
getPVFields
+
Returns the array of subfields. The set of subfields must all have + different field names.
+
getSubField(String fieldName)
+
Get a subField of a field. For a PVStructure a non-null result is + returned if fieldName is a field of the PVStructure. The fieldName can be + of the form name.name... + If the field does not exist the a Ptr to a NULL value is returned + without any error message being generated. +
+
getSubField(int fieldOffset)
+
Get the field located a fieldOffset, where fieldOffset is relative to + the top level structure. This returns null if the specified field is not + located within this PVStructure.
+
appendPVField
+
Append pvField to the end of this PVStructure. This should NOT be + called if any code is attached to any of the fields in the top level + structure.
+
appendPVFields
+
Append an array of pvFields to the end of this structure. Note that if + the original number of fields is 0 than pvFields replaces the original. + Thus the caller must NOT reuse pvFields after calling this method. This + should NOT be called if any code is attached to any of the fields in the + top level structure
+
removePVField
+
Remove the specified field from this structure. This should NOT be + called if any code is attached to any of the fields in the top level + structure.
+
getBooleanField
+
Look for fieldName. If found and it has the correct type return the + interface. This and the following methods are convenience methods that + allow a user to get the interface to a subfield without requiring + introspection. fieldName can be of the form name.name... + If the field does not exist or has the wrong type then + message will be called and a Ptr to NULL is returned. +
+
getByteField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getShortField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getIntField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getLongField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getUByteField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getUShortField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getUIntField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getULongField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getFloatField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getDoubleField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getStringField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getStructureField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getScalarArrayField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getStructureArrayField
+
Look for fieldName. If found and it has the correct type return the + interface.
+
getExtendsStructureName
+
Get the name of structure that this structure extends.
+
putExtendsStructureName
+
Specify the structure that this structure extends.
+
+ +

PVStructureArray

+ +

The interface for an array of structures is:

+
typedef PVArrayData<PVStructurePtr> StructureArrayData;
+
+class PVStructureArray : public PVArray
+{
+public:
+    POINTER_DEFINITIONS(PVStructureArray);
+    typedef PVStructurePtr  value_type;
+    typedef PVStructurePtr* pointer;
+    typedef const PVStructurePtr* const_pointer;
+    typedef PVArrayData<PVStructurePtr> ArrayDataType;
+    typedef std::vector<PVStructurePtr> vector;
+    typedef const std::vector<PVStructurePtr> const_vector;
+    typedef std::tr1::shared_ptr<vector> shared_vector;
+    typedef PVStructureArray &reference;
+    typedef const PVStructureArray& const_reference;
+
+    virtual ~PVStructureArray() {}
+    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 std::size_t get(std::size_t offset, std::size_t length,
+        StructureArrayData &data);
+    virtual std::size_t put(std::size_t offset,std::size_t length,
+        const_vector const & from, std::size_t fromOffset);
+    virtual void shareData(
+         shared_vector const & value,
+         std::size_t capacity,
+         std::size_t length);
+    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 pointer get() { return &((*value.get())[0]); }
+    virtual pointer get() const { return &((*value.get())[0]); }
+    virtual vector const & getVector() {return *value;}
+    virtual shared_vector const & getSharedVector() {return value;}
+ ...
+}
+ +

where

+
+
getStructureArray
+
Get the introspection interface shared by each element.
+
append
+
Create new elements and append them to the end of the array. It returns + the index of the first new element.
+
remove
+
Remove the specfied set of elements. It returns (false,true) if the + elements (were not, were) removed. It will not removed any elements + unless all requested elements exist or are null. Note that this deletes + the element and sets the array element to null. It does not change the + array capacity.
+
compress
+
This moves all null elements and then changes the array capacity. When + done there are no null elements.
+
+ +

The other methods are similar to the methods for other array types.

+ +

PVDataCreate

+ +

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);
+    PVScalarArrayPtr createPVScalarArray(ScalarArrayConstPtr const & scalarArray);
+    PVScalarArrayPtr createPVScalarArray(ScalarType elementType);
+    PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const  & scalarArrayToClone);
+    PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const & structureArray);
+    PVStructurePtr createPVStructure(StructureConstPtr const & structure);
+    PVStructurePtr createPVStructure(
+        StringArray const & fieldNames,PVFieldPtrArray const & pvFields);
+   PVStructurePtr createPVStructure(PVStructurePtr const & structToClone);
+ ...
+};
+
+extern PVDataCreatePtr getPVDataCreate();
+ +

where

+
+
createPVField
+
The PVField is created reusing the Field interface. Two methods are + provided. Each calls the corresponding createPVScalar, createPVArray, or + createPVStructure depending in the type of the last argument.
+
createPVScalar
+
Creates an instance of a PVScalar. Three versions are supplied. The + first is passed an introspection interface. The second provides the field + name and the scalarType. The last provides a field name and a PVScalar to + clone. The newly created PVScalar will have the same auxInfos as the + original.
+
createPVScalarArray
+
Create an instance of a PVArray. Three versions are supplied. The first + is passed an introspection interface. The second provides the field name + and the elementType. The last provides a field name and a PVArray to + clone. The newly created PVArray will have the same auxInfos as the + original.
+
createPVStructureArray
+
Create a PVStructureArray. It must be passed a structureToClone. This + will become the Structure interface for ALL elements of the + PVStructureArray. It MUST be used to create any new array elements.
+
createPVStructure
+
Create an instance of a PVStructure. Three methods are provided. The + first method uses a previously created structure introspection interface. + The second uses a PVField array to initialize the sub-fields. + The third initializes the subfields by cloning the fields contained in + structToClone. The newly created sub-fields will have the same values and + auxInfos as the original. If structToClone is null then the new structure + is initialized to have 0 sub-fields.
+
+ +

standardPVField.h

+ +

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,String const &properties);
+    PVStructurePtr scalarArray(ScalarType elementType, String const &properties);
+    PVStructurePtr structureArray(StructureConstPtr const &structure,String const &properties);
+    PVStructurePtr enumerated(StringArray const &choices);
+    PVStructurePtr enumerated(StringArray const &choices, String const &properties);
+ ...
+}
+
+
+extern StandardPVFieldPtr getStandardPVField();
+ +

convert.h

+ +

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 inline bool operator!=(PVField& a, PVField& b)
+{return !(a==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&);
+
+static inline bool operator!=(const Field& a, const Field& b)
+{return !(a==b);}
+static inline bool operator!=(const Scalar& a, const Scalar& b)
+{return !(a==b);}
+static inline bool operator!=(const ScalarArray& a, const ScalarArray& b)
+{return !(a==b);}
+static inline bool operator!=(const Structure& a, const Structure& b)
+{return !(a==b);}
+static inline bool operator!=(const StructureArray& a, const StructureArray& b)
+{return !(a==b);}
+class Convert;
+typedef std::tr1::shared_ptr<Convert> ConvertPtr;
+
+class Convert {
+public:
+    static ConvertPtr getConvert();
+    ~Convert();
+    void getFullName(StringBuilder buf,PVFieldPtr const & pvField);
+    bool equals(PVFieldPtr const &a,PVFieldPtr const &b);
+    bool equals(PVField &a,PVField &b);
+    void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel);
+    void getString(StringBuilder buf,PVFieldPtr const & pvField);
+    void getString(StringBuilder buf,PVField const * pvField,int indentLevel);
+    void getString(StringBuilder buf,PVField const * pvField);
+    std::size_t fromString(
+        PVStructurePtr const &pv,
+        StringArray const & from,
+        std::size_t fromStartIndex = 0);
+    void fromString(PVScalarPtr const & pv, String const & from);
+    std::size_t fromString(PVScalarArrayPtr const & pv, 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);
+    std::size_t copyScalarArray(
+        PVScalarArrayPtr const & from,
+        std::size_t offset,
+        PVScalarArrayPtr const & to,
+        std::size_t toOffset,
+        std::size_t length);
+    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);
+    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);
+    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);
+    std::size_t toByteArray(PVScalarArrayPtr const & pv,
+        std::size_t offset,
+        std::size_t length,
+        int8* to,
+        std::size_t toOffset);
+    std::size_t toShortArray(PVScalarArrayPtr const & pv,
+        std::size_t offset,
+        std::size_t length,
+        int16* to,
+        std::size_t toOffset);
+    std::size_t toIntArray(PVScalarArrayPtr const & pv,
+        std::size_t offset,
+        std::size_t length,
+        int32* to,
+        std::size_t toOffset);
+    std::size_t toLongArray(PVScalarArrayPtr const & pv,
+        std::size_t offset,
+        std::size_t length,
+        int64* to,
+        std::size_t toOffset);
+    std::size_t toUByteArray(PVScalarArrayPtr const & pv,
+        std::size_t offset,
+        std::size_t length,
+        uint8* to,
+        std::size_t toOffset);
+    std::size_t toUShortArray(PVScalarArrayPtr const & pv,
+        std::size_t offset,
+        std::size_t length,
+        uint16* to,
+        std::size_t toOffset);
+    std::size_t toUIntArray(
+        PVScalarArrayPtr const & pv,
+        std::size_t offset,
+        std::size_t length,
+        uint32* to,
+        std::size_t toOffset);
+    std::size_t toULongArray(
+        PVScalarArrayPtr const & pv,
+        std::size_t offset,
+        std::size_t length,
+        uint64* to,
+        std::size_t toOffset);
+    std::size_t toFloatArray(
+        PVScalarArrayPtr const & pv,
+        std::size_t offset,
+        std::size_t length,
+        float* to,
+        std::size_t toOffset);
+    std::size_t toDoubleArray(
+        PVScalarArrayPtr const & pv,
+        std::size_t offset,
+        std::size_t length,
+        double* to, std::size_t
+        toOffset);
+    std::size_t fromByteArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const int8* from, std::size_t fromOffset);
+    std::size_t fromByteArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const ByteArray & from, std::size_t fromOffset);
+    std::size_t fromShortArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const int16* from, std::size_t fromOffset);
+    std::size_t fromShortArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const ShortArray & from, std::size_t fromOffset);
+    std::size_t fromIntArray(
+       PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+       const int32* from, std::size_t fromOffset);
+    std::size_t fromIntArray(
+       PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+       const IntArray & from, std::size_t fromOffset);
+    std::size_t fromLongArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const int64* from, std::size_t fromOffset);
+    std::size_t fromLongArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const LongArray & from, std::size_t fromOffset);
+    std::size_t fromUByteArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const uint8* from, std::size_t fromOffset);
+    std::size_t fromUByteArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const UByteArray & from, std::size_t fromOffset);
+    std::size_t fromUShortArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const uint16* from, std::size_t fromOffset);
+    std::size_t fromUShortArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const UShortArray & from, std::size_t fromOffset);
+    std::size_t fromUIntArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const uint32* from, std::size_t fromOffset);
+    std::size_t fromUIntArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const UIntArray & from, std::size_t fromOffset);
+    std::size_t fromULongArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const uint64* from, std::size_t fromOffset);
+    std::size_t fromULongArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const ULongArray & from, std::size_t fromOffset);
+    std::size_t fromFloatArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const float* from, std::size_t fromOffset);
+    std::size_t fromFloatArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const FloatArray & from, std::size_t fromOffset);
+    std::size_t fromDoubleArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const double* from, std::size_t fromOffset);
+    std::size_t fromDoubleArray(
+        PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
+        const DoubleArray & from, std::size_t fromOffset);
+    void newLine(StringBuilder buf, int indentLevel);
+ ...
+}
+
+extern ConvertPtr getConvert();
+ +

The array methods all return the number of elements copied or converted. +This can be less than len if the PVField array contains less than len +elements.

+ +

newLine is a convenience method for code that implements toString It +generates a newline and inserts blanks at the beginning of the newline.

+ +

pvDataApp/property

+ +

Definition of Property

+ +

Only fields named "value" have 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 hieraracy 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
+ +

Standard Properties

+ +

The following field names have special meaning, i.e. support properties for +general purpose clients.

+
+
value
+
This is normally defined since most general purpose clients access this + field. All other fields in the structure support or describe the value + field. The type can any supported type but is usually one of the + following: +
+
scalar
+
Any of the scalar types.
+
scalarArray
+
An array with the elementType being a scalar type
+
enumerated structure
+
A structure that includes fields named index and choices. index + is an int that selects a choice. choices is an array of strings + that defines the complete set of choices.
+
other
+
Other structure or array types can also be defined if clients and + support code agree on the meaning. Some examples are: 1) A + structure defining a 2D matrix, 2) A structure defining an image, + 3) A structure that simulates a remote method, ...
+
+
+
timeStamp
+
The timeStamp. The type MUST be a timeStamp structure. Also if the + PVData structure does not have a timeStamp then a search up the parent + tree is made to find a timeStamp.
+
alarm
+
The alarm. The type MUST be an alarm structure.
+
display
+
A display structure as described below. It provides display + characteristics for the value field.
+
control
+
A control structure as described below. It provides control + characteristics for the value field.
+
history
+
Provides a history buffer for the value field. Note that currently + PVData does not define history suppoprt.
+
other
+
Other standard properties can be defined.
+
+ +

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:

+
+
input
+
A field with support that changes the value field. This can be + anything. It can be a channel access link. It can obtain a value from + hardware. Etc.
+
valueAlarm
+
A field with support that looks for alarm conditions based on the + value.
+
output
+
A field with support that reads the current value and sends it + somewhere else. This can be anything. It can be a channel access link. It + can write a value to hardware. Etc.
+
+ +

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. +

+ +

Overview of Property Support

+ +

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(String("testMessage"));
+    al.setSeverity(majorAlarm);
+    result = pvAlarm.set(al);
+    assert(result);
+    alarm = pvAlarm.get();
+     ...
+}
+ +

timeStamp

+ +

A timeStamp is represented by the following structure

+
structure timeStamp
+    long secondsPartEpoch
+    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 nanoSecconds part is normlized, +i. e. it has is 0<=nanoSeconds<nanoSecPerSec..

+ +

Two header files are provided for manipulating time stamps:

+
+
timeStamp.h
+
Defines a time stamp independent of pvData, i.e. it is a generally + useful class for manipulating timeStamps.
+
pvTimeStamp.h
+
A class that can be attached to a time stamp pvData structure. It + provides get and set methods to get/set a TimeStamp as defined by + timeStamp.h
+
+ +

timeStamp.h

+ +

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

+
+
TimeStamp()
+
The defauly constuctor. Both seconds and nanoSeconds are set to 0.
+
TimeStamp(int64 secondsPastEpoch,int32 nanoSeconds = 0)
+
A constructor that gives initial values to seconds and nanoseconds.
+
normalize
+
Adjust seconds and nanoSeconds so that + 0<=nanoSeconds<nanoSecPerSec.
+
fromTime_t
+
Set time from standard C time.
+
toTime_t
+
Convert timeStamp to standard C time.
+
getSecondsPastEpoch
+
Get the number of seconds since the epoch.
+
getEpicsSecondsPastEpoch
+
Get the number of EPICS seconds since the epoch. EPICS uses Jan 1, 1990 + 00:00:00 UTC as the epoch.
+
getNanoSeconds
+
Get the number of nanoSeconds. This is always normalized.
+
getUserTag
+
Get the userTag.
+
setUserTag
+
Set the userTag.
+
put(int64 secondsPastEpoch,int32 nanoSeconds = 0)
+
Set the timeStamp value. If necessary it will be normalized.
+
put(int64 milliseconds)
+
Set the timeStamp with a value the is the number of milliSeconds since + the epoch.
+
getCurrent()
+
Set the timeStamp to the current time.
+
toSeconds()
+
Convert the timeStamp to a value that is the number of seconds since + the epocj
+
operator =
+
operator!=
+
operator<=
+
operator<
+
operator>=
+
operator>
+
Standard C++ operators.
+
diff
+
diff = a - b
+
getMilliseconds
+
Get the number of milliseconds since the epoch.
+
+ +

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);
+ +

pvTimeStamp.h

+
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

+
+
PVTimeStamp
+
The default constructor. Attach must be called before get or set can be + called.
+
attach
+
Attempts to attach to pvField It returns (false,true) if a timeStamp + structure is found. It looks first at pvField itself and if is not an + appropriate pvData structure but the field name is value it looks up the + parent structure tree.
+
detach
+
Detach from the pvData structure.
+
isAttached
+
Is there an attachment to a timeStamp structure?
+
get
+
Copies data from the pvData structure to a TimeStamp. An exception is + thrown if not attached to a pvData structure.
+
set
+
Copies data from TimeStamp to the pvData structure. An exception is + thrown if not attached to a pvData structure.
+
+ +

alarm

+ +

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:

+
+
alarm.h
+
Defines an alarm independent of pvData, i.e. it is a generally useful + class for manipulating alarms.
+
pvAlarm.h
+
A class that can be attached to an alarm pvData structure. It provides + get and set methods to get/set alarm data as defined by alarm.h
+
+ +

alarm.h

+
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
+    String getMessage();
+    void setMessage(String const &value);
+    AlarmSeverity getSeverity() const;
+    void setSeverity(AlarmSeverity value);
+    AlarmStatus getStatus() const;
+    void setStatus(AlarmStatus value);
+};
+ +

Alarm Severity defines the possible alarm severities:

+
+
getSeverity
+
Get the alarm severity corresponding to the integer value.
+
getSeverityNames
+
Get the array of severity choices.
+
+ +

Alarm Status defines the possible choices for alarm status:

+
+
getStatus
+
Get the alarm status corresponding to the integer value.
+
getStatusNames
+
Get the array of status choices.
+
+ +

Alarm has the methods:

+
+
Alarm
+
The constructor. It sets the severity to no alarm and the message to + "".
+
getMessage
+
Get the message.
+
setMessage
+
Set the message.
+
getSeverity
+
Get the severity.
+
setSeverity
+
Set the severity.
+
getStatus
+
Get the status.
+
setStatus
+
Set the status.
+
+ +

pvAlarm.h

+
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

+
+
PVAlarm
+
The default constructor. Attach must be called before get or set can be + called.
+
attach
+
Attempts to attach to pvField It returns (false,true) if it found an + appropriate pvData structure. It looks first a pvField itself and if is + not an appropriate pvData structure but the field name is value it looks + to see if the parent structure has an appropriate sub structure.
+
detach
+
Just detaches from the pvData structure.
+
isAttached
+
Is there an attachment to an alarm structure?
+
get
+
Copies data from the pvData structure to an Alarm. An exception is + thrown if not attached to a pvData structure.
+
set
+
Copies data from Alarm to the pvData structure. An exception is thrown + if not attached to a pvData structure.
+
+ +

control

+ +

Control information is represented by the following structure

+
structure control
+    double limitLow
+    double limitHigh
+    double minStep
+ +

Two header files are provided for manipulating control:

+
+
control.h
+
Defines control independent of pvData, i.e. it is a generally useful + class for manipulating control.
+
pvControl.h
+
A class that can be attached to an control pvData structure. It + provides get and set methods to get/set control data as defined by + control.h
+
+ +

control.h

+
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

+
+
Control
+
The default constructure.
+
getLow
+
Get the low limit.
+
getHigh
+
Get the high limit.
+
setLow
+
Set the low limit.
+
setHigh
+
Set the high limit.
+
setMinStep
+
Set the minimum step size.
+
getMinStep
+
Get he minimum step size.
+
+ +

pvControl.h

+
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

+
+
PVControl
+
The default constructor. Attach must be called before get or set can be + called.
+
attach
+
Attempts to attach to pvField It returns (false,true) if it found an + appropriate pvData structure. It looks first a pvField itself and if is + not an appropriate pvData structure but the field name is value it looks + to see if the parent structure has an appropriate sub structure.
+
detach
+
Just detaches from the pvData structure.
+
isAttached
+
Is there an attachment to a control structure?
+
get
+
Copies data from the pvData structure to a Control. An exception is + thrown if not attached to a pvData structure.
+
set
+
Copies data from Control to the pvData structure. An exception is + thrown if not attached to a pvData structure.
+
+ +

display

+ +

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:

+
+
display.h
+
Defines display independent of pvData, i.e. it is a generally useful + class for manipulating display.
+
pvDisplay.h
+
A class that can be attached to an display pvData structure. It + provides get and set methods to get/set display data as defined by + display.h
+
+ +

display.h

+
class Display {
+public:
+    Display();
+    //default constructors and destructor are OK
+    double getLow() const;
+    double getHigh() const;
+    void setLow(double value);
+    void setHigh(double value);
+    String getDescription() const;
+    void setDescription(String const &value);
+    String getFormat() const;
+    void setFormat(String const &value);
+    String getUnits() const;
+    void setUnits(String const &value);
+};
+ +

where

+
+
Control
+
The default constructure.
+
getLow
+
Get the low limit.
+
getHigh
+
Get the high limit.
+
setLow
+
Set the low limit.
+
setHigh
+
Set the high limit.
+
getDescription
+
Get the description.
+
setDescription
+
Set the description.
+
getFormat
+
Get the format.
+
setFormat
+
Set the format.
+
getUnits
+
Get the units.
+
setUnits
+
Set the units.
+
+ +

pvDisplay.h

+
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

+
+
PVDisplay
+
The default constructor. Attach must be called before get or set can be + called.
+
attach
+
Attempts to attach to pvField It returns (false,true) if it found an + appropriate pvData structure. It looks first a pvField itself and if is + not an appropriate pvData structure but the field name is value it looks + to see if the parent structure has an appropriate sub structure.
+
detach
+
Just detaches from the pvData structure.
+
isAttached
+
Is there an attachment to a display structure?
+
get
+
Copies data from the pvData structure to a Display. An exception is + thrown if not attached to a pvData structure.
+
set
+
Copies data from Display to the pvData structure. An exception is + thrown if not attached to a pvData structure.
+
+ +

pvEnumerated.h

+ +

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();
+    String getChoice();
+    bool choicesMutable();
+    StringArrayPtr const & getChoices();
+    int32 getNumberChoices();
+    bool setChoices(StringArray &choices,int32 numberChoices);
+};
+ +

where

+
+
PVEnumerated
+
The default constructor. Attach must be called before any get or set + method can be called.
+
attach
+
Attempts to attach to pvField It returns (false,true) if pvField (is + not, is) an enumerated structure.
+
detach
+
Just detaches from the pvData structure.
+
isAttached
+
Is there an attachment to an enemerated structure?
+
setIndex
+
Set the index field in the pvData structure. An exception is thrown if + not attached to a pvData structure.
+
getIndex
+
Get the index field in the pvData structure.
+
getChoice
+
Get the String value corresponding to the current index field in the + pvData structure. An exception is thrown if not attached to a pvData + structure.
+
choicesMutable
+
Can the choices be changed? Note that this is often true. An exception + is thrown if not attached to a pvData structure.
+
getChoices
+
Get the array of choices. An exception is thrown if not attached to a + pvData structure.
+
getNumberChoices
+
Get the number of choices. An exception is thrown if not attached to a + pvData structure.
+
setChoices
+
Change the choices. An exception is thrown if not attached to a pvData + structure.
+
+ +

Examples

+ +

Accessing PVData

+ +

Assume that code wants to print two fields from a PVStructure:

+
+
value
+
Must be a PVDouble.
+
timeStamp
+
Just look for field with this name.
+
+ +

The following code uses introspection to get the desired information.

+
void getValueAndTimeStamp(PVStructurePtr pvStructure,StringBuilder buf) {
+   PVFieldPtr valuePV = pvStructure->getSubField(String("value"));
+   if(valuePV.get()==NULL) {
+       buf += "value field not found";
+       return;
+   }
+   buf += "value ";
+   valuePV->toString(&buf);
+   PVFieldPtr timeStampPV = pvStructure->getSubField(String("timeStamp"));
+   if(timeStampPV.get()==NULL) {
+       buf += "timeStamp field not found";
+       return;
+   }
+   buf += " timeStamp ";
+   timeStampPV->toString(&buf);
+}
+ +

Creating PVData

+ +

Example of creating a scalar field.

+
    PVDataCreatePtr pvDataCreate = getPVDataCreate();
+    PVDoublePtr pvValue = static_pointer_cast<PVDouble>(
+        pvDataCreate->createPVScalar(pvDouble));
+ +

Create a structure with a value and an alarm the hard way

+
    FieldCreatePtr fieldCreate = getFieldCreate();
+    PVDataCreatePtr pvDataCreate = getPVDataCreate();
+    FieldConstPtrArray fields;
+    StringArray names;
+    fields.resize(3);
+    names.resize(3);
+    fields[0] = fieldCreate->createScalar(pvInt);
+    fields[1] = fieldCreate->createScalar(pvInt);
+    fields[2] = fieldCreate->createScalar(pvString);
+    names[0] = "severity";
+    names[0] = "status";
+    names[0] = "message";
+    StructureConstPtr alarmField =  
+        fieldCreate->createStructure(names,fields);
+    fields.resize(2);
+    names.resize(2);
+    fields[0] = fieldCreate->createScalar(pvDouble);
+    fields[1] = alarmField;
+    names[0] = "value";
+    names[0] = "alarm";
+    StructureConstPtr structure =
+        fieldCreate->createStructure(names,fields);
+    PVStructurePtr pv = pvDataCreate->createPVStructure(structure);
+ +

Create an alarm structure the easy way.

+
    StandardPVFieldPtr standardPVField = getStandardPVField();
+    PVStructurePtr pv = standardPVField->scalar(pvDouble,"alarm");
+ +

Create a PVStructure with field name example that has a double value field , +timeStamp, alarm, and display. Do it the easy way.

+
    StandardPVFieldPtr standardPVField = getStandardPVField();
+    PVStructurePtr pvStructure = standardPVField->scalar(
+        pvDouble,"timeStamp,alarm.display");
+ +

pvDataApp/factory

+ +

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.

+ +

PVAuxInfoImpl.cpp implements auxInfo.

+ +

Convert.cpp automatically creates a single instance of Convert and +implements getConvert.

+ +

Other files implement PVData base classes

+ +

pvDataAPP/misc

+ +

Overview

+ +

This package provides utility code:

+
+
bitSet.h
+
An implementation of BitSet that can be serialized.
+
byteBuffer.h
+
Used to serialize objects.
+
destroyable.h
+
Provides method destroy.
+
epicsException.h
+
Exception with stack trace.
+
event.h
+
Signal and wait for an event.
+
executor.h
+
Provides a thread for executing commands.
+
lock.h
+
Support for locking and unlocking.
+
messageQueue.h
+
Support for queuing messages to give to requesters.
+
noDefaultMethods.h
+
When privately extended prevents compiler from implementing default + methods.
+
queue.h
+
A queue implementation that allows the latest queue element to continue + to be used when no free element is available.
+
requester.h
+
Allows messages to be sent to a requester.
+
serialize.h
+
Support for serializing objects.
+
serializeHelper.h
+
More support for serializing objects.
+
sharedPtr.h
+
Defines POINTER_DEFINITIONS.
+
status.h
+
A way to pass status information to a client.
+
thread.h
+
Provides thread support.
+
timeFunction.h
+
Time how long a function call requires.
+
timer.h
+
An implementation of Timer that does not require an object to be + created for each timer request.
+
+ +

Note that directory testApp/misc has test code for all the classes in misc. +The test code also can be used as examples.

+ +

bitSet.h

+ +

This is adapted from the java.util.BitSet. bitSet.h is:

+
class BitSet : public Serializable {
+public:
+    static BitSet::shared_pointer 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);
+    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;
+    void toString(StringBuilder buffer);
+    void toString(StringBuilder buffer, int indentLevel) const;
+private:
+};
+ +

where

+
+
BitSet()
+
Creates a bitSet of initial size 64 bits. All bits initially false.
+
BitSet(uint32 nbits)
+
Creates a bitSet with the initial of the specified number of bits. All + bits initially false.
+
~BitSet()
+
Destructor.
+
flip(uint32 bitIndex)
+
Flip the specified bit.
+
set(uint32 bitIndex)
+
Set the specified bit true.
+
clear(uint32 bitIndex)
+
Set the specified bit false.
+
set(uint32 bitIndex, bool value)
+
Set the specified bit to value.
+
get(uint32 bitIndex)
+
Return the state of the specified bit.
+
clear()
+
Set all bits to false.
+
nextSetBit(uint32 fromIndex)
+
Get the index of the next true bit beginning with the specified + bit.
+
nextClearBit(uint32 fromIndex)
+
Get the index of the next false bit beginning with the specified + bit.
+
isEmpty()
+
Return (false,true) if (at least one bit true, all bits are false)
+
cardinality()
+
Return the number of true bits.
+
size()
+
Returns the number of bits of space actually in use.
+
operator&=(const BitSet& set)
+
Performs a logical and of this target bit set with the argument bit + set. This bit set is modified so that each bit in it has the value true + if and only if it both initially had the value true and the corresponding + bit in the bit set argument also had the value.
+
operator|=(const BitSet& set)
+
Performs a logical or of this target bit set with the argument bit + set.
+
operator^=(const BitSet& set)
+
Performs a logical exclusive or of this target bit set with the + argument bit set.
+
operator-=(const BitSet& set)
+

Clears all of the bits in this bitSet whose corresponding bit is set + in the specified bitSet.

+
+
operator=(const BitSet &set)
+
Assignment operator.
+
or_and(const BitSet& set1, const BitSet& set2)
+
Perform AND operation on set1 and set2, and then OR this bitSet with + the result.
+
operator==(const BitSet &set)
+
Does this bitSet have the same values as the argument.
+
operator!=(const BitSet &set)
+
Is this bitSet different than the argument.
+
toString(StringBuilder buffer)
+
Show the current values of the bitSet.
+
toString(StringBuilder buffer, int indentLevel)
+
Show the current values of the bitSet.
+
virtual void serialize(ByteBuffer *buffer,SerializableControl *flusher) + const;
+
Serialize the bitSet
+
virtual void deserialize(ByteBuffer *buffer,DeserializableControl + *flusher);
+
Deserialize the bitSet.
+
+ +

byteBuffer.h

+ +

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();
+ ...
+};
+ +

destroyable.h

+
class Destroyable  {
+public:
+    POINTER_DEFINITIONS(Destroyable);
+    virtual void destroy() = 0;
+    virtual ~Destroyable() {};
+};
+ +

epicsException.h

+
/*
+ * 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.
+ */
+ +

event.h

+ +

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 */
+private:
+    epicsEventId id;
+}; 
+ +

where

+
+
Event
+
The constructor. The initial value can be full or empty. The normal + first state is empty.
+
signal
+
The event becomes full. The current or next wait will complete.
+
wait
+
Wait until event is full or until timeout. The return value is + (false,true) if the wait completed because event (was not, was) full. A + false value normally means that that a timeout occured. It is also + returned if an error occurs or because the event is being deleted.
+
tryWait
+
returns (false,true) if the event is (empty,full)
+
+ +

executor.h

+ +

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(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:

+
+
Executor
+
The constructor. A thread name and priority must be specified.
+
~Executor
+
The destructor. If any commands remain in the execute list they are not + called. All ExecutorNodes that have been created are deleted.
+
execute
+
Request that command be executed. If it is already on the run list + nothing is done.
+
+ +

lock.h

+
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 xx(mutex);
+        if(alreadyInitialized) return;
+        // initialization
+    }
+ +

messageQueue.h

+ +

Definitions

+ +

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:
+    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(String message,MessageType messageType,bool replaceLast);
+    bool isEmpty() ;
+    bool isFull() ;
+    int getClearOverrun();
+ ...
+};
+ +

A messageNode is a class with two public data members:

+
+
getMessage
+
The message.
+
getMessageType
+
The message type.
+
setMessageNull
+
Set the message to be a null string.
+
+ +

A messageQueue is an interface with public methods:

+
+
MessageQueue
+
The constructor. The queue size must be specified.
+
~MessageQueue
+
The destructor.
+
put
+
Put a new message into the queue. False is returned if the queue was + full and true otherwise. If replaceLast is true then the last message is + replaced with this message.
+
get
+
Get the oldest queue element. If the queue is empty null is returned. + Before the next get can be issued release must be called.
+
release
+
Release the queue element returned by the last get.
+
isEmpty
+
Is the queue empty?
+
isFull
+
Is the queue full?
+
getClearOverrun
+
Get the number of times put has been called but no free element is + available.
+
+ +

Look at miscTest/testMessageQueue.cpp for an example.

+ +

noDefaultMethods.h

+ +

If a class privately extends this class then the compiler can not create any +of the following: default constructor, default copy constructror, or default +assignment contructor.

+
/* 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 implment
+    NoDefaultMethods(const NoDefaultMethods&);
+    NoDefaultMethods & operator=(const NoDefaultMethods &);
+    };
+ +

queue.h

+ +

This provides a queue which has an immutable capacity. When the queue is +full the user code is expected to keep using the current element until a new +free element becomes avalable.

+
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 &element);
+    queueElementPtr & getUsed();
+    void releaseUsed(queueElementPtr &element);
+ ...
+};
+ +

testApp/misc/testQueue.cpp provides an example of how to define a queue.

+ +

The queue methods are:

+
+
clear
+
Make the queue empty.
+
getNumberFree
+
Get the number of free elements in the queue.
+
capacity
+
Get the capacity, i.e. the maximun number of elements the queue can + hold.
+
getNumberFree
+
Get the number of free elements.
+
getNumberUsed
+
Get the number of elements used.
+
getFree
+
Get the next free element. Null is returned if no free elements are + available. If a non null value is returned then the element belongs to + the caller until setUsed is called.
+
setUsed
+
Set a queue element used. This must be the element returned by the last + call to getFree.
+
getUsed
+
Get the next used element of null if no more used elements are + available.
+
releaseUsed
+
Set a queue element free. This must be the element returned by the last + call to getUsed.
+
+ +

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.h

+ +

A PVField extends Requester. Requester is present so that when database +errors are found there is someplace to send a message.

+
enum MessageType {
+   infoMessage,warningMessage,errorMessage,fatalErrorMessage
+};
+
+extern String getMessageTypeName(MessageType messageType);
+extern const size_t messageTypeCount;
+class Requester {
+public:
+    POINTER_DEFINITIONS(Requester);
+    virtual ~Requester(){}
+    virtual String getRequesterName() = 0;
+    virtual void message(String const & message,MessageType messageType) = 0;
+};
+ +

where

+
+
+
MessageType
+
Type of message.
+
messageTypeName
+
An array of strings of the message type names, i.e. + String("info"),String("warning"),String("error"),String("fatalError").
+
getRequesterName
+
Returns the requester name.
+
message
+
Gives a message to the requester.
+
+ +

serialize.h

+
    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;
+    };
+ +

serializeHelper.h

+ +

This is a helper class for serialization, which is required for sending and +receiving pvData over the nerwork.

+
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 String& value,
+        ByteBuffer* buffer,SerializableControl* flusher);
+    static void serializeSubstring(const String& value, int offset,
+        int count, ByteBuffer* buffer,
+        SerializableControl* flusher);
+    static String deserializeString(ByteBuffer* buffer,
+        DeserializableControl* control);
+ ...
+};
+ +

where

+
+
writeSize
+
Serialize the size.
+
readSize
+
Deserialize the size.
+
serializeString
+
Serialize a String.
+
serializeSubstring
+
Serialize a substring.
+
deserializeString
+
Deserialize a string.
+
+ +

sharedPtr.h

+
#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;
+ +

status.h

+ +

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, epics::pvData::String const & message);
+    Status(StatusType type, epics::pvData::String const & message, epics::pvData::String stackDump);
+    ~Status()
+    StatusType getType() const;
+    String getMessage() const;
+    String getStackDump() const;
+    bool isOK() const;
+    bool isSuccess() const;
+    String toString() const;
+    void toString(StringBuilder buffer, int indentLevel = 0) const;
+    void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
+    void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
+};
+ +

The Status methods are:

+
+
StatusType
+
An enum for the status type.
+
getType
+
Get the statusType.
+
getMessage
+
Get a message explaining the error.
+
getStackDump
+
Get a stack dump.
+
+ +

The StatusCreate methods are:

+
+
getStatusOK
+
Get a singleton that returns StatusType.OK and a null message and + stackDump.
+
createStatus
+
Create a new Status.
+
deserializeStatus
+
Use this method instead of Status.deserialize(), since this allows OK + status optimization.
+
+ +

thread.h

+ +

ThreadPriority

+
enum ThreadPriority {
+    lowestPriority,
+    lowerPriority,
+    lowPriority,
+    middlePriority,
+    highPriority,
+    higherPriority,
+    highestPriority
+};
+ +

Thread

+
class Runnable {
+public:
+    virtual void run() = 0;
+};
+
+class Thread;
+
+class Thread : public epicsThread, private NoDefaultMethods {
+public:
+    Thread(
+        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 +compeletes 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:

+
+
Thread
+
The constructor. A thread name and priority must be specified. The run + methods of runnable is executed. When the run methods returns the thread + will no longer be active but the client code must still delete the + thread.
+
~Thread
+
The destructor. This is called as the result of: +
    delete pthread;
+
+
+ +

timeFunction.h

+ +

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 iterrations 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:

+
+
function
+
This is the function.
+
+ +

TimeFunction has the methods:

+
+
TimeFunction
+
Constructor.
+
~TimeFunction
+
Destructor.
+
timeCall
+
Time how long it takes to execute the function. It starts by calling + the function one time. If it takes < 1 seconds to doubles the number + of times to call the function. It repeats this until it takes at least + one second to call it ntimes.
+
+ +

timer.h

+ +

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(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 toString(StringBuilder builder);
+ ...
+};
+ +

TimerCallback must be implemented by the user. It has the following methods: +

+
+
callback
+
This is called when a timer expires. This is called with no locks held. + When called a delay timer is no longer on the queue but a periodioc timer + is on a queue. Thus the callback for a delay timer can issue a new + schedule request but a periodic timer must not. Note the explaination of + TimerNode.cancel below.
+
timerStopped
+
Timer.stop was called when a timer request was queued. or if the timer + is stopped and a schedule request is made.
+
+ +

In order to schedule a callback client code must allocate a TimerNode It can +be used to schedule multiple callbacks. It has the methods:

+
+
TimerNode
+
The constructor. User code must create a TimeNode in order to call a + schedule method.
+
~TimerNode
+
The destructor. This is called as a result of the client calling: +
    delete timerNode;
+
+
cancel
+
This is called to cancel a timer request. If a callback has been + dequeued but the callback not called when cancel is called then a + callback may still happen. New schedule requests can be made after a + cancel request has been made.
+
isScheduled
+
Is the timerNode scheduled to be called.
+
+ +

Timer has the methods:

+
+
Timer
+
The consttructor.
+
~Timer
+
The destructor. The queue is emptied and TimerCallback.timerStopped is + called for each element of the queue.
+
scheduleAfterDelay
+
A request to schedule a callback after a delay specified in + seconds.
+
schedulePeriodic
+
Schedule a periodic callback.
+
+ +

pvDataApp/pvMisc

+ +

bitSetUtil.h

+ +

The following is also provided:

+
class BitSetUtil : private NoDefaultMethods {
+public:
+    static bool compress(BitSet *bitSet,PVStructure *pvStructure);
+};
+ +

This provides functions that operate on a BitSet for a PVStructure. It +currently has only one method:

+
+
compress
+
Compress the bits in a BitSet related to a structure.
+ For each structure: +
    +
  1. If the bit for the structure is set then the bit for all subfields + of the structure are cleared.
  2. +
  3. If the bit for the structure is not set but all immediate subfields + have their bit set then the bit for the structure is set and the bits + for all subfields are cleared.
  4. +
+ Note that this is a recursive algorithm. That is if every immediate + subfield has it's offset bit set then the bits for ALL fields that reside + in the structure will be cleared.
+
Channel Access can call this before sending data. It can then pass + entire structures if the structure offset bit is set.
+
+
+ +