EPICS V4 Developer's Guide

EPICS v4 Working Group, Working Draft, 25-Aug-2015

Latest version:
developerGuide.html
This version:
developerGuide_20150825.html
Previous version:
developerGuide_20150519.html
Editors:
Marty Kraimer, BNL
David Hickin, Diamond Light Source
Matej Sekoranja, CosyLab

Abstract

This is Developer's Guide for EPICS V4, which is one of a related set of products:
relatedDocumentsV4.html

Status of this Document

This is the 25-Aug-2015 version of the Developer's Guide. It is for EPICS V4 Release 4.5.

Table of Contents

Overview of V4

This document briefly describes a set of application programming interfaces (API) for EPICS V4.

These core APIs provide a toolkit for creating applications that access and/or provide sources of structured data. This document is intended for EPICS V4 software developers who want to implement applications via the core APIs.

V4 Modules

V4 includes the following core components:
pvData
The EPICS V4 type system, which describes and implements structured data.
normativeTypes
A set of standard pvData structures.
pvAccess
Support for connecting a client and server and for transporting pvData between client and server.
pvaClient
pvAccess is a callback based API. pvaClient is a synchronous interface for pvAccess and also provides a number of convenience methods.
pvDatabase
A pvAccess server for accessing pvData.
pvaSrv
A pvAccess server for EPICS V3 DBRecords.
pvaPy
Python wrapper for pvData and pvAccess.

pvaSrv and pvaPy are implemented only in C++. Each has a single github repository, e. g. pvaSrv

The other components are implemented in both C++ and Java, with each language having it's own github repository. For example pvData has the repositories pvDataJava and pvDataCPP

Terminology

API - Application Programming Interface
The pvData API is how a client accesses the type system and data objects for each type. In Java this consists mainly of Java interfaces. In C++ this is via mainly via C++ classes. This document uses a combination of psuedo code, Java code, and C++ code for describing APIs. It uses psuedo code when there is equivalent code in Java and in C++. The psuedo code is similar to Java interface definitions. The language specific APIs are provided in separate projects e. g. pvDataJava, and pvDataCPP. This document also describes the APIs for the other V4 core modules.
Introspection API
The type system supports both introspection and data interfaces. The introspection interfaces allow a client to determine the data types for objects without requiring a data instance.
Data API
These provide access to data instances.
type
Often used when talking about a field. In this case it means the intospection interface for the field.
PVScalarType
Generic name for the data type for a scalar. Thus a generic name for one of PVBoolean, PVByte, ..., PVString.
PVScalarArrayType
Generic name for the data type for a scalarArray. This a generic name for one of PVBooleanArray, PVByteArray, ..., PVStringArray.
PVType
Generic name for any valid Data API type.
Special Field
These are a set of widely used structure definitions: enum, alarm, timeStamp, control, display, and alarmLimit.

Overview: pvData

pvData supports structured data where a structure is a set of fields each of which is is composed of one of the following types:
scalar
The field holds data that has a scalarType:
boolean
Can be true or false.
signed Integer
Integers of 8, 16, 32, and 64 bits are supported.
unsigned Integer
Unsigned integers of 8, 16, 32, and 64 bits are supported.
float
IEEE 32 bit floating point.
double
IEEE 64 bit floating point.
string
In C++ std::string and in Java String. On network UTF8.
scalarArray
An array of one of the scalar types.
structure
A set of fields and a name for each field. Each field can have any valid type but the type can not change.
structureArray
An array of structures. Each element must have the same introspection interface.
union
A field that has a single sub field which can dynamically change type. A variant union allows any valid type. A restricted union allows for a set of valid types.
unionArray
A array of unions. Each element must have the same introspection interface.

Overview: normativeTypes

Each normative type defines a structure that has a set of standard fields. For example NTScalar defines:

epics:nt/NTScalar:1.0
    double value                        // mandatory and can be any numeric type
    string descriptor                   // optional
    alarm_t alarm                       // optional
        int severity
        int status
        string message
    time_t timeStamp                    // optional
        long secondsPastEpoch
        int nanoseconds
        int userTag
    display_t display                   // optional
        double limitLow
        double limitHigh
        string description
        string format
        string units
    control_t control                   // optional
        double limitLow
        double limitHigh
        double minStep
    string extra1                       // extra
    string[] extra2                     //

Overview: pvAccess

A client written in either Java or C++ can communicate with a server written in either Java or C++. All communication between client and server is done via the methods provided by pvAccess and by pvData objects.

pvAccess provides:

channelProviderRegistry
An arbitrary number of channelProviders can be created
channelProvider
Code that provides access to a pvData data source. It creates channels where a channel provides access to pvData structure that has an associated channelName.
channel
Methods for each of the following:
getField
Get the pvData introspection information.
channelGet
Get data.
channelPut
Put data.
channelPutGet
Put data, let server process it, and then get result.
monitor
Monitor pvData changes.
channelArray
get/put subArray data.
channelRPC
Like channelPutGet but on each request pvData interfaces for put and get can change.

channelPutGet and channelRPC provide the equivalent of a Remote Procedure Call. The client passes a pvData object to the server. This pvData object is the argument for the RPC. The server uses this to decide what to do and sends a pvData object back to the client, which is the RPC result.

Overview: pvaClient

pvaClient is a synchronous wrapper for the pvAccess API, which is a callback based API. In addition pvaClient provides many convenience methods. Thus it is easier to use than pvAccess itself.

Overview: pvDatabase

A framework for implementing a network accessible database of smart memory resident records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess. The framework can be extended in order to create record instances that implement services. The minimum that an extension must provide is a top level PVStructure and a process method.

Overview: pvaSrv

pvaSrv is a pvAccess server that runs in a EPICS V3 IOC. pvaSrv allows clients to get, put and monitor V3 PVs (fields of EPICS DB records) via pvAccess, translating the value and its meta data (graphics limits, alarm status, timestamp) to or from V4 Normative Type (NT) pvData structures (NTScalar, NTScalarArray).

Overview: pvaPy

A Python wrapper for pvData and pvAccess.

Overview: channelProvider implementations

The basic requirements for channel provider are:

  1. Given a channel name find and connect to the data source
  2. Implement one or more of the channel methods: getField, createChannelGet, etc.
  3. get/put all data as pvData.
  4. Prefer normative types instead of raw pvData

pvAccess implements channelProviderRegistry, which allows an arbitrary number of providers for a client.

In addition pvAccess implements two providers:

pva
This is a connection between a client and a server that uses the pva network protocal as defined in: pvAccess_Protocol_Specification.html
ca
This is a connection that uses channel access to access an epics V3 Database.

Provider pva has two components, client and remote, which is what the client uses. Network communcation is used between client and server. Remote pva transfers data between the network and channel providers that have registered at the remote node.

At present two providers are available for the remote side of pva

local
This is implemented by pvDatabase
pvSrv
This is a provider that directly accesses V3 DBRecord.

Thus at present a client that is not running as part of a V3 IOC or a pvDatabase has two choices for channelProvider: pva and ca. A client running as part of a V3 IOC or pvDatabase has all of the following choices: pva, ca, local, and pvSrv. Note that if a client directly connects to either local or pvSrv no network communication is involved.

And since channelProviderRegistry allows any arbitrary number of providers additional providers can be developed for either the client or remote side of pva.

EPICS V4 resources and website

This document is a tutorial rather then a detailed reference manual. The following should be consulted for detailed documentation:

In addition a standard for normativeTypes exists:

Current Status

pvData
Release 4.5 has a complete implementation for both Java and C++.
normativeTypes
Release 4.5 has C++ and Java helper classes for many, but not all, of the normative types.
pvAccess
Release 4.5 has a complete implementation for both C++ and Java.
pvaClient
Release 4.5 has an implementation for both Java and CPP However, getField and channelArray are not implemented.
pvDatabase
Release 4.4 has an implementation for both C++ and Java. For C++ the pvDatabase can run as part of a V3 IOC.
pvaSrv
Release 4.4 has an implementation for C++. Since this is for iocCore a Java implementation is not necessary.
pvaPy
Release 4.4 has an implementation for C++. Since this is for Python a Java implementation is not necessary.

pvlist, pvget, pvput, and eget

pvAccessCPP provides command line tools. Each provides help. For example:

pvlist -help

The examples shown in this section assume that the example database described in the next secton is running. Also your PATH environment variable must include the appropriate bin directory from pvAccessCPP. For example:

export PATH=$PATH:${EPICSV4}/pvAccessCPP/bin/${EPICS_HOST_ARCH}

pvlist

The options are:

mrk> pvlist -help

Usage: pvlist [options] [<server address or GUID starting with '0x'>]...

  -h: Help: Print this message
options:
  -i                 Print server info (when server address list/GUID is given)
  -w <sec>:          Wait time, specifies timeout, default is 3.000000 second(s)
  -q:                Quiet mode, print only error messages
  -d:                Enable debug output

examples:
	pvlist
	pvlist ioc0001
	pvlist 10.5.1.205:10000
	pvlist 0x83DE3C540000000000BF351F

Without any arguments this shows the location of all V4 servers it can locate. For example:

pvlist
GUID 0x3989545500000000B14EFE12, version 1: tcp@[10.0.0.11:36448]

This only shows one line because only the exampleDatabase server is running. In an operational system the output could be quite extensive.

Once the location of a server is known the list of channel names can be shown by asking for either the GUID or tcp address. Thus either:

pvlist 0x3989545500000000B14EFE12
or
pvlist 10.0.0.11:36448
produces:
ao01
double00
double01
bo00
bo01
calc00
...

pvget

pvget provides functionality similar to caget. For example:

mrk> caget double01
double01                       0
mrk> pvget double01
double01                       0

The options are:

mrk> pvget -help

Usage: pvget [options] <PV name>...

  -h: Help: Print this message
options:
  -r <pv request>:   Request, specifies what fields to return and options, default is 'field(value)'
  -w <sec>:          Wait time, specifies timeout, default is 3.000000 second(s)
  -t:                Terse mode - print only value, without names
  -i:                Do not format standard types (enum_t, time_t, ...)
  -m:                Monitor mode
  -p <provider>:     Set default provider name, default is 'pva'
  -q:                Quiet mode, print only error messages
  -d:                Enable debug output
  -F <ofs>:          Use <ofs> as an alternate output field separator
  -f <input file>:   Use <input file> as an input that provides a list PV name(s) to be read, use '-' for stdin
  -c:                Wait for clean shutdown and report used instance count (for expert users)
 enum format:
  -n: Force enum interpretation of values as numbers (default is enum string)

example: pvget double01

Some examples are:

mrk> pvget enum01
enum01                         zero
mrk> pvget -i enum01
enum01
epics:nt/NTEnum:1.0 
    enum_t value
        int index 0
        string[] choices [zero,one,two,three]


mrk> pvget -i -r "value,alarm,timeStamp" enum01
enum01
epics:nt/NTEnum:1.0 
    enum_t value
        int index 0
        string[] choices [zero,one,two,three]
    alarm_t alarm
        int severity 3
        int status 0
        string message UDF
    time_t timeStamp
        long secondsPastEpoch 631152000
        int nanoseconds 0
        int userTag 0

Multiple channels can be accessed witn a single command. For example:

mrk> pvget double01 double02
double01                       0
double02                       0

The above examples all used the pva server, i. e. the pvAccess server for network communication. It is also possible to use ca, i. e. the channel access server that comes with iocCore. Thus it can access a V3 IOC even if the IOC has no V4 support.

mrk> pvget -p ca double01
double01                       0
mrk> pvget -p ca -r "value,alarm,timeStamp" double01
double01
epics:nt/NTScalar:1.0 
    double value 0
    alarm_t alarm INVALID RECORD UDF_ALARM
    time_t timeStamp <undefined> 0

pvget can also be used to monitor, i. e. it has functionality similer to camonitor.

mrk> pvget -m -r "value,alarm,timeStamp" double02
'double02
epics:nt/NTScalar:1.0 
    double value 0
    alarm_t alarm INVALID NO_STATUS UDF
    time_t timeStamp <undefine>> 0


double02
epics:nt/NTScalar:1.0 
    double value 1
    alarm_t alarm NO_ALARM NO_STATUS NO_ALARM
    time_t timeStamp 2015-05-14T08:29:55.769 0

pvput

pvput provides functionality similar to caput. For example:

mrk> caput double01 1.0
Old : double01                       1
New : double01                       1
mrk> pvput double01 1.0
Old : double01                       1
New : double01                       1

The options are:

mrk> pvput -help

Usage: pvput [options] <PV name> <values>...

  -h: Help: Print this message
options:
  -r <pv request>:   Request, specifies what fields to return and options, default is 'field(value)'
  -w <sec>:          Wait time, specifies timeout, default is 3.000000 second(s)
  -t:                Terse mode - print only successfully written value, without names
  -p <provider>:     Set default provider name, default is 'pva'
  -q:                Quiet mode, print only error messages
  -d:                Enable debug output
  -F <ofs>:          Use <ofs> as an alternate output field separator
  -f <input file>:   Use <input file> as an input that provides a list PV name(s) to be read, use '-' for stdin
 enum format:
  default: Auto - try value as enum string, then as index number
  -n: Force enum interpretation of values as numbers
  -s: Force enum interpretation of values as strings

example: pvput double01 1.234

At the present time it is not possible to send output to multiple channels with one command.

eget

eget provides many of the same features but in addition supports channelRPC and understands some of the normative types.

The options are:

mrk> eget -h

Usage: eget [options] [<PV name>... | -s <service name>]

  -h: Help: Print this message

options:
  -s <service name>:   Service API compliant based RPC service name (accepts NTURI request argument)
  -a <service arg>:    Service argument in 'name[=value]' or 'name value' form
  -r <pv request>:     Get request string, specifies what fields to return and options, default is 'field(value)'
  -w <sec>:            Wait time, specifies timeout, default is 3.000000 second(s)
  -z:                  Pure pvAccess RPC based service (send NTURI.query as request argument)
  -N:                  Do not format NT types, dump structure instead
  -i:                  Do not format standard types (enum_t, time_t, ...)
  -t:                  Terse mode
  -T:                  Transpose vector, table, matrix
  -m:                  Monitor mode
  -x:                  Use column-major order to decode matrix
  -p <provider>:       Set default provider name, default is 'pva'
  -q:                  Quiet mode, print only error messages
  -d:                  Enable debug output
  -F <ofs>:            Use <ofs> as an alternate output field separator
  -f <input file>:     Use <input file> as an input that provides a list PV name(s) to be read, use '-' for stdin
  -c:                  Wait for clean shutdown and report used instance count (for expert users)
 enum format:
  -n: Force enum interpretation of values as numbers (default is enum string)


examples:

#! Get the value of the PV corr:li32:53:bdes
> eget corr:li32:53:bdes

#! Get the table of all correctors from the rdb service
> eget -s rdbService -a entity=swissfel:devicenames

#! Get the archive history of quad45:bdes;history between 2 times, from the archive service
> eget -s archiveService -a entity=quad45:bdes;history -a starttime=2012-02-12T10:04:56 -a endtime=2012-02-01T10:04:56

#! Get polynomials for bunch of quads using a stdin to give a list of PV names
> eget -s names -a pattern=QUAD:LTU1:8%:POLYCOEF | eget -f -

example code

