EPICS pvIOCJava

EPICS v4 Working Group, Working Draft, 11-Nov-2014

Latest version:
pvIOCJava.html
This version:
pvIOCJava_20141111.html
Previous version:
pvIOCJava_20140304.html
Editors:
Marty Kraimer, BNL

Abstract

pvIOCJava is the Java implementation of a pvIOC, which is one of a related set of products:
relatedDocumentsV4.html

Status of this Document

This is the 11-Nov-2014 version of the Java implementation of pvIOC. It is a complete implementation of pvIOC as currently defined.

Table of Contents

Introduction

This product is available via an open source license

This document is the project and package overviews for pvIOCJava.

NOTE Originally epics-pvdata was called javaIOC and consisted of a single eclipse project named javaIOC. This project is the IOC portion of the original javaIOC.

A pvIOC is a network accessable smart real time database. A database has memory resident records which can link to hardware or to other records. A record has a top level PVStructure, which is a structured set of fields. A record can be processed, i.e. asked to do something. Each field has an object which implements interface PVField that provides access to the field's data. A PVRecord has a PVRecordField associated with each PVField. Each field of a record can optionally have associated support, which is defined by a Java interface called Support. One of the methods of Support is named process. When a process request is made the process method of each field support is called. Support is what makes the database a "smart" database.

Most of the support, test records, and examples follow the pvIOC data model as described in: pvRequest.html

pvIOCJava project uses projects pvDataJava, which provides the data, and pvAccessJava, which provides network support for pvData. This package assumes that you are familiar with both of these projects.

An Extensible Markup Language (XML) parser is provided for creating a PVDatabase. pvIOCJava adds support that allows a PVDatabase to become a smart soft realtime database. pvIOCJava attaches support code to every record and optionally to any field of a record. The support is configured via xml definitions. A structure defining support provides the name of a Java factory that creates support for a field.

A simple example of a record instance defined via the XML syntax is :

<record recordName = "simple">
  <scalar name = "value" scalarType = "double" />
</record>

When the ioc adds a new record to the database it looks for support attached to the record. If it does not find any, it assigns generic support. The simple example without defaults would be:

<record recordName = "simple" >
  <auxInfo name = "supportFactory" scalarType =   
     "string">genericFactory</auxInfo>
  <scalar name = "value" scalarType = "double"/>
</record>

The definition for generic is:

<structure structureName = "genericFactory">
  <scalar name = "supportFactory" scalarType = "string">
     org.epics.pvioc.support.basic.GenericFactory</scalar>
</structure>
<structure structureName = "generic">
  <auxInfo name = "supportFactory" scalarType = "string">genericFactory</auxInfo>
</structure>

Thus generic is a structure that has no fields and support named generic.

The rest of this document has three parts:

Part I: pvIOCJava - Brief Description

Part I describes pvIOCJava. Detailed descriptions of pvIOCJava packages are provided in Part III.

EPICS is a set of Open Source software tools, libraries and applications developed collaboratively and used worldwide to create distributed soft real-time control systems for large scientific instruments such as a particle accelerators, telescopes, etc. An IOC (Input/Output Controller) is a network node that controls and/or monitors a collection of devices. An IOC contains a memory resident real time database. The real time database has a set of "smart" records.

pvIOCJava is a Java implementation of an IOC. It has many similarities to a EPICS V3 ( the 3.14 releases of EPICS base) but extends the data types to support structures and arrays and allows any field to optionally have support.

Getting Started

The best way to get started is to also install swtshellJava. swtshellJava.html

swtshell is a remote shell for interacting with a pvAccess server. In particular it can talk to an instance of a pvIOCJava. The swtshell project has files to start an example instance of a pvIOCJava and examples of using swtshell itself. Please see it for getting started.

org.epics.pvioc.JavaIOC is a Java main program that does the following:

The arguments to JavaIOC can be any combination of:

Look at the example provided with swtshellJava.

Package Summary

This document is the overview for both pvIOCJava itself and for the various Java packages in pvIOCJava.

The following top level directorys have xml and txt files for starting JavaIOC:

xml
This directory and the structures subdirectory contains the xml structure definitions for the javaIOC. It also loads the xml definitions from pvData.
example
This directory contains the example xml files. It also has a subdirectory named server with a file named pvRecord.txt. This has a file that can be used with the -pvRecord option for starting a JavaIOC. It creates a set of records with no special support. This all data changes are made by clients.
xmltest
This directory has xml files for testing.
service
The text files for stating the pvAccess and caV3 servers.

The packages that currently exists are:

org.epics.pvioc
This package has the JavaIOC class.
org.epics.pvioc.database
This package describes and implements the PVDatabase.
org.epics.pvioc.support
This package provides the framework for processing IOC database records. The subpackages of this package provide support that uses the framework. Each record instance must have associated support and each field of a record instance can optionally have support.
org.epics.pvioc.install
This package provides the code that installs structure and records into a javaIOC. It allows new structures or records to be installed into a running IOC.
org.epics.pvioc.pvCopy
This package describes and implements support for creating a PVStructure that contains a copy of a subset of the fields in a PVRecord. It is used by pvAccess.
org.epics.pvioc.monitor
This package describes and implements support for monitoring a subset of the fields in a PVRecord. It is a companion to pvCopy and is used by pvAccess.
org.epics.pvioc.support.basic
This provides basic support such as noop, generic, etc.
org.epics.pvioc.support.alarm
This provides support for alarms.
org.epics.pvioc.support.caLink
This provides for channel access links, i.e. it allows records to get/put/monitor data in other records.
org.epics.pvioc.support.dbLink
This provides for database links, i.e. it allows records to get/put/monitor data in other records in this javaIOC.
org.epics.pvioc.support.calc
The provides support for calculations. A calcaulator is support that produces a result that is assigned to a value field. Included is support named expressionCalculator, which supports scalar expressions that have standard Java syntax.
org.epics.pvioc.support.rpc
This provides remote procedure call support for pvAccess channel access clients. It provides the special features described in the documentation provided with the swtshell project.
org.epics.pvioc.support.device
This contains examples of support for "device" abstractions.
org.epics.pvioc.caV3
This package is Channel Access V3, e.g. channel access Version 3. The actual work is done by project pvAccessJava.
org.epics.pvioc.pvAccess
This package connects pvAccess to the javaIOC. It implements a Channe; as described by pvAccess. It can be used directly by other records in the same javaIOC for the pvAccess faculities or can be used by remote pvAccess to access records in this javaIOC.
org.epics.pvioc.util
This package provides utility code for a javaIOC:
Scan Field Support
Support for accessing the scan field of a record.
Periodic and Event Scanners
Support for records that are periodic or event scanned.

XML Syntax For JavaIOC Support

JavaIOC records can be created via database and pvData factories but an XML based parser is also provided for creating both structure and record definitions. In addition XML based macro substitution and include is supported. The complete syntax is described later in this document,

Support is defined via a structure definition. Support is assigned to a field via an auxInfo attached to the field. For example the definition for alarm support is:

<structure structureName = "alarmSupportFactory">
  <scalar name = "supportFactory" scalarType = "string">
     org.epics.pvioc.support.alarm.AlarmSupportFactory</scalar>
</structure>

<structure structureName = "alarm" extends = "org.epics.pvdata.alarm" >
  <auxInfo name = "supportFactory" scalarType = "string">alarmSupportFactory</auxInfo>
</structure>

Channel Access

Channel Access for pvData is implemented as a separate eclipse project named pvAccess. See it for details. This project provides the code that implements the pvAccess Channel interface. It can be used by local records directly or by the server for remote pvAccess. This project also provides server support for epics V3 channel access.

For channel access this project has the following features.

Record Processing

Package org.epics.pvioc.support describes and implements code directly related to record processing. The package overview has a section "Record Processing: Theory of Operation" that provides a description of record processing.

Sub-packagea of org.epics.pvioc.support describe and implement all the support code that comes with pvIOCJava. Applications can add additional support.

When a set of pvIOC record instances are created and initialized, a recordProcess object is created for each record instance. The primary function of recordProcess is to call record support code, which may in turn call field support code. RecordProcess has methods for the following:

The primary purpose of recordProcess is to be the "gatekeeper" for record processing. Only one object can process a record. A record can be declared to be self processed which allows an arbitrary number of clients to request processing. The default is self process true. Methods are available to request being the record processor and to request processing. A process can be synchronous or asynchronous. An asynchronous operation is an operation that blocks, e.g. file I/O. recordProcess provides methods that allow asynchronous support but that only lock a record instance while the record is being accessed.

Whenever any field of a record is being accessed or whenever anything is done that can modify the state of a record, the record must be locked. In most cases recordProcess automatically takes care of locking and unlocking.

Each record instance must have associated support and each field of a record can optionally have support.

Support implements interface Support:

    public interface Support extends Requester {
        String getSupportName();
        SupportState getSupportState();
        PVRecordField getPVRecordField();
        void initialize();
        void start(AfterStart afterStart);
        void stop();
        void uninitialize();
        void process(SupportProcessRequester supportProcessRequester);
    }

where

Requestor, getSupportName, getSupportState, getPVRecordField
See package org.epics.pvioc.support for details.
initialize
Initialization related to the record itself. Support must not connect to another record or to hardware.
start
Support can connect to other record or hardware.
stop
Disconnect from other record or hardware.
uninitialize
Remove any connection to the record.
process
Do whatever the support should do for record processing.

The primary purpose of a support module is to help with record processing. Most support does something with a "value" field. For example the support for a channel access input link will get a value and put it in the "value" field.

Typical support code does the following core functions:

There is no separate concept of record support. Record support just happens to be the support called by recordProcess, i.e. it is the highest level support for a record instance. The record support that comes with javaIOC is also designed to also be structure support, i.e. support for a structure field embeded within a record.

Support code should not be aware of specific structure types. A support modules works with some set of fields that it locates at initialization. While processing it uses the PV interfaces to access the fields. Thus support is generic. If a structure has the fields required by the support then the support can be used to help support that structure.

An extreme example is generic support. This can used for a record itself or for any field that is a stucture. All that it does is look at all the fields in the structure that it supports. For each field that has support it calls the support.

Database Examples

javaIOC/xml the structure definitions for the javaIOC. It also includes the xml definitions from pvData. Applications can add new structure definitions and support. This section just gives a few example of using these database definitions. The complete set of definitions are described in the second part of this document.

The following are a few examples of record instances. The examples uses the following support

Requires fields power, voltage, and current. When it processes it computes current from power and voltage.
Implements linear conversion from a rawValue to engineering units.
Implements linear conversion from engineering units to a rawValue.
javaIOC implements channel access links between records

doubleInput

The following creates a record instance of type double. It is an input record because input is initialized to a Channel Access inputLink.

<record recordName = "doubleInput">
    <structure name = "alarm" extends = "alarm" />
    <structure name = "timeStamp" extends = "timeStamp" />
    <scalar name = "value" scalarType = "double" />
    <structure name = "display" extends = "display" />
    <structure name = "input" extends = "caInputLink">
        <scalar name = "pvname">counter</scalar>
        <scalar name = "request">value,alarm</scalar>
    </structure>   
</record>

doubleOutput

The following creates a record instance of type double. It is an output record because output is initialized to a Channel Access outputLink.

<record recordName = "doubleOutput">
    <structure name = "alarm" extends = "alarm" />
    <structure name = "timeStamp" extends = "timeStamp" />
    <scalar name = "value" scalarType = "double" />
    <structure name = "display" extends = "display" />
    <structure name = "output" extends = "caOutputLink">
        <scalar name = "pvname">someOutput</scalar>
    </structure>   
</record>

ai

The following creates an instance of an aiRecord. The raw ADC value is read via channelAccess support and converted via linearConvertInput support.

<record recordName = "ai">
    <scalar name = "value" scalarType = "double" />
    <structure name = "alarm" extends = "alarm" />
    <structure name = "timeStamp" extends = "timeStamp" />
    <structure name = "input" extends = "linearConvertInput">
        <structure name = "linearConvert">
            <scalar name = "deviceHigh">2047</scalar>
            <scalar name = "deviceLow">-2048</scalar>
            <scalar name = "engUnitsLow">0.0</scalar>
            <scalar name = "engUnitsHigh">10.0</scalar>
        </structure>
        <structure name = "input" extends = "portDriverLink">
            <scalar name = "portName">somePort</scalar>
            <scalar name = "deviceName">0</scalar>
            <scalar name = "timeout">.2</scalar>
            <structure name = "input" extends = "pdrvInt32Input"/>
        </structure>
    </structure>    
</record>

ao

The following creates an instance of an aoRecord. The value is converted via linearConvertOutput support to a rawValue which is written via portDriver support.

<record recordName = "ao">
    <scalar name = "value" scalarType = "double" />
    <structure name = "alarm" extends = "alarm" />
    <structure name = "timeStamp" extends = "timeStamp" />
    <structure name = "output" extends = "linearConvertOutput">
        <structure name = "linearConvert">
            <scalar name = "deviceHigh">2047</scalar>
            <scalar name = "deviceLow">-2048</scalar>
            <scalar name = "engUnitsLow">0.0</scalar>
            <scalar name = "engUnitsHigh">10.0</scalar>
        </structure>
        <structure name = "output" extends = "portDriverLink">
            <scalar name = "portName">somePort</scalar>
            <scalar name = "deviceName">0</scalar>
            <scalar name = "timeout">.2</scalar>
            <structure name = "output" extends = "pdrvInt32Output"/>
        </structure>
    </structure>   
</record>

psSimple

The following creates a powerSupply instance that does no input or output. The power.value must be set via channel access.

<record recordName = "psSimple" >
    <structure name = "alarm" extends = "alarm" />
    <structure name = "timeStamp" extends = "timeStamp" />
    <structure name = "voltage">
       <scalar name = "value" scalarType = "double">10.0</scalar>
    </structure>
    <structure name = "current">
       <auxInfo name = "supportFactory" scalarType =
          "string">org.epics.pvioc.genericFactory</auxInfo>
       <scalar name = "value" scalarType = "double">
         <auxInfo name = "supportFactory" scalarType =
            "string">org.epics.pvioc.powerSupplyFactory</auxInfo>
       </scalar>
    </structure>
     <structure name = "power">
      <scalar name = "value" scalarType = "double">10.0</scalar>
    </structure>
    <structure name = "scan" extends = "scan">
        <scalar name = "processAfterStart">true</scalar>
    </structure>
</record>

psLinked

The following creates a powerSupply record that gets its voltage and writes its current via channel access.

<record recordName = "psLinked" >
   <structure name = "alarm" extends = "alarm" />
    <structure name = "timeStamp" extends = "timeStamp" />
    <structure name = "voltage" extends = "generic">
        <scalar name = "value" scalarType = "double" />
        <structure name = "input" extends = "caInputLink">
            <scalar name = "pvname">adcVoltageSupported</scalar>
            <scalar name = "process">true</scalar>
        </structure>
    </structure>
    <structure name = "current" extends = "generic">
        <scalar name = "value" scalarType = "double" >
           <auxInfo name = "supportFactory" scalarType =
              "string">org.epics.pvioc.powerSupplyFactory</auxInfo>
        </scalar>
        <structure name = "output" extends = "caOutputLink">
            <scalar name = "pvname">current</scalar>
            <scalar name = "request">record[process=true]</scalar>
        </structure>
    </structure>
    <structure name = "power">
        <scalar name = "value" scalarType = "double" />
    </structure>
</record>

psEmbeded

The following creates a powerSupply record that gets its voltage and writes its current via embeded support.

<record recordName = "psEmbeded">
    <structure name = "alarm" extends = "alarm" />
    <structure name = "timeStamp" extends = "timeStamp" />
    <structure name = "voltage" extends = "generic">
        <scalar name = "value" scalarType = "double" />
        <structure name = "alarm" extends = "alarm" />
        <structure name = "input" extends = "linearConvertInput">
            <structure name = "linearConvert">
                <scalar name = "deviceHigh">4095</scalar>
                <scalar name = "deviceLow">0</scalar>
                <scalar name = "engUnitsLow">0.0</scalar>
                <scalar name = "engUnitsHigh">10.0</scalar>
            </structure>
            <structure name = "input" extends = "caInputLink">
                <scalar name = "pvname">adcVoltageEmbeded</scalar>
            </structure>
        </structure>
    </structure>
    <structure name = "current" extends = "generic">
        <scalar name = "value" scalarType = "double">
            <auxInfo name = "supportFactory" scalarType =
               "string">org.epics.pvioc.powerSupplyFactory</auxInfo>
        </scalar>
        <structure name = "alarm" extends = "alarm" />
        <structure name = "output" extends = "linearConvertOutput">
            <structure name = "linearConvert">
                <scalar name = "deviceHigh">4095</scalar>
                <scalar name = "deviceLow">0</scalar>
                <scalar name = "engUnitsLow">0.0</scalar>
                <scalar name = "engUnitsHigh">10.0</scalar>
            </structure>
            <structure name = "output" extends = "caOutputLink">
                <scalar name = "pvname">dacCurrentEmbeded</scalar>
                <scalar name = "request">record[process=true]</scalar>
            </structure>
        </structure>
    </structure>
    <structure name = "power">
        <scalar name = "value" scalarType = "double" />
</record>

Part II: javaIOC - Database Definition

Part II describes the Database Definitions provided with the javaIOC.

Overview Of Part II

The create, and support definitions implemented by javaIOC are defined. In addition a set of structure definitions that use the support are provided. A brief summary is:

