Project

General

Profile

DRF3 RFC

Introduction

This document describes a standard data request format for the use in applications, data acquisition protocols, and middleware (DAE, DPM) of the Fermilab Accelerator Control System, known as ACSys.

The established practice of denominating control system's entities — devices, properties, and events — originates from several protocols and APIs developed over Fermilab’s history. Intuitive, yet sometimes ambiguous, the naming conventions have never been fully documented independently of their implementations. As such, various pieces of software interpret those concepts differently, making their own assumptions about the permitted syntax and character sets. The further evolution of the control system calls for a review of the existing naming practices in order to make them more rational, remove ambiguity, and to formalize the syntax.

The Data Request Format, Version 3 (DRF3) builds upon the success of its predecessor, DRF2. Much of it is backward compatible with DRF2’s canonical form, meaning that the new format will honor currently accepted device names, property qualifiers, array indices and range denominators, event names, as well as relevant ACL property and field names. The new format, however, generalizes some of the concepts used by DRF2 as well as deprecates some ugly, historical conventions. A standard DRF3 parser, fully compatible with this document, is provided in Java, Erlang, and C++.

The principal features of DRF3 are:
  • The format is lenient and requires only a device name to be specified. One data can be requested in several ways.
  • There is one canonical form for each semantically distinct request.
  • Within the standard parser, the syntactic validation of a request and its conversion to the canonical notation is performed off-line without consulting external resources.
  • The canonical form of a data request can be used as a unique key for a data pool entry. Note, however, that due to the complexity of the underlying control system it is impossible to tell, without checking the database, whether two semantically different requests are, in fact, distinct.

Conventions

This document uses a BNF-like grammar (similar to one from RFC2396) to describe the syntax of DRF3. The following definitions are common to many elements:

up-alpha :: ["A"-"Z"]
low-alpha :: ["a"-"z"]
alpha :: up-alpha | low-alpha
dec-digit :: ["0"-"9"]
dec-number :: 1*( dec-digit )
hex-digit :: ["0"-"9"] | ["A"-"F"] | ["a"-"f"]
hex-number :: 1*( hex-digit )

Canonical forms:

c-dec-number :: <a dec-number with no leading zeroes>
c-hex-number :: <a hex-number with no leading zeroes and all chars capitalized>

Request Structure

The data request is defined as a case-insensitive ASCII string with all characters in the range 0x21 ("!") to 0x7E ("~"). The request includes an ordered sequence of up to five attributes: device, property, range, field, and event. The only required attribute is device.

request :: device ?*( "." property ) ?*( range ) ?*( "." field ) ?*( "@" event )

In the canonical form of request, each attribute is individually transformed to its canonical notation. A missing property attribute is replaced with its default value, as described in Property Format. The range, field, and event attributes are present in the canonical form only if their values are not default. The notion of a NULL attribute, used later in this document, describes the entire attribute absent from the request along with its delimiter, not the delimiter and an empty string.

Device Format

The device attribute specifies an ACSys device name or a device index. Device names start with a prefix, consisting of a letter and colon, which is followed by “segments”, containing alphanumeric and underscore characters, separated by colons. The colon in the prefix may be replaced with a prop-qualifier. The size and number of segments are up to the device’s author. The device index form starts with a "0:" and includes only decimal digits.

device :: device-name | device-index
device-name :: device-prefix device-segment 0*( ":" device-segment )
device-prefix :: alpha prop-qualifier
device-segment :: 1*( device-char )
device-char :: alpha | dec-digit | "_"
device-index :: "0:" {1,6}*( dec-number )
prop-qualifier :: ":"
| "?"
| "_"
| "|"
| "&"
| "@"
| "$"
| "~"
; Reading and default
; Reading
; Setting
; Basic Status
; Basic Control
; Analog Alarm
; Digital Alarm
; Description

Whenever possible, the original character case shall be preserved to facilitate the recognition of device names by the users. In the canonical form, the property qualifier is changed to a colon and the corresponding property is specified.

Property Format

The property attribute specifies the name of a property within the device. Canonical property names are in upper case. Traditional devices in ACNET have a fixed set of possible properties, which model a power supply. DRF3 supports a more general model where devices aren’t forced to a power supply mold and can, instead, use properties that better describe them.

property :: 1*( alpha | dec-number | "_" )

Legacy ACNET devices will still be data collected using the GETS32 protocol. The layer of software that maps DRF3 requests to GETS32 packets will recognize certain property values and can translate them to the correct property index. Future ACNET protocols can do away with the property index and simply use the property name to access the correct data1. Software that translates DRF3 to foreign protocols, like Channel Access, can use the property name directly.

Range Format

The range attribute addresses an individual element or a sequence of elements in the data set.

A data set can be viewed either as an array of homogenous elements or as a sequence of raw bytes. Accordingly, a range may be specified in two forms, depending on which model is used: array indices are enclosed in brackets, a byte offset and a length are enclosed in braces. By default, the array notation returns scaled data and the byte-wise notation returns raw data. The use of the byte-wise form is discouraged, as it requires a knowledge of front-end data lengths.

An open-ended range is used to request an unknown number of items, either array elements or raw bytes, from the given start index (or byte offset) up to the end of the data set. The full range (a special case of the open-ended range) describes the entire data set, making no distinction between array and byte-wise forms.

range :: c-full-range | array-range | byte-range
array-range :: "[" start-index ?*( ":" ?*( end-index ) ) "]"
byte-range :: "{" ?*( offset ) ?*( ":" ?*( length ) ) "}"
start-index :: dec-number
end-index :: dec-number
offset :: dec-number
length :: dec-number

