EPICS pvRequest

EPICS V4 Working Group, Working Draft, 27-Feb-2014

Latest version:
pvRequest.html
This version:
pvRequest_20140227.html
Previous version:
pvRequest_20131106.html
Editors:
Marty Kraimer BNL

Abstract

Each create method of pvAccess::Channel has an argument PVStructure pvRequest. This document discusses how this argument is defined and used.

This product is available via an open source license

This document is for related set of products:

pvData
pvData (Process Variable Data) defines and implements an efficent way to store, access, and transmit memory resident structured data
pvAccess
pvAccess is network support for transmitting pvData.
pvDatabase
A pvDatabase is a network accessable smart real time database. The database consists of memory resident records. Each record has a name that is unique within the local area network and contains a top level pvData structure. Each field of a record can optionally have support code attached to it. The support is called when a request is made to process the record. The support code is what makes the record "smart". A pvAccess server is provided so that the records can be accesed via the network.
pvIOCJava
This provides a pvDatabase. In addition it provides the ability to optionally attach support to each field of a record.
pvaSrv
This implements a pvAccess server that provides access to iocCore records. It also accepts a pvRequest defined in this document.

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

Status of this Document

This is the 27-Feb-2014 version of the the description of pvRequest.

There is a major change since the last version. CreateRequest no longer "collapses" structures. Previously the request "field(alarm,TimeStamp,power.value" would return:

structure
   structure alarm
   structure timeStamp
   double value
Now it will return:
structure
   structure alarm
   structure timeStamp
   structure power
       double value

Table of Contents

Introduction

pvAccess defines interface Channel which has a number of create methods, which have a argument pvRequest:

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

A Channel is a connection between a client and a server. For each create method it is the server that determines how pvRequest should be defined. The client is expected to know what the server expects. If the client passes an illegal pvRequest to the server then the server will respond to the create method with an error message.

pvAcccess does not define the format of a pvRequest structure but it does provide a convenience method:

PVStructure createRequest(String request);
This creates a pvRequest structure that can be used to communicate with a server that supports the pvIOC Data Model as defined in a following section.

The pvdata project also defines a standard set of normative types, which are used to pass data between client and server. The pcIOC Data Model supports the general normative types NTScaler, NTScalarArrray, and NTEnum Other normative types could define their own convenience methods for creating pvRequest structures to pass between client and server. However this should not be done unless there is a real need since it means new conventions on both the client and server.

This document is based on material that is currently defined in:

pvDataJava.html
Java implementation of pvData
pvAccessJava.html,
Java implementation of pvAccess. It also implements CreateRequest.
pvDataCPP.html
C++ implementation of pvData
pvAccessCPP.html
C++ implementation of pvAccess. It also implements CreateRequest.
pvaSrv.html
Provides access to epics base records via pvAccess. Each pvRequest must be compatible with that created via CreateRequest.
pvIOCJava.html
Provides support and examples for records that are similar to the epics base records. It implements channelProvider. Each pvRequest must be compatible with that created via CreateRequest.
pvDatabaseCPP.html
It implements channelProvider. Each pvRequest must be compatible with that created via CreateRequest.
swtshellJava.html
Provides complete client support for pvAccess. It is like probe for pvData. It calls CreateRequest to create the pvRequest structures to send to the server.

This document makes pvRequest easier to understand by bringing all the concepts into a single document.

Goals

pvAccess provides the ability to pass structured data between clients and servers. Since the data can be quite complex it could be very difficult for clients to use. Lets consider a few typical types of clients.

General Purpose Tools

Think of tools like those provided by CSS/BOY/pvManager. Thus strip chart , alarm display, slider, etc. These types of tools want data like EPICS base provides. Thus some combination of value, alarm, timeStamp, display, and control information. Such tools want data that follows the pvIOC Data Model described in the next section. Note that both pvaSrv, pvIOCJava, and pvDatabaseCPP all support this model.

channelPutGet services

A service that is implemented via a channelPutGet request could provide data via a structure like:

structure recordName
    structure argument
       // details are service specific
    structure result
       // details are service specific
where
argument
Data sent by client
result
Data returned to the client from the service.

In this case the client could just say that it wants "putField(argument),getField(result)" With the facilities described below the user can do this. Note that swtshellJava provides a GUI tool that allows a client to make such a request.

Normative Type Suppport

There is automatic support for some normative types like NTScalar and NTArray. Other normative types could provide helper code that either uses the conventions and support described in this document or invent their own support for creating a pvRequest.

Other Specialized Support

For specialized support it is always possible to create private conventions for pvRequest. But then general pupose tools will be much less useful and it may also be necessary for the support to implement various Channel methods.

Create Request

Where Defined

pvAccess (both pvAccessJava and pvAccessCPP) have a convenience class with a method createRequest. For example pvAcccessJava has:

public class CreateRequestFactory {
   public static PVStructure createRequest(String request);{
}

Purpose

The purpose is to create a pvRequest structures for accesssing data in a server. It 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{request}     // 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 {}.

Examples

A Java client can create a request as follows:

PVStructure pvRequest = CreateRequestFactory.createRequest(request);

NOTE: The full path is org.epics.pvaccess.client.CreateRequestFactory.

A C++ client calls:

epics::pvData::PVStructurePtr pvRequest = CreateRequest::create()->createRequest(request);

For both Java and C++:

request
A string. The syntax is what is described above.

Simple Records

Clients like CSS, Synoptic Displays, Alarm, and Archive tools 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 

pvIOCJava and pvDatabaseCPP

pvIOCJava and pvDatabaseCPP both implement a local channel provider, e. g. each implements both ChannelProvider and Channel. A client can connect directly to the local channel provider or via remote pvAccess.

The local provider implements the create methods of the pvAccess Channel interface. This section describes the syntax of the request passed createRequest(request) that creates a valid pvRequest structure.

ChannelProcess

The request argument is ignored.

ChannelGet and ChannelPut

The request string has the form:

"record[options]field(fieldDef,...)"

An example of a record option is process=true. The default for channelGet is process=false and for channelPut process=true. fieldDef is defined in the previous section.

ChannelPutGet

The request string has the form:

"record[options]putField(fieldDef,...)getField(fieldDef,...)"

An example of a record option is process=false. The default is process=true. fieldDef is defined in the previous section.

pvIOCJava has a set of records with associated support that implement a remote procedure model intended to be accessed via channelPutGet. These records have a substructure argument and a substructure result. The client is expected to use the request string:

"record[process=true]putField(argument)getField(result)"

The details of argument and result depend on the support. The client makes a putGet request by setting values in argument and gets the result from result.

An example is a record that has support for getting a string array where each element is the name of a record in a pvIOCJava. The argument has a single subfield named regularExpression, which is a grep style string. An example record is:

record laptoprecordListPGRPC
    structure argument
        string regularExpression .*Double
    structure result
        string status success
        string[] names [scalarDouble,arrayDouble]

In this case the client gave an expression .*Double which finds all records with names that ended with Double. For this IOC there were two records scalarDouble and arrayDouble.

ChannelRPC

This is used by many services that are part of V4. Each service can optionally use pvRequest. There is no support for channelRPC in pvIOCJava or pvDatabaseCPP. pvAccess does have support for a service that is implemented via channelRPC. Most services use normative types for both the argument passed to request and for the structure returned by a request. For example a NTNameValue for the argument and NTTable for the result. Thus createRequest will not normally be used by channelRPC services.

ChannelArray

The request string has the form:

"field(fieldDef)"

FieldDef must refer to a subfield of the top level structure that has type scalarArray or structureArray. It it does not then an error is returned to the client.

Monitor

The request string has the form:

"record[options]field(fieldDef,...)"

options is server specific and will not be discussed here. fieldDef is defined in the previous section.

pvaSrv

NOTE: pvaSrv is under development by Ralph Lange. This section only describes the pvRequest for accessing individual V3 records.

pvaSrv implements a pvAcccess server for accessing records in an EPICS base IOC. A channel is a single V3 record. All the Channel create methods except ChannelPutGet and ChannelRPC are supported. A pvRequest can be created via createRequest as described above. A V3 record has a "flat" structure so it appears as a structure of the following type:

structure
    <someType> value
    structure alarm
    structure timeStamp
    structure display
    structure control

The v3Channel implemantation takes care of all conversions from the way V3 records are implemented and a top level PVStructure that a pvAccess client expects.

pvIOC Data Model

Quick Summary

A pvIOC has a database of smart memory resident records. Each record has a name, which is what pvAccces calls the channel name. A record has a top level PVStructure, which holds data that is accessed by clients. A record is smart because it can be processed which results in calling code attached to the record and optionally to fields in the record. In this document the term record is used but the discussion can also apply to servers that provide access to a top level pvStructure that can be accessed via a channel name but do not implement records.

The Data Model supports general purpose client tools. A set of structures are defined that support the data model. A pvAccess server supports the data model if it follows a few simple guidelines.

The model can briefly be described as follows: Clients access a field named value, which may be a field in the top level structure of a record or in a substructure. All other fields in the structure are considered properties of the value field. The fieldname is the property name. The value is usually a data field, i.e. a scalar type or an array with the elementType being scalar. All other fields of the structure support the value. The standard property fields are timeStamp, alarm, display, and control.

A structure may also have fields other than the standard property fields but these other fields are normally not of interest to clients and are not used by general purpose client tools. These additiional fields are normally used by support code as part of record processing.

For example the following record has a single value field. The value field has property fields timeStamp, alarm, and display. It also has a field valueAlarm which is not of interest to most clients.

record scalarDouble
    double value 0.0
    time_t 1969-12-31 19:00:00.000 userTag 0
    alarm_t alarm
        severity NONE status NONE
        message 
    display_t display
        double limitLow 0.0
        double limitHigh 0.0
        string description Sample Description
        string format %f
        string units volts
    valueAlarm_t valueAlarm
        boolean active true
        double lowAlarmLimit 2.0
        double lowWarningLimit 4.0
        double highWarningLimit 8.0
        double highAlarmLimit 10.0
        int lowAlarmSeverity 2
        int lowWarningSeverity 1
        int highWarningSeverity 1
        int highAlarmSeverity 2
        double hystersis 0.2

The following example has three value fields: voltage.value, current.value, and power.value The record itself has properties alarm and timeStamp voltage.value and power.value have no property fields. current.value has a property fields alarm and display.

record psSimple
    alarm_t alarm
        severity MAJOR status RECORD
        message highAlarm
    time_t 2013-02-25 10:07:46.529 userTag 0
    structure voltage
        double value 1.0
    structure current
        double value 10.0
        alarm_t alarm
            severity MAJOR status RECORD
            message highAlarm
        display_t display
            double limitLow -10.0
            double limitHigh 10.0
            string description 
            string format 
            string units current
    structure power
        double value 10.0

This data model supports existing EPICS V3 channel access clients. More powerful or special purpose clients can handle structured data. Such clients can access a structure. For example a client can ask for an entire record. An example is swtshell.

Details about pvIOC Data Model

Basic Concept

A structure follows the pvIOC Data Model if it has a set of fields that have names and types that support the data model. It can have additional fields, that can also be considered properties. The following field names have special meaning, i.e. are properties for general purpose clients.

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

In addition the javaIOC structure can have additional fields that support the value field but are not recognized by most general purpose client tools. Typical examples are:

input
A field with support that changes the value field. This can be anything. It can be a channel access link. It can obtain a value from hardware. Etc.
valueAlarm
A field with support that looks for alarm conditions based on the value.
output
A field with support that sends the current value somewhere else. This can be anything. It can be a channel access link. It can write a value to hardware. Etc.
link, links
A structure field that contains one or more fields that are database or channel access links to other records and that do not effect the record containing the link field. Thus the database or channel access links are either process or output links.

The model allows for device records. A device record has fields that are structures that support the javaIOC data model. For example a power supply record can have fields power, voltage, current that each support the javaIOC data model.

Definitions for Standard Properties

The set of structures for standard properties for general purpose client tools are defined in pvData. These are:

alarm
A structure that has the fields:
structure alarm
    int severity
    int status
    string message
       
An alarm also has associated convenience code for processing and displaying alarms. In particular the convenience code provides methods that treat severity and status like enumerated values.
timeStamp
A structure that has the fields:
structure timeStamp
    long secondsPastEpoch
    int nanoSeconds
    int userTag
       
A timeStamp also has associated convenience code for processing and displaying timeStamps..
display
A structure that has the fields:
structure display
    double limitLow
    double limitHigh
    string description
    string format
    string units
       
control
A structure that has the fields:
structure control
    double limitLow
    double limitHigh
    double minStep
       

See the documentation for either pvDataJava or pvDataCPP for more details about property fields.

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

Package org.epics.pvioc.pvCopy

This section describes the Java implementation of pvCopy, which is package org.epics.pvioc.pvCopy. It is implemented in pvIOCJava.html,

Overview

This package provides support for copying PVData between a client and server. For example the client can be a pvAccess client and the server a pvAccess server. It allows a client to access an arbitrary set of fields of a PVRecord that exists on the server. This package does not provide support for transfering the data between client and server but provides support for code that does, e. g. it can be used by channel access. In the examples below the data transfer code is called channel access.

This package uses the field offsets provided by PVField and also requires that user code creates a org.epics.pvdata.misc.BitSet.

PVField provides support for locating a field within a PVStructure or PVRecord via a field offset. PVField provides the methods:

getFieldOffset
Get offset of the PVField field within top level structure. Every field within the PVStructure has a unique offset. The top level structure has an offset of 0. The first field within the structure has offset equal to 1. The other offsets are determined by recursively traversing each structure of the tree.
getNextFieldOffset
Get the next offset. If the field is a scalar or array field then this is just offset + 1. If the field is a structure it is the offset of the next field after this structure. Thus (nextOffset - offset) is always equal to the number of fields within the field.
getNumberFields
Get the total number of fields in this field. This is equal to nextFieldOffset - fieldOffset.

A BitSet which has a bit for each field of a top level PVStructure can be created via:

    BitSet bitSet = new BitSet(pvStructure.getNumberFields());

The offsets for bitSet match the fieldOffsets. On the client side of Channel Access only a BitSet created from the PVStructure is required. On the server side PVCopy provides a way to map between the field in a PVRecord and the fields in the PVStructure. A copy of the PVStructure resides on both the Channel Access client and server. The client and server exchange data via these two PVStructures. PVCopy maps between the PVStructure and the PVRecord on the server side of Channel Access.

This package provides the following:

PVCopy
An interface for mapping between a PVRecord and a PVStructure that contains data for a subset of the fields in the PVRecord.
PVCopyMonitor
An interface for monitoring changes to fields of the PVRecord that have a corresponding field in PVStructure.
PVCopyFactory
The factory that implements PVCopy. It accepts a PVStructure that describes the set of fields of a PVRecord that should be mapped.

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.

interface PVCopy {
    PVRecord getPVRecord();
    Structure getStructure();
    PVStructure createPVStructure();
    int getCopyOffset(PVField recordPVField);
    int getCopyOffset(PVStructure recordPVStructure,PVField recordPVField);
    PVField getRecordPVField(int structureOffset);
    void initCopy(PVStructure pvCopy, BitSet bitSet,boolean recordLocked);
    void updateCopySetBitSet(PVStructure copyPVStructure,BitSet bitSet,boolean lockRecord);
    void updateCopyFromBitSet(PVStructure copyPVStructure,BitSet bitSet,boolean lockRecord);
    boolean updateRecord(PVStructure pvCopy,BitSet bitSet,boolean lockRecord);
    PVCopyMonitor createPVCopyMonitor(PVCopyMonitorRequester pvCopyMonitorRequester);
    PVStructure getOptions(PVStructure copyPVStructure,int fieldOffset);
    String dump();
}

where

getPVRecord
Get the PVRecord to which this PVCopy is attached
getStructure
Get the introspection interface which describes the subset of the fields in the PVRecord.
createPVStructure
Create a PVStructure which can hold a subset of the data from the PVRecord. 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 recordPVField)
Given a PVField from the record 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 recordPVStructure,PVField recordPVField)
Given a recordPVField within a recordPVStructure 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.
getRecordPVField
Given an offset within a PVStructure return the corresponding PVField in the PVRecord.
initCopy
Initialize PVStructure with the current data from the PVRecord. The bitSet will have offset 0 set to 1 and all other bits set to 0.
updateCopySetBitSet
Update PVStructure from PVRecord. The BitSet shows which fields in PVStructure have changed.
updateCopyFromBitSet
Update PVStructure from PVRecord. Only fields that have the offset in bitSet set to true are modified.
updateRecord
Update the fields in PVRecord with data from PVStructure. Only fields that have the offset in bitSet set to true are modified.
createPVCopyMonitor
Create a PVCopyMonitor. See next section.
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.