All of the following have examples that can be used while learning what is described in this document.

pvaClientJava
Example client code using the API for pvaClient
pvaClientCPP
Example client code using the API for pvaClient
pvDatabaseJava
Example server code implemented via PVRecords.
pvDatabaseCPP
Example server code implemented via PVRecords. In addition it shows how to have PVRecords and V3 Records both running as part of a V3 IOC. It also shows how to start pvaSrv so that both ca and pva can be used to access the V3 records.
pvaPy
Example python code

Examples for pvaClientJava, pvaClientCPP, and pvaPy require that the database in pvaClientTestCPP is started.

In linux it can be started as follows:

mrk> pwd
/home/epicsv4/pvaClientTestCPP/database/iocBoot/exampleDatabase
mrk> ../../bin/linux-x86_64/exampleDatabase st.cmd

The example database has both V3 IOC records and V4 PVRecords. In addition pvaSrv is running. Thus all V3 records are available via either ca or pva. The PVRecords are only available via pva. Examples of using ca and pva command line tools are:

mrk> pvlist 0x2298D455000000001236320D
ao01
double00
.... many more records
mrk> pvget long01
long01                         0
mrk> caget long01
Channel connect timed out: 'long01' not found.
mrk> caget double01
double01                       0
mrk> pvget double01
double01                       0
mrk> caget ushort01
Channel connect timed out: 'ushort01' not found.
mrk> pvget ushort01
ushort01                       0
mrk> 

The examples in pvaClientCPP and pvaClientJava can now be run. For example:

mrk> pwd
/home/epicsv4/pvaClientCPP/example
mrk> ls bin/linux-x86_64/
examplePvaClientGet          examplePvaClientNTMulti  helloWorldPutGet
examplePvaClientMonitor      examplePvaClientProcess  helloWorldRPC
examplePvaClientMultiDouble  examplePvaClientPut
mrk> bin/linux-x86_64/examplePvaClientGet
example double scalar
short way
as double 0
long way
as double 0
example double array
short way
as doubleArray {0}[]
long way
as doubleArray {0}[]
example powerSupply
short way
structure 
    alarm_t alarm
        int severity 0
        int status 0
        string message 
    time_t timeStamp
        long secondsPastEpoch 0
        int nanoseconds 0
        int userTag 0
    structure power
        double value 0
        alarm_t alarm
            int severity 0
            int status 0
            string message 
    structure voltage
        double value 0
        alarm_t alarm
            int severity 0
            int status 0
            string message 
    structure current
        double value 0
        alarm_t alarm
            int severity 0
            int status 0
            string message 

example double scalar
short way
as double 0
long way
as double 0
example double array
short way
as doubleArray {0}[]
long way
as doubleArray {0}[]
done
mrk> 

An example of running the examples in pvaPy is:

mrk> pwd
/home/epicsv4/pvaPy/examples
mrk> python testPut.py
****************************
Testing string
Got old value:  
Putting value:  ; a
Got new value:  ; a
Putting value:  ; b
Got new value:  ; b

...... lots more output
mrk>

API: pvData

ScalarType

This defines the pvData primitive types:

boolean
Can be either true or false
byte
An 8 bit signed integer.
short
A 16 bit signed integer.
int
A 32 bit signed integer.
long
A 64 bit signed integer.
ubyte
An 8 bit unsigned integer.
ushort
A 16 bit unsigned integer.
uint
A 32 bit unsigned integer.
ulong
A 64 bit unsigned integer.
float
A 32 bit IEEE floating point number.
double
A 64 bit IEEE floating point number.
string
In Java a Java String. In C++ a std::string. On the network a UTF8 encoded string.

Type

A pvData object consists of a set of fields where each field has one on the following types:

scalar
The type of the field is one of the scalar types.
scalarArray
The type of the field is an array one of the scalar types.
structure
The field has a set of sub-fields. Each sub-field has a name and a type that can be any valid Type.
structureArray
The field is an array of structure fields where each element has the same introspection interface.
union
The field has a single sub-field. Two types of union are supported: a restricted union and a variant union. For a variant union the sub-field can be have any valid Type. For a restricted union the sub-field can have any of a specified set of Types.
unionArray
The field is an array of union fields where each element has the same introspection interface.

Data Examples

NOTE: In the examples alarm_t, time_t, and enum_t are used as type names. All have type structure. They are examples of special fields described later. The core part of pvData and pvAccess, which are discussed before section interlude treat them as type structure.

The following is a top level structure that has three sub-fields:

value
This has type scalar and scalarType double.
alarm
This is a structure field.
timeStamp
This is also a structure field
structure
    double value 5.0
    alarm_t alarm
        int severity 0
        int status 0
        string message no alarm
    time_t timeStamp
        long secondsPastEpoch 0
        int nanoseconds 0
        int userTag 0

The following is an example where the value field is a scalar string array.

structure
    string[] value ["aaa","bbb","ccc","ddd"]
    time_t timeStamp
        long secondsPastEpoch 0
        int nanoseconds 0
        int userTag 0

The following is an example is a structure with a single subfield that is itself a structure.

structure
    enum_t value
        int index 0
        string[] choices [true,false]

The following has two examples of a restricted union.

structure
    union value
        time_t
            long secondsPastEpoch 1000
            int nanoseconds 0
            int userTag 0

structure
    union value
        double  100000

This is like the previous example but now the value field is a variant union.

structure
    any value
        time_t
            long secondsPastEpoch 1000
            int nanoseconds 0
            int userTag 0

structure
    any value
        double  100000

The first example is a union array where each element is variant union. The second is where each element is a restricted union.

structure
    any[] value
        any
            (none)
        any
            double  1.245
`
structure
    union[] value
        union
            (none)
        union
            double  1.245

This is an example of a structure array where each element is a time_t structure.

structure
    time_t[] value
        time_t
            long secondsPastEpoch 1000
            int nanoseconds 0
            int userTag 0
        time_t
            long secondsPastEpoch 3000
            int nanoseconds 0
            int userTag 0

This is a structure that has data for a power supply.

structure
    alarm_t alarm
        int severity 0
        int status 0
        string message
    time_t timestamp
        long secondsPastEpoch 0
        int nanoseconds 0
        int userTag 0
    structure power
        double value 0
        alarm_t alarm
            int severity 0
            int status 0
            string message
    structure voltage
        double value 0
        alarm_t alarm
            int severity 0
            int status 0
            string message
    structure current
        double value 0
        alarm_t alarm
            int severity 0
            int status 0
            string message

Introspection API

Field
    string getID()
    Type getType()
    serialize/deserialize
    display

    Scalar
        ScalarType getScalarType()

    Union
        size_t getNumberFields()
        Field getField(string fieldName)
        size_t getFieldIndex(string fieldName)
        Field[] getFields()
        Field getField(size_t fieldIndex)
        string[] getFieldNames()
        string getFieldName(size_t fieldIndex)
        boolean isVariant()

    Array
        ArraySizeType getArraySizeType()
        size_t getMaximumCapacity()

        ScalarArray
            ScalarType getElementType()

        StructureArray
            Structure getStructure()

        UnionArray
            Union getUnion()

     Structure
         Field getField(string fieldName)
         size_t getFieldIndex(string fieldName)
         Field[] getFields()
         Field getField(size_t fieldIndex)
         string[] getFieldNames()
         string getFieldName(size_t fieldIndex)

Field

This is the base class for the Introspection API. It has the members:

string getID()
Each field instance has an asociated ID, which is just a string. The core part of pvData and pvAccess do not attach any semantics to the value except that pvAccess transfers the ID when it transfers an introspection object. FieldCreate assigns a default ID to each type but also allows code to assign different values. This feature is used for both special fields and normative types.
Type getType()
Get the type.
serialize/deserialize
These are methods to convert an introspection object to/from a byte stream. These are used by pvAccess to transfer introspection objects between client and server. Other code could also use these methods. This document does not provide the details. See pvDataCPP or pvDataJava for details.
display
These methods are used to display the value of an introspection object. Java provides methods to implement toString. C++ provides methods that implement C++ steams. Thus the Java and C++ methods are completely different. See pvDataCPP or pvDataJava for details.

Scalar

This is the API for all scalar types, i. e. boolean, byte, ... , string. It has method:

ScalarType getScalarType()
Return the scalarType

Union

This is the API for type union. A union is a field that has a single subField. The subField has no name. A union can be either a variant union or a restricted union. The subField for a variant union can have any supported type. A restricted union has a Field array and a string array. Each element of the string array is associated with the corresponding element of the field array.

Union has the methods:

size_t getNumberFields()
Return the number of elements in the Field and string arrays. This is always 0 for a variant union.
Field getField(string fieldName)
Return the Field associated with the fieldName. A null Field is returned if the fieldName is not valid. For a variant array null is always returned.
size_t getFieldIndex(string fieldName)
Return the index associated with the fieldName. -1 is returned if the fieldName is not valid. For a variant array -1 is always returned.
Field[] getFields()
Get the field types. For a variant array and empty array is returned.
Field getField(size_t fieldIndex)
Get the introspection interface associates with the fieldIndex. A null Field is returned if the fieldIndex is not valid. For a variant array null is always returned.
string[] getFieldNames()
Get the field names. For a variant array and empty array is returned.
string getFieldName(size_t fieldIndex)
Get the name asociated with the fieldIndex. An empty string is returned if the fieldIndex is not valid. For a variant array an empty string is always returned.
boolean isVariant()
returns (false,true) if (restricted, variant) union.

Array

Base class for all array types. It has the methods:

ArraySizeType getArraySizeType()
Size means the number of elements. ArraySizeType is one of:
variable
The size is only limited by what cpu architecture allows.
fixed
The size is determined when an instance is created and can not be changed.
bounded
The size can be changed but only up to a maximum specified when an instance is created.
size_t getMaximumCapacity()
Get the maximum capacity and also size that array can have.

ScalarArray

This is the API for type scalarArray. It has the method:

ScalarType getElementType()
Get the ScalarType for each element.

StructureArray

This is the API for type structureArray. It has the method:

Structure getStructure()
Get the introspection interface that each element must have. Note that all elements MUST have exactly the same introspection interface.

UnionArray

This is the API for type unionArray. It has the method:

Union getUnion()
Get the introspection interface that each element must have. Note that all elements MUST have exactly the same introspection interface.

Structure

This is the API for type structure. It has the methods:

Field getField(string fieldName)
Get the subField with the specified name. A null Field is returned if the structure does not have a subField with the specified name.
size_t getFieldIndex(string fieldName)
Get the index of the subField with the specified name. -1 is returned if the structure does not have a subField with the specified name.
Field[] getFields()
Get the Field array for the subFields of the structure.
Field getField(size_t fieldIndex)
Get the subField with the specified index. A null Field is returned if the fieldIndex is invalid for this structure.
string[] getFieldNames()
Get fieldName array for the subFields.
string getFieldName(size_t fieldIndex)
Get the subField name with the specified index. An empty string is returned if the fieldIndex is invalid for this structure.

Introspection Factory

FieldCreate is a factory for creating introspection objects.

FieldCreate
    FieldBuilder createFieldBuilder()
    Scalar createScalar(ScalarType scalarType)
    BoundedString createBoundedString(size_t maxLength)
    ScalarArray createScalarArray(ScalarType elementType)
    ScalarArray createFixedScalarArray(ScalarType elementType, size_t size)
    ScalarArray createBoundedScalarArray(ScalarType elementType, size_t bound)
    StructureArray createStructureArray(Structure elementStructure)
    UnionArray createUnionArray(Union elementUnion)
    UnionArray createVariantUnionArray()
    Structure createStructure() //Java does not implement
    Structure createStructure(string[] fieldNames, Field[] fields)
    Structure createStructure(string id, string[] fieldNames, Field[] fields)
    Structure appendField(Structure structure,string fieldName, Field field)
    Structure appendFields(Structure structure,string[] fieldNames, Field[] fields)
    Structure createStructure(Structure structToClone) // CPP does not implement
    Union createVariantUnion()
    Union createUnion(string[] fieldNames, Field[] fields)
    Union createUnion(string id, string[] fieldNames, Field[] fields)
FieldBuilder
    FieldBuilder setId(string id)
    FieldBuilder add(string name, ScalarType scalarType)
    FieldBuilder addBoundedString(string name, size_t maxLength)
    FieldBuilder add(string name, Field field)
    FieldBuilder addArray(string name, ScalarType scalarType)
    FieldBuilder addFixedArray(string name, ScalarType scalarType, size_t size)
    FieldBuilder addBoundedArray(string name, ScalarType scalarType, size_t bound)
    FieldBuilder addArray(string name, Field field)
    Structure createStructure()
    Union createUnion()
    FieldBuilder addNestedStructure(string name)
    FieldBuilder addNestedUnion(string name)
    FieldBuilder addNestedStructureArray(string name)
    FieldBuilder addNestedUnionArray(string name)
    FieldBuilder endNested()

FieldCreate

The methods are:

FieldBuilder createFieldBuilder()
Create a FieldBuilder which is described below.
Scalar createScalar(ScalarType scalarType)
Create a Scalar of the specified type.
BoundedString createBoundedString(size_t maxLength)
Create a BoundedString, which is a Scalar with ScalarType pvString and that has a bounded size.
ScalarArray createScalarArray(ScalarType elementType)
Create a ScalarArray that has elements of the specified ScalarType.
ScalarArray createFixedScalarArray(ScalarType elementType, size_t size)
Create a ScalarArray of the specified ScalarType and that will have the specified fixed size.
ScalarArray createBoundedScalarArray(ScalarType elementType, size_t bound)
Create a ScalarArray of the specified ScalarType and that will have the specified maximum size.
StructureArray createStructureArray(Structure elementStructure)
Create a StructureArray where each element will have the specified introspection interface.
UnionArray createUnionArray(Union elementUnion)
Create a UnionArray where each element will have the specified introspection interface.
UnionArray createVariantUnionArray()
Create a UnionArray where each element can have any valid type.
Structure createStructure() //Java does not implement
Create a Structure with no subFields.
Structure createStructure(string[] fieldNames, Field[] fields)
Create a Structure with the specified set of fieldNames and fields. The length of the two arrays must be the same.
Structure createStructure(string id, string[] fieldNames, Field[] fields)
Create a Structure with the specified set of fieldNames and fields. The length of the two arrays must be the same. The Structure will have the ID specfied.
Structure appendField(Structure structure,string fieldName, Field field)
Create a new Structure that is the old structure with an appended subField.
Structure appendFields(Structure structure,string[] fieldNames, Field[] fields)
Create a new Structure that is the old structure with appended subFields.
Structure createStructure(Structure structToClone) // CPP does not implement
Create a new Structure that is a clone of an existing structure.
Union createVariantUnion()
Create a variant Union.
Union createUnion(string[] fieldNames, Field[] fields)
Create an restricted Union that can have a subField with an type specified by fields.
Union createUnion(string id, string[] fieldNames, Field[] fields)
Like the previous method but with the ID specified.

FieldBuilder

This is an easier way to create introspection interfaces. A single instance can be used to create multiple introspection interfaces because everytime createStructure or createUnion is called the internal state is reset to start over. Each method except createStructure and createUnion return the FieldBuilder itself so that methods can be chained together. See the examples below. The methods are:

FieldBuilder setId(string id)
Specify the ID for the next Structure or Union to create.
FieldBuilder add(string name, ScalarType scalarType)
Add a scalar field.
FieldBuilder addBoundedString(string name, size_t maxLength)
Add a bounded string field.
FieldBuilder add(string name, Field field)
Add a field with the specified type.
FieldBuilder addArray(string name, ScalarType scalarType)
Add a scalarArray with the specified element type.
FieldBuilder addFixedArray(string name, ScalarType scalarType, size_t size)
Add a fixed size scalarArray with the specified element type.
FieldBuilder addBoundedArray(string name, ScalarType scalarType, size_t bound)
Add a bounded size scalarArray with the specified element type.
FieldBuilder addArray(string name, Field field)
Add an array with elementType field.
Structure createStructure()
Create a Structure from what has been defined so far. The internal state is reset after creation.
Union createUnion()
Create a Union from what has been defined so far. The internal state is reset after creation.
FieldBuilder addNestedStructure(string name)
Add a nested Structure. All fields added until the corresponding endNested will be in the nested Structure.
FieldBuilder addNestedUnion(string name)
Add a nested Union. All field added until the corresponding endNested will be in the nested Union.
FieldBuilder addNestedStructureArray(string name)
Add a nested StructureArray. All fields added until the corresponding endNested will be in the nested StructureArray.
FieldBuilder addNestedUnionArray(string name)
Add a nested UnionArray. All fields added until the corresponding endNested will be in the nested UnionArray.
FieldBuilder endNested()
End of the current nested Structure, Union, StructureArray, or UnionArray.

Java Introspection Basic Examples

The first example creates a Structure with a single subField:

String[] fieldName = new String[1];
Field[] field = new Field[1];
fieldName[0] = "value";
field[0] = fieldCreate.createScalar(ScalarType.pvDouble);
Structure structure = fieldCreate.createStructure(fieldName, field);
System.out.println(structure);

This produces:

structure
    double value

Using FieldBuilder the code is:

FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure = 
    fb.add("value", ScalarType.pvDouble).
    createStructure();
System.out.println(structure);

The output is again:

structure
    double value

The next example shows how to create a structure that has three field: a value field that is a scalarArray with element type double, an alarm structure, and a timeStamp structure. Later examples show that fieldBuilder and standard fields make it much easier to create complex structures.

String[] fieldName = new String[3];
Field[] field = new Field[3];
fieldName[0] ="severity";
fieldName[1] ="status";
fieldName[2] ="message";
field[0] = fieldCreate.createScalar(ScalarType.pvInt);
field[1] = fieldCreate.createScalar(ScalarType.pvInt);
field[2] = fieldCreate.createScalar(ScalarType.pvString);
Structure alarm = fieldCreate.createStructure(fieldName, field);
fieldName = new String[3];
field = new Field[3];
fieldName[0] = "secondsPastEpoch";
fieldName[1] = "nanoseconds";
fieldName[2] = "userTag";
field[0] = fieldCreate.createScalar(ScalarType.pvLong);
field[1] = fieldCreate.createScalar(ScalarType.pvInt);
field[2] = fieldCreate.createScalar(ScalarType.pvInt);
Structure timeStamp = fieldCreate.createStructure(fieldName, field);
fieldName = new String[3];
field = new Field[3];
fieldName[0] = "value";
fieldName[1] = "alarm";
fieldName[2] = "timeStamp";
field[0] = fieldCreate.createScalarArray(ScalarType.pvDouble);
field[1] = alarm;
field[2] = timeStamp;
Structure structure = fieldCreate.createStructure(fieldName, field);
System.out.println(structure);
This produces:
structure
    double[] value
    structure alarm
        int severity
        int status
        string message
    structure timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag

The section after next shows the same example using FieldBuilder.

C++ Introspection Basic Examples

The first example creates a Structure with a single subField:

StringArray fieldName(1);
FieldConstPtrArray field(1);
fieldName[0] = "value";
field[0] = fieldCreate->createScalar(pvDouble);

StructureConstPtr structure =
    fieldCreate->createStructure(fieldName, field);
cout << *structure << endl;

This produces:

structure
    double value

The next example shows how to create a structure that has three field: a value field that is a scalarArray with element type double, an alarm structure, and a timeStamp structure.

size_t n = 3;
StringArray fieldName(n);
FieldConstPtrArray field(n);
fieldName[0] ="severity";
fieldName[1] ="status";
fieldName[2] ="message";
field[0] = fieldCreate->createScalar(pvInt);
field[1] = fieldCreate->createScalar(pvInt);
field[2] = fieldCreate->createScalar(pvString);
StructureConstPtr alarm = fieldCreate->createStructure(fieldName, field);
fieldName = StringArray(n);
field = FieldConstPtrArray(n);
fieldName[0] = "secondsPastEpoch";
fieldName[1] = "nanoseconds";
fieldName[2] = "userTag";
field[0] = fieldCreate->createScalar(pvLong);
field[1] = fieldCreate->createScalar(pvInt);
field[2] = fieldCreate->createScalar(pvInt);
StructureConstPtr timeStamp = fieldCreate->createStructure(fieldName, field);
fieldName = StringArray(n);
field = FieldConstPtrArray(n);
fieldName[0] = "value";
fieldName[1] = "alarm";
fieldName[2] = "timeStamp";
field[0] = fieldCreate->createScalarArray(pvDouble);
field[1] = alarm;
field[2] = timeStamp;
StructureConstPtr structure = fieldCreate->createStructure(fieldName, field);
cout << *structure << endl;
This produces:
structure
    double[] value
    structure alarm
        int severity
        int status
        string message
    structure timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag

The next two sections shows the same example using FieldBuilder.

Java Introspection Examples Using FieldBuilder

valueAlarmTimeStamp
System.out.println("valueAlarmTimeStamp");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure alarm =
     fb.add("severity", ScalarType.pvInt).
     add("status",ScalarType.pvInt).
     add("message",ScalarType.pvString).
     createStructure();
Structure timeStamp =
     fb.add("secondsPastEpoch", ScalarType.pvLong).
     add("nanoseconds",ScalarType.pvInt).
     add("userTag",ScalarType.pvInt).
     createStructure();
Structure structure =
     fb.addArray("value", ScalarType.pvDouble).
     add("alarm",alarm).
     add("timeStamp",timeStamp).
     createStructure();
System.out.println(structure);
This produces:
valueAlarmTimeStamp
structure
    double[] value
    structure alarm
        int severity
        int status
        string message
    structure timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag
valueAlarmTimeStampNested
System.out.println("valueAlarmTimeStampNested");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure =
    fb.addArray("value", ScalarType.pvDouble).
    addNestedStructure("alarm").
         add("severity", ScalarType.pvInt).
         add("status",ScalarType.pvInt).
         add("message",ScalarType.pvString).
    endNested().
    addNestedStructure("timeStamp").
         add("secondsPastEpoch", ScalarType.pvLong).
         add("nanoseconds",ScalarType.pvInt).
         add("userTag",ScalarType.pvInt).
    endNested().
    createStructure();
System.out.println(structure);
This produces the same output as valueAlarmTimeStamp.
valueAlarmTimeStampSimple
System.out.println("valueAlarmTimeStampEasy");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure =
    fb.addArray("value", ScalarType.pvDouble).
    add("alarm",standardField.alarm()).
    add("timeStamp",standardField.timeStamp()).
    createStructure();
System.out.println(structure);
This produces:
structure
    double[] value
    alarm_t alarm
        int severity
        int status
        string message
    time_t timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag
union
System.out.println("union");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Union union =
    fb.add("short", ScalarType.pvShort).
    add("long", ScalarType.pvLong).
    createUnion();
Structure structure = 
    fb.add("value",union).
    createStructure();
System.out.println(structure);
This produces:
union
structure
    union value
        short short
        long long`