xml
This directory has a file structures.xml ,which includes all the definitions from xml/structure, and a file records.xml , which includes all the definitions from xml/record.
xml/structure
This directory has the following files.
analog.xml
Support for analog I/O.
calc.xml
Support for calculations.
caLink.xml
Support for links to other records.
commonFields.xml
Contains definitions for the commonly defined fields.
control.xml
Defines control characteristics.
dbLink.xml
Support for links to other records in the same javaIOC.
deadband.xml
Support for monitor deadbands.
delay.xml
Support that implements an asynchronous delay when the process method is called. It is normally only used for testing.
event.xml
Support that announces an event when the process method is called.
generic.xml
Support code that can be used to support many records and or structures. It just looks for fields that have associated support and calls the support.
supportState.xml
Defines the current state of support for a record or field.
rpc.xml
Defines support for RPC records implemented by the javaIOC.

This package overview does not discuss the algorithms implemented by the support implementations. See package org.epics.pvioc.support and sub-packages for details.

javaIOC/xml/structures.xml

structures.xml

This file includes all definitions needed for the support provided by javaIOC.

<database>
<import name = "org.epics.pvioc.*" />
<include addPath = "${JAVAIOC}/xml/structure" />
<package name = "org.epics.pvioc" />
<include href = "deadband.xml" />
<include href = "generic.xml" />
<include href = "commonFields.xml" />
<include href = "control.xml" />
<include href = "supportState.xml" />
<include href = "caLink.xml" />
<include href = "dbLink.xml" />
<include href = "analog.xml" />
<include href = "event.xml" />
<include href = "calc.xml" />
<include href = "delay.xml" />
<include href = "rpc.xml" />
<include href = "powerSupply.xml" />
<include removePath = "${JAVAIOC}/xml/structure" />
</database>

records.xml

This file includes RPC record definition and support provided by the javaIOC.

<database>
<import name = "org.epics.pvioc.*" />
<include addPath = "${JAVAIOC}/xml/record" />
<package name = "org.epics.pvioc" />
<include href = "rpc.xml" />
<include removePath = "${JAVAIOC}/xml/record" />
</database>

The single record is:

<database>
<import name = "org.epics.pvioc.*" />
<import name = "org.epics.pvdata.*" />
<record recordName = "${IOCNAME}structureListRPC" extends = "structureList" />
<record recordName = "${IOCNAME}iocShowRPC" extends = "iocShow" />
<record recordName = "${IOCNAME}recordShowRPC" extends = "recordShow" />
<record recordName = "${IOCNAME}supportStateSetRPC" extends = "supportStateSet" />
</database>

These two files crate a set of RPC records for a javaIOC. The record types are defined in structure/rpc.xml below.

xml/structure/analog.xml

This is the support for analog I/O. See org.epics.pvioc.support.basic for details

linearConvert

Structure linearConvert is for linear conversions. The slope and intercept can be specified directly or can be computed from the other four fields. Normally the record instance defines engUnitsLow and engUnitsHigh and support code provides values for deviceHigh and deviceLow but other combinations are also permitted. Structure linearConvert has the fields:

engUnitsLow
Engineering units value for deviceLow.
engUnitsHigh
Engineering units value for deviceHigh.
deviceHigh
Highest possible raw value.
deviceLow
Lowest possible raw value.
slope
Slope for converting raw value to engineering units.
intercept
Intrercept for converting raw value to engineering units.

linearConvertInput

Structure linearConvertInput is for converting a raw value to an enginerering units value. It has the fields:

value
The place to get the raw value.
linearConvert
The structure defining the conversion.
input
A structure that inputs the raw value.

linearConvertOutput

Structure linearConvertOutput is for converting a raw value to an enginerering units value. It has the fields:

value
The place to put the raw value.
linearConvert
The structure defining the conversion.
input
A structure that outputs the raw value.

incrementalDouble

This is for rate limited output. The output value incrementally reaches the desired value. The structure has the fields:

desiredValue
The desired value.
input
A structure for reading the desired value.
incrementalOutput
If false the output is set to the desired value if it falls within the control limits.
rateOfChange
Rate of change per process if incrementalInput is true.
units
units.
controlLimit
control limits. The output value is forced to be within the control limits.

xml/structure/calc.xml

This is the support for calculations. See org.epics.pvioc.support.calc for details. Note that expressionCalculator is the default calculator..

xml/structure/caLink.xml

This is the support for a links to other records. See org.epics.pvioc.support.ca for details.

caProcessLink

Structure caProcessLink has the fields:

pvname
recordName.fieldName of link
alarm
alarm for problems with link
providerName
The name of the channelProvider.

caMonitorLink

Structure caMonitorLink has the fields:

pvname
recordName.fieldName of link
alarm
alarm for problems with link
providerName
The name of the channelProvider.
type
A monitorType menu.
deadband
If monitorType is absoluteChange or percentageChange this is the deadband for reporting monitors.
onlyWhileProcessing
Look only for changes while record is being processed.
queueSize
Must be greater than 1. The default is 2.
reportOverrun
If the data queue is overrun should it be reported by setting status and severity?
process
Should the record containing the link be processed after the monotered data is read.
request
Specifies the fields to monitor and options.

caMonitorNotifyLink

Structure caMonitorNotifyLink has the fields:

pvname
recordName.fieldName of link
alarm
alarm for problems with link
providerName
The name of the channelProvider.
type
A monitorType menu.
deadband
If monitorType is absoluteChange or percentageChange this is the deadband for reporting monitors.
onlyWhileProcessing
Look only for changes while record is being processed.

caInputLink

Structure caInputLink has the fields:

pvname
recordName.fieldName of link
alarm
alarm for problems with link
providerName
The name of the channelProvider
request
Specifies the fields to get and options. If a requested field is alarm than this record inherits the alarm from the linked record.

caOutputLink

Structure caOutputLink has the fields:

pvname
recordName.fieldName of link
alarm
alarm for problems with link
providerName
The name of the channelProvider.
request
Field to put and options.

xml/structure/dbLink.xml

dbProcessLink

Structure dbProcessLink has the fields:

pvname
recordName.fieldName of link
alarm
alarm for problems with link

caInputLink

Structure caInputLink has the fields:

pvname
recordName.fieldName of link
alarm
alarm for problems with link
request
fields to get and options.

caOutputLink

Structure caOutputLink has the fields:

pvname
recordName.fieldName of link
alarm
alarm for problems with link
request
field to put and options.

xml/structures/commonFields.xml

This file contains database definitions for fields scan and timeStamp.

Definitions for the following structuress:

scanPriority
The scan priorities: lowest,...,highest
scanType
An enumerated structure that defines the scan types:
passive
A record that is neither periodically or event scanned. Something elase can make it process. For example another record with a process link.
event
An event scanned record. In this case an eventName is also assigned to the record.
periodioc
A periodically scanned record. In this case a rate is also assigned to the record.
scan
priority
The thread priority for a periodic and event scanning.
type
Scan type, i.e. passive, event, or periodic
rate
Periodic scan rate in seconds
eventName
The event name for event scanned records.
singleProcessRequester
Is only a single requester allowed to request processing? The default is false..
processAfterStart
determines if the record instance should be processed one time after the record enters the ready state. If the value is true than recordProcess attempts to process the record immeriately after it becomes ready. The attempt is only successfull if no record processor is registered of if the record has been initialized to be processSelf.
maxConsecutiveActive
The periodic and event scanners will generate a message if they find the record active maxConsecutiveActive times.

xml/structures/control.xml

This is a structure and support for control limits.

xml/structure/delay.xml

This is the support that delays before completing. It is used for testing. See org.epics.pvioc.support.basic for details.

xml/structure/event.xml

This is the support for announcing events. See org.epics.pvioc.support.basic for details.

xml/structure/generic.xml

Generic is the default support for many record types. It just calls the support for any fields that have support. See org.epics.pvioc.support.basic for details.

xml/structure/rpc.xml

This contains for RPC records and support:

structureList

This provides a list of structure names selected via a regular expression. See swtshell for an example of how a client issues a request.

iocShow

This provides information about tjhe javaIOC: badRecords, threads, and memory usage. It also provides the ability to ask java to garbage collect.

recordShow

This provides the following features:

trace
Trace can be turned on or off for a record instance.
enable
Processing of a record instance can be enabled or disabled.
timeProcess
If no record processor is registered foe the record or if it is selfProcessd a request can be made to measure how many times per second the record can be processed..
releaseProcessor
A request can be made to release the record processor. THIS IS A DANGEROUS OPERATION. It should only be issued if the record processor fails.

supportStateSet

This allows a client to set the support state for a record.

Part III: pvIOCJava - Package Descriptions

The following sections provide documentation for packages that belong to pvIOCJava.

Package org.epics.pvioc

This package has a single class called pvIOCJava. It's purpose is to start a pvIOCJava.

NOTE: The environment variables IOCNAME, PVDATA, PVACCESS. and JAVAIOC should be defined.

How to run pvIOCJava was described in the "Getting Started" subsection of "Part I: pvIOCJava - Brief Description".

See the swtshell documentation for how to use JavaIOC.

Package org.epics.pvioc.xml

Overview

One way to create structures and records for a PVDatabase is via XMLToPVDatabaseFactory, which parses structure and record definitions from an xml file, creates structure and record instances and adds then to a PVDatabase. This overview first defines the xml syntax and then interfaces and code for reading the xml files.

Database XML Syntax

database

A pvIOCJava database file is an XML file with the following structure:
 <?xml version="1.0" ?>
<database
   
</database>

auxInfo

An auxInfo defines additional information for a record, structure, or field. It is for use by applications that require additional information for a field. An arbitrary number of auxInfo can be created for any field.

An auxInfo is defined as follows:

<auxInfo name = "auxInfoName" scalarType = "scalarType">
   value
</auxInfo>

where:

auxInfoName
The auxInfo name.
scalarType
The type as described below.
value
The value as described below.

The following auxInfo is supported for every field:

    <auxInfo name = "pvReplaceFactory" scalarType = "string">
         value
    </auxInfobu>

value must be the name of a structure that provides the name of a factory that will provide the PVField implementation.

structure and record

Structure definitions exist so that a structure field of a record can be initialized with the fields of a previously defined structure definition. A structure is defined as follows:

<structure structureName = "structureName" extends = "otherStructureName" >
     <!-- sequence of field -->
</structure>

where:

structureName
The structure name.
otherStructureName
Optional. If given it must be the name of an already defined structure definition. The current structure will be initialized to have all attributes and fields of the other structure. The current structure can changed the attributes and fields and can append additional fields to the structure.
field
Zero or more fields can be defined. Each field must have a unique name. Order is important.

A record is a structure instance which has a record instance name. A record is defined as follows:

<record recordName = "recordName" extends = "structureName" >
     <!-- sequence of field -->
</structure>

where:

recordName
The record name. If the record with this name already exists then this definition can modify fields in the existing record but structureName must not be defined. recordName which must be specified,is a string with a combination of the following characters:
  • 0-9 A-Z a-z _ - : ; [ ]
  • Any Unicode/UTF-8 character outside of the Basic Latin set
structureName
Optional. If given it must be the name of an already defined structure definition. The current record will be initialized to have all attributes and fields of the structure. The record can changed the attributes and fields and can append additional fields to the structure. The name should follow the same convention that Java uses for package names. See the next section for details.

package and import

These two elements are both related to structures defined in the previous section.

<package name = "packageName" />
<import name = "packageName" />

For both the packageName is of the form:

     name.name...
     or for import
     name.name...*

package applys to the structureName in a structure definition: For example the following:

<package name = "org.epics.pvdata" />
<structure structureName = "alarm">
  <!-- field definitions -->
</structure>

Is the same as:

<structure structureName = "org.epics.pvdata.alarm">
   <!-- field definitions -->
</structure>

import applys to extends structureNames in structure, record, and field structure definitions. For example the following:

<import name = "org.epics.pvdata.*" />
<import name = "org.me.myStuff.*" />
<record recordName = "xxx" extends = "myStructure">
    <structure name = "alarm" extends = "alarm">
</record>

Is the same as:

<record recordName = "xxx" extends = "org.me.myStuff.myStructure">
    <structure name = "alarm" extends = "org.epics.pvdata.alarm">
</record>


Field definition

A field of a record or structure can have one of the following tag names: scalar, scalarArray, or structure,.

A scalar field is defined as follows:

  <scalar name = "fieldName" scalarType = "scalarType">
     value
  </scalar>

where:

fieldName
The name of the field.
scalarType
The scalar type as defined below.
value
The value. The syntax is described below where scalar types are defined.

An array field is defined as follows:

  <array name = "fieldName" scalarType = "scalarType"
   capacity = "capacity" capacityMutable = "true/false" length = "length" offset = "offset">
     arrayValues
  </array>

where:

fieldName
The name of the field.
scalarType
The element type as defined below.
capacity,capacityMutable,length,offset
Each is these is optional.
arrayValues

arrayValues is a comma separated set of values appropriate to the element type. It can optionally be enclosed in []. Examples:

     <array name = "field0" scalarType = "double">
         2.3,5e10,66.0
     </array>
     <array name = "field1" scalarType = "double">
         [2.3,5e10,66.0]
     </array>

For all array elementTypes except string the convert library will remove all white space so white space is permitted. If the elementType is string then white space is not removed. Also each array element is not allowed to have the character ','. What to do? Should also allow other escape sequences like \n, etc.

A structure field is defined as follows:

  <structure name = "fieldName" extends = "structureName">
     <!-- sequence of field -->
  </structure>

where:

fieldName
The name of the field.
structureName
Optional. If given it must be the name of an already defined structure definition. The current record will be initialized to have all attributes and fields of the structure. The record can change the attributes and field values and append additional fields appended to the instance structure.

Scalar Types

The scalar types are:

boolean
byte
short
int
long
ubyte
ushort
uint
ulong
float
double
string

Thus all Java primitive types except char are support and are implemented via the corresponding Java type. Type string is implemented as a Java String.

NOTE: Since Java does not support unsigned integers, each unsigned integer type is implements as the corresponding signed type. The only exception is the Convert facility. It does implement the proper conversions between unsigned types and other types.

For example

     
    <scalar name = "value", scalarType = "double" />
    <scalar name = "rawValue" scalarType = "int" />
    <scalar name = "description" scalarType = "string" />

value for scalar fields must be specified as follows:

boolean
Must be true or false.
byte
A valid Java long literal value that is cast to a byte
short
A valid Java long literal value that is cast to a short
int
A valid Java long literal value that is cast to a int
long
A valid Java long literal value
float
A valid Java float literal value
double
A valid Java double literal value
string
A valid Java string literal value
structure
If this is the first time the field is being crated than an extends must also be specified. The field will hold a PVStructure with a structure defined by extends. This value is just definitions for fields in the structure.

NOTE about byte, short, int. The syntax allows unsigned instead of signed values for hex values. For example the following is legal syntax although Java would complain.

    <scalar name = "mask" scalarType = "byte">0xff</scalar>

Enumerated Structure

An enumerated structure is a structure that extends enumerated. It has:

  1. Has exactly two fields.
  2. The first field is named index and has scalarType int
  3. The second field is named choices and is an array with element type string

If the current structure is an enumerated structure then the following syntax is allowed:

    <scalar name = "choice">someChoice</scalar>

where someChoice must be one of the elements of choices. This results in the index field being initialized to the correct value.

Examples

If fieldName does not exist then a new field can be created and appended to the end of the current structure. In this case a new field will be appended to the end of the structure in which this field appears.

For example:

<record recordName = "simple" >
  <scalar name = "value" scalarType = "double" />
</record>

Because the record definition does not specify a scalarType = "structureName", it starts with the generic structure, which has no fields. A field with name value does not exist so it is created and appended to the structure. i.e. the record will have a single field of type double and named "value".

The following creates a record which has a structure field that represents a timeStamp..

<record recordName = "structureField" >
  <structure name = "timeStamp">
     <scalar name = "secondsSinceEpoch" scalarType = "long">
     <scalar name = "nanoSeconds" scalarType = "int">
  </structure>
</record>

The following creates a record which has a field named output that is an array of structures:

<record recordName = "complexExample">
  <stucture name = "lotsOfStuff" >
     <scalar name = "value" scalarType = "double">
     <structure name = "output">
         <structure name = "0">
            <scalar name = "dest" scalarType = "string">dest0</scalar>
            <stucture name = "otherInfo">
               <!-- other defs -->
            </structure>
         </structure>
         <structure name = "1">
            <scalar name = "dest" scalarType = "string">dest1</scalar>
            <stucture name = "otherInfo">
               <!-- other defs -->
            </structure>
         </structure>
      </structure>
  </structure>
</record>

Field Initialization

If multiple field instance definitions appear then the last instance determines how the field is initialized.

The syntax for the initializer depends on the field type.

Scalar Types

For scalar types the initializer has the same format as the Java constants for the type. For example if the type for field value is double:

    <scalar name = "value">.98</scalar>

Note: For integer data types Long.decode is used to convert a string to a long, which is then converted to the final integer data type . Thus hex values are allowed. Java does not allow the sign bit to be set. By converting first to a long all interger types except long can have the sign bit set. For example the byte value 0xff is allowed even though Java would raise an exception if Byte.decode was used. The sign problem does exist for long values.

string

For string types the initializer is a valid Java string constant, which can optionally be enclosed in quotes. For example:

    <scalar = "units">voltage</scalar>

structure scalar

A structure scalar field is initialized by giving field definitions for any fields in the associated structure. For example assume that the following structure definitions have been given:

<structure structureName = "test.point">
  <scalar name = "x" scalarType = "double" />
  <scalar name = "y" scalarType = "double" />
</structure>

<structure structureName = "test.testStructure">
    <scalar name = "value" scalarType = "double">10.0</scalar>
    <structure name = "location" extends = "test.point" />