PVCopyMonitor

PVCopyMonitor is a PVListener for the PVRecord to which PVCopy is attached. It updates two bitSets when it receives PVListener.dataPut callbacks. changeBit shows all fields that have changed between calls to switchBitSets. overrunBitSet shows all fields that have changed value more than once between calls to switchBitSets. It notifies the PVCopyMonitorRequester when data has changed.

interface PVCopyMonitorRequester {
    void dataChanged();
    void unlisten();
}

interface PVCopyMonitor {
    void startMonitoring(BitSet changeBitSet, BitSet overrunBitSet);
    void stopMonitoring();
    void switchBitSets(BitSet newChangeBitSet,BitSet newOverrunBitSet, boolean lockRecord);
}

PVCopyMonitorRequester is the interface implemented by the caller that calls PVCopy.createPVCopyMonitor:

dataChanged
Data being monitored has changed.
unlisten
PVCopyMonitor has been told to unlisten so no more monitors will occur.

PVCopyMonitor is the interface returned by a call to PVCopy.createPVCopyMonitor.

startMonitoring
Start monitoring.
stopMonitoring
Stop monitoring.
switchBitSets
If the pvStructure is not shared all fields that changeBitSet shows were changed are copied from the corresponding PVField of the PVRecord to the PVField of the PVStructure. Then the bitSets are replaced by the new bitSets. Note that a client needs just two instances of the bitSets and can just cycle between the two sets. Even if the PVStructure is shared this method is important since the caller will not miss data changes. It is illegal to call this if startMonitoring was called with no arguments.