unionNested
System.out.println("unionNested");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure = 
    fb.addNestedUnion("value").
        add("short", ScalarType.pvShort).
        add("long", ScalarType.pvLong).
        endNested().
    createStructure();
System.out.println(structure);
This produces the same result as union.
unionArray
System.out.println("unionArray");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Union union =
    fb.add("short", ScalarType.pvShort).
    add("long", ScalarType.pvLong).
    createUnion();
Structure structure = 
    fb.addArray("value",union).
    createStructure();
System.out.println(structure);
This produces:
unionArray
structure
    union[] value
        union
            short short
            long long
unionArrayNested
System.out.println("unionArrayNested");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure = 
    fb.addNestedUnionArray("value").
        add("short", ScalarType.pvShort).
        add("long", ScalarType.pvLong).
    endNested().
    createStructure();
System.out.println(structure);
This produces the same result as unionArray.
structureArray
System.out.println("structureArray");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure subStruct =
    fb.add("short", ScalarType.pvShort).
    add("long", ScalarType.pvLong).
    createStructure();
Structure structure = 
    fb.addArray("value",subStruct).
    createStructure();
System.out.println(structure);
This produces:
structureArray
structure
    structure[] value
        structure
            short short
            long long
structureArrayNested
System.out.println("structureArrayNested");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure = 
   fb.addNestedStructureArray("value").
        add("short", ScalarType.pvShort).
        add("long", ScalarType.pvLong).
    endNested().
    createStructure();
System.out.println(structure);`
This produces the same result as structureArray.

C++ Introspection Examples Using FieldBuilder

valueAlarmTimeStamp
cout << "valueAlarmTimeStamp\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr alarm =
   fb->add("severity", pvInt)->
   add("status",pvInt)->
   add("message",pvString)->
   createStructure();
StructureConstPtr timeStamp =
        fb->add("secondsPastEpoch", pvLong)->
        add("nanoseconds",pvInt)->
        add("userTag",pvInt)->
        createStructure();
StructureConstPtr structure  =
    fb->addArray("value", pvDouble)->
    add("alarm",alarm)->
    add("timeStamp",timeStamp)->
    createStructure();
cout << *structure << endl;
This produces:
valueAlarmTimeStamp
structure
    double[] value
    structure alarm
        int severity
        int status
        string message
    structure timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag
valueAlarmTimeStampNested
cout << "valueAlarmTimeStampNested\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr structure  =
    fb->addArray("value", pvDouble)->
    addNestedStructure("alarm")->
        add("severity", pvInt)->
        add("status",pvInt)->
        add("message",pvString)->
    endNested()->
    addNestedStructure("timeStamp")->
        add("secondsPastEpoch", pvLong)->
        add("nanoseconds",pvInt)->
        add("userTag",pvInt)->
        endNested()->
    createStructure();
cout << *structure << endl;
This produces the same output as valueAlarmTimeStamp.
valueAlarmTimeStampSimple
cout << "valueAlarmTimeStampEasy\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr structure  =
    fb->addArray("value", pvDouble)->
    add("alarm",standardField->alarm())->
    add("timeStamp",standardField->timeStamp())->
        createStructure();
    cout << *structure << endl;

This produces:
structure
    double[] value
    alarm_t alarm
        int severity
        int status
        string message
    time_t timeStamp
        long secondsPastEpoch
        int nanoseconds
        int userTag
union
cout << "union\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
UnionConstPtr unionx =
    fb->add("short", pvShort)->
    add("long", pvLong)->
    createUnion();
StructureConstPtr structure  =
    fb->add("value",unionx)->
        createStructure();
    cout << *structure << endl;
This produces:
union
structure
    union value
        short short
        long long`
unionNested
cout << "unionNested\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr structure  =
    fb->addNestedUnion("value")->
        add("short", pvShort)->
        add("long", pvLong)->
        endNested()->
    createStructure();
cout << *structure << endl;
This produces the same result as union.
unionArray
cout << "unionArray\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
UnionConstPtr unionx =
    fb->add("short", pvShort)->
    add("long", pvLong)->
    createUnion();
StructureConstPtr structure  =
    fb->addArray("value",unionx)->
    createStructure();
cout << *structure << endl;
This produces:
unionArray
structure
    union[] value
        union
            short short
            long long
unionArrayNested
cout << "unionArrayNested\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr structure  =
    fb->addNestedUnionArray("value")->
        add("short", pvShort)->
        add("long", pvLong)->
    endNested()->
        createStructure();
    cout << *structure << endl;
This produces the same result as unionArray.
structureArray
cout << "structureArray\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr subStruct =
    fb->add("short", pvShort)->
    add("long", pvLong)->
    createStructure();
StructureConstPtr structure  =
    fb->addArray("value",subStruct)->
createStructure();
cout << *structure << endl;
This produces:
structureArray
structure
structure[] value
        structure
            short short
            long long
structureArrayNested
cout << "structureArrayNested\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr structure  =
    fb->addNestedStructureArray("value")->
    add("short", pvShort)->
    add("long", pvLong)->
    endNested()->
        createStructure();
    cout << *structure << endl;
This produces the same result as structureArray.

Data API