</structure>

Then the following creates a structure scalar field:

<record recordName = "structureScalarTest">
    <structure name = "timeStamp" extends = "timeStamp" />
    <scalar name = "value" scalarType = "structure" extends = "test.testStructure">
        <scalar name = "value">100.0</scalar>
        <structure name = "location">
           <scalar name = "x">1.0</scalar>
            <scalar name = "y">2.0</scalar>>
        </structure>
    </scalar>
</record>

structure

Structure fields are initialized via a recursive definition of field.

Assume the following structure definitions:

    <structure structureName = "doubleLimit">
        <scalar name = "low" type ="double"/>
        <scalar name = "high" type ="double"/>
   </structure>

   <structure structureName = "control">
     <structure name = "limit" extends = "doubleLimit" />
     <scalar name = "minStep" scalarType = "double" />
   </structure>

limit is initilized as follows:.

    <structure name = "control" extends = "control">
      <structure name = "limit">
         <scalar name = "low">0.0</scalar>
         <scalar name = "high">10.0</scalar>
      </structure>
      <scalar name = "minStep">.1</scalar>
   </structure>

It is permissible, in a database definition, to define a field to be a structure without providing a structure name. In this case the default is "null" which is a structure with no fields.

The default structure and auxInfo can be overridden when a field instance is defined. The syntax is:

    <structure name = "fieldName" extends = "structureName">
       <auxInfo name = "pvReplaceFactory" scalarType = "string">someFactory</auxinfo>
    </structurte>

array

The syntax for a array initializer is:
    <array name = "fieldName" scalarType = "scalarType"
    capacity = "capacity" capacityMutable = "true/false" length = "length" offset = "offset" >
        valueList
    </array>

where

capacity
The amount of storage to allocate for the array. This is optional and the capacity will be equal to the number of elements initialized. If the capacity is given a value > 0 and capacityMutable is not specified then capacityMutable is set to true.
capacityMutable
Can the capacity be changed?
length
The initial length for the array.
offset
The offset of the first element being defined.
valueList
A list of values, which is a comma separated set of values.

The following perform the same initialization:

    <array name = "intArray" scalarType = "double">
        0.0,1.0,0.0
    </array>
    <array name = "intArray" scalarType = "double" length = "3">
        0.0,1.0
    </array>

The following initializes an array of structures

    <complexArray name = "example">
      <structure name = "structArray" >
        <structure name = "0" extends = "doubleLimit" >
            <scalar name = "low">0.0</scalar>
            <scalar name = "high">10.0</scalar>
        </structure>
        <structure name = "1"  extends = "doubleLimit">
            <scalar name = "low">-10.0</scalarmit>
            <scalar name = "high">10.0</scalar>
        </structure>
      </structure>
    </array>

structureArray

The first time a structure array field is created an extends must also be provided. The extended structure is used to create the array elements. For example assume that the following structures have been defined:

<structure structureName = "test.point">
  <scalar name = "x" scalarType = "double" />
  <scalar name = "y" scalarType = "double" />
</structure>

<structure structureName = "test.testStructure">
    <scalar name = "value" scalarType = "double">10.0</scalar>
    <structure name = "location" extends = "test.point" />
</structure>

Then the following creates a structure array

<record recordName = "structureArrayTest">
    <structure name = "timeStamp" extends = "timeStamp" />
    <array name = "value" scalarType = "structure" extends = "test.testStructure" capacity = "2">
       <structure>
          <scalar name = "value">100.0</scalar>
          <structure name = "location">
             <scalar name = "x">0.0</scalar>
              <scalar name = "y">0.0</scalar>>
          </structure>
       </structure>
        <structure>
          <scalar name = "value">200.0</scalar>
          <structure name = "location">
             <scalar name = "x">5.0</scalar>
              <scalar name = "y">10.0</scalar>>
          </structure>
       </structure>
       
    </array>
</record>

Macro Substitution and Include

Include

The XML file can include other files also containing Record Instance Definitions. Included files can also include other files. The syntax is:
    
<include addPath = "path" removePath = "path" href = "filename" />

Where

href
The filename, which must be a valid XML Record Instance file, is processed. If any addPaths have been defined the last one specified is prefixed to the filename.
addPath
Add a path.
removePath
Remove a path.

Macro Substitution

Macro substitution replaces a string of the form "${from}" with some other text. The syntax is:

    <substitute from = "fromString" to = "toString" fromTo = "from=to,from=to,..."/>

Where:

from
fromString is the string that appears in ${from}. If from is specified then to must also be specified.
to
toString replaces ${from}
toFrom
The attribute value is a series of "from=to" pairs separated by commas.

Macro substitution can be performed on the foillowing:

  1. Any attribute value in any element definition.
  2. The content of any element definition.

NOTE: If a substitution is being performed and a substitute is not found then if the value is found in the system environment table that value is used.

Example Include and Macro Substitution

The following is a template file:

<?xml version="1.0" ?>
<database>
<record recordName = "ai${recordExtension}Record">
    <scalar name = "value" scalarType = "double"/>
    <structure name = "timeStamp" extends = "timeStamp">
    <structure name = "alarm" extends = "alarm" />
    <structure name = "input" extends = "linearConvertInput" >
        <structure name = "input" extends = "inputSupport">
            <scalar name = "pvname">${pvname}</scalar>
            <scalar name = "wait">true</scalar>
        </structure>
        <structure name = "linearConvert">
            <scalar name = "engUnitsLow">${engUnitsLow}</scalar>
            <scalar name = "engUnitsHigh">${engUnitsHigh}</scalar>
        </structure>
    </structure>
    <structure name = "display" extends = "display" >
        <scalar name = "units">volts</scalar>
        <structure name = "limit">
            <scalar name = "low">${displayLow}</scalar>
            <scalar name = "high">${displayHigh}</scalar>
        </structure>
    </structure>
</record>
</database>
se>

The following creates two instance files from the template:

<?xml version="1.0" ?>
<database>
<include addPath = "src/org/epics/ioc/dbAccess/example" />
<substitute from = "recordExtension" to = "01" />
<substitute from = "pvname" to = "nameFor01" />
<substitute from = "displayLow" to = "0.0" />
<substitute from = "displayHigh" to = "10.0" />
<substitute from = "engUnitsLow" to = "0.0" />
<substitute from = "engUnitsHigh" to = "9.0" />
<include href = "protoAiDB.xml" />
<substitute fromTo = "recordExtension=02,pvname=nameFor02" />
<include href = "protoAiDB.xml" />
</database>

Database XML Code

This section describes the Java support for converting files, which have XML definitions for PVData structures and records, to PVDatabase PVStructures and PVRecords.

The support has two components:

  1. Include and Substitute
    Support for macro substitution and include.
  2. XML to PVDatabase
    Support that parsers the PVData XML statements. It uses the Include and Substitute support

This section first shows the Java Definitions, then it discusses XML to PVDatabase parsing, and last Include and Substitute.

Warning About XML element syntax

This is a warning for utility code that genetrates xml for PVData. The problem is the special XML characters:

These symbols are part of the xml syntax. This is a problem when the value for a string is being defined. For example:

    <scalar name = "xxx" elementType = "string">value</scalar>

In order to set value = "a<b" Then one of the following must be entered.

    <scalar name = "xxx" elementType = "string">a&lt;b</scalar>

or

    <scalar name = "xxx" elmentType = "string"><![CDATA[a<b]]></scalar>

I (Marty Kraimer) do not know how to determine, using SAX, what appears in the original xml source file. What appears to the ContentHandler callback is just the converted characters. What to do? One suggestion is that any code that generates PVData xml should look at all string scalar and scalar array element values. If any of the special XML characters are present then use the<![CDATA[value]]> method of encoding the value.

Java Definitions

    class XMLToPVDatabaseFactory {
        static void convert(PVDatabase pvDatabase, String fileName,Requester requester,
            boolean reportSubstitutionFailure,
            XMLToPVDatabaseListener pvListener,
            IncludeSubstituteXMLListener isListener,
            IncludeSubstituteDetailsXMLListener detailsListener);
        static void convert(PVDatabase pvDatabase, String fileName,Requester requester);
    }

    interface XMLToPVDatabaseListener {
        void startStructure(PVStructure pvStructure);
        void endStructure();
        void startRecord(PVRecord pvRecord);
        void endRecord(); 
        void newStructureField(PVStructure pvStructure);
        void endStructureField();
        void startArray(PVArray pvArray);
        void endArray();
        void startScalar(PVScalar pvScalar);
        void endScalar();
        void startAuxInfo(String name,Map<String,String> attributes);
        void endAuxInfo();
    }

    interface IncludeSubstituteXMLListener {
        void endDocument();
        void startElement(String name, Map<String,String> attributes);
        void element(String content);
        void endElement(String name);
    }

    interface IncludeSubstituteDetailsXMLListener {
        void startElementBeforeSubstitution(String name, Map<String,String> attributes);
        void elementBeforeSubstitution(String content);
        void newSourceFile(String fileName);
        void endSourceFile();
        void addPath(String pathName);
        void removePath(String pathName);
        void substitute(String from,String to);
        void removeSubstitute(String from);
    }
    
    interface IncludeSubstituteXMLReader {
        void parse(String rootElementName,String fileName,Requester requester,
            boolean reportSubstitutionFailure,
            IncludeSubstituteXMLListener listener,
            IncludeSubstituteDetailsXMLListener detailsListener);
        void message(String message,MessageType messageType);
    }

    class IncludeSubstituteXMLReaderFactory {
        static public IncludeSubstituteXMLReader getReader();
    }

XML To PVDatabase

This support processes PVData XML statements. Code that wants to parse PVData XML statements calls one of the XMLToPVDatabaseFactory.convert methods. The only difference between the two methods is that the first provides access to detailed information about parsing while the second only provides errors..

XMLToPVDatabaseFactory

This provides two methods both named convert. The first provides detailed information about parsing. It is intended for use by VDCT. The second reports all errors including substitution failues but none of the detailed information. The arguments for the first method are:

pvDatabase
The PVDatabase into which structure and record instances are put.
fileName
The name of the XML file.
requester
The Requester interface which must be implemented by the caller.
reportSubstitutionFailure
Should substitution failures be reported?
pvListener
The XMLToPVDatabaseListener interface, which can be null. If implemented the caller is notified when PV XML elements have been parsed.
isListener
The IncludeSubstituteXMLListener interface, which can be null. XMLToPVDatabaseFactory implements it's own version but will also call this instance if implemented.See the interface description below for details.
detailsListener
The IncludeSubstituteDetailsXMLListener interface, which can be null.
XMLToPVDatabaseListener

This provides a callback for the beginning and end of the parsing of PVData XML elements not related to macro substitution and include. It provides the following methods:

startStructure
A new structure instance is being created.
endStructure
The definition of the new structure is complete.
startRecord
A new record instance is being created or an existing record is being modified.
endRecord
The definition on the new or existing record is complete.
newStructureField
A new structure field is being created.
endStructureField
The definition on the new structure field is complete
startArray
A new array field is being created.
endArray
The definition on the new array field is complete
startScalar
A new scalar field is being created.
endScalar
The definition on the new scalar field is complete
startAuxInfo
A new auxInfo is being created.
endAuxInfo
The definition on the new auxInfo is complete

Include and Substitution

This support completely handles all details of Macro Substitution and Include. The code that calls this support sees only the results of substitution and include.. This support also implements the SAX2 ContentHandler and EventHandler interfaces. Instead of the SAX2 interfaces, code that uses this code must implement at least the IncludeSubstituteXMLListener interface. Support that wants additional information can also implement the IncludeSubstituteDetailsXMLListener interface. This code, in addition to macro substitution, provides a simplified version of what SAX2 provides, which also means that it does not provide access to all of SAX2.

This code does not understand the complete pvData XML syntax. It only understands the include, substitute, package, and import elements. Thus it could be used by code other than XML to PVDatabase but any such code must realize that it does not provide access to all of SAX2.

IncludeSubstituteXMLListener

This interface must be implemented by the caller. It is a simplified version of the SAX2 ContentHandler. The methods are:

endDocument
The end of the xml input file. This is NOT called for included files.
startElement
The opening tag of an xml element is being processed.
element
The value of an xml element, i.e. what appears between the opening and closing tags. Any leading and trailing white space of any element fragment is removed.
endElement
The end tag opf an xml element is being processed.
IncludeSubstituteDetailsXMLListener

This interface can optionally be implemented by the caller. It provides details about include and substitution details. The methods are:

startElementBeforeSubstitution
This is the opening tag of an xml element before any substitutions.
elementBeforeSubstitution
This is an xml element value before any substitutions.
newSourceFile
A new file is being included.
endSourceFile
End of an included file,
addPath
A new addPath
removePath
A addPath is being removed.
substitute
A new substitute is defined.
removeSubstitute
A substitute is being removed.
IncludeSubstituteXMLReader

The interface implemented by IncludeSubstituteXMLReaderFactory. It provides two methods: parse and message. The arguments to parse have already been describes. The message method adds the location within the input xml files when this method is called.

IncludeSubstituteXMLReaderFactory

The factory that implements macro substitution and include.

Package org.epics.pvioc.util

Overview

This package provides utility code for a javaIOC:

Scan Field
Interface that makes it easier to access the scan field of a record.
Periodic and Event Scanners
Support for records that are periodic or event scanned.

Scan Field Support

Definitions

    public interface ScanField {
        ThreadPriority getPriority();
        PVInt getPriorityIndexPV();
        ScanType getScanType();
        PVInt getScanTypeIndexPV();
        double getRate();
        PVDouble getRatePV();
        String getEventName();
        PVString getEventNamePV();
        boolean getProcessSelf();
        PVBoolean getProcessSelfPV();
        boolean getProcessAfterStart();
        PVBoolean getProcessAfterStartPV();
    }
     
    public enum ScanType {
        passive,
        event,
        periodic;
        public static Enumerated getScanType(PVField dbField);
    }
    
    public class ScanFieldFactory {
        public static ScanField create(PVRecord dbRecord);
    }

ScanField

ScanField is a convenience interface for accessing the scan field of a record.

ScanType

This is a Java enum which defines the scan types:

passive
This is a record that is not periodically or event scanned. It can be processed by another requester. For example database links can request processing and Channel Access clients can also request processing.
event
A record can be event scanned. If so the record also has an eventName assigned to it. An event announcer, defined below, can declare and event. This makes all records with the associated eventName process.
periodic
The record is periodically scanned. A peridically scanned record has a rate assigned it it.

The method is:

getScanType
If dbField has an Enumerated Create interface and if the choices match the ScanType enum names than it returns the Enumerated interface. Otherwise it returns null.

ScanFieldFactory

This is a factory for creating a ScanField.

create
Create a ScanField.

Periodic and Event Scanners

Definitions

    public interface EventAnnounce {
        void announce();
    }
    public interface EventScanner {
        boolean addRecord(PVRecord pvRecord);
        boolean removeRecord(PVRecord pvRecord,String eventName,ThreadPriority scanPriority));
        EventAnnounce addEventAnnouncer(String eventName,String announcer);
        void removeEventAnnouncer(EventAnnounce eventAnnounce,String announcer);
        String show(String eventName);
    }
    
    public interface PeriodicScanner {
        boolean addRecord(PVRecord pvRecord);
        boolean removeRecord(PVRecord pvRecord,double rate,ThreadPriority threadPriority);
        String show(ThreadPriority priority);
        String show(double rate);
        String show(double rate,ThreadPriority priority);
    }
    
    public class ScannerFactory {
         public static PeriodicScanner getPeriodicScanner();
         public static EventScanner getEventScanner();
    }

EventAnnounce

This is the interface for announcing an event. The event scanner implements this interface. An announcer calls eventScanner.addEventAnnouncer in order to get an EventAnnounce. The announcer then just calls:

    eventAnnounce.announce();

when it wants to announce an event.

EventScanner

This is the interface for the event scanning facility implemented by ScannerFactory. It implements the methods:

addRecord
Add an event scanned record.
removeRecord
Remove a record from being event scanned.
addEventAnnouncer
Add an event announcer.
removeEventAnnouncer
Remove an event announcer.
show
report announcers and event scanned records

PeriodicScanner

This is the interface for the periodic scanning facility implemented by ScannerFactory. It implements the methods:

addRecord
Add a new record to a periodically scanned list.
removeRecord
Remove a record from being periodically scanned.
show
Show periodically scanned records.

Package org.epics.pvioc.install

Overview

This package provides code to install structures and records into a javaIOC. A javaIOC is started via JavaIOC.main. Once started structures and records can be installed either by JavaIOC or by any thread running as part of the javaIOC.

A javaIOC has two databases: a PVDatabase and an IOCDatabase. The PVDatabase, which is described in project pvData, holds the memory resident data. The IOCDatabase provides access to the PVDatabase and to support code. Both databases are named master.

New structure instances or record instances can be installed into a running javaIOC. It is not legal to install both new structures and records at the same time. Installation is done as follows: New instances are read into a new PVDatabase named beingInstalled. If any error is detected while reading the file, nothing more is done, i.e. installation fails. If the beingInstalled database has only structure definitions the new definitions are merged into master and installation is complete. If the beingInstalled database has only record instances then the record instances are initialized and started. If any record can not be started nothing more is done, i.e. the installation fails. If all records start then an AfterStart procedure described below is performed. As part of this procedure the new record instances are merged into master. When the AfterStart procedure is done installation is done. The InstallFactory ensures that only one installation at a time is allowed.

This overview describes the following:

Install
The interface for installing structures and records.
InstallFactory
The factory which implements a single instance of Install.
SupportCreation
Support to create, initialize, and start records.
AfterStart
Support that allows support and servers to perform various functions after new records have started but before installation is complete. After Start allows unrelated support to execute in parallel.

Install Factory

InstallFactory is used to install structure or records into master database of a javaIOC. Only one set of definitions at a time can be installed.

Definitions

interface Install {
    boolean installStructures(String xmlFile,Requester requester);
    boolean installStructures(PVDatabase pvDatabase,Requester requester);
    boolean installStructure(PVStructure pvStructure,Requester requester);
    boolean installRecords(String xmlFile,Requester requester);
    boolean installRecords(PVDatabase pvDatabase,Requester requester);

    boolean installRecord(PVRecord pvRecord,Requester requester);
}

class InstallFactory {
    public static Install get();
}

installStructures

Three methods are provided. The first install structure definitions from file. The second installs structure definitions from a PVDatabase. The last installs a single PVStructure.

The xml file must contain xml structure definitions as described in project pvData. The file is read into a PVDatabase named beingInstalled. If the file is read successfully the second installStructures method is called.

The next method attempts to install structures from a PVDatabase. The pvDatabase must not have any records and must not have any structure that is already in master. If these checks succeed the new definitions are merged into master. The return value is (false,true) if the new structures (were not, were) installed.

The last method installs a PVStructure if the structure does not already exist in the master.

installRecords

Three methods are provided. The first Install record definitions from file. The second installs records from a PVDatabase. The last installs a single PVRecord.

  1. The xml file must contain xml record definitions as described in project pvData. The file is read into a PVDatabase named beingInstalled. If the file is read successfully method 2 is called
  2. This method attempts to install records from a PVDatabase. The pvDatabase must not have any structuress and must not have any record that is already in master. If these checks succeed an attempt is made to initialize and start the records instances as described below.
  3. The last method creates a PVDatabase named beingInstalled, adds the PVRecord to it, and calls method 2.

Initialize, and Start Record Instances

PVReplaceFactory.replace is called for the PCDatabase holding the new records.

An IOCDatabase is created for the PVDatabase holding the new records.

A SupportCreation named beingInstalled is created and the following steps performed

createSupport
supportCreation.createSupport is called. If it fails installation fails.
initialize
supportCreation.initializeSupport is called. If it fails installation fails.
start
An AfterStart is created and then supportCreation.start(afterStart) is called. If it fails installation fails.
before merge
afterStart.callRequesters(false) is called.
merge
The beingInstalled databases (PVDatabase and IOCDatabase) are each merged into the corresponding master database.
after merge
afterStart.callRequesters(true) is called.

The return value is (false,true) if the new records (were not, were) installed.

Support Creation

A SupportCreation is used to create, initialize, and start record instances. After it is done it is no longer accessable.

Definitions

public class SupportCreationFactory {
    static public SupportCreation create(
         IOCDatabase supportDatabase,Requester requester);
}

public interface SupportCreation {
    boolean createSupport();
    boolean initializeSupport();
    boolean  startSupport(AfterStart afterStart);
}

Factory

This has the single method which creates a SupportCreation.

SupportCreation

createSupport
Create the support. It first created a RecordProcess and then support for fields with support.
initializeSupport
Initialize the support. For each record it calls recordProcess.initialize. It returns true if all records are initialized.
startSupport
Start the support. For each record it calls recordProcess.start. It returns true if all records are started.

After Start

After Start is a facility that allows support code and servers like Channel Access to perform various functions after new records are started but before installation completes. It is designed so that unrelated functions can execute in parallel and so that related functions can execute in the order they require

Code can request to be called back before or after the beingInstalled is merged into the master. Each request also specifies a priority. A callback should not block. When it is done it must notify AfterStart that is is done. All callbacks at a particular priority must complete before the callbacks at the next lower priority are called.

The start method of Support is defined as:

    void start(AfterStart afterStart);

The support code can call afterStart.requestCallback. If so it must implement interface AfterStartRequester. When AfterStartRequester.callback is called the support code can do what it wants but should not block. Instead it should arrage for some other thread to do the work. When done the support code must call afterStart.done.

Servers, i. e. code that is not attached to a record can call AfterStartFactory.newAfterStartRegister. An example of a server is Channel Access. The NewAfterStartRequester is called each time a new AfterStart is created, i.e. every time a new set of records are being installed. The server can then call afterStart.requestCallback just like support code.

Definitions

public interface AfterStartNode {}

public interface AfterStartRequester {
    void callback(AfterStartNode node);
}

public class AfterStartFactory {
    public static  AfterStart create();
    public static AfterStartNode allocNode(AfterStartRequester requester);
    public static void newAfterStartRegister(NewAfterStartRequester requester);
    public static void newAfterStartUnregister(NewAfterStartRequester requester);
}

public interface AfterStart {
    void callRequesters(boolean afterMerge);
    void requestCallback(AfterStartNode node,boolean afterMerge,ThreadPriority priority);
    void done(AfterStartNode node);
    void doneAndRequest(AfterStartNode node,boolean afterMerge,ThreadPriority priority);
}


public interface NewAfterStartRequester {
    void callback(AfterStart afterStart);
}

AfterStartNode

Any code that calls afterStart.requestCallback must create an afterStartNode by calling AfterStartFactory.allocNode. It passes this to afterStart.requestCallback. A node can only be on one request list at a time.

AfterStartRequester

This is the interface which must be implemented by code that calls afterStart.requestCallback. It has a single method which is the callback.

NewAfterStartRequester

This is the interface which must be implemented by code that calls AfterStartFactory.NewAfterStartRegister.

AfterStartFactory

create
Create a new AfterStart. This is called by InstallFactory.
allocNode
This is called by any code that calls afterStart.requestCallback. It can be reused as desired but a node can only be on a single request queue at any given time.
NewAfterStartRegister
This is called by code that wants to be notified when a new AfterStart is created, i.e. when new records are being installed.
NewAfterStartUnregister
Remove a NewAfterStartRequester.

AfterStart

callRequesters
Call requesters. This is called by InstallFactory.
requestCallback
A request to be called back. The ThreadPriority does not choose a thread but just a priority.
done
The callback is done.
doneAndRequest
The callback is done but want to be called back again. The new request queue must be for a later time then the current queue.

Package org.epics.pvioc.database

Overview

This package provides everything required to create and access a PVDatabase.

A PVDatabase consists of :

  1. A set of structures. Each has a unique name and is implemented as a top level PVStructure. The primary use of these structures is as "templates" for creating structure fields within a PVRecord.
  2. A set of record instances. Each has a unique name and is implemented as a PVRecord.

Each PVRecord has a unique record name and has top level PVStructure, which is a structured set of PVFields. A PVRecord can be:

processed
A record can be processed. In addition each field of a record can optionally have attached support. The database does not implement processing but allows other code to attach support to fields and recordProcess to a record.
locked
Whenever a record is accessed it can be locked. pvIOCJava requires that a record be locked whenever it is accessed.
monitored
Any code can register to be called whenever the data for a field is modified. If the code listens for changes to a structure field it is notified whenever any scalar or array field in the structure is modified. PVField provides a method postPut, which must be called by the code that calls the put method of the PVField. Note the caller must call postPut because for array fields the array might be written in chunks. Only the caller knows when it is done.
a message source
Every PVField has a method message, which can be called by any code that has access to the PVField. Code can register to be called whenever a message is generated.

RecordField Interfaces

Each field of a record has an associated PVRecordField and each structure field a PVRecordStructure.

PVRecordField

    interface PVRecordField extends Requester{
        Support getSupport();
        void setSupport(Support support);
        PVRecordStructure getParent();
        PVField getPVField();
        void replacePVField(PVField newPvField);
        String getFullFieldName();
        String getFullName();
        PVRecord getPVRecord();
        void renameField(String newName);
        boolean addListener(PVListener pvListener);
        void removeListener(PVListener pvListener);
        void postPut();
    }

where

getSupport
Get the attached support. This is null if no support has been attached.
setSupport
Set support for the field.
getParent
Get the parent PVRecordStructure for this field.
getPVField
Get the PVField associated with this PVRecordField.
replacePVField
If the associated PVField is being replaced it must be replaced by calling this instead if directly replacing the PVfield.
getFullName
This gets recordname plus the full name of the field, i.e. recordName.field,field,..
getFullFieldName
This gets the full name of the field, i.e. field,field,..
getPVRecord
Returns the PVRecord to which this field belongs.
renameField
Renames the field name. This must be called rather than directly calling PVField.renameField.
addListener
Add A PVListener to this field. Whenever this field or any subfield if this field is modified the listener will be notified. PVListener is described below. Before a listener can call addListener it must first call PVRecord.registerListener.
removeListener
Remove a PVListener.
postPut
This is called by the code that implements the data interface. It is called whenever the put method is called.

PVRecordStructure

Each structure field has the following interface: Note that it extends PVRecordField

    public interface PVRecordStructure extends PVRecordField {
        PVRecordField[] getPVRecordFields();
        PVStructure getPVStructure();
    }

where

getPVRecordFields
Get the PVRecordField array.
getPVStructure
Get the PVStructure this field accesses.

Record Interfaces

PVListener

A PVlistener can attach itself to any field or fields of a record. It will be notified whenever a put is issued to the field, i.e. the field is modified. If the field is a structure then the PVListener is notified whenever that field or any subfield is modified. Please note that PVStructureScalar and PVStructureArray fields are treated as leaf fields so that the underlying fields can not have attached listeners.

    public interface PVListener {
        void dataPut(PVRecordField pvRecordField);
        void dataPut(PVRecordStructure requested,PVRecordField pvRecordField);
        void beginGroupPut(PVRecord pvRecord);
        void endGroupPut(PVRecord pvRecord);
        void unlisten(PVRecord pvRecord);
    }

where

dataPut(PVRecordField pvRecordField)
pvField has been modified. This is called if the listener has called PVRecordField.addListener for pvRecordField.
dataPut(PVRecordStructure requested,PVRecordField pvRecordField)
pvField has been modified. Requested is the field to which the requester issued a pvField.addListener. This is called if the listener has called PVRecordField.addListener for requested.
beginGroup
A related set of changes is being started.
endGroup
A related set of changes is done.
unlisten
The PVLister is being removed from the record. This is called when the record is being destroyed or when the record structure (not the data values) is being changed.

PVRecordClient

Any client that accesses a PVRecord must call registerClient so that the client can be notified when the record is being removed from the master database. The client must imnplement the following interface:

    public interface PVRecordClient {
        void detach(PVRecord pvRecord);
    }

PVRecord

A PVRecord has a top level PVStructure that provides the following methods:

    interface PVRecord extends Requester {
        RecordProcess getRecordProcess();
        void setRecordProcess(RecordProcess recordProcess);
        PVRecordField findPVRecordField(PVField pvField);
        PVRecordStructure getPVRecordStructure();
        String getRecordName();
        void message(String message, MessageType messageType);
        void addRequester(Requester requester);
        void removeRequester(Requester requester);
        void lock();
        void unlock();
        void lockOtherRecord(PVRecord otherRecord);
        void beginGroupPut();
        void endGroupPut();
        void registerListener(PVListener pvListener);
        void unregisterListener(PVListener pvListener);
        boolean isRegisteredListener(PVListener pvListener);
        void removeEveryListener();
        void registerClient(PVRecordClient pvRecordClient);
        void unregisterClient(PVRecordClient pvRecordClient);
        void detachClients();
        int getNumberClients();
    }

where

getRecordProcess
Get the record process for the record.
setRecordProcess
Set the record process for the record.
findPVRecordField
Given a PVField find the PVRecordField.
getPVRecordStructure
Get the top level PVRecordStructure for the record.
getRecordName
Returns the record name.
message
This is called by AbstractPVField if it has a RecordField. It can be called by other code but most code will not need it.
addRequester
Add a requester to receive messages.
removeRequester
Remove a message requester
lock
Lock the record. See next sub-section.
unlock
Unlock the record.
lockOtherRecord
While code has a record locked, It can also lock another record. If the other record is already locked than this record may be temporily unlocked and then relocked. The caller must call the unlock merthod of the other record when done with it. The implementation prevents deadlocks BUT code must not try to lock more than two records at the same time or deadlocks can occur.
beginGroupPut
Begin a group of puts. This results in all registered PVListeners being called.
endGroupPut
End a group of puts. This results in all registered PVListeners being called.
registerListener
Register a PVListener. This must be called before calling pvRecordField.addListener.
unregisterListener
Unregister a listener. The listener will also be removed from all fields to which it is attached.
isRegisteredListener
Id the PVListener registered?
removeEveryListener
This must be called by any code that is deleting or changing the structure of a record.
registerClient
Every client that accesses the record must call this so that the client can be notified when the record is deleted.
unregisterClient
Client is no longer accessing the record.
detachClients
All client are asked to detach from the record.
getNumberClients
Get the number of registered clients.
Record Locking

Whever code access a record it must be locked. The code for accessing a record should use the following pattern:

    pvRecord.lock();
    try {
       // access the record
    } finally {
        pvRecord.unlock();
    }

Depending on the application, for example pvIOCJava, it may be required that the thread does not block between lock and unlock.

PVRecord Definition and Creation

PVDatabase

The interface is:

    interface PVDatabase extends Requester{
        PVDatabase getMaster();
        String getName();
        void mergeIntoMaster();
        PVRecord findRecord(String name);
        boolean addRecord(PVRecord pvRecord);
        boolean removeRecord(PVRecord pvRecord);
        String[] getRecordNames();
        PVRecord[] getRecords();
        PVStructure findStructure(String name);
        boolean addStructure(PVStructure pvStructure);
        boolean removeStructure(PVStructure pvStructure);
        String[] getStructureNames();
        PVStructure getStructures();
        void message(String message, MessageType messageType);
        void addRequester(Requester requester);
        void removeRequester(Requester requester);
        String[] recordList(String regularExpression);
        String[] structureList(String regularExpression);
        String recordToString(String regularExpression);
        String structureToString(String regularExpression);
    }

where

getMaster
Get the master database. This is just a convenience mthhod.
getName
Get the name of the database.
mergeIntoMaster
Merge this database into the master database.
findRecord
Find a record. Null is returned if the record is not in the database.
addRecord
Add a record to the database. If the record already exists it is not modified and false is returned.
removeRecord
Remove a record from the database. If the record was not in the database false is returned.
getRecordNames
Get an array of the record names.
getRecords
Get a array of all the records.
findStructure
Find a structure. Null is returned if the structure is not in the database.
addStructure
Add a structure to the database. If it already exists false is returned.
removeStructure
Remove a structure from the database. If it did not exist false is returned.
getStructureNames
Get an array of the structure names.
getStructures
Get a array of all the structures.
message
Report a message. If no listeners are registered the messages are sent to System.out (info) or System.err (all other message types). If at least one requester is present then the messages are given to the requesters without writing to System.out or System.err. If the database is the master, the message is put of a queue that is emptied by another thread. This messages sent to the master do not block.
addRequester
Add a requester to receive messages.
removeRequester
Remove a requester.
recordList
Get a list of all records with names that match a regular expression.
structureList
Get a list of all structures with names that match a regular expression.
recordToString
Get a dump of all records with names that match a regular expression.
structureToString
Get a dump of all structures with names that match a regular expression.

PVRecordCreate

Interface and factory for creating PVrecords and PVStructures.

    interface PVRecordCreate {
        PVRecord createPVRecord(String recordName,PVStructure pvStructure);
    }

    class PVRecordCreateFactory{
        PVRecordCreate getPVRecordCreate();
    }

where

createPVRecord
Create a PVRecord with pvStructure as the top level structure.

PVReplaceFactory