PVCopyFactory

Java Definition

    class PVCopyFactory {
        static PVCopy create(PVRecord pvRecord,PVStructure pvRequest,String structureName);
    }

create has the arguments

pvRecord
The PVRecord to which the server is attached.
pvRequest
A PVStructure which describes the fields of PVRecord to which the server wants access. It is described below.
structureName
This must be one of: "field", "putField", or "getField"
request
As defined in previous examples.
requester
Definition is in org.epics.pvdata.pv.Requester.

createRequest is an easy way to create a pvRequest structure to pass to create. It is described above.

Package org.epics.pvioc.monitor

This section describes the Java implementation of monitor, which is package org.epics.pvioc.monitor. It is implemented in pvIOCJava.html.

Overview

Package org.epics.pvdata.monitor defines the monitor interfaces as seen by a client. See that package overview for details. It is described in pvDataJava.html. This package implements the monitoring interfaces for a PVRecord.

The implementation uses PVCopy and PVCopyMonitor which are implemented in package org.epics.pvioc.pvCopy. When PVCopyMonitor tells monitor that changes have occurred, monitor applies the appropriate algorithm to each changed field and if any algorithm says to raise a monitor a monitor is sent to the client.

This package implements support for the following monitor algorithms: onPut, onChange, deadband, and periodic. Each is described in a subsection below.