PVField
    serialize/deserialize
    display
    string getFieldName()
    string getFullName()
    size_t getFieldOffset()
    size_t getNextFieldOffset()
    size_t getNumberFields()
    boolean isImmutable()
    void setImmutable()
    Field getField()
    PVStructure getParent()
    void postPut()
    void setPostHandler(PostHandler postHandler)

    PVScalar
        Scalar getScalar()

        PVScalarType // each scalarType, e. g. PVBoolean
            scalarType get()
            void put (scalarType value)

    PVUnion
        Union getUnion()
        PVField get()
        PVType get(Class c)           //PVType is valid PVField extension
        PVField select(int index)
        PVType select(Class c,int index)
        PVField select(string fieldName)
        PVType select(Class c,string fieldName)
        int getSelectedIndex()
        string getSelectedFieldName()
        void set(PVField value)
        void set(int index, PVField value)
        void set(string fieldName, PVField value)

    PVArray
        Array getArray()
        size_t getLength(
        void setLength(size_t length)
        size_t getCapacity(
        void setCapacity(size_t length)
        boolean isCapacityMutable()
        void setCapacityMutable(boolean isMutable)

        PVScalarArray
            ScalarArray getScalarArray()

            PVScalarTypeArray  // each scalarType, e.g. PVBooleanArray
                // C++ and Java have different semantics. See below

        PVUnionArray
            UnionArray getUnionArray()
            // C++ and Java have different semantics. See below

        PVStructureArray
            StructureArray getStructureArray()
            // C++ and Java have different semantics. See below.

PVField

serialize/deserialize
These are methods to convert a data object to/from a byte stream. These are used by pvAccess to transfer data objects between client and server. Other code could also use these methods. This document does not provide the details. See pvDataCPP or pvDataJava for details.
display
These methods are used to display the value of a data object. Java provides methods to implement toString. C++ provides methods that implement C++ steams. Thus the Java and C++ methods are completely different. See pvDataCPP or pvDataJava for details.
string getFieldName()
Get the name of the field. The name of a top level field is an empty string.
string getFullName()
Fully expand the name of this field using the names of its parent fields with a dot '.' separating each name. For example if an alarm is a top level field named alarm then the status field has the name alarm.status.
size_t 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 recursivelys traversing each structure of the tree.
size_t getNextFieldOffset()
Get the next offset. If the field is a scalar or union 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 number of fields within the field.
size_t getNumberFields()
Get the total number of fields in this field. This is equal to nextFieldOffset - fieldOffset.
boolean isImmutable()
Is the field immutable, i.e. does it not allow changes.
void setImmutable()
Set the field to be immutable, i. e. it can no longer be modified. This is permanent, i.e. once done the field can not be made mutable.
Field getField()
Get the Field that describes the field.
PVStructure getParent()
Get the parent of this field. A top level field has a null parent.
void postPut()
Called when the field is updated by the implementation.
void setPostHandler(PostHandler postHandler)
Set the handler for postPut. At most one handler can be set.

PVScalar

Scalar getScalar()
Get the Scalar that describes the field.

PVScalarType // each scalarType, e. g. PVBoolean

scalarType get()
Get the value. For example PVDouble has a method double get().
void put (scalarType value)
Change the value. For example PVDouble has a method void put(double value).

PVUnion

Union getUnion()
Get the Union that describes the field.
PVField get()
Get the current data member. This can be null.
PVType get(Class c)
Get the current data member. This returns null if no member or if current member is not of the type sepecified.
PVField select(int index)
If the union is a restricted union than select the field specified by index. If the curent field has a different type than a new field is created. An exception is thrown if the index is out of range or for a variant union. The interface to the data object is returned.
PVType select(Class c,int index)
Like the previous method but null is returned if the data object does not have the specified type.
PVField select(string fieldName)
If the union is a restricted union than select the field specified by fieldName. If the curent field has a different type than a new field is created. An exception is thrown if the fieldName is not valid or for a variant union. The interface to the data object is returned.
PVType select(Class c,string fieldName)
Like the previous method but null is returned if the data object does not have the specified type.
int getSelectedIndex()
Get the index of the current field. A -1 is returned if no field defined or for a variant union.
string getSelectedFieldName()
Get the fieldName of the current field. A null string is returned if no field defined or for a variant union.
void set(PVField value)
Set the data member to the specified value. An exception is thrown if the value is not valid for this PVUnion.
void set(int index, PVField value)
Set the data member to the specified index and value. An exception is thrown if the value is not valid for this index.
void set(string fieldName, PVField value)
Set the data member to the specified fieldName and value. An exception is thrown if the value is not valid for this fieldName.

PVArray

Array getArray()
Get the Array that describes the field.
size_t getLength(
Get the current length of the array.
void setLength(size_t length)
Set the length of the array. An exception is thrown if the value is not legal for this array.
size_t getCapacity(
Get the current capacity of the array.
void setCapacity(size_t length)
Set the capacity. An exception is thrown if the value is not legal for this array.
boolean isCapacityMutable()
Returns (true,false) if the capacity (can,can not) be changed.
void setCapacityMutable(boolean isMutable)
Set capacityMutable to the specified value.

PVScalarArray

Most methods are different for Java and C++. See following sections.

ScalarArray getScalarArray()
Get the ScalarArray that describes the field.

PVUnionArray

Most methods are different for Java and C++. See following sections.

UnionArray getUnionArray()
Get the UnionArray that describes the field.

PVStructureArray

Most methods are different for Java and C++. See following sections.

StructureArray getStructureArray()
Get the StructureArray that describes the field.

Data Factory

PVDataCreate
    PVField createPVField(Field field)
    PVField createPVField(PVField fieldToClone)
    PVScalar createPVScalar(Scalar scalar)
    PVScalar createPVScalar(ScalarType fieldType)
    PVScalar createPVScalar(PVScalar scalarToClone)
    PVScalarType createPVScalar(Class scalarType) // generic 
    PVUnion createPVUnion(Union union)
    PVUnion createPVVariantUnion()
    PVUnion createPVUnion(PVUnion unionToClone)
    PVStructure createPVStructure(Structure structure)
    PVStructure createPVStructure(string[] fieldNames,PVField[] pvFields)
    PVStructure createPVStructure(PVStructure structToClone)
    PVScalarArray createPVScalarArray(ScalarArray array)
    PVScalarArray createPVScalarArray(ScalarType elementType)
    PVScalarArray createPVScalarArray(PVScalarArray arrayToClone)
    PVScalarTypeArray createPVScalarArray(Class element) // generic 
    PVStructureArray createPVStructureArray(StructureArray structureArray)
    PVStructureArray createPVStructureArray(Struture structure)
    PVUnionArray createPVUnionArray(UnionArray unionArray)
    PVUnionArray createPVVariantUnionArray()
    PVUnionArray createPVUnionArray(Union union)
where
PVField createPVField(Field field)
Create a PVField with the specified introspection interface.
PVField createPVField(PVField fieldToClone)
Create a PVField with the same introspection interface as fieldToClone and then copy data from fieldToClone to newly created PVField.
PVScalar createPVScalar(Scalar scalar)
Create a PVScalar with the specified introspection interface.
PVScalar createPVScalar(ScalarType fieldType)
Create a PVScalar with the specified fieldType.
PVScalar createPVScalar(PVScalar scalarToClone)
Create a PVScalar with the same introspection interface as scalarToClone and then copy data from scalarToClone to newly created PVScalar.
PVScalarType createPVScalar(Class scalarType)
Generic version of createPVScalar. See pvDataJava or pvDataCPP for language specific syntax.
PVUnion createPVUnion(Union union)
Create a PVUnion with the specified introspection interface.
PVUnion createPVVariantUnion()
Create a variant PVUnion.
PVUnion createPVUnion(PVUnion unionToClone)
Create a PVUnion with the same introspection interface as unionToClone and then copy data from unionToClone to newly created PVUnion.
PVStructure createPVStructure(Structure structure)
Create a PVStructure with the specified introspection interface.
PVStructure createPVStructure(string[] fieldNames,PVField[] pvFields)
Create a PVStructure with the specified set of fieldNames. The introspection interface for the subFields is the same as the introspection interfaces of pvFields. Why does this method exist?
PVStructure createPVStructure(PVStructure structToClone)
Create a PVStructure with the same introspection interface as structToClone and then copy data from structToClone to newly created PVStructure.
PVScalarArray createPVScalarArray(ScalarArray array)
Create a PVScalarArray with the specified introspection interface.
PVScalarArray createPVScalarArray(ScalarType elementType)
Create a PVScalarArray with the specified elementType.
PVScalarArray createPVScalarArray(PVScalarArray arrayToClone)
Create a PVScalarArray with the same introspection interface as arrayToClone and then copy data from arrayToClone to newly created PVScalarArray.
PVScalarTypeArray createPVScalarArray(Class element)
Generic version. See pvDataJava or pvDataCPP for language specific syntax.
PVStructureArray createPVStructureArray(StructureArray structureArray)
Create a PVStructureArray with the specified introspection interface.
PVStructureArray createPVStructureArray(Struture structure)
Create a PVStructureArray where each element has the specified introspection interface.
PVUnionArray createPVUnionArray(UnionArray unionArray)
Create a PVUnionArray with the specified introspection interface.
PVUnionArray createPVVariantUnionArray()
Create a variant PVUnionArray.
PVUnionArray createPVUnionArray(Union union)
Create a PVUnionArray where each element has the specified introspection interface.

Java Array API

The following is for PVDoubleArray. There are similar definitions for each scalarType.

public class DoubleArrayData {
    public double[] data
    public int offset
}

interface PVDoubleArray extends PVArray {
    int get(int offset, int len, DoubleArrayData data)
    int put(int offset,int len, double[] from, int fromOffset)
    void shareData(double[] from)
}

For PVStructureArray and PVUnionArray the definitions are:

public class StructureArrayData {
    public PVStructure[] data
    public int offset
}

interface PVStructureArray extends PVArray {
    StructureArray getStructureArray()
    int get(int offset, int length, StructureArrayData data)
    int put(int offset,int length, PVStructure[] from, int fromOffset)
    void shareData(PVStructure[] from)
}

public class UnionArrayData {
    public PVUnion[] data
    public int offset
}

interface PVUnionArray extends PVArray{
    UnionArray getUnionArray()
    int get(int offset, int length, UnionArrayData data)
    int put(int offset,int length, PVUnion[] from, int fromOffset)
    void shareData(PVUnion[] from)
}

C++ Array API

The C++ Array API inforces Copy On Write (COW) semantics. The actual definition is template based. But the following is the psuedo code for PVDoubleArray. Each scalarType, PVUnionArray, and PVStructureArray have similar psuedo code.

class PVDoubleArray
    ...
    shared_vector<const double> view()
    void swap(shared_vector<const double> other)
    void replace(const shared_vector<const double> next)
    shared_vector<double> reuse()
    ...
// to change the raw array use code like:
shared_vector<double> data(n)
// put values into data and then
pvDoubleArray->replace(freeze(data))

Java Data Examples

simpleExample
System.out.println("simple");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure = 
    fb.add("value", ScalarType.pvDouble).
    createStructure();
PVStructure pvStructure = pvDataCreate.createPVStructure(structure);
PVDouble pvDouble = pvStructure.getSubField(PVDouble.class, "value");
pvDouble.put(10.0);
System.out.println(pvStructure);
This produces:
simple
structure 
    double value 10.0
valueAlarmTimeStamp
System.out.println("valueAlarmTimeStamp");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure =
        fb.addArray("value", ScalarType.pvDouble).
        add("alarm",standardField.alarm()).
        add("timeStamp",standardField.timeStamp()).
        createStructure();
PVStructure pvStructure = pvDataCreate.createPVStructure(structure);
PVDoubleArray pvDoubleArray = pvStructure.getSubField(PVDoubleArray.class, "value");
int length = 4;
double[] data = new double[length];
for (int i=0; <length; ++i) data[i] = i+1;
convert.fromDoubleArray(pvDoubleArray, 0, length, data, 0);
System.out.println(pvStructure);
This produces:
valueAlarmTimeStamp
structure 
    double[] value [1.0,2.0,3.0,4.0]
    alarm_t alarm
        int severity 0
        int status 0
        string message 
    time_t timeStamp
        long secondsPastEpoch 0
        int nanoseconds 0
        int userTag 0
union
System.out.println("union");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure = 
    fb.addNestedUnion("value").
        add("short", ScalarType.pvShort).
        add("long", ScalarType.pvLong).
        endNested().
    createStructure();
PVStructure pvStructure = pvDataCreate.createPVStructure(structure);
PVUnion pvUnion = pvStructure.getSubField(PVUnion.class,"value");
PVLong pvLong = (PVLong)pvDataCreate.createPVScalar(ScalarType.pvLong);
pvLong.put(1000);
pvUnion.set("long",pvLong);
System.out.println(pvStructure);
This produces:
union
structure 
    union value
        long  1000
unionArray
System.out.println("unionArray");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure = 
    fb.addNestedUnionArray("value").
        add("short", ScalarType.pvShort).
        add("long", ScalarType.pvLong).
    endNested().
    createStructure();
PVStructure pvStructure = pvDataCreate.createPVStructure(structure);
PVUnionArray pvValue = pvStructure.getSubField(PVUnionArray.class,"value");
int len = 2;
PVUnion[] pvUnions = new PVUnion[len];
for(int i=0; <len; ++i) pvUnions[i] = pvDataCreate.createPVUnion(pvValue.getUnionArray().getUnion());
pvUnions[0].select("short");
pvUnions[1].select("long");
PVShort pvShort = pvUnions[0].get(PVShort.class);
pvShort.put((short)1);
PVLong pvLong = pvUnions[1].get(PVLong.class);
pvLong.put(5);
pvValue.put(0, len, pvUnions, 0);
System.out.println(pvStructure);
This produces:
unionArray
structure 
    union[] value 
        union 
            short  1
        union 
            long  5
structureArray
System.out.println("structureArray");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure = 
        fb.addNestedStructureArray("value").
        add("short", ScalarType.pvShort).
        add("long", ScalarType.pvLong).
    endNested().
    createStructure();
PVStructure pvStructure = pvDataCreate.createPVStructure(structure);
PVStructureArray pvValue = pvStructure.getSubField(PVStructureArray.class,"value");
int len = 2;
PVStructure[] pvStructures = new PVStructure[len];
for(int i=0; i<len; ++i) {
    pvStructures[i] = pvDataCreate.createPVStructure(pvValue.getStructureArray().getStructure());
    PVStructure pvs = pvStructures[i];
    PVShort pvShort = pvs.getSubField(PVShort.class,"short");
    pvShort.put((short)i);
    PVLong pvLong = pvs.getSubField(PVLong.class,"long");
    pvLong.put(i);
}
pvValue.put(0, len,pvStructures , 0);
System.out.println(pvStructure);
This produces:
structureArray
structure 
    structure[] value 
        structure 
            short short 0
            long long 0
        structure 
            short short 1
            long long 1
structureArray
System.out.println("structureArray");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure = 
   fb.addNestedStructureArray("value").
        add("short", ScalarType.pvShort).
        add("long", ScalarType.pvLong).
    endNested().
    createStructure();
System.out.println(structure);`
This produces the same result as structureArray.

CPP Data Examples

simpleExample
cout << "simple\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr structure  =
    fb->add("value", pvDouble)->
    createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure);
PVDoublePtr pvDouble = pvStructure->getSubField<PVDouble>( "value");
pvDouble->put(10.0);
cout << *pvStructure << endl;
This produces:
simple
structure 
    double value 10.0
valueAlarmTimeStamp
cout << "valueAlarmTimeStamp\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr structure =
    fb->addArray("value", pvDouble)->
    add("alarm",standardField->alarm())->
    add("timeStamp",standardField->timeStamp())->
    createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure);
PVDoubleArrayPtr pvDoubleArray = pvStructure->getSubField<PVDoubleArray>("value");
size_t len = 4;
PVDoubleArray::svector data(4);
for(size_t i=0; i<len; ++i) data[i] = i+1;
pvDoubleArray->replace(freeze(data));
    cout << *pvStructure << endl;
This produces:
valueAlarmTimeStamp
structure 
    double[] value [1.0,2.0,3.0,4.0]
    alarm_t alarm
        int severity 0
        int status 0
        string message 
    time_t timeStamp
        long secondsPastEpoch 0
        int nanoseconds 0
        int userTag 0
union
cout << "unionNested\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr structure  =
    fb->addNestedUnion("value")->
        add("short", pvShort)->
        add("long", pvLong)->
        endNested()->
    createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure);
PVLongPtr pvlong = pvDataCreate->createPVScalar<PVLong>();
pvlong->put(1000);
PVUnionPtr pvUnion = pvStructure->getSubField<PVUnion>("value");
pvUnion->set("long",pvlong);
    cout << *pvStructure << endl;
This produces:
union
structure 
    union value
        long  1000
unionArray
cout << "unionArrayNested\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr structure  =
    fb->addNestedUnionArray("value")->
        add("short", pvShort)->
        add("long", pvLong)->
    endNested()->
    createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure);
PVUnionArrayPtr pvValue = pvStructure->getSubField<PVUnionArray>("value");
size_t len = 2;
PVUnionArray::svector pvUnions(len);
for(size_t i=0; i<len; ++i) pvUnions[i] =
    pvDataCreate->createPVUnion(pvValue->getUnionArray()->getUnion());
pvUnions[0]->select("short");
pvUnions[1]->select("long");
PVShortPtr pvshort = pvUnions[0]->get<PVShort>();
pvshort->put(1);
PVLongPtr pvlong = pvUnions[1]->get<PVLong>();
pvlong->put(5);
pvValue->replace(freeze(pvUnions));
cout << *pvStructure << endl;
This produces:
unionArray
structure 
    union[] value 
        union 
            short  1
        union 
            long  5
structureArray
cout << "structureArrayNested\n";
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
StructureConstPtr structure  =
    fb->addNestedStructureArray("value")->
        add("short", pvShort)->
        add("long", pvLong)->
    endNested()->
    createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure);
PVStructureArrayPtr pvValue = pvStructure->getSubField<PVStructureArray>("value");
size_t len = 2;
PVStructureArray::svector pvStructures(len);
for(size_t i=0; i<len; ++i) {
    pvStructures[i] = pvDataCreate->createPVStructure(
        pvValue->getStructureArray()->getStructure());
    PVStructurePtr pvs = pvStructures[i];
    PVShortPtr pvshort = pvs->getSubField<PVShort>("short");
    pvshort->put(i);
    PVLongPtr pvlong = pvs->getSubField<PVLong>("long");
    pvlong->put(i);
}
pvValue->replace(freeze(pvStructures));
    cout << *pvStructure << endl;
This produces:
structureArray
structure 
    structure[] value 
        structure 
            short short 0
            long long 0
        structure 
            short short 1
            long long 1
structureArray
System.out.println("structureArray");
FieldBuilder fb = fieldCreate.createFieldBuilder();
Structure structure = 
   fb.addNestedStructureArray("value").
        add("short", ScalarType.pvShort).
        add("long", ScalarType.pvLong).
    endNested().
    createStructure();
System.out.println(structure);`
This produces the same result as structureArray.

BitSet and PVStructure

Some important features of pvAccess are:

PVAccess Transmits Top Level PVStructures
For example a channelGet sends data from server to client as a top level PVStructure. For a channelPutGet a top level PVStructure is sent from the client to the server and a different top level PVStructure is returned from the server to the client.
Top Level Introspection Immutable
Once a top level PVStructure is created it's introspection can not be modified. Thus pvAccess has no need to send introspection information with data. Consider channelGet as an example. When a channelGet is created the server creates a top level pvStructure for get requests. The server sends the introspection info back to the client side of pvAccess, which also creates a top level pvStructure. Each time the client issues a get request the data is copied into the top level pvStructure of the server and transmitted to the client side of pvAccess, which puts the data in it's top level pvStructure, and finally presented to the client.
Only fields that change are transmitted.
Only the data for fields that change value between requests are sent.
Clients can request an arbitrary set of fields from server.
The client does not have to receive all fields provided by the server but can request an arbitrary subset of the fields.

In order to implement the above features pvAccess uses bitSets, where each bit is associated with a field. The following is a top level pvStructure and how bits from a bitSet are assigned:

bit#    field
0    structure
1        double scalarValue
2        double[] scalarArrayValue
3        structure timeStamp
4            long secondsPastEpoch
5            int nanoSeconds
6            int userTag
7        union unionValue
             structure timeStamp
                 long secondsPastEpoch
                 int nanoSeconds
                 int userTag
8        structure[] structureValue
             structure timeStamp
                 long secondsPastEpoch
                 int nanoSeconds
                 int userTag
             structure timeStamp
                 long secondsPastEpoch
                 int nanoSeconds
                 int userTag
9        any[] unionValue
             any
                 structure timeStamp
                     long secondsPastEpoch
                     int nanoSeconds
                     int userTag
             any
                 double value
10       string lastValue

Note that bits for structure subfields are assigned recursively. But each scalar, union, scalarArray, structureArray, and unionArray field are assigned a single bit. This means that each subfield of a union, structuctureArray, or unionArray is treated just like a new top level field. If ANY change is made to a union, scalarArray, structureArray, or unionArray, the complete set of data for that field is sent.

Below the following are discussed:

Convert
A facility that supports copy and convert methods for PVData.
pvCopy
A facility that transfers data between a client top level PVStructure and the top level PVStructure from the server.

An important featured provided by Convert is to copy data between compatible PVStructures.

Java feature: pvDataJava does a deep copies of all fields with the possible exception of scalar array fields. If the source and destination have the same scalarType and the source is immutable then the raw data array is shared and the destination is made immutable.

C++ feature: pvDataCPP does deep copies between scalar and structure fields but shallow copies between scalarArray, structureArray, and unionArray fields. For scalarArray fields this is safe because the implementation of arrays implements COW (Copy on Write) by making the array data const. This forces code to create new raw data in order to change a scalar array field. It also uses const for structureArray and unionArray fields but this does not force all elements of the array to be const. Thus the elements can be changed. Thus any code that wants to share a top level PVStructure must be very careful when changing the value of a union, structureArray, or unionArray field. The rule is that the union, structureArray, or unionArray must be replaced with a new value.

Since the pvCopy facility makes extensive use of Convert the same rules apply to it.

API: normativeType

Dave Hickin please update this section

normativeTypes defines a set of standard structures. Each normative type consists of a set of mandatory fields, a set of optional fields, and any arbitrary number of extra fields. The mandatory and optional fields are meant for use by standard tools such as Display Managers and Alarm Handlers. The extra fields are for specialized tools.

normativeTypesCPP provides a set of helper classes for implementing and using normative types. At present it has support for the following:

NTScalar
This has a value field that has type scalar
NTScalarArray
This has a value field that has type scalarArray
NTNameValue
This has a field name that is a string array and a field value that has type scalarArray. Each name[i] is associated with value[i].
NTTable
This has a string array field named labels For each label there is a scalar array field with name = label.
NTMultiChannel
This has a value field that is a union array. A primary use of this type is to access data from a set of pvAccess channels. Each element of value holds data from a channel.
NTNDArray
This type holds NDArray data as defined by the areaDetector facility.

For example NTScalar is defined as :

epics:nt/NTScalar:1.0
    double value                        // mandatory and can be any numeric type
    string descriptor                   // optional
    alarm_t alarm                       // optional
        int severity
        int status
        string message
    time_t timeStamp                    // optional
        long secondsPastEpoch
        int nanoseconds
        int userTag
    display_t display                   // optional
        double limitLow
        double limitHigh
        string description
        string format
        string units
    control_t control                   // optional
        double limitLow
        double limitHigh
        double minStep
    string extra1                       // extra
    string[] extra2                     //

API: pvAccess

ChannelProvider

ChannelProviderRegistry
    ChannelProvider getProvider(string providerName)
    ChannelProvider createProvider(string providerName)
    string[] getProviderNames()

ChannelProvider
    string getProviderName()
    ChannelFind channelFind(
        string channelName,
        ChannelFindRequester channelFindRequester)
    ChannelFind channelList(
        ChannelListRequester channelListRequester)
    Channel createChannel(
         string channelName,
         ChannelRequester,
         short priority)
    Channel createChannel(
         string channelName,
         ChannelRequester channelRequester,
         short priority,
         string address)

ChannelFindRequester
    void channelFindResult(
        Status status,
        ChannelFind channelFind,
        boolean wasFound)

ChannelFind
    ChannelProvider getChannelProvider()
     void cancelChannelFind()

ChannelProviderRegistry

getProvider
This gets the requested provider.Two providers are registered automatically: pva, which uses the pvAccess network protocol, and ca, which uses the Channel Access network protocol.
createProvider
This registers a ChannelProvider. User code does not call this, e.g. it is called via code that implements the ChannelProvider interface.
getProviderNames
Returns the names of the providers that have been created.

ChannelProvider

destroy
The channel provider will shutdown and remove all resources it is using.
getProviderName
Get the name of the provider.
channelFind
Find a channel. The details are described in this section.
createChannel
Create a channel. A Channel is described in the next section.

ChannelFindRequester

channelFindResult
This is called by the implementation. It may or may not get called. For a remote call it is normally called only if the channel is found. A local provider will usually call it immediately and report if it has the requested channel. Thus this can be called before the channelFind method returns.

ChannelFind

This method is to be used to by local pvAccess implementations (e.g. pvAccess server queries pvIOCJava. A client can determine if a channel exists without creating a channel. The client must implement a requester interface and the implementation provides an interface that the client can use to cancel the request.

getChannelProvider
Get the channel provider.
cancelChannelFind
Cancel the find request.

Channel

ChannelRequester extends Requester
    void channelCreated(
        Status status,
        Channel channel)
    void channelStateChange(
        Channel channel,
        ConnectionState connectionState)

enum AccessRights {
    none,
    read,
    readWrite
}

Channel extends Requester
    ChannelProvider getProvider()
    string getRemoteAddress()
    ConnectionState getConnectionState()
    void destroy()
    string getChannelName()
    ChannelRequester getChannelRequester()
    boolean isConnected()
    AccessRights getAccessRights(PVField pvField)
    void getField(GetFieldRequester requester,string subField)
    ChannelProcess createChannelProcess(
        ChannelProcessRequester channelProcessRequester,
        PVStructure pvRequest)
    ChannelGet createChannelGet(
        ChannelGetRequester channelGetRequester,
        PVStructure pvRequest)
    ChannelPut createChannelPut(
        ChannelPutRequester channelPutRequester,
        PVStructure pvRequest)
    ChannelPutGet createChannelPutGet(
        ChannelPutGetRequester channelPutGetRequester,
        PVStructure pvRequest)
    ChannelRPC createChannelRPC(
        ChannelRPCRequester channelRPCRequester,
        PVStructure pvRequest)
    ChannelArray createChannelArray(
        ChannelArrayRequester channelArrayRequester,
        PVStructure pvRequest)
    Monitor createMonitor(
        MonitorRequester MonitorRequester,
        PVStructure pvRequest)

ChannelRequester

The caller must implement the interface ChannelRequester.

Requester
This is defined in package org.epics.pvdata.pv. It has two methods: getRequesterName and message.
channelCreated
This is called when a channel has been created. The argument provides the channel unless status was not success.
channelStateChange
A channel connection state change has occurred. This is called the first time when a channel has been created and connected to a server or destroyed.

Channel

where

getProvider
Get the provider.
getRemoteAddress
Get the network address of the server.
destroy
Destroy the channel and all resources used by the channel.
getChannelName
The name of the channel, e.g. the name if the PVRecord.
getChannelRequester
Get the channel requester. This is normally called by the implementation rather than the client.
isConnected
Is the channel connected?
getAccessRights
Get the access rights for the channel.

The remaining methods are described in later sections of this package overview.

Many of the interface described in the later sections are created via a create call that has as one of it's arguments:

PVStructure pvRequest

This is also discussed in a later section.

GetField

The method:

    Channel.getField(GetFieldRequester requester, String subField);

Gets the introspection interface for the specified sub field of the record it which the channel is connected. The subField can be null, which means get the introspection interface for the entire record, or is of the form "name.name..." . Thus it can be a request for any field within a record. The requester must implement the interface:

interface GetFieldRequester extends Requester {
    void getDone(Status status, Field field);
}

where

getDone
A getField request has finished. A null is returned if the request fails and status contains a reason of a failure. If the request succeeds Field is the introspection interface.

ChannelRequest

Many of the interfaces described in later sections extend the following interface.

interface ChannelRequest extends Lockable, Destroyable {
    Channel getChannel();
    void cancel();
    void lastRequest();

where

destroy
Destroy whatever the extended interface implements. It will free all resources it uses.
getChannel
Get the channel instance to which this request belongs.
cancel
Cancel the current request.
lastRequest
The next request will be the last request.

ChannelProcess

A ChannelProcess is created via a call to:

interface Channel extends Requester {
   ChannelProcess createChannelProcess(
       ChannelProcessRequester channelProcessRequester);
}

The definition is:

ChannelProcessRequester extends Requester
    void channelProcessConnect(
        Status status,
        ChannelProcess channelProcess)
    void processDone(
        Status status,
        ChannelProcess channelProcess)

ChannelProcess extends ChannelRequest
    void process()

ChannelProcessRequester

The requester must implement this interface.

channelProcessConnect
This returns the interface for requesting that a record be processed. Status is the result for the create request. channelProcess is null if status is not success.
processDone
This is called when a process request is done. Status is the result for the process request.

ChannelProcess

process
Process the record. Another process request must not be issued until processDone is called.

ChannelGet

A ChannelGet is created via a call to:

interface Channel extends Requester {
    ChannelGet createChannelGet(
        ChannelGetRequester channelGetRequester,
        PVStructure pvRequest);
}

The definition is:

ChannelGetRequester extends Requester
    void channelGetConnect(
        Status status,
        ChannelGet channelGet,
        Structure structure)
    void getDone(
        Status status,
        ChannelGet channelGet,
        PVStructure pvStructure,
        BitSet bitSet)

ChannelGet extends ChannelRequest
    void get()

ChannelGetRequester

channelGetConnect
This is called if the createProcess fails or when the client request is connected to the server. Status provides the result of the createChannel request. If status is not success than the other arguments are null. channelGet is the interface for requesting gets. structure is the introspection interface for data that is returned to getDone.
getDone
The get request is done. status provides the result of the get request. If successful the pvStructure and bitSet contain the data returned as a result of a get request. bitSet shows which fields have new data. If a bit of bitSet is set for a structure field that means that all fields of the structure have new values. For example of bit 0 of bitSet is set then all fields of pvStructure have new data. Note that each PVField implements a method getFieldOffset(). this can be used with bitSet to determine which fields have new data values. See BitSet and PVField in org.epics.pvdata for details.

ChannelGet

get
Get data. Another get request must not be issued until getDone is called.

ChannelPut

A ChannelPut is created via a call to:

interface Channel extends Requester {
    ChannelPut createChannelPut(
        ChannelPutRequester channelPutRequester,
        PVStructure pvRequest);
}

The definition is:

ChannelPutRequester extends Requester
    void channelPutConnect(
        Status status,
        ChannelPut channelPut,
        Structure structure)
    void putDone(
        Status status,
        ChannelPut channelPut)
    void getDone(
        Status status,
        ChannelPut channelPut,
        PVStructure pvStructure,
        BitSet bitSet)

ChannelPut extends ChannelRequest
    void put(PVStructure pvPutStructure, BitSet bitSet)
    void get()

ChannelPutRequester

The requester must implement this interface.

channelPutConnect
This is called if the createChannelPut fails or when the client request is connected to the server. Status provides the result of the createChannelPut request. If status is not success than the other arguments are null. channelPut is the interface for requesting puts and gets. Structure is the introspection interface that must be used for data that is put to the server or that is returned by a get request.
putDone
The put request is done. status provides the result of the put request.
getDone
The get request is done. status provides the result of the put request. pvStructure has the data returned from the server. bitSet to shows which fields have new data before making a put request. If a bit of bitSet is set for a structure field that means that all fields of the structure have new values. For example of bit 0 of bitSet is set then all fields of pvStructure have new data. Note that each PVField implements a method getFieldOffset(). this can be used with bitSet to determine which fields have new data values. See BitSet and PVField in org.epics.pvdata for details.

ChannelPut

put
Put data. pvPutStructure is the data to send to the server, bitSet determines which fields are sent.
get
Get the current data from the record. The record is never processed. The request just gets the current values which is put into the pvStructure returned in the call to channelPutConnect.

NOTE: Only one of put and get can be outstanding at the same time. Another get or put must not be issued until getDone or putDone is called.

ChannelPutGet

A channelPutGet request puts data into a record, optionally processes the record, and gets data from the record.

A channel putGet is created via a call to:

interface Channel extends Requester {
    ChannelPutGet createChannelPutGet(
        ChannelPutGetRequester channelPutGetRequester,
        PVStructure pvRequest);
}

The definition is:

ChannelPutGetRequester extends Requester
    void channelPutGetConnect(
        Status status,
        ChannelPutGet channelPutGet,
        Structure putStructure,
        Structure getStructure)
    void putGetDone(
        Status status,
        ChannelPutGet channelPutGet,
        PVStructure getPVStructure,
        BitSet getBitSet)
    void getPutDone(
        Status status,
        ChannelPutGet channelPutGet,
        PVStructure putPVStructure,
        BitSet putBitSet)
    void getGetDone(
        Status status,
        ChannelPutGet channelPutGet,
        PVStructure getPVStructure,
        BitSet getBitSet)

ChannelPutGet extends ChannelRequest
    void putGet(PVStructure pvPutStructure, BitSet putBitSet)
    void getPut()
    void getGet()

ChannelPutGetRequester

The requester must implement this interface.

channelPutGetConnect
This is called if the createChannelPutGet fails or when the client request is connected to the server. Status provides the result of the createChannelPutGet request. If status is not success than the other arguments are null. channelPutGet is the interface for requesting putGet, getPut and getGet. putStructure is the introspection interface that is used for data sent by the client and getStructure the introspection interface for data received by the client.
putGetDone
The putGet request is done. If status is not success then the other arguments may be null. getPVStructure is the data returned to the client and getBitSet shows which fields have changed value since the last putGet request.
getPutDone
The getPut request is done. If status is not success then the other arguments may be null. putPVStructure is the data returned to the client and putBitSet shows which fields have changed value since the last getPut request.
getGetDone
The getGet request is done. If status is not success then the other arguments may be null. getPVStructure is the data returned to the client and getBitSet shows which fields have changed value since the last getGet request.

ChannelPutGet

putGet
First put the pvPutStructure data into the record. Then if process is true process the record. Finally get data from the record and put it into pvGetStructure.
getPut
Get current put data from the record and put it into pvPutStructure. The record is never processed.
getGet
Get current data from the record and put it into pvGetStructure. The record is never processed.

NOTE: Only one of putGet, getPut, or getGet can be outstanding at the same time. Another request must not be issued until the appropriate xxxDone is called.

ChannelArray

ChannelArray provides the ability to read or write a sub-array of an array field in a record. Note that all the other transfer methods can also read or write arrays but always transfer entire arrays. ChannelArray provides the ability to transfer a subarray. A ChannelArray is created via a call to:

interface Channel extends Requester {
    ChannelArray createChannelArray(
        ChannelArrayRequester channelArrayRequester,
        PVStructure pvRequest);
}

The definition is:

ChannelArrayRequester extends Requester
    void channelArrayConnect(
        Status status,
        ChannelArray channelArray,
        Array array)
    void putArrayDone(
        Status status,
        ChannelArray channelArray)
    void getArrayDone(
        Status status,
        ChannelArray channelArray,
        PVArray pvArray)
    void getLengthDone(
        Status status,
        ChannelArray channelArray,
        int length,
        int capacity)
    void setLengthDone(
        Status status,
        ChannelArray channelArray)

ChannelArray extends ChannelRequest
    void putArray(
        PVArray putArray,
        int offset,
        int count,
        int stride)
    void getArray(
        int offset,
        int count,
        int stride)
    void getLength()
    void setLength(
        int length)

ChannelArrayRequester

The requester must implement this interface.

channelArrayConnect
This is called if the createChannelArray fails or when the client request is connected to the server. Status provides the result of the createChannelArray request. If status is not success than the other arguments are null. channelArray is the interface for requesting puts and gets. array is the interface for the data that transfered between client and server.
putArrayDone
The put request is done.
getArrayDone
The get request is done. pvArray holds the data.
getLengthDone
The getLength request is done. length and capacity hold the result.
setLengthDone
The setLength request is done.

ChannelArray

putArray
Put array data. The offset and stride are the offset and stride in the server and the count is the total number of elements to write.
getArray
Get array data. The offset and stride are the offset and stride in the server and the count is the total number of elements to read.
getLength
Get the current length and capacity of the array in the server.
setLength
Set the length and capacity of the array in the server.

Monitor

Monitor provides the ability to set monitors on data in a PVRecord. What triggers a monitor depends on the monitor support in the server. The standard server provides support for the following: onPut, onChange, onAbsoluteChange, and onPercentChange.

A Monitor is created via a call to:

    void createMonitor(
        MonitorRequester monitorRequester,
        PVStructure pvRequest);
}

The definition is:

MonitorRequester extends Requester
    void monitorConnect(Status status, Monitor monitor, Structure structure))
    void monitorEvent((Monitor monitor)
    void unlisten()

Monitor
    Status start()
    Status stop()
    MonitorElement poll()
    void release(MonitorElement monitorElement)

MonitorElement
    PVStructure getPVStructure()
    BitSet getChangedBitSet()
    BitSet getOverrunBitSet()

MonitorRequester

The requester must implement this interface.

monitorConnect
This is called if the createMonitor fails or when the client request is connected to the server.
status
The result of the createMonitor request. If status is not success than the other arguments are null.
monitor
The interface for the Monitor.
structure
The introspection interface for the data that will be returned for each monitor event.
monitorEvent
monitorEvent is called when a monitor occurs. The client must call monitor.poll to get data for the monitor. See below.
unlisten
The server has issued an unlisten request.

The following is the Monitor interface which is defined in project pvData

interface Monitor extends Destroyable {
    Status start();
    Status stop();
    MonitorElement poll();
    void release(MonitorElement monitorElement);
}

where

start
Start monitoring
stop
Stop monitoring
poll
Poll for monitor event. Null is returned when no more events are available. The client must call this method in order to get monitor data.
release
When the client has processed the monitor event returned by poll the client must call release before again calling poll.

A monitorElement is defined as:

interface MonitorElement {
    PVStructure getPVStructure();
    BitSet getChangedBitSet();
    BitSet getOverrunBitSet();
}

where

getPVStructure
The data structure.
getChangedBitSet
A bitset which has a bit set for each field of the data structure which has changed since the last monitor.
getOverrunBitSet
A bitset which has a bit set for each field of the data structure which has changed more than once since the last monitor.

Monitor

start
Start monitoring
stop
Stop monitoring
poll
Poll for monitor event. Null is returned when no more events are available. The client must call this method in order to get monitor data.
release
When the client has processed the monitor event returned by poll the client must call release before again calling poll.

ChannelRPC

A ChannelRPC is like a channelPutGet except that a completely different pvStructure can be sent and returned for each request. It is created via a call to:

interface Channel extends Requester {
    ChannelRPC createChannelRPC(
        ChannelRPCRequester channelRPCRequester,
        PVStructure pvRequest);
}

The definition is:

ChannelRPCRequester extends Requester
    void channelRPCConnect(
        Status status,
        ChannelRPC channelRPC)
    void requestDone(
        Status status,
        ChannelRPC channelRPC,
        PVStructure pvResponse)

ChannelRPC extends ChannelRequest
    void request(PVStructure pvArgument)

ChannelRPCRequester

The requester must implement this interface.

channelRPCConnect
Status provides the result of the createChannelRPC request. If status is not success than the other argument is null.
requestDone
The request is done. status provides the result of the request. If successful a pvResponse is returned.

ChannelRPC

request
pvArgument is the structure that is sent to the server. If lastRequest is true than it is a one time request, i.e. Send it is the same as calling destroy after the request is complete.

API: pvaClient

PvaClient is a synchronous API for accessing PVData via PVAccess. It also provides a number of convenience methods. It allows the client to request access without checking for failure, but throws an exception when a reuest fails. A client can also check for failues and thus prevent failures.

The PvaClient API has the following features:

  1. Provides a synchronous API rather than the callback API provided by pvAccess.
  2. Makes common requests easy.
  3. Provides full access to the pvAccess API for more demanding applications
  4. Allows efficient client side programs.
  5. Takes care of most object resource management problems.

Simple examples of using pvaClient:

// easyGet
PvaClientPtr pvaClient = PvaClient::create();
double value = pvaClient->channel("exampleDouble")->get()->getData()->getDouble();

// easyPut
PvaClientChannelPtr channel = pvaClient->channel("exampleDouble");
PvaClientPutPtr put = channel->put();
PvaClientPutDataPtr putData = put->getData();
putData->putDouble(3.0); put->put();

// easyMonitor
PvaClientMonitorPtr monitor = pvaClient->channel("examplePowerSupply")->monitor("");
PvaClientMonitorDataPtr easyData = monitor->getData();
while(true) {
    monitor->waitEvent();
    cout << "changed\n";
    easyData->showChanged(cout);
    cout << "overrun\n";
    easyData->showOverrun(cout);
    monitor->releaseEvent();
}
// easyProcess
PvaClientChannelPtr channel = pvaClient->channel("exampleDouble");
PvaClientProcessPtr process = channel->createProcess();
process->process();

API: pvDatabase

A brief description of a pvDatabase is that it is a set of network accessible, smart, memory resident records. Each record has data composed of a top level PVStructure. Each record has a name which is the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and Channel interfaces as defined by pvAccess. The local provider provides access to the records in the pvDatabase. This local provider is accessed by the remote pvAccess server. A record is smart because code can be attached to a record, which is accessed via a method named process.

Implementations for both Java and C++ are available. With the C++ implementation (pvDatabaseCPP) the pvDatabase can be provided via a Main program or can be part of a V3IOC. In the later case the IOC has both a database of V3 Records and a PVRecords. This version allows the development of V4 services for V3IOCs.

pvDatabaseJava and pvDatabaseCPP both have example databases. Project pvaClientTestCPP has a database that is similar to pvDatabaseJava/exampleDatabase but also adds exampleHello, exampleHelloRPC, and powerSupply. This section will mainly describe the pvaClientTestCPP database, which also describes pvDatabaseJava/exampleDatabase. It shows how create a V3 IOC that has both V3 Records, PVRecords, and pvaSrv. After reading this section the examples in pvaDatabaseJava and pvDatabaseCPP should be easy to understand.

Starting the example

The example database can be run either as a standalone main program or as part of a V3 IOC (Input Output Controller). If as part of a V3 IOC the IOC has both V3 and V4 records. It also starts pvaSrv so that the V3 records can be accessed via either ca or pva.

To run the example as a main program:

mrk> pwd
/home/epicsv4/pvaClientTestCPP/database
mrk> bin/linux-x86_64/exampleDatabaseMain 

To start the example as part of a V3 IOC:

mrk> pwd
/home/epicsv4/pvaClientTestCPP/database/iocBoot/exampleDatabase
mrk> ../../bin/linux-x86_64/exampleDatabase st.cmd

Once the database is running then the following can access exampleHello:

pvput -r "argument" exampleHello World
pvget -r "result.value" exampleHello
exampleHello
structure 
    structure result
        string value Hello World

The following also works:

mrk> pwd
/home/epicsv4/pvaClientCPP/example
mrk> bin/linux-x86_64/helloWorldPutGet
helloWorldPutGet
structure 
    structure result
        string value Hello World
        time_t timeStamp
            long secondsPastEpoch 1440095693
            int nanoseconds 281748793
            int userTag 0

mrk>

source code

pvaClientTestCPP/database/src has the following examples:

exampleHello
This is an hello world example that is meant to be accesed via a channelPutGet request. It can also be accessed via pvput followed by a pvget.
exampleHelloRPC
The is an hello world example that is accessed via a channelRPC request.
exampleDatabase
This creates an exampleHello record. It also creates a large set of records of all possible types that have only the default process semantics, which only sets the timeStamp when the record is processed.
powerSupply
This has a example record that models a power supply. Given a value for desired voltage and power, it computes the current.
The src directory also has the following files:
exampleDatabaseMain.cpp
code to run example as main program
exampleDatabaseInclude.dbd
exampleDatabaseRegister.cpp
code to run example as part of V3 IOC

exampleDatabaseMain.cpp

This is the file that runs the example as a main program. The main program is:

int main(int argc,char *argv[])
{
    PVDatabasePtr master = PVDatabase::getMaster();
    ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
    ExampleDatabase::create();
    ServerContext::shared_pointer ctx =
        startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
    cout << "exampleDatabase\n";
    PVStringArrayPtr pvNames = master->getRecordNames();
    cout << "recordNames" << endl << *pvNames << endl;
    string str;
    while(true) {
        cout << "Type exit to stop: \n";
        getline(cin,str);
        if(str.compare("exit")==0) break;

    }
    ctx->destroy();
    epicsThreadSleep(1.0);
    channelProvider->destroy();
    return 0; 
}
The only code that is not generic is:
    ExampleDatabase::create();

exampleDatabaseRegister.cpp

This is used to create an iocshell command to start the example database as part of a V3 IOC. It is almost generic. The guts of the code is:
static const iocshArg testArg0 = { "prefix", iocshArgString };
static const iocshArg *testArgs[] = {
    &testArg0};

static const iocshFuncDef exampleDatabaseFuncDef = {
    "exampleDatabase", 1, testArgs};
static void exampleDatabaseCallFunc(const iocshArgBuf *args)
{
    ExampleDatabase::create();
}

static void exampleDatabaseRegister(void)
{
    static int firstTime = 1;
    if (firstTime) {
        firstTime = 0;
        iocshRegister(&exampleDatabaseFuncDef, exampleDatabaseCallFunc);
    }
}

extern "C" {
    epicsExportRegistrar(exampleDatabaseRegister);
}
Other than exampleDatabase as part of the names it is boiler plate code.

exampleDatabaseInclude.dbd

This is just:
registrar("exampleDatabaseRegister")
It again is generic except for exampleDatabase as part of the name.

Makefile

Look at the Make file to see how each other file is used.

exampleDatabase

exampleDatabase.h is almost completely generic. It has the code:
class epicsShareClass  ExampleDatabase{
public:
    static void create();
};
It defines a factory methods for creating the example database.

exampleDatabase.cpp is not generic. It shows how to create records of various types. Most of the records have only the default process method. The default process does nothing except that if a timeStamp field is present the time is set to the current time. Look at the code to see examples of how to create records.

pvaClientTestCPP/database/ioc

This directory has two subdirectories:
Db
This creates some V3 records.
src
This has to files to load the V3 and V4 support for a V3 IOC.

src

exampleDatabaseMain.cpp is standard code to start a V3 IOC

exampleDatabaseInclude.dbd contains:

include "base.dbd"
include "PVAServerRegister.dbd"
include "registerChannelProviderLocal.dbd"
include "dbPv.dbd"
registrar("exampleDatabaseRegister")

base.dbd is standard way to include the base V3 code. PVAServerRegister.dbd is how the pvAccess Server code is included. registerChannelProviderLocal.dbd is how the local pva server is started. The local server is implemented by pvDatabaseCPP. dbPv.dbd is how pvaSrv, the pva server that accesses V3 revords, is started.

registrar("exampleDatabaseRegister") is the only example specific statement. It is used to start the example database.

pvaClientTestCPP/database/iocBoot/exampleDatabase

This is where the V3 IOC is started. The st.cmd starts with normal way to start a V3 IOC. What is different is the statements after iocInit:

exampleDatabase
startPVAServer

The first statement creates the example database. The second statement starts the pva server. After it is started clients can access the V4 records and the V3 records via pva.

API: pvaSrv

pvaSrv is a pvAccess server that runs in the EPICS V3 IOC

pvaSrv allows you to get, put and monitor V3 PVs (fields of EPICS DB records) over pvAccess, translating the value and its meta data (graphics limits, alarm status, timestamp) to or from V4 Normative Type (NT) pvData structures (NTScalar, NTScalarArray).

API: pvaPy

pvaPy provides a python interface to pvData and pvAccess.

The following:

#!/usr/bin/env python

from pvaccess import Channel

c = Channel('double01')
oldValue = c.get().getDouble()
print 'Got old value: ', oldValue
value = oldValue + 1.1
print 'Putting value via putDouble(): ', value
c.putDouble(value) 
newValue = c.get().getDouble()
print 'Got new value: ', newValue
produces:
python examplePut.py
Got old value:  5.3
Putting value via putDouble():  6.4
Got new value:  6.4

pvAccess Channel Providers.

pvAccessJava and pvAccessCPP implement the following providers:

pva
This is a provider that trasfers data via the network protocol defined in pvAccess Protocol Specification
This provides the client and server side of the network protocol. The client side is a complete implementation. The server side requires additional code to access data sources but takes care of all network code.
ca
This is client support for transfering data via the EPICS V3 channel access protocol.

Providers can be provided for other data sources. A provider must implement ChannelProvider and Channel. pvAccess supports an arbitrary number of providers. On the server side of remote pvAccess providers must be implemented, because it calls the providers to implement the CHannel methods.

At present C++ provides two server side providers:

pvaSrv
This is a pvAccess server that accesses V3 records,
local
This is implemented by pvDatabaseCPP

At present Java provides one server side provider:

local
This is implemented by pvDatabaseJava

Convert Facility

Both pvDataJava and pvDataCPP have a Convert Facility. Although they have some common features they are different enough that they will be discussed separately.

They main difference is support for scalar arrays.

The Java Convert facility supports sub-array copies between any two numeric arrays. It does a deep copy except for a complete copy between two array of the same type and the source array is immutable. In this case to calls the shareData method and also makes the destination array immutable.

The C++ faclity only supports complete array copies between two scalar arrays of the same type and only does a shallow copy. It also does a shallow copy for union, unionArray, and structureArray fields. It also has a separate facility that does sub-array copies between two arrays of the same type.

Java

NOTE: 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.

interface Convert {
    void getFullFieldName(StringBuilder builder,PVField pvField)
    void getString(StringBuilder buf,PVField pv, int indentLevel);
    void getString(StringBuilder buf,PVField pv);
    void fromString(PVScalar pv,String from);
    void fromString(PVScalarArray pv,String from);
    int fromStringArray(PVScalarArray pv,
         int offset, int len, String[]from, int fromOffset);
    int toStringArray(PVScalarArray pv,
         int offset, int len, String[]to, int toOffset);
    boolean isCopyCompatible(Field from, Field to);
    void copy(PVField from,PVField to);
    boolean isCopyScalarCompatible(Field from, Field to);
    void copyScalar(PVField from, PVField to);
    boolean isCopyScalarArrayCompatible(ScalarArray from, ScalarArray to);
    int copyScalarArray(PVScalarArray from, int offset,
         PVScalarArray to, int toOffset, int len);
    boolean isCopyStructureCompatible(Structure from, Structure to);
    void copyStructure(PVStructure from, PVStructure to);
    boolean isCopyUnionCompatible(Union from, Union to);
    void copyUnion(PVUnion from, PVUnion to);
    boolean isCopyStructureArrayCompatible(StructureArray from, StructureArray to);
    void copyStructureArray(PVStructureArray from, PVStructureArray to);
    boolean isCopyUnionArrayCompatible(UnionArray from, UnionArray to);
    void copyUnionArray(PVUnionArray from, PVUnionArray to);
    // For the following the pv Type must be PVByte, ...., PVDouble
    byte toByte(PVField pv);
    short toShort(PVField pv);
    int   toInt(PVField pv);
    long  toLong(PVField pv);
    float toFloat(PVField pv);
    double toDouble(PVField pv);
    String toString(PVScalar pv);
    void  fromByte(PVField pv, byte from);
    void  fromShort(PVField pv, short from);
    void  fromInt(PVField pv, int from);
    void  fromLong(PVField pv, long from);
    void  fromUByte(PVField pv, byte from);
    void  fromUShort(PVField pv, short from);
    void  fromUInt(PVField pv, int from);
    void  fromULong(PVField pv, long from);
    void  fromFloat(PVField pv, float from);
    void  fromDouble(PVField pv, double from);
// For the following the element type must be pvByte, ...., pvDouble
    int toByteArray(PVScalarArray pv,
        int offset, int len, byte[]to, int toOffset);
    int toShortArray(PVScalarArray pv,
        int offset, int len, short[]to, int toOffset);
    int toIntArray(PVScalarArray pv,
        int offset, int len, int[]to, int toOffset);
    int toLongArray(PVScalarArray pv,
        int offset, int len, long[]to, int toOffset);
    int toFloatArray(PVScalarArray pv,
        int offset, int len, float[]to, int toOffset);
    int toDoubleArray(PVScalarArray pv,
        int offset, int len, double[]to, int toOffset);
    int fromByteArray(PVScalarArray pv,
        int offset, int len, byte[]from, fromOffset);
    int fromShortArray(PVScalarArray pv,
        int offset, int len, short[]from, fromOffset);
    int fromIntArray(PVScalarArray pv,
        int offset, int len, int[]from, fromOffset);
    int fromLongArray(PVScalarArray pv,
        int offset, int len, long[]from, fromOffset);
    int fromUByteArray(PVScalarArray pv,
        int offset, int len, byte[]from, fromOffset);
    int fromUShortArray(PVScalarArray pv,
        int offset, int len, short[]from, fromOffset);
    int fromUIntArray(PVScalarArray pv,
        int offset, int len, int[]from, fromOffset);
    int fromULongArray(PVScalarArray pv,
        int offset, int len, long[]from, fromOffset);
    int fromFloatArray(PVScalarArray pv,
        int offset, int len, float[]from, fromOffset);
    int fromDoubleArray(PVScalarArray pv,
        int offset, int len, double[]from, fromOffset);
    void newLine(StringBuilder builder, int indentLevel);
}

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.

The getString methods dump the data in the metadata syntax described in the pvData project overview. Note that the toString methods of PVField are implemented by calling these convert methods.

C++

Many of the Java convert methods have been moved to class PVField and it's extensions. This include all the comparison methods and also conversion between numeric types.

convert.h

class Convert;
typedef std::tr1::shared_ptr<Convert> ConvertPtr;

class Convert {
public:
    static ConvertPtr getConvert();
    ~Convert();
    void getString(std::string * buf,PVFieldPtr const & pvField,int indentLevel);
    void getString(std::string * buf,PVFieldPtr const & pvField);
    void getString(std::string * buf,PVField const * pvField,int indentLevel);
    void getString(std::string * buf,PVField const * pvField);
    std::size_t fromString(
        PVStructurePtr const &pv,
        StringArray const & from,
        std::size_t fromStartIndex = 0);
    void fromString(PVScalarPtr const & pv, std::string const & from);
    std::size_t fromString(PVScalarArrayPtr const & pv, std::string const &from);
    std::size_t fromStringArray(
        PVScalarArrayPtr const & pv,
        std::size_t offset, std::size_t length,
        StringArray const & from,
        std::size_t fromOffset);
    std::size_t toStringArray(PVScalarArrayPtr const & pv,
        std::size_t offset,
        std::size_t length,
        StringArray & to,
        std::size_t toOffset);
    int8 toByte(PVScalarPtr const & pv);
    int16 toShort(PVScalarPtr const & pv);
    int32 toInt(PVScalarPtr const & pv);
    int64 toLong(PVScalarPtr const & pv);
    uint8 toUByte(PVScalarPtr const & pv);
    uint16 toUShort(PVScalarPtr const & pv);
    uint32 toUInt(PVScalarPtr const & pv);
    uint64 toULong(PVScalarPtr const & pv);
    float toFloat(PVScalarPtr const & pv);
    double toDouble(PVScalarPtr const & pv);
    std::string toString(PVScalarPtr const & pv);
    void fromByte(PVScalarPtr const & pv,int8 from);
    void fromShort(PVScalarPtr const & pv,int16 from);
    void fromInt(PVScalarPtr const & pv, int32 from);
    void fromLong(PVScalarPtr const & pv, int64 from);
    void fromUByte(PVScalarPtr const & pv,uint8 from);
    void fromUShort(PVScalarPtr const & pv,uint16 from);
    void fromUInt(PVScalarPtr const & pv, uint32 from);
    void fromULong(PVScalarPtr const & pv, uint64 from);
    void fromFloat(PVScalarPtr const & pv, float from);
    void fromDouble(PVScalarPtr const & pv, double from);
}

extern ConvertPtr getConvert();

pvSubArrayCopy.h

This supports sub-array copying between arrays that have the same type.

template<typename T>
void copy(
    PVValueArray<T> & pvFrom,
    size_t fromOffset,
    size_t fromStride,
    PVValueArray<T> & pvTo,
    size_t toOffset,
    size_t toStride,
    size_t count);

void copy(
    PVScalarArray & from,
    size_t fromOffset,
    size_t fromStride,
    PVScalarArray & to,
    size_t toOffset,
    size_t toStride,
    size_t count);

void copy(
    PVStructureArray & from,
    size_t fromOffset,
    size_t fromStride,
    PVStructureArray & to,
    size_t toOffset,
    size_t toStride,
    size_t count);

void copy(
    PVArray & from,
    size_t fromOffset,
    size_t fromStride,
    PVArray & to,
    size_t toOffset,
    size_t toStride,
    size_t count);

The last copy is the only one most client need to call. It either throws an error if the element types do not match or calls the other copy functions. The arguments are:

from
The source array.
fromOffset
The offset into the source array.
fromStride
The interval between source elements.
to
The destination array. The element type must be the same as for the source array. If the element type is structure then the introspection interface for the element types must be the same.
toOffset
The offset into the destination array.
toStride
The interval between destination elements.
count
The number of elements to copy.

An exception is thrown if:

type mismatch
The element types for the source and destination differ.
immutable
The destination array is immutable.
capacity immutable
The destination array needs to have it's capacity extended but the capacity is immutable.

PVField::copy

PVField has a method copy. It allows copying between any two compatible fields. Both fields must have the same type. For scalar and scalarArray conversion between the various scalarTypes is supported.

The following:

    PVDataCreatePtr create = getPVDataCreate();
    PVDoublePtr pvDouble = create->createPVScalar<PVDouble>();
    PVBytePtr pvByte = create->createPVScalar<PVByte>();
    pvByte->put(10);
    pvDouble->copy(*pvByte);
    cout << "double " << pvDouble << " byte " << pvByte << endl;

    PVStringPtr pvString = create->createPVScalar<PVString>();
    pvString->copy(*pvByte);
    cout << "string " << pvString << " byte " << pvByte << endl;
produces:
double 10 byte 10
string 10 byte 10

Likewise for scalarArray:

    PVDataCreatePtr create = getPVDataCreate();
    PVDoubleArrayPtr pvDoubleArray = create->createPVScalarArray<PVDoubleArray>();
    PVByteArrayPtr pvByteArray = create->createPVScalarArray<PVByteArray>();
    shared_vector<int8> data(2);
    data[0] = 1; data[1] = 10;
    pvByteArray->replace(freeze(data));
    pvDoubleArray->copy(*pvByteArray);
    cout << "double " << pvDoubleArray << " byte " << pvByteArray << endl;

    PVStringArrayPtr pvStringArray = create->createPVScalarArray<PVStringArray>();
    pvStringArray->copy(*pvByteArray);
    cout << "string " << pvStringArray << " byte " << pvByteArray << endl;
produces:
double [1,10] byte [1,10]
string [1,10] byte [1,10]

Interlude

What has been defined prevously is the core part of pvData and pvAccess. Any code that is implemented via the above can be used to transfer data via the pva or the ca network protocol.

The remainder of this document describes additional features provided by pvData. These additional features make it easier to create services based on the pvAccess network protocol.

Standard for Field::ID

The introspection interface for every field has an ID, which is available via method:

class Field {
...
    string getID();
...
};

This section describes how the IDs are assigned.

Scalar

boolean
byte
short
int
long
ubyte
ushort
ulong
float
double
string

Scalar Array

boolean[]
byte[]
short[]
int[]
long[]
ubyte[]
ushort[]
ulong[]
float[]
double[]
string[]

Union

any        // variant union
union      // restricted union

Union Array

any[]
union[]

structure

default

structure

standard fields

alarm_t
time_t
display_t
control_t
enum_t
alarmLimit_t
valueAlarm_t

Issues:

display_t
This has field
string format
The allowed syntax should be defined.
alarmLimit_t,valueAlarm_t
standardField and standardPVField define valueAlarm for boolean, each numeric scalar type, and for enum_t. alarmLimit_t has the same fields as valueAlarm for double. I suspect that most tools will only use alarmLimit_t. What to do?

structure array

Like structure except that [] is appended.

pvRequest and pvCopy

Both pvDataJava and pvDataCPP provide facilities:

CreateRequest
Creates a PVStructure that is a valid pvRequest to be passed between a client a server. The Channel class of pvAccess has methods that have pvRequest arguments. For example:
ChannelGet createChannelGet(
    ChannelGetRequester channelGetRequester,
    PVStructure pvRequest);
PVCopy
A client can request an arbitrary subset of the fields in the top level PVStructure that server provides. PVCopy is a facility that copies data between a top level PVStructure that has the clients data and the top level PVStructure from the server. CreateRequest allows the client to select fields desired. PVCopy is used by the server side of pvAccess to transfer data between the two top level PVStructures.

CreateRequest

Definition

CreateRequest
    PVStructure createRequest(string request)
    string getMessage()
createRequest
Create a pvRequest PVStructure. If an invalid request is made a null PVStructure is returned.
getMessage
The reason why the last request failed.

Purpose

CreateRequest allows the clients to select an arbitrary subset of the fields in the top level structure associated with the channel. It also allows the client to specify options. Thus the client can specify:

Global Options
Global options are options that apply to the record itself.
Desired Fields
An arbitrary set of fields can be selected from the top level structure that holds the data in the record.
Field Options
These are options that apply to a selected field.

NOTE: The term record is adapted from pvDatabase. A pvDatabase has a memory resident database of smart records. A pvAcccess channel is a connection to a record. A record has a top level PVStructure that holds the data for the record. A pvAcccess server can be implemented that does not use the pvDatabase model but it must provide top level PVStructures to which a pvAcccess Channel can be attached. pvaSrv, which provides access to iocCore V3 records, is an example that also accepts a pvRequest created by a call to createRequest.

Syntax

A request argument has the syntax:

record[option,...]field(fieldDef,...)putField(fieldDef,...)getField(fieldDef,...)
OR
fieldDef,...

Thus a request consists of record options and sets of field definitions or just field definitions. A record option is of the form:

record[name=value,...]

A field,putFeld,getField is a comma separated set of fieldDefs which are of the form:

fullFieldName
or
fullFieldName[option,...]
or
fullFieldName{fieldDef}     // recursive definition

A fullFieldName is the full name of a field in the PVRecord. The name in a generated data structure will have just the field name. If fieldName{request} is given then the generated data structure will have a structure field with subfields. Note that request is a recursive definition.

If request is null or an empty string than the entire top level structure of the PVRecord is selected.

The syntax was chosen to be easy to use and to parse:

record[]
Specifies a set of global options, i. e., options that apply to the record itself.
field()
putField()
getField()
Each selects a set of subfields of the top level structure. Each defines a comma separated set of fieldDefs.
fieldDef
Selects a single subfield of the current structure.
option
A name=value pair. Both name and value are character strings.
[]
Holds a comma separated set of options.
{}
Selects a set of subfields of a substructure within the top level structure. Each defines a comma separated set of fieldDefs. This is a recursive definition. Thus a fullFieldName within {} is relative to structure that is referenced by {}.

Standard Options

At present the following record options are in use:

queueSize
This is used to define the queueSize for monitors. The default is:
record[queueSize=2]
A larger size can be specified.
process
This is used by pvaSrv and pvDatabaseCPP to specify of records should be processed. The default is false channelGet and true for channelPut and channelPutGet, An example is:
record[process=false]
block
This is used by pvaSrv to specify if a request to process a record should block until the record completes processing. The default is the same as the value ofi the process option. An example is:
record[block=false]

Simple Examples

Clients like CSS, Synoptic Displays, Alarm, and Archive only want access to some combination of the following fields: value, alarm, timeStamp, display, and control. If the request is for a record that has these all as top level fields the request string is just a comma separated list of the field names. For example:

"value,alarm,timeStamp"

If the record is does not have the desired field at the top level then the field can still be accessed but in this case the full structure is preserved. For example:

"alarm,timeStamp,power.value"

Will get the top level alarm and timeStamp and the value from a structure named power. Thus the above works for a record that is structured as follows:

powerSupply
    alarm
    timeStamp
    power
       value
       display
       ...
    ...
What is returned to the client is:
powerSupply
    alarm
    timeStamp
    power
       value

The only option most clients want is to request that a record be processed as part of a get or put requests. This is done via requests like the following:

"record[process=true]field(value,alarm,timeStamp)"

Power Supply Example

The following examples are for a power supply record:

powerSupply
    alarm
    timeStamp
    power
       value
       alarm
       .. other fields
    voltage
       value
       alarm
       .. other fields
    current
       value
       alarm
       .. other fields
    .. other fields

The following request:

"field(alarm,timeStamp,power.value)"

Will return to the client the following:

record psSimple
    alarm_t alarm
        severity NONE status NONE
        message null
    time_t 2013-02-27 06:04:30.997 userTag 0
    structure power
        double value 10.0

Note that if the actual record does not have a requested field than it will not be present in the structure returned to the client.

The following is the same except that a record option and an option for the value field will be given.

"record[process=true]field(alarm,timeStamp,power.value[monitorAlgorithm=onChange])"

The options are to process the record and to cause power.value to cause a monitor only if the value changes.

The following:

"field(alarm,timeStamp,power{value,alarm},current{value,alarm},voltage{value,alarm})"

Will return to the client the following:

record psEmbeded
    alarm_t alarm
        severity NONE status NONE
        message
    time_t 1969-12-31 19:00:00.000 userTag 0
    structure power
        double value 0.0
    structure current
        double value 0.0
        alarm_t alarm
            severity NONE status NONE
            message
    structure voltage
        double value 0.0
        alarm_t alarm
            severity NONE status NONE
            message

Syntax for pvRequest structure created by createRequest

NOTE: This section is only of interest to someone who is implementing code that has to introspect a structure generated by createRequest.

pvRequest is a PVStructure that describes 1) record options and 2) field requests and options. It has the following structure:

structure
  structure record
    structure _options
      option
      ...
  structure field
    structure fieldName
      structure _options
        option
        ...
      structure fieldName
        structure _options
          option
          ...
        ...
  structure putField
    structure fieldName
      structure _options
        option
        ...
      structure fieldName
        structure _options
          option
          ...
        ...
  structure getField
    structure fieldName
      structure _options
        option
        ...
      structure fieldName
        structure _options
          option
          ...
        ...

where

record
The options that apply to the entire record.
option
This is of the form string <name> <value>
field
Definitions that select fields of the PVRecord and options for the fields. This definition is recursive.
fieldName
The field name that will appear in the PVStructure that is a copy of the fields selected from the PVRecord.

Note:

An example of option is process.

Process is a record option:

structure
  structure record
    structure _options
      string process true

For example if process is an option to createGet then the record will be processed before data is fetched. NOTE: scalarType boolean is also supported.

The following is an example of a field option:

structure
    structure field
        structure value
            structure _options
                string monitorAlgorithm onChange

Some examples are:

request
structure

request alarm,timeStamp,power.value
structure
    structure alarm
    structure timeStamp
    structure power
        structure value

request record[process=true]field(alarm,timeStamp,power.value)
structure
    structure record
        structure _options
            string process true
    structure field
        structure alarm
        structure timeStamp
        structure power
            structure value
request record[process=true]field(alarm,timeStamp[algorithm=onChange,causeMonitor=false],power{value,alarm})
structure
    structure record
        structure _options
            string process true
    structure field
        structure alarm
        structure timeStamp
            structure _options
                string algorithm onChange
                string causeMonitor false
        structure power
            structure value
            structure alarm

request record[process=true,xxx=yyy]field(alarm,timeStamp[causeMonitor=true],power.value)
structure
    structure record
        structure _options
            string process true
            string xxx yyy
    structure field
        structure alarm
        structure timeStamp
            structure _options
                string causeMonitor true
        structure power
            structure value

PVCopy

This is the interface for mapping between a PVStructure that contain a copy of the data for a subset of the fields in a PVRecord. Note that this interface is NOT for a single PVStructure but for a single PVRecord and a single Structure introspection interface that describes a subset of the fields in the PVRecord. For example if a server supports monitor queues then the server will allocate a PVStructure for each queue element but will create a single PVCopy.

PVCopy
    PVMaster getPVMaster()
    void traverseMaster(PVCopyTraverseMasterCallback callback)
    Structure getStructure()
    PVStructure createPVStructure()
    int getCopyOffset(PVField masterPVField)
    int getCopyOffset(PVStructure masterPVStructure,PVField masterPVField)
    PVField getMasterPVField(int structureOffset)
    void initCopy(PVStructure pvCopy, BitSet bitSet,boolean masterLocked)
    void updateCopySetBitSet(PVStructure copyPVStructure,BitSet bitSet,boolean lockMaster)
    void updateCopyFromBitSet(PVStructure copyPVStructure,BitSet bitSet,boolean lockMaster)
    boolean updateMaster(PVStructure pvCopy,BitSet bitSet,boolean lockMaster)
    PVStructure getOptions(PVStructure copyPVStructure,int fieldOffset)
    String dump()
}

where

getPVMaster
Get the PVMaster to which this PVCopy is attached
traverseMaster
Traverse all the fields in master. The callback is called for each field in master.
getStructure
Get the introspection interface which describes the subset of the fields in the PVMaster.
createPVStructure
Create a PVStructure which can hold a subset of the data from the PVMaster. A client may require multiple PVStructures. For example if a monitor request supports a queue than a PVStructure is required for each queue element.
getCopyOffset(PVField masterPVField)
Given a PVField from the master determine the offset within the PVStructure where the copy of the data is located. PVStructure.getSubField(offset) can be called to locate the PVField within the PVStructure.
getCopyOffset(PVStructure masterPVStructure,PVField masterPVField)
Given a masterPVField within a masterPVStructure determine the offset within the PVStructure where the copy of the data is located. PVStructure.getSubField(offset) can be called to locate the PVField within the PVStructure.
getMasterPVField
Given an offset within a PVStructure return the corresponding PVField in the PVMaster.
initCopy
Initialize PVStructure with the current data from the PVMaster. The bitSet will have offset 0 set to 1 and all other bits set to 0.
updateCopySetBitSet
Update PVStructure from PVMaster. The BitSet shows which fields in PVStructure have changed.
updateCopyFromBitSet
Update PVStructure from PVMaster. Only fields that have the offset in bitSet set to true are modified.
updateMaster
Update the fields in PVMaster with data from PVStructure. Only fields that have the offset in bitSet set to true are modified.
getOptions
Get options for a field in a PVStructure created by pvCopy The arguments are the pvStructure and the offset of the field for which the options are wanted. It returns the options or null if the field did not have options.
dump
Provides a dump of the internal pvCopy nodes. This is useful for debugging monitor algorithms.

Guidelines for pvDatabase Services

This section is for services that use pvDatabaseCPP. Such services do not have to provide a top level PVStructure and methods init, process, and destroy. pvDatabaseCPP and pvAccessCPP provide a complete implementation of the server side of pvAccess. From the PVStructure a PVRecord is created. This record can be locked.

A server is providing data for multiple clients. Each client has it's own top level PVStructures that has data for a subset of the fields in the servers top level PVStructure. The service must be careful of how it updates data in it's top leve PVStructure or else data for a client can change after process completes and before it is sent to the client.

Previously the mapping between a PVStructure and it's associated bitSet as shown: bitSet for pvStructure

This can also be used to present guidelines for modifing fields in the top level PVStructure for the service:

The pvRecord must be locked whenever any field is modfied.

Any union, unionArray, or structureArray field that has a bit of the bitSet assigned to it must be replaced. Modifing subFields of the field is not permisible.

Special Fields

enum

An enumerated structure is a structure that has fields:

enum_t
    int index
    string[] choices

PVEnumerated

PVEnumerated
    boolean attach(PVField pvField)
    void detach()
    boolean isAttached()
    boolean setIndex(int index)
    int getIndex()
    String getChoice()
    boolean choicesMutable()
    String[] getChoices()
    boolean setChoices(String[] choices)

where

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

alarm

An alarm structure is defined as follows:

alarm_t alarm
    int severity
    int status
    string message

Note that severity and status are NOT defined as enumerated structures. The reason is performance, i. e. prevent passing the array of choice strings everywhere. The AlarmStatus and AlarmSeverity provide the equivalent of choices for an enumerated structure.

AlarmSeverity

Alarm Severity defines the possible alarm severities

enum AlarmSeverity
    NONE,MINOR,MAJOR,INVALID,UNDEFINED
    AlarmSeverity getSeverity(int value)
    final String[] alarmSeverityNames
    String[] getSeverityNames()
where
getSeverity
Get the alarm severity corresponding to the integer value.
getSeverityNames
Get the array of severity choices.

AlarmStatus

Alarm Status defines the possible alarm status conditions

enum AlarmStatus
    NONE,DEVICE,DRIVER,RECORD,DB,CONF,UNDEFINED,CLIENT;

    AlarmStatus getStatus(int value)
    String[] alarmStatusNames
    String[] getStatusNames()
where
getStatus
Get the alarm status corresponding to the integer value.
getStatusNames
Get the array of status choices.

Alarm

Alarm
    String getMessage()
    void setMessage(String message)
    AlarmSeverity getSeverity()
    void setSeverity(AlarmSeverity alarmSeverity)
    AlarmStatus getStatus()
    void setStatus(AlarmStatus alarmStatus)
}
where
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

PVAlarm 
    boolean attach(PVField pvField)
    void detach()
    boolean isAttached()
    void get(Alarm alarm)
    boolean set(Alarm 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.

timeStamp

A timeStamp is represented by the following structure

time_t timeStamp
    long secondsPastEpoch
    int nanoseconds
    int userTag

The Epoch is the POSIX epoch, i.e. Jan 1, 1970 00:00:00 UTC. Both the seconds and nanoseconds are signed integers and thus can be negative. Since the seconds is kept as a 64 bit integer, it allows for a time much greater than the present age of the universe. Since the nanoseconds portion is kept as a 32 bit integer it is subject to overflow if a value that corresponds to a value that is greater than a little more than 2 seconds of less that about -2 seconds. The support code always adjust seconds so that the nanoSecconds part is normalized, i. e. it has is 0<=nanoseconds<nanoSecPerSec..

TimeStamp

The definition of TimeStamp is:

TimeStamp 
    void normalize()
    long getSecondsPastEpoch()
    long getEpicsSecondsPastEpoch()
    int getNanoseconds()
    int getUserTag()
    void setUserTag(int userTag)
    void put(long secondsPastEpoch,int nanoseconds)
    long getMilliSeconds()
    void put(long milliSeconds)
    void getCurrentTime()
    boolean equals(TimeStamp other)
    boolean lt(TimeStamp other)
    boolean le(TimeStamp other)
    void add(long seconds)
    void add(double seconds)
    double diff(TimeStamp a,TimeStamp b)
}

where:

normalize
Adjust secondsPastEpoch and nanoseconds so that 0<=nanoseconds< nanoSecPerSec.
getSecondsPastEpoch
Get the seconds part of timeStamp
getEpicsSecondsPastEpoch
Get seconds relative to the EPICS epoch. The epics epoch starts on Jan 1 1990 00:00:00 UTC.
getNanoseconds
Get the nanoseconds part of timeStamp.
getUserTag
Get the userTag
setUserTag
Set the userTag
put(long secondsPastEpoch,int nanoseconds)
Put a value into the timeStamp.
getMilliSeconds
Get the number of milliseconds since the epoch.
put(long milliSeconds);
Put a value into the timeStamp given the number of milliSeconds since the epoch.
getCurrentTime
Get the current time.
equals
Is this time equal other?
lt
Is this time less than other.
le
Is this time less that or equal to other.
add(long seconds)
Add the specified number of seconds.
add(double seconds)
Add the specified number of seconds.
diff
Compute a-b. The result is in seconds.

The TimeStamp class provides arithmetic and comparison methods for time stamps. The result is always kept in normalized form, which means that the nanosecond portion is 0≤=nano<nanoSecPerSec. Note that it is OK to have timeStamps for times previous to the epoch.

PVTimeStamp

PVTimeStamp 
    boolean attach(PVField pvField)
    void detach()
    boolean isAttached()
    void get(TimeStamp timeStamp)
    boolean set(TimeStamp timeStamp)
where
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.

display

Display information is represented by the following structure

display_t display
    double limitLow
    double limitHigh
    string description
    string format
    string units

Display

Display
    double getLow()
    double getHigh()
    void setLow(double value)
    void setHigh(double value)
    String getDescription()
    void setDescription(String value)
    String getFormat()
    void setFormat(String value)
    String getUnits()
    void setUnits(String value)

where

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

PVDisplay
    boolean attach(PVField pvField)
    void detach()
    boolean isAttached()
    void get(Display display)
    boolean set(Display display)

where

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.
create
Create a PVDisplay instance. Attach must be called before get or set can be called.

control

Control information is represented by the following structure

structure control
    double limitLow
    double limitHigh
    double minStep

Control

The definition for Control is:
Control
    double getLow()
    double getHigh()
    void setLow(double value)
    void setHigh(double value)

where

getLow
Get the low limit.
getHigh
Get the high limit.
setLow
Set the low limit.
setHigh
Set the high limit.

PVControl

PVControl
    boolean attach(PVField pvField)
    void detach()
    boolean isAttached()
    void get(Control control)
    boolean set(Control control)

where

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.
create
Create a PVControl instance. Attach must be called before get or set can be called.

alarmLimit

This has unresolved issues.