Factory that looks for and calls factories that replace the default implementation of a field.

    class PVReplaceFactory {
        public static void replace(PVDatabase pvDatabase);
        public static void replace(PVDatabase pvDatabase,
            PVRecord pvRecord,PVRecordStructure pvRecordStructure);
        public static void replace(PVDatabase pvDatabase,
            PVRecord pvRecord,PVRecordField pvRecordField);

where

replace(PVDatabase pvDatabase)
Look at every field of every record in the database and see if field implementation should be replaced.
replace(PVDatabase pvDatabase,PVRecord pvRecord,PVRecordStructure pvRecordStructure)
Look at every field of pvStructure and see if the field implementation should be replaced.
replace(PVDatabase pvDatabase,PVRecord pvRecord,PVRecordField pvRecordField)

Look at the field and see if the field implementation should be replaced. If it is a structure field also look at the subfields.

PVDatabase

PVDatabase is an interface for accessing a PVData database.

A PVDatabase contains structures and records. Structures provided an easy way to create an initial set of subfields of a structure field of record instances or other structures. When a structure field of a record is defined as follows:

    <record name = ... />
        <!-- other fields -->
        <structure name = "name" extends = "structName" />
        <!-- ... -->
    </record>

Then the fields in the structure are initialized with a copy of the fields in structure "structName".

The Interface definition is:

    interface PVDatabase extends Requester{
        PVDatabase getMaster();
        String getName();
        void mergeIntoMaster();
        PVRecord findRecord(String recordName);
        boolean addRecord(PVRecord record);
        boolean removeRecord(PVRecord record);
        String[] getRecordNames();
        PVRecord[] getRecords();
        PVStructure findStructure(String structureName);
        boolean addStructure(PVStructure structure);
        boolean removeStructure(PVStructure structure);
        String[] getStructureNames();
        PVStructure[] getStructures();
        void message(String message, MessageType messageType);
        void addRequester(Requester requester);
        void removeRequester(Requester requester);
        String[] recordList(String regularExpression);
        String[] structureList(String regularExpression);
        String recordToString(String regularExpression);
        String structureToString(String regularExpression);
    }

where

getMaster
Get the master database. This is the only database that is processed,
getName
Get the name of this database.
mergeIntoMaster
Merge this database into master. The database must be named "beingInstalled". After this returns another beingInstalled database can be created.
findRecord
Find a PVRecord. If not found null is returned.
addRecord
Add a record to the database.
removeRecord
Remove a record from the database.
gerRecordNames
Get an array of the names of the current records in the database.
getRecords
Get an array of the current records in the database.
findStructure
Find a PVStructure. If not found null is returned.
addStructure
Add a PVStructure to the database.
removeStructure
Removed a PVStructure from the database.
getStructureNames
Get an array of the names of the current structures in the database.
getStructures
Get an array of the current structuress in the database.
message
Called by a PVDatabase to report messages. This gives a way for a client to get all messages from all records in a database.
addRequester
Add a requester.
removeRequester
Remove a requester.
recordList
Get an array of record names that satisfy a regular expression.
structureList
Get an array of structure names that satisfy a regular expression.
recordToString
Dumps all records with record names that satisfy a regular expression.
structureToString
Dumps all structures with structure names that satisfy a regular expression.

PVDatabaseFactory

This is a factort that creates a PVDatabase.

    class PVDatabaseFactory {
        public static PVDatabase create(String name);
        public static PVDatabase getMaster();
        public static PVDatabase getBeingInstalled();
    }
create
Create a PVDatabase. If this is a database that is intended to merge into master it MUST be named "beingInstalled". If a beingInstalled database already exists than an IllegalStateException is thrown.
getMaster
Get the master database. This is the only database than can be processed and the only database pvAccess uses.
getBeingInstalled
Get the beingInstalled database. In not present null is returned.

Package org.epics.pvioc.support

Overview

This package describes how records are processed. Package install describes how records are initialized and started. During database creation each record is assigned an instance of RecordProcess, which coordinates record processing. In addition each record has a Support instance and each field can optionally have an associated Support instance.

RecordProcess

The following interfaces are involved with record processing:

RecordProcess
An instance is created for each IOC record. It has methods for use by any code interested in record processing.
ProcessToken
A token that allocated by RecordProcess and used by RecordProcessRequesters.
RecordProcessRequester
Implemented by code that calls recordProcess.process..
ProcessCallbackRequester
Implemented by code that calls recordProcess.requestProcessCallback.
ProcessContinueRequester
Implemented by code that calls recordProcess.processContinue.

Support

Every pvIOCJava record instance has associated support code and each field of a record instance can optionally have associated support code. This package contains:

Support
The interface which is implemented by every support module.
AbstractSupport
An abstract class that is the base class for every support module.

This package has sub-packages for the support modules implemented by the javaIOC itself. Other pvIOCJava applications can implement additional support modules. The sub-packages are:

basic
Implements the following support:
generic
Generic support for a record type, structure, and an array of arrays or structures.
noop
Support that does nothing except complete successfully.
linearConvert
Implements linear conversion for a numeric scalar field.
digital
Support for digital I/O.
incremental
Support for incremental output.
delay
Adds a delay to record processing.
event
Support for a string field that is the name of an event.
processControl
Support for the processControl record type. This is a record type that attaches to another record. The scan state of the record can be changed, the trace and enable states can be changed, and the structure of a sub-field can be changed.
scan
Support for the scan field.
supportArray
Support for an array field where each element is a structure.
ca
Implements support for channel access links, i.e. links to other records.
dbLink
Implements support for database links, i.e. links to other records in the same javaIOC.
alarm
Raises alarms for value fields.
calc
Support for performing calculations.
device
Examples of support that implements device abstractions.
drv
Support for communicating with portDriver.

Record Processing Theory of Operation

A pvIOCJava Database is a "smart" database. Each record has associated support code and each field of a record can optionally have associated support.

Each record has an implementation of recordProcess associated with it. recordProcess can be requested to process the record. It in turn calls the process method of the support attached to the record. A record is also the top level structure. The record support process method calls the support for any field of the top level structure that has associated support. Any support can call other support.

Definitions

synchronous
Code that does not block, i.e. does not perform actions like waiting for I/O to complete.
asynchronous
Code that can block.
record
A record instance.
process
Processing a record instance.
support
Code that is involved with implementing record processing. This code can be either synchronous or asynchronous. Support code can invoke other support code.
record support
The top level support for a record instance. Support that is attached to a structure can also be record support if the structure is the top level structure.
recordProcess
During database initialization every record instance is assigned an instances of RecordProcess, which coordinates record processing.
process requester
Code that asks recordProcess to process a record. A process requester must get a ProcessToken from record process in order to request that a record can be processed. A record instance can optionally be set to allow only a single process requester, in which case only the first requester that asks for a token will receive a token..
active
A record instance is active while a process request is active. A request to set a record active will fail if it is already active..
lock
Short for record instance lock. A record must be locked whenever any field of a record is accessed. Code executing with a record locked must be synchronous. There is no way to detect if code violates this rule so code must be implemented carefully.

Requester Examples

Local Channel Access
An example is a channel access server that is accessing IOC database. The following are typical requests:
get or put
Just get or put data from a record instance.
process and get
An example is to process a record and get an array of data as well as the status, severity, and timeStamp.
put, process, get
A example is to put something into the record, make it process, and after processing get some data as well as the status, severity, and timeStamp.
Database Links
Links between records in the same IOC. When a database link makes a request to process a linked record, the record containing the link MUST be unlocked or deadlocks may occur. For efficency requests should be done with as few lock/unlock cycles and context switches as possible. In particular only asynchronous support should cause a context switch.
Typical requests are:
process and get
Process and after procsss completes get data and/or severity.
put, process, and get severity
Put data to the linked record, process it, and then get the severity.

RecordProcess Overview

A record is processed via a call to RecordProcess.process. It in turn calls the record support process method. Record support optionally calls the process methods of field support modules. Each support module can optionally call the process method of support code for subfields. Record support is just like field support except that it is attached to the record rather than to a subfield of the record.

Record processing has the following features:

The methods involved in processing are:

Local Channel Access Example

As an example assume that a channel access server does the following to a record:

This can be implemented as follows:

Link Support Example

As an example assume that a record type double has the following fields:

value
A PVDouble field, i.e. a field that holds a double value.
input
A PVStructure field which is by default a null structure, i.e. it has no fields and no support. A record instance can override this to be any structure defined in the master Database Definition Database. The default support can also be overridden.
output
Also a null PVStructure field.
valueAlarm
Also a null PVStructure field.
supportArray
An array field with the elementType set to structure and the supportName set to supportArray.
...
Several other null PVStructure fields are present.

In addition the following support modules are available.

generic
Support for a structure. For each field in the structure that has support, generic calls it.
inputLink
A link support modules that supports channel access input links, i.e. a link that gets input from another IOC record.
processLink
A link support modules that supports channel access process links, i.e. a link that can request that another record be processed.
outputLink
A link support module that supports channel access output links, i.e. a link that can put data to another record.
...
Support modules are also available that can be attached to other null PVStructure fields.

Assume a record instance is defined as follows:

<record name = "double01" type = "generic">
    <structure name = "alarm" type = "alarm" />
    <structure name = "timeStamp" type = "timeStamp" />
    <scalar name = "value" type = "double" />
    <structure name = "display" type = "display" />
    <structure name = "input" type = "inputSupport">
        <scalar name = "pvname">recordForInput</scalar>
        <scalar name = "process">false</scalar>
        <scalar name = "propertyNames">alarm,display</scalar>
    </structure>
    <structure name = "link" type = "generic" >
        <structure name = "process" type = "processSupport">
            <scalar name = "pvname">processRecord</scalar>
            <scalar name = "wait" type = "boolean" >false</scalar>
        </structure>
        <structure name = "output" type = "outputSupport">
             <scalar name = "pvname">outputRecord</scalar>
             <scalar name = "process">false</scalar>
        </structure>
    </structure>
</record>

When the record is processed, via a call to recordProcess.process, the following happens:

Locking

The locking strategy is based on the following:

Support Overview

A support module implements the following methods:

initialize
The support can do any initialization that does not connect outside the record.
start
The support can connect outside the record. For example channel access support can connect to another record.
stop
The support must terminate outside connections.
uninitialize
The support must undo everything it did during initialization.
process
Implements the semantics of record procession.

The methods initialize, start, stop, and uninitialize provide the ability to dynamically modify a record.

Support is associated with a structure, record, or field definition via an auxInfo definition that has a name of "supportFactory". In addition there must be a structure definition for the factory itself. Look at the xml structure definitions that come with the javaIOC for examples.

Record Process

Definitions

The following are the interfaces for record processing:

    
    public interface RecordProcess {
        // general purpose methods
        boolean isEnabled();
        boolean setEnabled(boolean value);
        boolean isActive();
        PVRecord getRecord();
        boolean isTrace();
        boolean setTrace(boolean value);
        SupportState getSupportState();
        // support lifecycle methods
        void initialize();
        void start(AfterStart afterStart);
        void stop();
        void uninitialize();
        // record process requester methods
        ProcessToken requestProcessToken(RecordProcessRequester recordProcessRequester);
        void releaseProcessToken(ProcessToken processToken);
        void forceInactive();
        String getRecordProcessRequesterName();
        void queueProcessRequest(ProcessToken processToken);
        void process(ProcessToken processToken,
            boolean leaveActive, TimeStamp timeStamp);
        void setInactive(ProcessToken processToken);
        // support processing methods
        void processContinue(
            ProcessContinueRequester processContinueRequester);
        void requestProcessCallback(
            ProcessCallbackRequester processCallbackRequester);
        void setTimeStamp(TimeStamp timeStamp);
        void getTimeStamp(TimeStamp timeStamp);
        // self processing method
    }

    public interface ProcessToken {}

    public interface RecordProcessRequester extends Requester{
        void becomeProcessor();
        void canNotProcess(String reason);
        void lostRightToProcess();
        void recordProcessResult(RequestResult requestResult);
        void recordProcessComplete();
    }

    public interface ProcessCallbackRequester extends Requester{
        void processCallback();
    }

    public interface ProcessContinueRequester {
        void processContinue();
    }
    
    public interface SupportProcessRequester {
        void supportProcessDone(RequestResult requestResult);
    }

An instance of RecordProcess is created for each IOCrecord. Each method falls into one of the following classes:

  1. General Purpose. These are methods that can be called by any code. If necessary a method locks the record while performing its action and unlocks before returning.
  2. Record Support Lifetime. Initialize,start,stop,ininitialize.
  3. Record Process Requester: These are methods for code that requests record processing.
  4. Support Processing. These are methods for use by support code, i.e. code that implements record processing.

RecordProcess - General Purpose Methods

isEnabled
Is the record enabled?
setEnabled
When record is disabled then all requests to process the record fail. If the record is active when a record is disabled the current process is allowed to complete.
isActive
Is the record active, i.e. processing?
getRecord
Get the record instance to which this RecordProcess is attached.
isTrace
Is trace active for this record?
setTrace
Set tracing on or off. When true info messages are sent to pvRecord.message whenever any processing related method of RecordProcess is called.
getSupportState
Get the current support state.

RecordProcess - Record Lifetime Methods.

RecordProcess looks for the fields timeStamp, processAfterStart , and scan. It handles these fields itself. The record support code must ignore these fields.

initialize
Initialize record support. record support, in turn, initializes support that it invokes. Initialize should perform any initialiation not requiring access aanything outside the record. For example it is not permissible to connect to other records. If initialize is successful record support enters state SupportState.readyForStart
start
Start record support. Again record support calls start for any support it invokes. If successful, the support enters state SupportState.ready. Until record support is in the ready state any attempt to process a record will fail.
stop
Stop record support. Record support calls stop for any support it invokes. The support enters state SupportState.readyForStart.
uninitialize
Unitialize record support. It calls unitialize for any support it invokes. The support enters state SupportState.readyForInitialize.

RecordProcess - Record Process Requester Methods

These are methods called by code that wants a record processed.

requestProcessToken
Called by a code that wants to call queueProcessRequest.
releaseProcessToken
Called by code that no longer wants to call queueRequest.
forceInactive
Called by code that has a ProcessToken but will no longer be allowed to call queueProcessRequest.
getRecordProcessRequesterName
Get the name of the recordProcessRequester.
queueProcessRequest
Request to be the record processor. Each record instance can have only one record process requester. If a requester is already registered a message is sent to the requester and false is returned.
process
Request that the record be processed. If the caller has not called setActive the record is prepared for processing. In either case if the record is ready record support process is called. If true is returned the methods implemented by the recordProcessRequester are called to show the results of the process request. If leaveActive is true than when the record completes processing it is left active until setInActive is called. Until the record becomes inactive another request to process the record will fail. Record support is called with the record locked.
If false is returned the request has failed and recordProcessRequester.message is called to provide the reason. If recordProcessRequester is null an IllegalStateException is thrown.
setInActive
Call by the record process requester when it is done with processing. Calling process with leaveActive true and then calling setInactive allows the requester to communicated with other code after the record is unlocked but before it becomes inactive.

RecordProcess - Support Processing methods.

Methods called by support code which may be record support or support called directly or indirectly by record support. Except for processContinue these methods throw an exception unless process or processContinue is running.

requestProcessCallback
Request to be called back after record support has returned but before RecordProcess.process returns. The callback is made with the record unlocked. Thus the callback can request that other records be processed. This is the way support code can process other records. If support code directly request processing of linked records deadlocks can occur.
processContinue
Request that the processContinue method of the support be called. The record will be locked before the support is called. This is the only way asynchronous support code should access a record after it's process method has returned active.
setTimeStamp
Set the time stamp for the record. If no code calls this while a record is being processed, then RecordProcess will set the time stamp if the record has a timeStamp field.
getTimeStamp
Get the latest time stamp set by calls to setTimeStamp

RecordProcessRequester

Methods implemented by code that requests that a record be processed.

becomeProcessor
Called as a result of queueRequeProcessst. The requester can the call process.
canNotProces
Called as a result of queueProcessRequest but the record can not be processed. For example it might be disabled.
lostRightToProcess
Called when code that has a ProcessToken will no longer be allowed to call queueProcessRequest. This can happen if a record is dynamically set to allow only a single process requester.
recordProcessResult
The results of record processing. This is called with the record locked so that the process requester can access data from the record.
recordProcessComplete
Processing is complete. This is called with the record unlocked. If the process requester called process with leaveActive true then the requester must call setInactive.

ProcessCallbackRequester

The method implemented by code that calls requestProcessCallback.

processCallback
The callback to call when the record support process method returns it RecordProcess. Any support code that wants to process other records must use this interface. The callback is called with the record unlocked.

ProcessContinueRequester

The method implemented by code that calls processContinue.

processContinue
A request to call support with the record locked. This is the only way asynchronous support should continue processing.

RecordProcessFactory

A factory is provided to create an instance of RecordProcess for a record instance. It has the method:

public class RecordProcessFactory {
    static public RecordProcess createRecordProcess(
          RecordSupport recordSupport,PVRecord pvRecord);
}

Support

This section describes the interfaces and abstract base class involved with support for fields of an IOC record. This also means support for the record itself.

Support State

Before support is ready for processing it must be ready. In addition on-line add and delete is supported. Thus it is possible to dynamically redefine link fields, array fields, etc. Unless a support module is in the ready state it's process method should not be called and if it is it should just report failure.

    public enum SupportState {
        readyForInitialize,
        readyForStart,
        ready,
        zombie;
    }

    public static SupportState getSupportState(int value);
    public static Enumerated getSupportState(PVField pvField);

SupportState has the following values:

readyForInitialize
Initial state for support. It has been created but has not done much.
readyForStart
Support has done any initialization that does not involve connecting to other records and/or support.
ready
Support is ready for processing.
zombie
Support is being removed and can never again process.

Support

The following are used by support code, i.e. record support, link support, and any other support code that is involved with record processing:

    
    public interface Support extends Requester {
        String getSupportName();
        SupportState getSupportState();
        PVField getPVField();
        void initialize();
        void start(AfterStart afterStart);
        void stop();
        void uninitialize();
        void process(SupportProcessRequester supportProcessRequester);
    }

    public interface SupportProcessRequester {
        void supportProcessDone(RequestResult requestResult);
    }

Support has the methods:

getSupportName
Get the support name.
getRequesterName
A requester method to get the name of the support.
message
A Requester method. This is called to pass messages to the support.
getSupportState
Get the support state.
getPVField
Get the PVField interface for the field that is being supported. For record support this will be the record itself.
initialize
Perform initialization that does not involve accessing other records and/or support.
start
Connect to other records and/or support.
stop
Disconnect from other records and/or support and be ready to again start.
uninitialize
Remove all internal state are prepare to again initialize.
process
Process.

Every Support module must implement the methods initialize, start, stop, and uninitialize. Initialize performs initialization related to the record instance being supported but can not access anything outside the record. Start completes all initialization including linking to the outside, e.g. to other records. Stop must remove all access to the outside. Uninitialize must remove all access to the record instance being supported.

SupportProcessRequester has the method:

supportProcessDone
The callback to call when support is done . Any support code that wants to process other records must implement this interface. This MUST be called with either process or processContinue running.

Record Support

Every record instance has an attached RecordSupport:

    public interface RecordSupport {
        RecordProcess getRecordProcess();
        void setRecordProcess(RecordProcess recordProcess);
        Support getSupport(PVField pvField);
        void setSupport(PVField pvField,Support support);
    }

AbstractSupport

AbstractSupport

Definitions

    public abstract class AbstractSupport implements Support {
        protected AbstractSupport(String name,PVRecordField pvRecordField);
        // methods from Requester
        public String getRequesterName();
        public void message(String message, MessageType messageType);
        // methods that are rarely overridden
        public SupportState getSupportState();
        public PVField getPVField();
        // following normally overridden
        public void initialize();
        public void start(AfterStart afterStart);
        public void stop();
        public void uninitialize();
        public void process(SupportProcessRequester supportProcessRequester);
        // following must always be called when support state changes
        protected void setSupportState(SupportState state);
        // following is for use by support code
        protected boolean checkSupportState(
            SupportState expectedState,String message);
    }

All support code should extend AbstractSupport. Abstract Support implements all Support methods. Thus support code only has to override the methods it needs.

AbstractSupport
The constructor which must be called by the derived support constructor.
getRequesterName
The returns the name passed to constructor.
message
Calls pvField.message.
getSupportState
Gets the current support state.
getPVField
Returns pvField.
initialize
Normally overridden. The default version always succeeds, i.e. enters state readyForStart.
start
Normally overridden. The default version always succeeds, i.e. enters state ready.
stop
Normally overridden. The default version always succeeds, i.e. enters state readyForStart.
unintialize
Normally overridden. The default version always succeeds, i.e. enters state readyForInitialize.
process
Normally overridden. The default version just calls supportProcessRequester.supportProcessDone(RequestResult.success);
setSupportState
This must be called by support whenever it changes state.
checkSupportState
Checks that the state is the expected state and generates an error message if it isn't.

Package org.epics.pvioc.support.rpc

Overview

This package provides support for remote procedure calls from a channel access client. Two types of RPCs are possible:

putProcessGet
This is used if the PVStructure for the data returned by a request always has the same structure.
channelRPC
This is used if a new PVStructure must be send for each request.
putProcessGet RPC

A RPC is implemented via a structure that has the following fields:

argument
A structure that has a set of fields that are defined by the implementation. It defines the argument required by the RPC.
result
Also a structure that has a set of fields that are defined by the implementation. It contains the results.

The client issues a putGet with process request. The put contains the argument and the get retrieves the result.

javaIOC/xml/structure/rpc.xml has the definitions for the structures required by the support provided by this package. The following sections provide a brief description of the argument and result for each support.

channelRPC

A ChannelRPC allows a different PVStructure to be passed to the server and returned to the client for each request.

ExampleChannelRPC

This is an example of how to implement support for a record that supports a ChannelRPC request. See the package description for org.epics.pvaccess.client for details about ChannelRPC.

The example uses the record instance that is in test/channelRPC/channelRPCDB.xml :

<record recordName = "exampleChannelRPC">
    <scalar name = "factoryRPC" scalarType = "string">org.epics.pvioc.support.rpc.ExampleChannelRPCFactory</scalar>
    <structure name = "element">
        <scalar name = "value" scalarType = "double"/>
        <structure name = "alarm" extends = "alarm"/>
        <structure name = "timeStamp" extends = "timeStamp"/>
    </structure>
</record>
</database>

Note that factoryName field. It must give the name of the factory that creates an object that implements interface RPCServer. The example create a PVStructure that has size subfields each of which is a clone of element. Look at the source code for details.



RecordList

This returns a list of the names of a set of records specified by a regular expression. The argument fields are:

database
A scalar string that specifies the name of the database, e. g. master.
regularExpression
A scalar string that is the regular expression. The expression ".*" will return a list of all the records in the database.

The result fields are:

status
A scalar string that is used to report errors.
names
An array wih element type of string. It contains the record names.

StructureList

This returns a list of the names of a set of structures specified by a regular expression. The argument fields are:

database
A scalar string that specifies the name of the database, e. g. master.
regularExpression
A scalar string that is the regular expression. The expression ".*" will return a list of all the structures in the database.

The result fields are:

status
A scalar string that is used to report errors.
names
An array wih element type of string. It contains the structure names.

IocShow

This provides some useful commands for getting information about a pvIOCJava. The argument fields are:

command
This is an enumerated structure that has the following choices:
showBadRecords
This gets a list of all records than have something unusual about them.
showThreads
This provides a list of the names of all the threads created by ThreadCreate.
showMemory
Produces a report of memory usage by Java.
garbageCollect
Asks java to collect garbage and then get memory usage.

The result fields are:

value
A scalar string that provides the result for the request.

RecordShow

This provides some useful commands for getting information about a record The argument fields are:

command
This is an enumerated structure that has the following choices:
showState
Get the state of the record.
setTraceOn
Set trace on for the record.
setTraceOff
Set trace off for the record.
timeProcess
Time how many times per second the record can be processed. This will only succeed if the record does not already have a record process requester.
setEnableOn
Enable the record.
setEnableOff
Disable the record. This prevents the record from processing.
releaseProcessor
Release the current record processor. This should only be used as a last attempt to fee a record with a record process requester that crashed.

The result fields are:

value
A scalar string that provides the result for the request.

SupportStateSet

This allows the support state of a record to be changed The argument fields are:

command
This is an enumerated structure that has the following choices:
idle
A do nothing request.
initialize
Initialize the record. The record must be in the readyForInitialize state.
start
Start the record. It must be in the readyForStart state.
stop
Stop the record and put it in the readyForStart state. It must be in the ready state.
uninitialize
Uninitialize the record and put it in the readyForeInitialize state. It must be in the ready or readyForStart state.

The result fields are:

message
A scalar string that provides the result for the request.

Package org.epics.pvioc.support.basic

Overview

This package contains a set of modules that provide basic support services.

The following factories are provided:

GenericFactory
Generic support for a structure or for an array with elementType of array or structure.
NoopFactory
Support for all fields that just acts like it always succeeds successfully.
ScanFactory
Complete support for the scan field which is defined in comon.xml
Support for linear conversions.
LinearConvertInputFactory
Support for linear conversion of input fields.
LinearConvertOutputFactory
Support for linear conversion of output fields.
ControlLimit
Enforce control limits.
IncrementalFactory
Support for incremental outputs.
EventFactory
Support for a string field that is the name of an event.
DelayFactory
It just causes an asynchronous delay before completing successfully.

Generic Support

    public class GenericFactory {
        public static Support create(PVRecordStructure pvRecordStructure);
    }
Generic Support is used for many record/structure definitions . It is often used because it just looks for fields that have associated support and calls the support. It also has a few conventions so that it works with a variety of support modules. It implements the following semantics:
scan,timeStamp
It does not call the support for field scan or timeStamp because recordProcess handles these fields.
alarm
If field alarm is present and has AlarmSupport then it is handled properly.
fields with associated support.
For each field with support, the support methods are called, i.e. initialize,start,stop,uninitialize, and process. For process, by default, generic waits for each support to finish before it calls the next support. For a stucture subfield the default can be changed by appending a boolean scalar field to the structure and setting the value to false.

The generic support does not force the support for input to do input, the support for output to do output, etc. The generic support merely calls support if it exists. The generic support also does not check the types of any fields but looks for support and calls it if it exists. Thus the generic support can be used for many different types of data and many different types of support.

Noop Support

    public class NoopFactory {
        public static Support create(PVRecordField pvRecordField);
        public static Support create(PVRecordStructure pvRecordStructure);
    }

This can be used for record types that just hold data. It can also be used to provide support for any field. The support acts as though it is synchronous. All Support methods are implemented by just extending AbstractSupport without overriding any methods.

ScanFactory

Support is provided for the scan field. This support is called by recordProcess. The support handles all the fields in structure scan:

The following definitions are provided:

    public class ScanFactory {
        public static Support create(PVRecordStructure pvRecordStructure);
    }

Control Limit

This is code to enforce control limits. It handles the following type of definitions:

<record name = "aoIncremental">
    <scalar name = "value" type = "double">
        <auxInfo name = "pvReplaceFactory" type = "string">controlLimitFactory</auxInfo>
    </scalar>
    <structure name = "alarm" type = "alarm" />
    <structure name = "timeStamp" type = "timeStamp" />
    <structure name = "control" type = "control" >
        <structure name = "limit">
            <scalar name = "low">0.0</scalar>
            <scalar name = "high">8.0</scalar>
        </structure>
    </structure>

Linear Conversion

Support is available for input and output linear conversions. The xml definitions for linear conversions are:

linearConversion

The structure linearConversion defines the fields used for linear conversions. The fields slope and intercept are the values used to convert a rawValue to engineering units. The rawValue is an integer value usually read from an ADC (Analog to Digital Convertor). The slope and intercept can be specified directly of calculated from the low and high engineering and device values. If the later method is chosen the engUnitsLow and engUnitsHigh must be provided. deviceLow and deviceHigh are either provided automatically by support of must be provided. The following are the fields in structure lineraConversion:

engUnitsLow
A double equal to the engineering units value corresponding to the value for deviceHigh.
engUnitsHigh
A double equal to the engineering units value corresponding to the value for deviceLow.
deviceHigh
An int equal to the maximum value for the rawValue.
deviceLow
An int equal to the minimum value for the rawValue.
slope
The slope for the linear conversion.
intercept
The intercept for the linear conversion.
LinearConvertInputFactory
    public class LinearConvertFactory {
        public static Support create(PVStructure pvStructure);
    }

This is the factory that implements linear input conversion, i.e. it converts a rawValue to engineering units. The auxInfo must have supportName "linearConvertInputFactory" .A field for linear conversion for input is a structure containing the following fields:

rawValue
The raw value which is obtained via the support attached to the input field or by a put to this field.
linearConvert
The structure providing the conversion parameters.
input
The link for reading the rawValue. If a field named is defined and has support the support is called.
LinearConvertOutputFactory
    public class LinearConvertFactory {
        public static Support create(PVStructure pvStructure);
    }

This is the factory that implements linear output conversion, i.e. it converts a value in engineering units to a rawValue.The auxInfo must have supportName "linearConvertOutputFactory". A field for linear conversion for output is a structure containing the following fields:

rawValue
The raw value which is obtained via the support attached to the input field or by a put to this field.
linearConvert
The structure providing the conversion parameters.
output
The link for reading the rawValue. If a field named is defined and has support the support is called.

Incremental Support

This is support for incremental outputs.For example it supports a record that has the following structure:

<record name = "aoIncremental">
    <scalar name = "value" type = "double" />
    <structure name = "alarm" type = "alarm" />
    <structure name = "timeStamp" type = "timeStamp" />
    <structure name = "desired" type = "incrementalDouble" >
        <scalar name = "value">
            <auxInfo name = "pvReplaceFactory" type = "string">controlLimitFactory</auxInfo>
        </scalar>
        <scalar name = "rateOfChange">.02</scalar>
        <scalar name = "incremental">true</scalar>
        <structure name = "control" type = "control" >
            <structure name = "limit">
                <scalar name = "low">0.0</scalar>
                <scalar name = "high">8.0</scalar>
            </structure>
        </structure>
    </structure>
</record>

This uses the Java definitions:

    
    public class IncrementalFactory {
        public static Support create(PVField pvField);
    }

This supports the following fields:

value
The value field.
desired.value
This must be a double field. When this field changes the support changes the value field until it has the desired value. If control limits are specified then the desired value is forced to be within the control limits. If incrementalOutput is true then each time the record is processed the value field is changed by rateOfChange until the desired value is reached.
incremental
This field is optional. If the record/structure has a field named then it must be have type boolean. If not present the default is true. If this has the value true the output is adjusted by rateOfChange otherwise the value field is changed in one step to the desired value.
rateOfChange
If incrementalOutput is true this is the amount the value will change each time the record is processed.

Event Support

    public class EventFactory {
        public static Support create(PVField pvField);
    }

EventFactory implements record or structure support for announcing a scan event. The event name is given in the field:

value
This must be a string field named located in the parent of this field, which is normally the value field itself.

Whenever the record is processed eventScanner.announce is called, i.e. the support announces an event. All event scanned records with the event name associated with the value field are processed. Each time process is called, the event support checks to see if the event name has changed.

DelaySupport

This is link support that simulates asynchronous support. It uses a configStructure that has the definition:

<structure name = "delayFactory">
 <scalar name = "supportFactory" type = "string">
   org.epics.pvioc.support.basic.DelayFactory</scalar>
</structure>

<structure name = "delay">
  <auxInfo name = "supportFactory" type = "string">delayFactory</auxInfo>
  <!-- min, max, inc are delay in milliseconds -->
  <scalar name = "min" type = "long" />
  <scalar name = "max" type = "long" />
  <scalar name = "inc" type = "long" />
</structure>

where

min
The minimum delay
max
The maximum delay
inc
The delay increment between process requests

Each time process is called it delays a number of milliseconds determined by min,max, and inc. It starts with a delay on min. Each time it proceses it increases the delay by inc until it reaches max. It then goes back to a delay of min.

The factory definition is:

    public class DelaySupportFactory {
        public static Support create(PVStructure pvStructure);
    }

Package org.epics.pvioc.support.calc

Overview

This package provides support for calculations. A calculation computes a result that is assigned to the value field. This package provides:

  1. ExpressionCalculator
    This is support for an expression that has the same syntax as a Java scalar expression. For example:
          a + b*c * Math.sin(d)
        
    For such expressions a complete expression factory is provided.
  2. Calculation Intrastructure Support
    CalcArgArray support,AbstractCalculatorSupport, and the Database Definitions related to calculations.

Basic calculation support is described first and then ExpressionCalculator.

Basic Calculation Support

Database Definitions for Calculations

xml/structure/calx.xml defines the following:

<structure name = "calcArgsFactory">
  <scalar name = "supportFactory" type = "string">
     org.epics.pvioc.support.calc.CalcArgsFactory</scalar>
</structure>

<structure name = "calcArg" >
  <auxInfo name = "supportFactory" type = "string">genericFactory</auxInfo>
  <!-- instance must define value -->
  <scalar name = "name" type = "string" />
</structure>

<structure name = "expressionCalculator" >
  <auxInfo name = "supportFactory" type = "string">expressionCalculatorFactory</auxInfo>
  <scalar name = "expression" type = "string" />
</structure>

<structure name = "calculation" >
  <auxInfo name = "supportFactory" type = "string">genericFactory</auxInfo>
  <structure name = "calcArgs">
     <!-- each field of calcArgs must be a calcArg structure -->
     <auxInfo name = "supportFactory" type = "string">calcArgsFactory</auxInfo>
  </structure>
  <structure name = "calculator" type = "expressionCalculator" />
  <structure name = "alarm" type = "alarm" />
</structure>

calculation is the structure used for calculations. The parent of calculation must have a field with the name value and must have a type compatible with the calculator.

Structure calculation has the fields:

calcArgs
A field is a sequence of structures with each being a calcArg structure and the support calcArgArray. If the calculator uses any arguments from calcArgs this must be present. The name assigned to a calcArg field is the argument name for the calculation.
calculator
This field has support that implements the calculation. The default support and structure name is expressionCalculator. This field must be present and must have support.
alarm
This is present so that a record can be put in alarm if a calculation finds problems.

calcArg is a structure that must contain at least the field

value
This must be defined in record instances with a type that is compatible with the expression.
other
Other fields can also be defined. For example a field named input can be defined as a structure with associated support that puts data into the value field.

expressionCalculator is the default structure for the calculator field of structure calculation. It is the structure required by support expressioncalculator. It has a single field:

expression
The expression using Java syntax.

Support calcArgsFactory is the support for field calcArgs. Support expressionCalculator is the support described in the next section.

Performing Calculations

A calculation is performed by a calculation support. The following is done. When the calculation support, which is generic, is called it calls the calcArgArray support and the calculator support. For each element of calcArgArray, the calcArgArray support calls The support for any subfields that have support. The calcArgArray support extends Support to provide the additional method

    PVField getPVField(String argName);

which is used by the calculator support to get arguments. The calculator support uses the calcArgArray values to compute the calculated value.

calcArgs

This support implements support for a structure than is a sequence of calcArg structures, which has the fields:

value
A value for this argument. NOTE that record instances must define a value specifying the type required by the calculation expression.
other
Other fields can be defined. For example a field input which is a link for obtaining the value for this argument. If no additional field specified then no input is read and the value field can just be set by the user.

ExpressionCalculator

This is support for an expression that has the form of a valid java expression.

Simple Examples

The following example is a counter, i.e. each time the record is processed the value field is incremented by 1.

<record name = "reallySimpleCounter">
    <scalar name = "value" type = "byte" />
    <structure name = "alarm" type = "alarm" />
    <structure name = "timeStamp" type = "timeStamp" />
    <structure name = "input" type = "calculation" >
      <structure name = "calculator">
        <scalar name="expression">value+1</scalar>
      </structure>
    </structure>
</record>

The following is an example that has arguments min, max, and inc. Each time the record is processed the current value is incremented by inc. If the result is less than or equal to max it becomes the new value; otherwise value is set to max. Note that < must be given as the xml escape sequence for < , i.e. &lt;

<record name = "counter">
    <structure name = "alarm" type = "alarm" />
    <structure name = "timeStamp" type = "timeStamp" />
    <scalar name = "value" type = "double" />
    <structure name = "input" type = "calculation" >
       <structure name = "calcArgs">
          <structure name = "min">
            <scalar name = "value" type = "double" >0.0</scalar>
          </structure>
          <structure name = "max">
            <scalar name = "value" type = "double" >10.0</scalar>
          </structure>
          <structure name = "inc">
            <scalar name = "value" type = "double" >0.5</scalar>
          </structure>
       </structure>
       <structure name = "calculator">
         <scalar name = "expression">(value+inc)&lt;=max ? value+inc : min</scalar>
       </structure>
    </structure>    
</record>

The next example computes the sin of an argument given in radians:

<record name = "sin">
    <scalar name = "value" type = "double" />
    <structure name = "alarm" type = "alarm" />
    <structure name = "timeStamp" type = "timeStamp" />
    <structure name = "input" type = "calculation" >
       <structure name = "calcArgs">
          <structure name = "a">
            <scalar name = "value" type = "double" >0.5</scalar>
          </structure>
       </structure>
       <structure name = "calculator">
         <scalar name = "expression">
             Math.sin(Math.PI*a)
         </scalar>
       </structure>
    </structure>   
</record>

The last example demonstrates the use of the ?: operator:

<record name = "check">
    <scalar name = "value" type = "boolean" />
    <structure name = "alarm" type = "alarm" />
    <structure name = "timeStamp" type = "timeStamp" />
    <structure name = "input" type = "calculation" >
       <structure name = "calcArgs">
          <structure name = "a">
            <scalar name = "value" type = "byte" >0</scalar>
          </structure>
          <structure name = "b">
            <scalar name = "value" type = "byte" >1</scalar>
          </structure>
       </structure>
       <structure name = "calculator">
         <scalar name = "expression">
            (a-b)==0 ? true : false
         </scalar>
       </structure>    </structure>
</record>
Expression Syntax

A expression is has the form of a valid Java scalar expression. The result of the expression is assigned to the value field.

The precedence is the same as the Java precedence. For example the following:

   a + b*c + Math.sin(e*f)
Is the same as:
   ((a + (b*c)) + Math.sin((e*f)))
Expression Arguments

An argument can be one of the following:

variable
The argument is one of the calcArgArray names.
value
The "value" appears as an argument than the argument is the value field itself. Note that this is the first value field found searching up the parent tree.
boolean constant
The argument is "true" or "false"
string constant
A argument enclosed in "" is a string constant.
integer constant
The argument is a valid java integer constant. It becomes an int constant unless it is terminated with the character L, which means it is a long integer constant. The value can also be given as a valid hex integer, e.g. 0x0fff.
real constant
The argument is a valid java real constant, i.e. it is either a float or double constant.
Math constant
The argument is either Math.PI or Math.E
Unary Operators

The supported unary operators are:

+
Unary plus. The argument can be any numeric type.
-
Unary minus. The argument can be any numeric type.
~
Bitwise Complement. The argument can be any integer type.
!
Boolean not. The argument must be boolean.
Binary Operators

The supported binary operators are:

*
Multiplication. The argument can be any numeric type.
/
Division. The argument can be any numeric type.
%
Remainder. The argument can be an integer type.
+
Binary plus. The arguments can be any numeric type.
+
String concatenation. The first argument must be a string.
-
Binary minus. The arguments can be any numeric type.
<<
Left shift. The arguments must be an integer type.
>>
Right shift sign extended. The arguments must be an integer type.
>>>
Right shift zero extended. The arguments must of an integer type.
<
Less than. The arguments must be numeric.
<=
Less than or equal. The arguments must be numeric.
>
Greater than. The arguments must be numeric.
>=
Greater than or equal. The arguments must be numeric.
==
Equal. The arguments can be any supported type.
!=
Not equal. The arguments can be any supported type.
&
Integer and. The arguments must be integer.
&
Boolean and. The arguments must be boolean.
^
Bitwise XOR. The arguments must be integer.
^
Boolean XOR. The arguments must be boolean.
|
Bitwise or. The arguments must be integer.
|
Boolean or. The arguments must be boolean.
&&
Conditional and. The arguments must be boolean.
||
Conditional or. The arguments must be boolean.
Ternary Operator

The ternary operator ?: is supported.

Math Functions

All the functions defined in java.lang.Math are supported.

Constant optimization

If the arguments of an operator are all constants then the result is determioned during initialization and the operation not performed when the record is processed.

Test

test/calc contains tests for ExpressionCalculator. After the test is initialized use the swtshell to bring up the introspectDatabase screen. Select the showBadRecordss button. No records should appear except possibly active records. The only records without checks are random, calcSimpleCounter, and calcCounter. These can be checked manually. For random issue get with process requests. For calcSimpleCounter and calcCounter just monitor the records.

Package org.epics.pvioc.support.calc.example

This package gives some examples of how to extend AbstractCalculatorSupport. It has the following examples:

arrayIncrement
The value field must be an array of doubles. When process is called 1 is added to each element of the array.
booleanArrayToggle
The value field must be an array of boolean. When process is called each array element is toggled between false and true.
arrayAdd
It has arguments named a and b. The fields a, b, and value must each be a double array. When process is called it sets value equal to a + b.

Package org.epics.pvioc.support.alarm

Overview

Support is provided for the alarm field itself and raising alarms for the primitive types and for an enumerated structure.

The next section describes the xml syntax for attaching alarm support to a value field and raising alarms for the value field. The remaining sections describe the support.

An alarm is defind as follows:

<structure structureName = "alarm">
  <scalar name = "severity" scalarType = "int" />
  <scalar name = "status" scalarType = "int" />
  <scalar name = "message" scalarType = "string" />
</structure>

Thus an alarm is defined by a structure that has two fields:

severity
An integer that represents a severity index. org.epics.pvdata.property has definitions for AlarmSeverity, Alarm, and AlarmFactory that implements a enum where the severity is the index.
status
An integer that represents a status index. org.epics.pvdata.property has definitions for AlarmStatus, Alarm, and AlarmFactory that implements a enum where the status is the index.
message
A string field named message.

The following factories are provided:

AlarmSupportFactory
Complete support for field alarm.
BooleanAlarmFactory
Alarm support for boolean fields.
ByteAlarmFactory
Alarm support for byte fields.
ShortAlarmFactory
Alarm support for short fields.
IntAlarmFactory
Alarm support for int fields.
LongAlarmFactory
Alarm support for long fields.
FloatAlarmFactory
Alarm support for float fields.
DoubleAlarmFactory
Alarm support for double fields.
EnumeratedAlarmFactory
Alarm support for enum field..

XML definitions For alarms

Support for raising alarms is provided for all the primitive types and for an enumerated structure. Each can be defined for any field of a record that has the corresponding type and has the field name "value". A record instance can have multiple fields with associated alarm support. Since a structure can have only one field named value, the top level of a structure can only have a single alarm support but each substructure can also have alarm support. Three basic types of support are provided: numeric, boolean, and enumerated. Each is discussed in a separate section below.

Numeric Scalar

Support is provided for all the numeric scalar types: byte, short, long, float, and double. The following desription is for double but the support for the other types is similar.

The structures associated with doubleAlarm are :

<structure structureName = "doubleAlarm" >
  <auxInfo name = "supportFactory" scalarType = "string">org.epics.pvioc.doubleAlarmFactory</auxInfo>
  <scalar name = "active" scalarType = "boolean" />
  <scalar name = "lowAlarmLimit" scalarType = "double" />
  <scalar name = "lowWarningLimit" scalarType = "double" />
  <scalar name = "highWarningLimit" scalarType = "double" />
  <scalar name = "highAlarmLimit" scalarType = "double" />
  <scalar name = "lowAlarmSeverity" scalarType = "int" />
  <scalar name = "lowWarningSeverity" scalarType = "int" />
  <scalar name = "highWarningSeverity" scalarType = "int" />
  <scalar name = "highAlarmSeverity" scalarType = "int" />
  <scalar name = "hystersis" scalarType = "double" />
</structure>

The doubleAlarm structure must appear in a structure at the same level as a double scalar field named value. There must be an alarm field at the same level.:q

An example for a double field is:

<record recordName = "simpleCounter" >
    <structure name = "alarm" extends = "alarm" />
    <structure name = "timeStamp" extends = "timeStamp" />
    <scalar name = "value" scalarType = "int" />
    <structure name = "input" extends = "calculation" >
      <structure name = "calculator">
        <scalar name ="expression">(value+1)&lt;=10 ? value+1 : 0</scalar>
      </structure>
    </structure>
    <structure name = "valueAlarm" extends = "intAlarm">
      <scalar name = "active">true</scalar>
      <scalar name = "lowAlarmLimit">2</scalar>
      <scalar name = "lowAlarmSeverity">2</scalar>
      <scalar name = "lowWarningLimit">4</scalar>
      <scalar name = "lowWarningSeverity">1</scalar>
      <scalar name = "highWarningLimit">8</scalar>
      <scalar name = "highWarningSeverity">1</scalar>
      <scalar name = "highAlarmLimit">10</scalar>
      <scalar name = "highAlarmSeverity">2</scalar>
    </structure>
</record>

This example reproduces the semantics of alarm support for an EPICS V3 ai record but the details are different. The above xml definition is for a record instance but it could also apply to a substructure of a record if record is replaced by structure in the above example. What is important is that the structure has fields named value and alarm and that a structure field that extends doubleAlarm is defined.

Boolean

A example of attaching alarm support to a boolean record or structure is:

<record recordName = "booleanExample">
    <scalar name = "value" scalarType = "boolean"/>
    <structure name = "alarm" extends = "alarm" />
    <structure name = "timeStamp" extends = "timeStamp" />
    <structure name = "valueAlarm" extends = "booleanAlarm">
      <scalar name = "active">true</scalar>
      <scalar name = "falseSeverity">1</scalar>
      <scalar name = "trueSeverity">2</scalar>
    </structure>
</record>

The booleanAlarm structure also has a fields named changeOfStateAlarm and changeOfStateMessage. It semantics should be easy to see.

Enumerated

Before explaining the example let's first define the structure associated with enumerated alarm support.

<structure structureName = "enumeratedAlarm">
  <auxInfo name = "supportFactory" scalarType = "string">org.epics.pvioc.enumeratedAlarmFactory</auxInfo>
  <scalar name = "active" scalarType = "boolean" />
  <array name = "stateSeverity" scalarType = "int" />
  <scalar name = "changeStateSeverity" scalarType = "int" />
</structure>

An enumerated structure appears in a structure at the same level as an enumerated field named value. It has the fields:

active
Is alarm processing active?
stateSeverity
An array of alarmSeverity values. There must be exactly 1 for each element of the value field.
changeStateSeverity
The alarm severity for change of state.

The following shows how to create a record with enumerated alarms.

<record recordName = "enumerated">
     <structure name = "value" extends = "enumerated">
       <array name = "choices">zero,one,two,three,four</array>
    </structure>
    <structure name = "alarm" extends = "alarm" />
    <structure name = "timeStamp" extends = "timeStamp" />
    <structure name = "valueAlarm" extends = "enumeratedAlarm">
            <scalar name = "active">true</scalar>
            <scalar name = "changeStateSeverity">0</scalar>
            <array name = "stateSeverity">2,1,0,1,2</array>
    </structure>

</record>

Alarm Support

AlarmSupport is support for a field named which must have type structure and the structure must be an alarm structure. Within the structure hierarchy of a record multiple alarm fields can exist. Some support, e.g. generic, calls the support for the alarm field defined in the top level structure (defined in common.xml). If multiple alarm fields reside in a record then the top level alarm field, which is what the outside world normally accesses has a severity at least as great as any of the lower level alarms.

interface AlarmSupport extends Support{
    void beginProcess();
    void endProcess();
    boolean setAlarm(String message, AlarmSeverity severity,AlarmStatus status);
    Alarm getAlarm();
}

class AlarmSupportFactory {
    public static Support create(PVRecordStructure,pvRecordStructure)
    public static AlarmSupport getAlarmSupport(PVRecordField pvRecordField);
}

AlarmSupport provides the methods:

Support
Standard support methods..
beginProcess
This is called when a field begins processing. It must be called by support for the structure that has alarm as a subfield. Support generic calls it.
endProcess
This is called when a record finishes processing.It must be called by support for the structure that has alarm as a subfield. Support generic calls it. If setAlarm was not called since beginProcess was called than it makes sure that the severity is noAlarm. If the severity and/or message was changed during record processing it calls postPut.
setAlarm
While a record is processing code, normally another support module, can call setAlarm. This method changes the new message, severity, and status only if the severity passed to setAlarm is greater than the current new severity or if this is the first call since the record started processing.
getAlarm
Get the Alarm interface. This interface is defined in org.epics.pvdata.property.

AlarmFactory provides the static methods:

create
Create support for a alarm field. This is called by SupportCreation.
getAlarmSupport
Get the alarm support for the field or return null if none is found.

Value Alarms

Support is provided for alarms for the following types of fields: boolean, numeric, and enumerated.

Boolean Alarms
    public class BooleanAlarmFactory {
        public static Support create(PVRecordStructure pvRecordStructure);
    }

This provides support for reporting alarms for boolean fields. The configurationStructure must be a structure booleanAlarm, which has the fields:

active
A boolean field. If (false,true) then alarm conditions (are not,are) checked.
falseAlarm
An alarmSeverity menu. This specifies the severity if the value field is false.
trueAlarm
An alarmSeverity menu. This specifies the severity if the value field is true.
changeStateAlarm
An alarmSeverity menu. This specifies the severity if the value field changes.
Numeric Alarms
    public class ByteAlarmFactory {
        public static Support create(PVRecordStructure pvRecordStructure);
    }
    public class ShortAlarmFactory {
        public static Support create(PVRecordStructure pvRecordStructure);
    }
    public class IntAlarmFactory {
        public static Support create(PVRecordStructure pvRecordStructure);
    }
    public class LongAlarmFactory {
        public static Support create(PVRecordStructure pvRecordStructure);
    }
    public class FloatAlarmFactory {
        public static Support create(PVRecordStructure pvRecordStructure);
    }
    public class DoubleAlarmFactory {
        public static Support create(PVRecordStructure pvRecordStructure);
    }

The above factories provide alarm support for the associated type of field, e.g. FloatAlarmFactory provides alarm support for a field of type float. The support for each type except that float and double also support hystersis: If value goes into alarm this is the amount it must come out of alarm before the alarm severity is modified. This prevents alarm .

Enumerated Alarms
    public class EnumeratedAlarmFactory {
        public static Support create(PVRecordStructure pvRecordStructure);
    }

The above factory provides support for an enumerated structure field.

The enumeratedAlarm structure has the following fields:

active
A boolean field. If (false,true) then alarm conditions (are not,are) checked.
stateSeverity
An array of stateSeverity alarmSeverity menu definitions. When the process method is called the value field is the index for this array. The corresponding alarmSeverity menu is found and it determines the alarm severity.
changeStateAlarm
An alarmSeverity menu. This specifies the severity if the value field changes.

Package org.epics.pvioc.support.caLink

Overview

This is support for channel access links. It is implemented by making client calls to CAJv4. It provides an implementation of support for the following:

caProcessLink
Support that requests that another record process without transfering any data.
caInputLink
Support that 1) optionally requests that another record process, and 2) transfers data from the other record this record..
caOutputLink
Support that 1) transfers data to another record, and 2) optionally requests that the other record process.
caMonitorLink
Support for monitoring another record. A monitor returns data.
caMonitorNotifyLink
Support for monitoring another record. A monitor does not return data.

