This document defines a set of standard high level data types, to aid interoperability of peers at the application level of an EPICS V4 network.
The abstract type definition and function of each such standard type is described.
The data types described here are approximately equivalent to EPICS V3 Database Request types (commonly known as "DBR" types), although Normative Types extend the concept to structured data. Additionally, Normative Types may be used to define pvIOC records, or may be used purely for data exchange though the dynamic data exchange interfaces offered by EPICS V4's pvAccess and pvData modules.
For more information about EPICS, please refer to the home page of the Experimental Physics and Industrial Control System, and to the homepage of EPICS Version 4.
This is the 18 Oct 2012 version of the Normative Types document. This version is a minor edit fixing the table of types. The last significant draft was the previous version which added NTURI.
Items planned but not described (ie "TODO"): Add MultiChannelVariantArray. Each optional field of each Normative type, where the option field is not in the Standard Optional Fields (so whose semantics are deliberately not defined), must be defined within the normative type. Ie, find all display and control, and define what they mean. Specify the order of all fields - we're not semi-structure any more.
See Appendix A for items that may be added to future revisions of this specification.
This version is an Editors Draft towards the First Public Working Draft. The First Public Working Draft will be intended for the EPICS community to review and comment. Resulting comments will drive subsequent revisions of the Normative Types specification and the EPICS V4 Working Group's reference implementations of software that helps create, populate and exchange Normative Type PVData.
Comments are welcome, though bear in mind this is a pre-public release version.
The terms MUST, MUST NOT, SHOULD, SHOULD NOT, REQUIRED, and MAY when highlighted (through style sheets, and in uppercase in the source) are used in accordance with RFC 2119 [RFC2119]. The term NOT REQUIRED (not defined in RFC 2119) indicates exemption.
The Normative Types described in this document are a set of software designs for high level composite data types suitable for the application level data exchange between EPICS V4 network endpoints. In particular, they are intended for use in online scientific data services. The intention is that where the endpoints in an EPICS V4 network use only Normative Types, each peer in the network should be able to understand all the data transmitted to it, at least syntactically, and be able to take processing steps appropriate to that data.
We call these types the Normative Types, to emphasise their role as the prescriptions of abstract data structures, whose role and intended semantics are described in this document, as opposed to implemented software; and that conformance to these semantics is a necessary condition for interoperability of using systems.
The EPICS version 4 module PVData bib:pvdata supplies a typing mechanism and object management API for efficiently defining, creating, accessing and updating memory resident structured data. EPICS V4 module PVAccess bib:pvaccess supports the efficient exchange of PVData defined data between EPICS V4 network peers. EPICS V4 Normative Types, defines some general purpose data types, that build on PVData. These are designed to be generally applicable to the process control, and the software applications level, of scientific instruments.
A simple example of a normative type described in this document, is the one for exchanging any single scalar value, such as one floating point number, one integer or one string. That normative type is named "NTScalar". When a client receives a PVData datum which identifies itself as being of type NTScalar, the client will know to expect that the structure which carries the NTScalar will include the scalar value in question (along with its type), and that value may accompanied up to 5 additional fields; a description of the quality in question, timeStamp, an indication of alarm severity, fields that help in how to display the value, and data about its operating limits. See the example below.
An example of a simple normative type is the NTScalar:
structure NTScalar
scalar_t value
string descriptor :opt
time_t timeStamp :opt
alarm_t alarm :opt
display_t display :opt
control_t control :opt
A more complex example: If a client receives a PVData datum which identifies itself as being of type NTTable, this document specifies that it should expect the datum to contain 0 or more arrays of potentially different types. The description of NTTable in this document will say that the client should interpret the arrays as the columns of a table, and should render such a datum appropriately as a table, with row elements being taken from the same numbered elements of each array.
structure NTTable
string[] labels // Very short text describing each field below, i.e. column labels
structure value
{scalar_t[] colname}0+ // 0 or more scalar array type
instances, the column values.
string descriptor : opt
alarm_t alarm : opt
time_t timeStamp : opt
All the EPICS V4 Normative Types are defined as particular structure instance definitions of a pvData structure. This is true even of the Normative Types describing simple values like a single int, since all Normative Types optionally include descriptor, alarm and timestamp. The fields of any given Ntype datum instance can be ascertained at runtime using the pvData Field introspection interface bib:pvdata.
See the Normative Type Instance Self Identificationsection below for more on how to examine a given pvData instance to see which fields it includes. That section also includes how to mark a pvData instance as a Normative Type, and how to look for that mark.
Definition: Normative Type
The Normative Types definitions in this document each have the following general form:
A Normative Type can be used both for sending data from client to service and from service to client. In this document we refer generally to an agent, being either a client or a server. If the agent is specifically at the user's end, we call it the user agent. Client and server refer to the directionality of the transaction, server being the agent that is doing the sending.
The word "Ntype" is used as a short form of "Normative Type".
The Normative Type data descriptions are given with the syntactic conventions and grammar given below. This is a hybrid of the pvData "Meta" Language and BNF, in order to add clear distinctions between symbol types, particularly terminality, recurrence, which names a user is expected to add and which are predefined.
italics - a non-terminal. Used to stand for a choice of pvData type, or named sequence of fields, or for fields that are themselves defined as structures, and hence non-terminal. In implementation the latter will have pvData field Type structure
plaintext - terminals, either a terminal pvData type name or a label. In the case of terminal pvData type, in implementation these will be instances of pvData Field types scalar or scalarArray, eg double or int [].
name - A user provided label name. This is a kind of terminal. A programmer using the Normative Type will choose what goes in the <>.
{ } - a sequence of occurrences of the item or items in the braces. The number of occurrences is given in the following subscript, 0+ means 0 or more, 1+ means 1 or more.
The grammar for a normative type definition follows the pattern below. That is, a Normative Type is defined as a structure composed of fields. A field may be optional, and may be described along with a comment:
structure NTname { ( ntfield fieldName [:opt] [// comment text] ) }1+
where:
This section defines the fields that may appear in a Normative Type's definition.
Each field of a normative type ( ntfield_t ) will be one of the following:
ntfield := scalar_t // a simple numerical, boolean, or string value | scalar_t[] // an array of simple values | enum_t // an enumeration | enum_t[] // an array of enumerations | time_t // a point in time, used for timestamps | time_t[] // an array of points in time | alarm_t // a summary diagnostic of a control system event | alarm_t[] // an array of summary diagnostics | alarmlimit_t // value thresholds for a control system diagnostic report | alarmlimit_t[] // an array of threshold values | display_t // meta data of displayed data | display_t[] // an array of display mata data | control_t // control setpoint range boundaries | control_t[] // an array of control setpoint range boundaries
Note that of all the Normative Type fields only scalar_t is of simple type, that is, having a single or array value. All the others are represented by a structure (see Structure Normative Fields below).
The field is a scalar value. Scalar fields would be implemented with PVData field Type "scalar":
scalar_t :=
boolean // true or false
| byte // 8 bit signed integer
| ubyte // 8 bit unsiged integer
| short // 16 bit signed integer
| ushort // 16 bit unsigned integer
| int // 32 bit signed integer
| uint // 32 bit unsigned integer
| long // 64 bit signed integer
| ulong // 64 bit unsigned integer
| float // single precision IEEE 754
| double // double precision IEEE 754
| string // UTF-8 *
The field is an array of scalars. Scalar array fields would be implemented with PVData field Type "scalarArray":
scalar_t[] :=
boolean[] // array of true or false
| byte[] // array of 8 bit signed integer
| ubyte[] // array of 8 bit unsiged integer
| short[] // array of 16 bit signed integer
| ushort[] // array of 16 bit unsigned integer
| int[] // array of 32 bit signed integer
| uint[] // array of 32 bit unsigned integer
| long[] // array of 64 bit signed integer
| ulong[] // array of 64 bit unsigned integer
| float[] // array of single precision IEEE 754
| double[] // array of double precision IEEE 754
| string[] // array of UTF-8 *
This subsection defines those fields of a Normative Type structure definition, that are themselves structures or arrays of structures.
The structured normative fields would be implemented with type PVData field Type "structure" or "structureArray".
An enum_t[] describes an enumeration. The field is a structure describing a value drawn from a given set of valid values also given. It is implemented as a pvData Field of Type "structure" with the following form:
enum_t :=
structure enum
int index
string[] choices
where:
An enum_t[] describes an array of enumerations. The field is an array of structures each describing a value drawn from a given set of valid values also given in each. It is implemented as a PVData field of Type "structureArray" each element of which with the form of enum_t above.
A time_t describes a defined point in time. The field is a structure describing a time relative to midnight on January 1st, 1970 UTC. It is implemented as a pvData field of Type "structure" with the following form:
time_t :=
structure timeStamp
long secsPastEpoch
int nanoseconds
int userTag
where:
Interpretation: The point in time being identified by a time_t, is given by Jan 1, 1970 00:00:00 UTC plus some nanoseconds given by its secsPastEpoch times 109 plus its nanoseconds.
pvData provides two helper classes for a timeStamp structure: timeStamp, and PVTimeStamp.
A time_t[] describes an array of points in time. The field is an array of structures each describing a time relative to January 1st, 1970 UTC. It is implemented as a PVData field of Type "structureArray" each element of which with the form of time_t above.
An alarm_t describes a diagnostic of the value of a control system process variable. It indicates essentially whether the associated value is good or bad, and whether agent systems should alert people to the status of the process.
Processes in EPICS V3 and V4 IOCs include extensive support for evaluating alarm conditions. The definition of the fields in an alarm are given in bib:epicsrecref. The field is a structure describing an alarm. It is implemented as a PVData field of Type "structure" with the following form:
alarm_t :=
structure alarm
int severity
int status
string message
where:
Interpretation MUST be as with V3 IOC record processing, as described in the EPICS Reference Manual bib:epicsrecref.
pvData provides two helper classes for an alarm structure: alarm, and PVAlarm.
An alarm_t[] is an array of alarm conditions. The field is an array of structures each describing an alarm condition. It is implemented as a PVData field of Type "structureArray" each element of which with the form of alarm_t above.
An alarmlimit_t is a structure that gives the numeric intervals to be used for the high and low limit ranges of an associated limit type alarm. The specific instance of the alarm to which the alarmlimit refers, is not specified in the alarmlimit structure, it may be any EPICS alarm. alarmlimit_t is implemented as a PVData field of Type "structure" with the following form:
alarmlimit_t :=
structure alarmlimit
double highalarm
double highwarning
double lowwarning
double lowalarm
where:
The interpretation is that where the Normative Type instance's value field is:
Since the above conditions do not at all form a three valued function over all possible values of the limits, the invariant lowalarm ≤ lowwarning ≤ highwarning ≤ highalarm SHOULD be observed when setting the those thresholds.
Code in both V3 IOC record support and in V4 IOC raises alarms based on how the alarm limits are valued according to the following algorithm:
If the value is >= highalarm then a major alarm is raised else if value>=highwarning then a minor alarm is raised else if value<= lowalarm then a major alarm is issued else if value<=lowwarning then a minor alarm is raised else do not raise an alarm.
Where an alarmlimit_t structure instance is present in a Normative Type structure, it MUST be interpreted as referring to that Normative Type's field named "value". Therefore it is only used in Normative Types that have a single numeric "value" field.
An alarmlimit_t[] is an array of alarm limit conditions. The field is an array of structures each describing an alarm limit. It is implemented as a PVData field of Type "structureArray" each element of which with the form of alarmlimit_t above.
A display_t is a structure that describes some typical attributes of a numerical value that are of interest when displaying the value on a computer screen or similar medium. The units field SHOULD contain a string representation of the physical units for the value, if any. The description field SHOULD contain a short (one-line) description of what the value represents, such as can be used as a label in a display. The fields lowlimit and highlimit represent the range in between which the value should be presented as adjustable.
The field is a structure describing a display_t. It is implemented as a PVData field of Type "structure" with the following form:
display_t :=
structure display
double lowlimit
double highlimit
string description
string format
string units
where:
Where an display_t structure instance is present in a Normative Type structure, it MUST be interpreted as referring to that Normative Type's field named "value". Therefore it is only used in Normative Types that have a single numeric "value" field.
A display_t[] is an array of display_t. The field is an array of structures each describing the display media oriented metadata of some corresponding process variable value, as described by display_t above. It is implemented as a PVData field of Type "structureArray" each element of which with the form of display_t above.
An control_t is a structure that describes a range, given by the interval (limitlow,limithigh), within which it is expected some control software or hardware shall bind the control PV to which this Normative Type instance's value field refers.
The field is a structure describing a control_t. It is implemented as a PVData field of Type "structure" with the following form:
control_t :=
structure control
double lowlimit
double highlimit
where:
A control_t[] is an array of control_t. The field is an array of structures each describing the setpoint range interval of some process variable. It is implemented as a PVData field of Type "structureArray" each element of which with the form of control_t above.
Meta data are included in runtime instances of Normative Types. The meta data includes to which Normative Type the structure instance conforms, version information, and other data to aid efficient processing, diagnostics and displays.
Normative Type instance data MUST identify themselves as such by including a string in a well known part of their pvData instance datum (see below), that encodes an identifier of the Normative Type to which they conform. This is the Normative Type Identifier, or "Ntype identifier" string for short. Ntype identifiers have the syntax <namespace-name>:<type-name>. There are two parts to this Ntype identifier:
A Normative Type Identifier MUST be considered to be "case sensitive."
The Namespace Name corresponding to this draft of the normative types document is:
uri:ev4:nt/2012/pwd
The normative list of the Normative Type Identifiers corresponding to this draft of the EPICS V4 Normative Types specification document (this document), is given in Appendix B.
As an example, one of the simplest normative types is NTScalar. It has formal Type Name "NTScalar" (see Appendix B). Therefore, the Normative Type Identifier for an NTScalar, is uri:ev4:nt/2012/pwd:NTScalar.
At present it is envisaged that the same namespace value shall be used for all versions of this document prior to Recommendation, including all Public Working Drafts of this document and those marked Last Call or similar.
In the EPICS v4 pvData/pvAccess binding, the structure identification string (ID) of pvData structures is used to communicate the Normative Type of the datum carried by the pvData structure. Every pvData datum which is intended to conform to a normative type, MUST identify the normative type to which it conforms through its ID field. Its ID field MUST have the value of its Normative Type Identifier. For instance, a pvData structure conforming to NTScalar, must have ID field equal to "uri:ev4:nt/2012/pwd:NTScalar". Every EPICS V4 agent which is encoding or decoding pvData data that is described by normative types, SHOULD examine the ID field of such data, to establish the normative type to which each datum conforms.
Recall that in the pvData system, data variables are constructed in two equally important parts; the introspection interface, in which data types are defined, and the data interface, in which instance variables are created and populated. The introspection interface can be used to examine an existing instance, to see what fields it posses. Getting and setting values, is done through the data interface. As a programmer, you have to define both parts, the introspection interface of your type, and its data interface. Both the data and the introspection interfaces are exchanged by pvAccess. That is, when a sender constructs a data type, such as one conforming to an Normative Type, plus an instance of that type, and it sends the instance to a receiver, the receiver can check that the instance indeed contains the member fields it should find for that type, using the type's introspection interface.
The following Java code snippets give an example of the use of a pvData structure of Normative Type NTScalar, as defined below. in this example we show code as may be included in a trivial "multiplier" service, and a client of the multiplier service.
The sender typically first creates an introspection definition, using the pvData introspection interfaces (Field, Structure etc). It then creates an instance of the type and populates it with the pvData data interfaces (PVField, PVstructure etc).
Example of creating the introspection interface of an NTScalar, as may be done on a server that will be returning one. In this example, only one of the optional fields of NTScalar, named "descriptor" is included, along with the required field named "value".
// Create the data type definition, using the pvData introspection interface (Structure etc).
FieldCreate fieldCreate = FieldFactory.getFieldCreate();
Structure resultStructure = fieldCreate.createStructure( "uri:ev4:nt/2012/pwd:NTScalar",
new String[] { "value", "descriptor" },
new Field[] { fieldCreate.createScalar(ScalarType.pvDouble),
fieldCreate.createScalar(ScalarType.pvString) } );
Subsequently, the sender would create an instance of the type, and populate it.
Example of creating an instance and data interface of an NTScalar, as may be done on a data server, and populating it.
// If a and b were arguments to this service, the following creates an instance of
// a resultStructure, which conforms to the NTScalar normative type definition,
// and populates it. It would then return this PVStructure instance.
PVStructure result = PVDataFactory.getPVDataCreate().createPVStructure(resultStructure);
result.getDoubleField("value").put(a * b);
result.getStringField("descriptor").put("The product of arguments a and b");
The PVStructure instance, in the example called "result" would be returned to the receiver.
Having in some way done a pvaccess get, the receiver could simply extract the primary value:
PVStructure result = easyPVA.createChannel("multiplierService").createRPC().request(request);
double product = result.getDoubleField("value").get();
A well written receiver would check that the introspection interface (Structure etc) says that the received instance is indeed of the type it expects. It may extract the data fields individually, checking their type. Importantly, it can also see which optional fields it received, before attempting to access them. Here is a more complete receiver example for the NTScalar sent above. This code might be in the client side of the Multiplier service.
Example of a receiver of an NTScalar. The example checks that the returned pvData datum was an instance of an NTScalar, extracts the required value field, and then, if it's present, extracts the optional "descriptor" field.
// Call the multiplier service sending the request in a structure
PVStructure result = easyPVA.createChannel("multiplierService").createRPC().request(request);
// Examine the returned structure via its introspection interface, to check whether its
// identifier says that it is a normative type, and the type we expected.
if (!result.getStructure().getID().equals("uri:ev4:nt/2012/pwd:NTScalar"))
{
System.err.println("Unexpected data identifier returned from multiplierService: " +
"Expected Normative Type ID uri:ev4:nt/2012/pwd:NTScalar, but got "
+ result.getStructure().getID());
System.exit(-1);
}
// Get and print the required value member field as a Double.
System.out.println( "value = " + result.getDoubleField("value").get());
// See if there was also the descriptor subField, and if so, get it and print it.
PVString descriptorpv = (PVString)result.getSubField("descriptor");
if ( descriptorpv != null)
System.out.println( "descriptor = " + descriptorpv.get());
// Or just print everything we got:
System.out.println("\nWhole result structure toString =\n" + result);
In future drafts of this specification, a pattern to create extensions to the EPICS V4 Normative Types may be presented. It may be based on a formalized link to the XML namespace and XML Schema system, whereby the namespace part of the Normative Type Identifier of a datum whose type is an extension of one of these Normative Types, is replaced by another namespace that extends this one through an XML Schema out of band. In that case, the type name part would identify a type in that other namespace, though it may extend a type in this namespace.
All of the Normative Types defined below, optionally include a descriptor, alarm and timeStamp field. There is no required interpretation of these fields, and therefore their meaning is not further described in the Normative Type definitions. Additionally, Normative Types may have other optional fields, as defined individually below.
An object of Normative Type may optionally include a field named "descriptor" and of type string, to be used to give identity, name, or sense information. For instance, it may be valued with the name of a device associated with control data, or the run number of a table of model data.
string descriptor :opt // Contextual information
An object of Normative Type may optionally include an alarm field.
alarm_t alarm :opt // Control system event summary
An object of Normative Type may optionally include a timeStamp field.
time_t timeStamp :opt // Event time
The General Normative Types are for encapsulating data of any kind of application or use case. Compare to Specific Normative Types defined later in this document, and which are oriented to particular use cases.
NTScalar is the EPICS V4 Normative Type that describes a single scalar value plus metadata:
structure NTScalar
scalar_t value
string descriptor :opt
time_t timeStamp :opt
alarm_t alarm :opt
display_t display :opt
control_t control :opt
where:
NTScalarArray is the EPICS V4 Normative Type that describes an array of values, plus metadata. All the elements of the array of the same scalar type.
structure NTScalarArray
scalar_t[] value
string descriptor :opt
time_t timeStamp :opt
alarm_t alarm :opt
display_t display :opt
control_t control :opt
where:
NTEnum is an EPICS V4 Normative Type that describes an enumeration (a closed set of possible values each described by an n-tuple).
structure NTEnum
enum_t value
string[] longdescriptions :opt
string descriptor :opt
time_t timeStamp :opt
alarm_t alarm :opt
where:
NTMatrix is an EPICS V4 Normative Type used to define a matrix, specifically a 2-dimensional array of real numbers.
structure NTMatrix
double[] value
int[2] dim :opt
string descriptor :opt
time_t timeStamp :opt
alarm_t alarm :opt
display_t display :opt
where:
User agents that print or otherwise render an NTMarix SHOULD print row vector, column vector, and non-vector matrices appropriately.
NTVariantArray is an EPICS V4 Normative Type to define a single structure which contains an number of arrays, each of different type, but where the value of the NTVariantArray as a whole is taken to be the value of only one of the arrays at a time. In that way, it can be used to encode data in arrays whose type may be changed according to runtime conditions and the data to be expressed.
NTVariantArray is defined with arrays of each pvData scalar type. At any
particular time its value MUST be interpreted to be only one of these arrays. The
dataType member specifies which array MUST be taken to be the
NTVariantArray's type. The data arrays need not be all the same length. Arrays other
than that presently selected by dataType MAY be populated; in this way
dataType can be used as a value selector.
structure NTVariantArray
int dataType // Identifies which scalar array defines the present value
boolean [] booleanValue // Defines the NTVariantArray's value if dataType == 0
byte [] byteValue // Defines the NTVariantArray's value if dataType == 1
short [] shortValue // Defines the NTVariantArray's value if dataType == 2
int [] intValue // Defines the NTVariantArray's value if dataType == 3
long [] longValue // Defines the NTVariantArray's value if dataType == 4
float [] floatValue // Defines the NTVariantArray's value if dataType == 5
double [] doubleValue // Defines the NTVariantArray's value if dataType == 6
string [] stringValue // Defines the NTVariantArray's value if dataType == 7
time_t[] timeStampValue // Defines the NTVariantArray's value if dataType == 8
alarm_t [] alarmValue // Defines the NTVariantArray's value if dataType == 9
string descriptor :opt
time_t timeStamp :opt
alarm_t alarm :opt
display_t display :opt
where:
0 - booleanValue
1 - byteValue
2 - shortValue
3 - intValue
4 - longValue
5 - floatValue
6 - doubleValue
7 - stringValue
8 - timeStampValue
9 - alarmValue
NTURI is the EPICS V4 Normative Type that describes a Uniform Resource Identifier (URI) bib:uri. Specifically, NTURI carries the four parts of a "Generic URI", as described in bib:uri as the subset of URI that share a common syntax for representing hierarchical relationships within the namespace. As such, NTURI is intended to be able to encode any generic URI sheme's data. However, NTURI's primary purpose in the context of EPICS, is to offer a well formed and standard compliant way that EPICS agents can make a request for an identified resource from a channel, especially an EPICS V4 RPC channel. See ChannelRPC.
The "pva" scheme is introduced here for EPICS V4 interactions. The pva scheme implies but does not require use of the pvaccess protocol. A scheme description for Channel Access (implying the ca protcol) will be added later. What follows is a description of the syntax and semantics for the pva scheme.
structure NTURI
string scheme
string authority : opt
string path
structure query : opt
{string | double | int }0+
{<field-type> <field-name>}0+
The following describes how the fields of the NTURI must be interpretted when the scheme is "pva":
The channel name given in the path MAY BE the name of an RPC channel. In that case, it's important to note that this specification makes no normative statement about where in the NTURI is encoded the name of the entity about which the RPC service is being called. For instance, an archive service, that gives the historical values of channels, may advertise itself as being on a single channel called say "archiveservice" (so the NTURI path field in that case would be set to "archiveservice", and in that case, the name of the EPICS channel about which archive data is wanted might well be encoded into one of the NTURI's query field parameters. Alternatively, the archive service might advertise a number of channels, each named perhaps after the channels whose historical data is being requested. For instance, a path may be "quad45:bdes;history", if that was the name of one of the channels offered by the archive service. An example of this second form is given below.
Use of NTURI may be explained by example. The following is an example client side of Channel RPC exchange, where a notional archive service, is asked for the data for a PV between two points in time. In this example, the archive service is advertising the channel name "quad45:bdes;history". Presumably, that service knows the archive history of a (second) channel, named probably, "quad45:bdes".
Construct the introspection interface (ie type definition) of the NTURI conformant structure that will be used to make requests to the archive service.
// Construct an NTURI for making a request to a service that understands
// query arguments named "starttime" and "endtime".
FieldCreate fieldCreate = FieldFactory.getFieldCreate();
Structure queryStructure = fieldCreate.createStructure(
new String[] {"starttime", "endtime"},
new Field[] { fieldCreate.createScalar(ScalarType.pvString),
fieldCreate.createScalar(ScalarType.pvString)});
Structure uriStructure =
fieldCreate.createStructure("uri:ev4:nt/2012/pwd:NTURI",
new String[] { "path", "query" },
new Field[] { fieldCreate.createScalar(ScalarType.pvString),
queryStructure } );
Populate our uriStructure (conformant to NTURI) with a specific request.
// Get a EasyPVA singleton.
EasyPVA easyPVA = EasyPVAFactory.get();
// Construct an NTURI with which to ask for the archive data of quad45:bdes
PVStructure request = PVDataFactory.getPVDataCreate().
createPVStructure(uriStructure);
request.getStringField("path").put("quad45:bdes;history");
PVStructure query = request.getStructureField("query");
query.getStringField("starttime").put("2011-09-16T02.12.55");
query.getStringField("endtime").put("2011-09-16T10.01.03");
// Ask for the data, using the NTURI
PVStructure result = easyPVA.createChannel(request.getStringField("path").get()).createRPC().request(request);
if ( result != null )
System.out.println("The URI request structure:\n" + request
+"\n\nResulted in:\n" + result);
The server side is not illustrated, but clearly its code would have registered a number of ChannelRPC services, each named after the PV whose historical data it offered.
NTNameValue is the EPICS V4 Normative Type that describes a system of name and scalar values.
For the related problem of expressing a key-value system where each value may be array valued, see NTVariantArray or NTTable.
Use cases: In a school, a single NTNamedValue might describe the grades from a number of classes for for one student.
structure NTNameValue string[] name scalar_t[] value string descriptor :opt time_t timeStamp :opt alarm_t alarm :opt
where:
Each name (or "key") in the array of names, MUST be interpreted as being associated with its same indexed element of the value array.
NTTable is the EPICS V4 Normative Type for "2-d" tabular datasets.
An NTTable is made up of a number of arrays, each array being of a scalar type. Each array can be thought of as a column. Each ith array member makes up one row, or n-tuple.
Use case examples: a table of twiss paramaters of all lattice elements in an accelerator section. Another example, where the columns might vary call-to-call would be that of an EPICS V4 SQL database service. In that example one NTTable returned by the service would contain all the tabular results of a SQL SELECT, essentially a recoded JDBC or ODBC ResultSet - see the rdbservice.
structure NTTable
string[] labels // Very short text describing each field below, i.e. column labels
structure value
{scalar_t[] colname}0+ // 0 or more scalar array instances, the column values.
string descriptor : opt
alarm_t alarm : opt
time_t timeStamp : opt
where:
This represents a table. The number of "columns" is equal to the number of fields which follows field "labels." Each colname scalar array field contains the data for the "column" corresponding to the same indexed element of the labels field. The value of each element of labels SHOULD be used as a column heading for the corresponding colname field.
Note that the above description is given in terms of a table and its columns, but there is nothing specifically columnar about how this data may be rendered. A user may choose to print the fields row wise. For instance, if there are many fields, but each has only length 1 or 2. E.g., if you wanted to give all the scalar data related to one device, then you might use an NTTable rendered in such a way. Note that one column of a table would also be easily described by NTNameValue.
The number of scalar_t[] fields in the value structure, and the length of labels MUST be the same. All scalar_t[] fields in the value structure, MUST have the same length, being the number of "rows" in the table. No array field within the value structure may itelf be named "value".
The "specific normative types" below are types oriented towards application level scientific and engineering use cases. Compare to General Normative Types defined above. The currently defined types are each described in a section below.
Unless otherwise stated:
MultichannelArray is an EPICS V4 Normative Type that aggregates an array of scalar values from different EPICS Process Variable (PV) channel sources, into a single variable.
Use cases; in a particle accelerator, a single NTMultichannelArray might include the data of a number of Beam Positon Monitors' X offset values, or of a number of quadrupoles' desired field values.
structure NTMultichannelArray scalar_t[] value // The channel values string[] PVnames // Process Variable names time_t timeStamp // Base value time stamp int[] severities :opt // Alarm severity associated with each value double[] positions :opt // The position of each value element double[] deltaTimes :opt // The time relative to the timeStamp, in seconds string descriptor :opt alarm_t alarm :opt
where:
The above descriptions of the optional fields, pertain in particular to when a NTMultichannelArray expresses measured values, but a NTMultichannelArray can be used to express desired values or setpoint values too.
NTContinuum is the EPICS V4 Normative Type used to express a sequence of point values in time or frequency domain. Each point has N values (N>=1) and an additional value which describes the index of the list. The additional value is carried in the 'base' field. The 'value' field carries the values which make up the point in index order.
An additional 'units' field gives a units string for the N values and the additional value.
structure NTcontinuum
double[] base
double[] value
string[] units
string descriptor :opt
alarm_t alarm :opt
time_t timeStamp :opt
The number of values in a point must be derived as:
Nvals = len(value)/len(base)And the following invariant must be preserved:
len(units)-1 == NvalsThe order of the point (A, B, C) for indices 1, 2, 3 the order of the 'value' array is:
[A1, B1, C1, A2, B2, C2, A3, B3, C3]NTHistogram is the EPICS V4 Normative Type used to encode the data and representation of a (1 dimensional) histogram. Specifically, it encapsulates frequency binned data.
For 2d histograms (i.e. both x and y observations are binned) and n-tuple data (e.g. land masses of different listed countries) see NTMatrix or NTTable.
structure NTHistogram
double [] ranges // The start and end points of each bin
(short[] | int[] | long[]) value // The frequency count, or otherwise value, of each bin
string descriptor :opt
alarm_t alarm :opt
time_t timeStamp :opt
One NTHistogram gives the information required to convey a histogram representation of some underlying observations. It does not convey the values of each of the observations themselves.
The number of bins is given by the length of the value array. ranges indicates the low value and high value of each bin. The range for bin(i) is given by ranges(i) to ranges(i+1). Specifically, since we want end points of both the first bin and last bin included, all bin intervals except the last one, MUST be right half open; from that bin's low value ranges(i) (included) to that bin's high value ranges(i+1) (excluded). The last bin MUST be fully open (low and high value included).
A log plot histogram (in which the independent variable x is binned on a log scale), would be communicated using a range array of decades (1.0E01, 1.0E02, 1.0E03 etc).
The array length of range MUST be the array length of value + 1.
NTAggregate is the EPICS V4 Normative Type to compactly convey data which combines several measurements or observation. NTAggregate gives simple summary statistic bib:agg about the central tendency and dispersion of a set of data points.
Use cases: for instance, an NTAggregate could be used to summarize the value of one beam position offset reading over some number of pulses (N). It also includes the time range of the sampled points, so it could be used for time domain rebasing. For instance, an FPGA sending data at 10KHz, and you want to display its output, but you don't want to display at the native rate. Also, it could be used for transmitting or storing compressed archive data.
NTAggregate doesn't cover the shape of a distribution so it only reasonably helps you do symmetrical distributions (no skewness or kurtosis), and it doesn't include any help for indicating the extent of dependency on another variable (correlation).
structure NTAggregate
double value // The center point of the observations,
// nominally the mean.
long N // Number of observations
double dispersion opt // Dispersion of observations;
// nominally the Standard Deviation or RMS
double first opt // Initial observation value
time_t firstTimeStamp opt // Time of initial observation
double last opt // Final observation value
time_t lastTimeStamp opt // Time of final observation
double max opt // Highest value in the N observations
double min opt // Lowest value in the N observations
string descriptor opt
alarm_t alarm opt
time_t timeStamp opt
Where:
One NTAggregate instance describes some number (given by N) of observations. If firstTimeStamp and lastTimeStamp are given, then the N observations MUST have been taken over the period of time specified. If first, last, max or min are given, they MUST refer to the actual values of the N observations being summarized.
The value field value computed by server agents may be the arithmetic mean of the observation data being summarized by this NTAggregate, but NTAggregate does not normatively define that. Other measures of mean (geometric, harmonic) may be assigned. Indeed other measures of central tendency may be used. The interpretation to give an instance of an NTAggregate SHOULD be conveyed in the descriptor.
Where dispersion is a measure of the standard deviation, which estimator of the standard deviation [1/N or 1/(N-1)] was used, is also not defined normatively.
NTImage is the EPICS V4 Normative Type to express image data, particularly camera images. One NTImage gives one frame.
The EPICS V3 image type is provided by areaDetector. See the NDArray class declaration for details of the image properties. The EPICS V4 image type (NTImage) is a superset of this functionality.
Byte [] data may contain a
compressed image so the size may not be at least prod(dim) *
element_size(datatype).
An NTImage is composed of three parts:
structure NTImage
Arraypart
Imagepart
Metadatapart
Each of these will be discussed separately.
The Arraypart of an NTImage is composed of the following fields:
(boolean [] | byte[] | short[] | int[] | long[] | float[] | double[]) value
int[] dim
string descriptor :opt
time_t timeStamp :opt
alarm_t alarm :opt
display_t display :opt
These fields are the same as for NTMatrix defined previously.
A generic tool that operates on NTMatrixs will be able to use the image as long as compression is not used.
The Imagepart of an NTImage is composed of the following fields:
int colorMode
int bayerPattern
char [4] fourcc
int [] offset // same length as dim, start of readout
int [] binning
int [] reverse
int [] fullDim
where:
NDColorModeMono = 0, /** Monochromatic image */
NDColorModeBayer = 1, /** Bayer pattern image,
1 value per pixel but with color filter on detector */
NDColorModeRGB1 = 2, /** RGB image with pixel color interleave,
data array is [3, NX, NY] */
NDColorModeRGB2 = 3, /** RGB image with row color interleave,
data array is [NX, 3, NY] */
NDColorModeRGB3 = 4, /** RGB image with plane color interleave,
data array is [NX, NY, 3] */
NDColorModeYUV444 = 5, /** YUV image, 3 bytes encodes 1 RGB pixel */
NDColorModeYUV422 = 6, /** YUV image, 4 bytes encodes 2 RGB pixel */
NDColorModeYUV411 = 7 /** YUV image, 6 bytes encodes 4 RGB pixels */
NDBayerRGGB = 0, /** First line RGRG, second line GBGB... */
NDBayerGBRG = 1, /** First line GBGB, second line RGRG... */
NDBayerGRBG = 2, /** First line GRGR, second line BGBG... */
NDBayerBGGR = 3 /** First line BGBG, second line GRGR... */
The Metadatapart of an NTImage is composed of the following fields:
int uniqueId
string [] attributeDescriptions
int [] attributeSourceTypes
string [] attributeSources
NTVariantArray [] attributes
where:
NDAttrSourceDriver = 0, /** Attribute is obtained directly from driver */
NDAttrSourceParam, /** Attribute is obtained from parameter library */
NDAttrSourceEPICSPV /** Attribute is obtained from an EPICS PV */
The following types may be added to this specification, following further refinement and according to feedback to this draft. Comments welcome on these definitions or alternatives.
anydata_t describes a pvData structure that contains an array of elements, each of which may be a scalar array or structure array. Such structures would then be able to transport an essentially unlimited variety of data. However, the use of anydata_t in a Normative Type's specification would considerably complicate agent implementations that may receive instances of those Normative Types.
anydata_t := structure { scalar_t[]| structure_t[] }1+
NTAny would be a Normative Type for interoperation of essentially data structure, plus description, alarm and timeStamp.
structure NTAny
string description : opt
time_t timeStamp : opt
alarm_t alarm : opt
string[] label : opt
anydata_t value
NTSnapshot would be the Normative Type for interoperation of EPICS V4 snapshot and configuration services, such as MASAR, with their clients.
structure NTSnapshotData // snapshot data [that may inc waveform ]
time_t timeStamp // time of snapshot
time_t timeStamp :opt
alarm_t alarm :opt
string[] channelNames
alarm_t[] alarms // Alarm of each data value
anydata_t value
Maybe rather than anydata_t here, we should say any Normative Type instance? That would usefully constrain the potential types agents must implement.
NTArchive would be the Normative Type for interoperation of EPICS V4 capable archive services, with their clients.
structure NTArchivedata string channelName // EPICS channel name time_t[] timeStamps // Timestamps of each sample alarm_t[] alarms anydata_t value
Maybe rather than anydata_t here, we should say any Normative Type instance? That would usefully constrain the potential types agents must implement.
This Appendix normatively describes the Normative Type Identifiers of the abstract data types defined by this document. It gives the namespace value as it MUST appear in the "Namespace Name" part of the Normative Type Identifier, and it gives the type names as they MUST appear in the "Type Name" part of a Normative Type Identifier. These identifier part values MUST be considered case sensitive.
The Normative Type Identifier "Namespace Name" part, corresponding to this draft of the Normative Types Document (this document), is:
uri:ev4:nt/2012/pwd
The Normative Type Identifier "Type Name" part corresponding to this draft of the Normative Types Document (this document), MUST be valued only as one of the following:
| Type Name | Short Description |
|---|---|
| NTScalar | A single scalar value |
| NTScalarArray | An array of scalar values of some single type. Compare with NTVariantArray |
| NTEnum | An enumeration list and a value of that enumeration |
| NTMatrix | A real number matrix |
| NTVariantArray | An array of some scalar type, where the type and values may be changed |
| NTURI | A structure for encapsulating a Uniform Resource Identifier (URI) |
| NTNameValue | An array of scalar values where each element is named |
| NTTable | A table of scalars, where each column may be of different scalar array type |
| NTMultichannelArray | An array of PV names, their values, and metadata |
| NTContinuum | Expersses a sequence of data points in time or frequency domain |
| NTHistogram | An array of real number intervals, and their frequency counts. Expresses a 1D histogram. |
| NTAggregate | A mean value, standard deviation, and other meta data. Expresses the central tendency and dispersion of a set of data points |
| NTImage | A general purpose pixel and meta data type, to encode image data of a single picture frame. |
Following drafts of this document MAY well correspond to the same Namespace Name and Type Names as used in this draft. Note that the same namespace may well be used for a different collection of types or Type Names, as this document matures.