In addition code for additional monitoring algorithms can be created and registered with the monitoring system.

onPut

onPut means that a monitor is issued whenever a put is issued to the field. This is the default unless the record defines a different algorithm for a field.

An exception is the top level timeStamp which by default is made onChange This is so that a monitor is not a monitor will not be raised if the only change to fields being monitored is the top level timeStamp.

onChange

This provides two options: 1) A monitor is raised whenever a field changes value, and 2) A monitor will never be raised for the field.

The client can ask for this option be asking for a field option that specifies the options algorithm and causeMonitor. An example is to pass the following request to createRequest.
"field(value[algorithm=onChange,causeMonitor=true])"

The default for causeMonitor is true so it only has to be specified if the client wants to specify false.

deadband

The field must be a numeric scalar. Whenever the absolute or percentage value of the field changes by more than a deadband then a monitor is issued.

The complete set of options for deadband are:

algorithm
Thus the client has specified algorithm=deadband
deadband
A numeric value
isPercent
This has the value true or false. The default is false. This determines if an absolute or percentage change is desired.
type
This must have to value archive or display. This is used if the client does not specify a deadband but, as described below, the record does define deadbands. The default is display.
An example is to pass the following request to createRequest.
"field(value[algorithm=deadband,deadband=1.0,isPercent=true])"

The record instance can also define the default deadband. For example:

record example
    double value
    structure deadband
        structure display
             double value
             boolean isPercent       // optional
        structure archive
             double value
             boolean isPercent       // optional

periodic

I record will be monitored at a periodic rate if the pvRequest specifies a record option requisting it. A client can request this by passing the following request to createRequest

"record[periodicRate=rate]"

where

rate
This is the rate in seconds. For example record[periodicRate=.5].

A monitor is issued at a periodic rate if a put was issued to any field being monitored.

Implementing New Monitor Algorithms

This section discusses how to implement new monitor algorithms in addition to the onPut, onChange, etc, implemented by this package.

The monitor algorithm must register by calling:

    MonitorFactory.registerMonitorAlgorithmCreater(MonitorAlgorithmCreate monitorAlgorithmCreate)

The implementation must implement interfaces MonitorAlgorithmCreate and MonitorAlgorithm which are described below.

MonitorFactory

This is a request to create a monitor.

class MonitorFactory {
    static Monitor create(PVRecord pvRecord,
        MonitorRequester monitorRequester,PVStructure pvRequest);
    static void registerMonitorAlgorithmCreater(MonitorAlgorithmCreate monitorAlgorithmCreate)
}

where

create
Create a monitor. The arguments are:
pvRecord
The record being monitored.
monitorRequester
The monitor requester. This is the code to which monitot events will be delivered.
pvRequest
The request options
registerMonitorAlgorithmCreater
Called by code that implements a monitor algorithm.

MonitorAlgorithm

The following must be implemented by code that implements a monitor algorithm.

interface MonitorAlgorithm  {
    String getAlgorithmName();
    boolean causeMonitor();
    void monitorIssued();
}

where

getAlgorithmName
return the name of the algorithm.
causeMonitor
Called to see if a change to this field should cause a monitor
monitorIssued
Called after a monitor has been issued.

MonitorAlgorithmCreate

The following must be implemented by code that implements a monitor algorithm.

interface MonitorAlgorithmCreate {
    String getAlgorithmName();
    MonitorAlgorithm create(
            PVRecord pvRecord,
            MonitorRequester monitorRequester,
            PVField fromPVRecord,
            PVStructure pvOptions);
}

where

getAlgorithmName
return the name of the algorithm.
create
Create a new instance of the algorithm.

pvDatabaseCPP

This implements the following:

channelProviderLocal
A complete implementation of channel provider. This is called by the server side of remote pvAccess,
pvCopy and monitor
Like what pvIOCJava provides but there is no support for monitor algorithms.
database
It supports records but unlike pvIOCJava there is no support for fields. There is a single process method for a record.