Data Types Supported

Each requires that other support code, e.g. record support knows how to call them.

The types of data that can be transfered are.

where

valueType
The Type for the value field.
linkType
The Type for the pvname.

Support Structure Definition

Look at the structure definitions in javaIOC/dbd/structures/caLink.xml for a description of how the various structures are defined.

The following is an example of a definition for using caInputLink.

<record recordName = "exampleInput">
    <scalar name = "value" scalarType = "double"/>
    <structure name = "alarm" extends = "alarm" />
    <structure name = "timeStamp" extends = "timeStamp" />
    <structure name = "display" extends = "display" />
    <structure name = "input" extends = "caInputLink">
        <scalar name = "providerName">pvAccess</scalar>
        <scalar name = "pvname">targetRecord</scalar>
        <scalar name = "request" scalarType = "string">value,alarm,display</scalar>
    </structure>
</record>

The request must provide a request definition as defined in package org.epics.pvdata.pvCopy. It can be given as either a scalar string or as a structure. The example above uses the easiest method, which is to define a scalar string field. The value of the field is a comma separated list of top level fields in the record to which the support is attached. The example asks to get the value, alarm, and display from the target record.

Package org.epics.pvioc.support.dbLink

Overview

This is support for channel access links. It is implemented by making client calls to org.epics.pvioc.dbLink. It provides an implementation of support for the following:

dbProcessLink
Support that requests that another record process without transfering any data.
dbInputLink
Support that 1) optionally requests that another record process, and 2) transfers data from the other record this record..
dbOutputLink
Support that 1) transfers data to another record, and 2) optionally requests that the other record process.

Data Types Supported

Each requires that other support code, e.g. record support knows how to call them.

The types of data that can be transfered are.

where

valueType
The Type for the value field.
linkType
The Type for the pvname.

Look at the structure definitions in javaIOC/dbd/structures/dbLink.xml for a description of how the various structures are defined.

Package org.epics.pvioc.support.device

Overview

This package will have support for device abstractions. For now it only has a power supply example.

Power Supply Support

    public class PowerSupplyFactory {
        public static Support create(PVStructure pvStructure);
    }

This is an example of support for a power supply. Given a voltage and power it computes the current. It supports fields for reading the voltage and for writing the current. The complete set of fields it suppports are:

voltage
This is required. It must be a structure containing a scalar double field named value and an alarm field.
current
This is required. It must be a structure containing a scalar double field named value and an alarm field.
power
This is required. It must be a a structure containing a scalar double field named value and an alarm field.

Package org.epics.pvioc.pvAccess

pvAccess Server

This allows a pvAccess client to access pvIOCJava records.

pvAccess client

This allows code in the JavaIOc to access remote pvAccess servers.

Package org.epics.pvioc.pvCopy