The canonical form of a range is defined as follows:

c-range :: c-full-range | c-array-range | c-byterange
c-full-range :: "[]"
c-array-range :: ?*( "[" c-start-index ?*( ":" ?*( c-end-index ) ) "]" )
c-byte-range :: "{" c-offset ?*( ":" ?*( c-length ) ) "}"
c-start-index :: c-dec-number
c-end-index :: c-dec-number
c-offset :: c-dec-number
c-length :: c-dec-number

Field Format

The field attribute specifies a flavor of data, such as raw, scaled, or a particular field inside a complex structure. Each property has its own set of valid fields (canonical field names are in upper case.)

field :: reading-fld | setting-fld | status-fld | control-fld | analog-alarm-fld | digitalalarm-fld | description-fld
reading-fld :: "RAW" | "PRIMARY" | "VOLTS" | "SCALED" | "COMMON"
setting-fld :: "RAW" | "PRIMARY" | "VOLTS" | "SCALED" | "COMMON"
status-fld :: "RAW" | "ALL" | "TEXT" | "ON" | "READY" | "REMOTE" | "POSITIVE" | "RAMP"
control-fld :: NULL
analog-alarm-fld :: "RAW" | "ALL" | "TEXT" | "MIN" | "MINIMUM" | "MAX" | "MAXIMUM" | "NOM" | "NOMINAL" | "TOL" | "TOLERANCE" | "RAW_MIN" | "RAWMIN" | "RAW_MAX" | "RAWMAX" | "RAW_NOM" | "RAWNOM" | "RAW_TOL" | "RAWTOL" | "ALARM_ENABLE" | "ENABLE" | "ALARM_STATUS" | "STATUS" | "TRIES_NEEDED" | "TRIES_NOW" | "ALARM_FTD" | "FTD" | "ABORT" | "ABORT_INHIBIT" | "FLAGS"
digital-alarm-fld :: "RAW" | "ALL" | "TEXT" | "NOM" | "NOMINAL" | "MASK" | "ALARM_ENABLE" | "ENABLE" | "ALARM_STATUS" | "STATUS" | "TRIES_NEEDED" | "TRIES_NOW" | "ALARM_FTD" | "FTD" | "ABORT" | "ABORT_INHIBIT" | "FLAGS"
description-fld :: NULL

Event Format

The event attribute specifies on which moments of time the data should be read or set. The syntax of event descriptors is based on the one used in the Get32 protocol and in the DataEventFactory class.

The time values used in events (periods, delays) are specified as an integer number optionally followed by a time unit. By default, the numeric value is in milliseconds. The unit suffixes can also be used to switch between a time notation and a frequency
notation.

time-freq :: dec-number ?*( time-freq-unit )
time-freq-unit :: "S" | "M" | "U" | "H" | "K"

The canonical form of time and frequency values is defined as follows:

c-time-freq :: c-dec-number ?*( "S" | "U" | "K" | "H" )

The format supports five types of events: Default, Once Immediate, Periodic, Clock, and State. The first two are trivial and do not require any additional values.

event :: default-evt | immediate-evt | periodic-evt | clock-evt | state-evt
default-evt :: "U"
immediate-evt :: "I"

The Periodic event acquires data at a fixed rate. A special flavor of it, the periodic, noncontinuous event, does not fire (skips cycles) unless the data provided by the front-end has changed.

periodic-evt :: ( "P" | "Q" ) ?*( "," period ?*( "," immediate ) )
period :: time-freq
immediate :: "TRUE" | "T" | "FALSE" | "F"

The Clock event uses signals provided by the global timing system.

clock-evt :: "E" ?*( "," type ) 1*( "," evt-spec )
evt-spec :: hex-number ?*( "+" time-freq )
type :: "H" | "S"
delay :: time-freq

The State event acquires data upon a state transition on a device.

state-evt :: "S," device "," value "," delay "," expression
value :: dec-number
expression :: "=" | "!=" | ">" | "<" | "<=" | ">=" | "*"

The canonical form of events is defined as follows:

c-event :: c-default-evt | c-immediate-evt | c-periodic-evt | c-clock-evt | c-state-evt
c-default-evt :: NULL
c-immediate-evt :: "I"
c-periodic-evt :: ( "P" | "Q" ) "," c-time-freq "," ( "TRUE" | "FALSE" )
c-clock-evt :: "E," c-hex-number "," ( "H" | "S" | "E" ) "," c-time-freq
c-state-evt :: "S," c-device "," c-dec-number "," ctime-freq "," expression

Changes from DRF2

Although DRF3 looks superficially like DRF2, there are a few differences that may not be backward-compatible. This section tries to point out these changes.
  • Device names are made up of segments, containing alphanumeric and underscore characters, separated by colons. The size and number of segments is up to the device’s author. The only limit is the 64-character limit that our database enforces. Historical ACSys device names fit this definition.
  • The property field has been generalized to include more than just the traditional ACNET properties.
  • Using array notation defaults to returning scaled data. Byte-wise ranges default to returning raw data.
  • Data acquisition on multiple clock events will require support to be added to the front-ends.

Further Discussion

  • Charlie King: Add notation which selects a source of the data (i.e. Data Loggers, Redirections, etc.)
  • Rich Neswold: We should think about ways to specify FTP or Snapshot data requests. Most of FTP can be done with current event descriptors. Advanced FTP and SNAP parameters may require new notation.

1 The ACSys/FE framework already allows "attributes" to be named. We don’t have an acquisition protocol that allows us to use it.