Overview

NOTE FOR Casual Users: For users that just want to create pvRequest arguments for pvAccess skip to the next section.

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.

The Channel interface provided by pvAccess has create calls for each type of request, e. g. createChannelGet, createChannelPut, etc. Each of these has an argument "PVStructure pvRequest". The pvRequest describes two things: 1) The set of fields of the record to which the channel is connected, and 2) record and field options. This package provides two services: 1) a utility method that, given a specially encoded string, creates a pvRequest structure that can be passed to the Channel create methods. and 2) Implements the mapping between the client request fields and the record.

The next section describes the utility for creating a pvRequest. This is the only section of interest to users. The remaining sections are of interest to developers including developers who create new services.

The third section describes the layout of a pvRequest structure. This is of interest to developers of client applications that use new services.

The remaining sections describe the code implemented by this package.

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:

BitSetUtil
An interface that curently has only one method, compress, which optimizes the bit settings for a PVStructure.
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.
PVShareFactory
A factory that replaces a PVField with an implementation that accesses the data from a shared field.

Request String

Issuing the request:

    PVStructure pvRequest = CreateRequestFactory.createRequest(String request,this);

creates a pvRequest argument for the various create methods provided by interface Channel. NOTE: The full path is org.epics.pvaccess.client.CreateRequestFactory.

Simple Requests

Before starting lets first give some examples that satisfy clients such as Synoptic Display, Alarm, and Archive tools. These clients 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:

    PVStructure pvRequest = CreateRequestFactory.createRequest("value,alarm,timeStamp",this);

If the record is does not have the desired field at the top level then the field can still be accessed with a simple string. For example:

    pvRequest = CreateRequestFactory.createRequest("power.value,alarm,timeStamp,power.display",this);

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

powerSupply
    alarm
    timeStamp
    power
       value
       display
       ...
    ...

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:

    pvRequest = CreateRequestFactory.createRequest("record[process=true]field(value,alarm,timeStamp)",this);

Full Request Syntax

A request is of the form:

    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,...]

This will generate the equivalent of :

    <structure name = "record">
         <scaler name = "name" scalarType = "string">value</scalar>
         <!-- other options -->
    </structure>

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

    fullFieldName[option,...]    // options are optional
or
    fieldName{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 PVRecord is selected.

Examples

The following examples are for either a simple record or for a power supply record. These are records that have one of the following structures:

simpleRecord
    value
    alarm
    timeStamp
    display
    .. other fields like input, etc

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

The following gets the alarm, timeStamp, and power.value.

    PVStructure pvRequest = CreateRequestFactory.createRequest("alarm,timeStamp,power.value",this);

The following does the same thing.

    PVStructure pvRequest = CreateRequestFactory.createRequest("field(alarm,timeStamp,power.value)",this);


In either case the PVStructure holding data for the requester will have the structure:

 top
     alarm           // from record.alarm
     timeStamp       // from record.timeStamp
     value           // from record.power.value

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.

     PVStructure pvRequest = CreateRequestFactory.createRequest{
        "record[process=true]field(alarm,timeStamp,power.value[shareData=true])",this);

The options are to process the record and to share the value data with the power.value field in the PVRecord.

Power Supply Example

The following:

    PVStructure pvRequest = CreateRequestFactory.createRequest(
       "field(alarm,timeStamp"
       + ",power{power.value,power.alarm}"
       + ",current{current.value,current.alarm}"
       + ",voltage{voltage.value,voltage.alarm})",this);

Defines a client structure as follows:

top
   alarm          // from record.alarm
   timeStamp      // from record.timeStamp
   power          // appears because of pvRequest
      value       // from record.power.value
      alarm       // from record.power.alarm
   current        // appears because of pvRequest
      value       // from record.current.value
      alarm       // from record.current.alar.
   voltage        // appears because of pvRequest
      value       // from record.voltage.value
      alarm       // from record.voltage.alarm

pvRequest

PVStructure pvRequest

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

    <structure>
        <structure name = "record">
            <!-- 0 or more options with the definition-->
            <scalar name = "optionName" scalarType = "string">value</scalar>
        </structure>
        <structure name = "field"> <!-- or putField and separate definition for getField -->
            <!-- 0 or 1 fieldList definition -->
            <scalar name = "fieldList" scalarType = "string">
                fullPVRecordFieldName,...,fullPVRecordFieldName
            </scalar>
            <!-- 0 or more fieldName definitions of the form -->
            <structure name = "fieldName">
                 <!-- 0 or 1 definition of -->
                 <structure name = "leaf">
                     <scalar name = "source" scalarType = "string">
                          fullPVRecordFieldName
                     </scalar>
                     <!-- 0 or more options for field -->
                 </structure>
                 <!-- If not a leaf than 1 or more-->
                 <structure name = "fieldName">
                     <!-- recursive definition of field-->
                 </structure>
            </structure
        </structure
    </structure>

     OR
    <structure>
        <!-- 0 or 1 fieldList definition -->
        <scalar name = "fieldList" scalarType = "string">
            fullPVRecordFieldName,...,fullPVRecordFieldName
        </scalar>
        <!-- 0 or more fieldName definitions of the form -->
        <structure name = "fieldName">
            <!-- 0 or 1 definition of -->
            <structure name = "leaf">
                <scalar name = "source" scalarType = "string">
                    fullPVRecordFieldName
                </scalar>
                <!-- 0 or more options for field -->
            </structure>
            <!-- If not a leaf than 1 or more-->
            <structure name = "fieldName">
                <!-- recursive definition-->
            </structure>
        </structure
    </structure>

where

record
The options that apply to the entire record.
option
This is of the form
<scalar name = "optionName" scalarType = "string">value</scalar>
field
Definitions that select fields of the PVRecord and options for the fields. This definition is recursive.
fieldList
A comma separated list of fullPVRecordFieldNames. Each will become a single field in the structure created by PVCopy with a field name that is the same as the field name of the corresponding fullPVRecordFieldName. For example if the fullPVFieldName = "power.value" then the field name is "value".
fieldName
The field name that will appear in the PVStructure that is a copy of the fields selected from the PVRecord.
leaf
This definition is a leaf element in the pvRequest structure. The field name in the copy structure will be fieldName. The field type will be is same as the type of fullPVRecordFieldName. This it could be a structure.
fullPVRecordFieldName
The full fieldname of PVRecord to which the field of copy will map.

Note:

Two examples of options are process and shareData.

Process is a record option:

    <structure name = "record">
         <scalar name = "process" scalarType = "string">true</scalar>
    </structure>

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 name = "field">
       ...
       <structure name = "value">
           <structure name = "leaf">
              <scalar name = "source" scalarType = "string">value</scalar>
              <scalar name = "shareData" scalarType = "string">true</scalar>
           </structure>
       </structure>
       ...
   </structure>

This is a request to share the actual data rather than creating a copy.

A pvRequest structure can be created via the PVDataCreate interface implemented by PVDataCreateFactory or by a call to CreateRequestFactory.createRequest.

Examples

The following examples are for the simple and powerSupply records described in the previous section.

Simple example
The quickest Way

The following structure defines a request for three fields: alarm, timeStamp, and power.value

<structure>
    <scalar name = "fieldList" scalarType = "string">
       alarm,timeStamp,power.value
    </scalar>
</structure>

The following shows how example can be done by directly calling pvDataCreate.

    PVStructure pvRequest = pvDataCreate.createPVStructure(null, "", new Field[0]);
    PVArrayString pvString = (PVString)pvDataCreate.createPVScalar(pvRequest,"fieldList",ScalerType.pvString);
    pvString.put("alarm,timeStamp,power.value");
    pvRequest.appendPVField(pvString);
Using the field notation

The following structure defines a request for three fields: alarm, timeStamp, and power.value

<structure>
    <structure name = "field">
        <scalar name = "fieldList" scalarType = "string">
           alarm,timeStamp,power.value
        </scalar>
    </structure>
</structure>

The following shows how the example can be done by directly calling pvDataCreate.

    PVStructure pvRequest = pvDataCreate.createPVStructure(null, "", new Field[0]);
    PVStructure pvField = pvDataCreate.createPVStructure(pvRequest,"field", new Field[0]);
    PVArrayString pvString = (PVString)pvDataCreate.createPVScalar(pvField,"fieldList",ScalerType.pvString);
    pvString.put("alarm,timeStamp,power.value");
    pvField.appendPVField(pvString);
    pvRequest.appendPVField(pvField);

In either case (quickest way or using the field notation) the PVStructure holding data for the requester will have the structure:

 top
     alarm           // from record.alarm
     timeStamp       // from record.timeStamp
     value           // from record.power.value

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.

<structure>
    <structure name = "record">
        <scalar name = "process" scalarType = "string">true</scalar>
    </structure>
    <structure name = "field">
        <scalar name = "fieldList" scalarType = "string">
           alarm,timeStamp
        </scalar>
        <structure name = "value">
            <scalar name = "leaf" scalarType = "string">power.value</scalar>
            <scalar name = "shareData" scalarType = "string">true</scalar>
        </structure>
    </structure>
</structure>

The options are to process the record and to share the value data with the power.value field in the PVRecord.

Power Supply Example

The following structure defines a request for alarm, timeStamp, power, current, and voltage. Power, current, and voltage will each be a structure with two fields: value and alarm.

<structure>
    <structure name = "field">
        <scalar name = "fieldList" scalarType = "string">alarm,timeStamp</scalar>
        <structure name = "power">
            <scalar name = "fieldList" scalarType = "string">
                power.value,power.alarm
            </scalar>
        </structure>
        <structure name = "current">
            <scalar name = "fieldList" scalarType = "string">
                current.value,current.alarm
            </scalar>
        </structure>
        <structure name = "voltage">
            <scalar name = "fieldList" scalarType = "string">
                voltage.value,voltage.alarm
            </scalar>
        </structure>
    </structure>
</structure>

The following shows how this can be done by directly calling pvDataCreate.

    PVStructure pvRequest = pvDataCreate.createPVStructure(null, "", new Field[0]);
    PVStructure pvField = pvDataCreate.createPVStructure(pvRequest,"field", new Field[0]);
    PVString pvString = (PVString)pvDataCreate.createPVField(pvField,"fieldList",ScalerType.pvString);
    pvString.put("alarm,timeStamp");
    pvField.appendPVField(pvString);
    PVStructure pvStructure = pvDataCreate.createPVStructure(pvField, "power", new Field[0]);
    pvString = (PVString)pvDataCreate.createPVField(pvStructure,"fieldList",ScalerType.pvString);
    pvString.put("power.value,power.alarm");
    pvStructure.appendPVField(pvString)
    pvField.appendPVField(pvStructure);
    pvStructure = pvDataCreate.createPVStructure(pvField, "current", new Field[0]);
    pvString = (PVString)pvDataCreate.createPVField(pvStructure,"fieldList"ScalerType.pvString);
    pvString.put("current.value,current.alarm");
    pvStructure.appendPVField(pvString)
    pvField.appendPVField(pvStructure);
    pvStructure = pvDataCreate.createPVStructure(pvField, "voltage", new Field[0]);
    pvString = (PVString)pvDataCreate.createPVField(pvStructure,"fieldList"ScalerType.pvString);
    pvString.put("voltage.value,voltage.alarm");
    pvStructure.appendPVField(pvString)
    pvField.appendPVField(pvStructure);
    pvRequest.appendField(pvField);

In either case the resulting structure that appears to the client has the form:

pvData
   alarm          // from record.alarm
   timeStamp      // from record.timeStamp
   power          // appears because of pvRequest
      value       // from record.power.value
      alarm       // from record.power.alarm
   current        // appears because of pvRequest
      value       // from record.current.value
      alarm       // from record.current.alar.
   voltage        // appears because of pvRequest
      value       // from record.voltage.value
      alarm       // from record.voltage.alarm

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

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.

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

PVShare

This is a factory that replaces a scalar or scalarArray field with a version that shares the data from another field. When a get or put is issued the get or put method of the shared PVField is called.

class PVShareFactory {
    public static PVScalar replace(PVScalar pvNow,PVScalar pvShare);
    public static PVArray replace(PVArray pvNow,PVArray pvShare);
}

Package org.epics.pvioc.monitor

Overview

Package org.epics.pvdata.monitor defines the monitor interfaces as seen by a client. See that package overview for details. 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
A monitor is issued whenever a put is issued to the field. This is the default unless the record defines deadbands for a field.
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.
deadband
The field must be a numeric scalar. Whenever the absolute or percentage value of the field changes by more than a deadband a monitor is issued. The record instance can also define deadbands.
periodic
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 are implemented by code that implements a monitor algorithm.

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

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.

Package org.epics.pvioc.caV3

Overview

This package provides support for Channel Access Version 3. The server allows an existing Channel Access client to access a javaIOC database. The client allows the javaIOC to communicate with a Version 3 server, e.g. a javaIOC database can have links to records in a V3 IOC database.

In order to be available to a javaIOC, each must be started via the appropriate factory. This is just a call to the start method. For example:

    org.epics.pvioc.caV3.ClientFactory.start();

The client must be started before the IOC is started and the server after. The javaIOC overview provides instructions for using XMLToDatabase to start everything.

Both the client and server use the JCA/CAJ support provided by cosylab. In addition the server uses the CAS support that comes with the latest versions of JCA/CAJ.

Server

Syntax

A V3 client can access any field of a javaIOC record that is a scalar, an array of scalars, or an enumerated structure. A boolean field appears as a DBR_ENUM with choices = {"false","true"}.

A pvName has the form:

    recordName.name.name...{options}

where

recordName
The name of a javaIOC record
name.name...
Each name is a fieldName or propertyName or index as described in package org.epics.pvioc.pv. The final field must a scalar, an array of scalars, or an enumerated structure.
options
options are of the form "name=value". The options are described below.

The following examples use the channel access utility shell commands that come with EPICS base. The database is the example/exampleDB.xml that comes with the javaIOC.

    caput double 6

This writes the value 6 to the value field of a record named double.

    caput double.{process=true} 5

This writes the value 5 to record double and also requests that the record be processed. The value is written before the record is processed.

     caget -d 20 double.{process=true}

This gets the value field of record double. The record is processed.

    caput powerSupplyArray.supply.1.power{process=true} 2

This writes the value 2 to the power.value field of the second supply of the powerSupplyArray record.

Get and Put Options

The currently supported options are:

    process=true
    shareData=true

For get the record is processed before the get and for put the record is processed after the put. In order for either to work, the record must not already have a recordProcessor assigned to it.

monitor options

Currently no options are supported.

Client

NOTE: The client code is implemented by pvAccess.

Overview

The client code implements a ChannelProvider that communicates with Channel Access version 3 IOCs. It allows access to all the V3 data types. The provider name is "caV3".

The channelName is of the form recordName.fieldName, where fieldName is optional. See naming conventions below for details. MARTY SYNTAX FOR fieldName IS LIKE request

The client code implements the standard ChannelProvider interface as defined by cajV4. This means that it also implements interface Channel. However only the features that make sense for caV3 are implemented.

For Channel the implementation of the following methods is:

getField
Returns a Structure. The structure has a field named "value", which is related to the fieldName of the channel. The type of the value field depends on the caV3 native type. If the type is DBR_ENUM then the value field will be an enumerated structure. For the other DBR types the value field will be either a scalar or an array depending of the DBR type. The scalarType of the field will match the DBR type. For all types the Structure will have fields timeStamp and alarm, which are the standard timeStamp and alarm structures. If the native DBR Type is numeric then the Structure will also have structure fields for control and display.
getChannelProcess
Not supported.
createChannelArray
Not supported.
createChannelGet
Supported. Also support for alarm, timeStamp, display, and control.
createChannelPut
Supported but no support for properties.
createChannelPutGet
Not supported.
createMonitor
Supported. Also support for alarm and timeStamp. Note that a single get request is made after connection so that enum choices and control and display information can be obtained. For a numeric value field support for display and control is implemented. Note that the display and control information will not change. This matches the caV3 semantics.

Naming conventions.

A PV Name (Process Variable Name) must be of the form:

    recordName.fieldName

where

recordName
Is the name of a record in a V3 IOC database.
fieldName
Must be a valid caV3 fieldname like VAL or RVAL. It is optional since it is optional for v3.

The pvRequest passed to createChannelGet, createChannelPut, and createMonitor must define a request that makes sense for a v3 record. For all three the request should include the definition for a value field, which is associated with the fieldName of the pvName. For all it is OK to attach to a record which has a VAL field that is a DBR_ENUM. In this case the value can be retrieved as an enumerated structure or just the index or string value can be retrieved.

The following request structure will get the value, alarm, and timeStamp:

<structure name = "request">
    <scalar name = "fieldList" scalarType = "string">
       value,alarm,timeStamp
    </scalar>
</structure>

The following will access the index of an DBR_ENUM:

<structure name = "request">
     <scalar name = "value" scalarType = "string">value.index</scalar>
     <scalar name = "alarm" scalarType = "string">alarm</scalar>
</structure>

The following will access the choice of an DBR_ENUM:

<structure name = "request">
     <scalar name = "value" scalarType = "string">value.choice</scalar>
     <scalar name = "alarm" scalarType = "string">alarm</scalar>
</structure>

Data Types Supported

The V3 data types are supported via a corresponding javaIOC data type. A V3 char is a javaIOC byte. The types short, int, float, and double are common to both. A V3 string becomes a javaIOC String. Arrays of byte,short,...,string are also supported. A V3 ENUM becomes a javaIOC enumerated structure. V3 properties (status, severity, timeStamp, display limits, and control limits) become standard pvData structures (alarm, timeStamp, display, and control).