Protocol messages specification

The pvAccess protocol uses two protocol message types:

  • Control messages. These include flow control and have no payload

  • Application messages. These are the requests and their responses.

Each message consists of a message header and for Application messages, a message payload immediately following the header. Messages MUST BE aligned on a 64-bit boundary (TODO really?).

Every implementation of the protocol which purports to support this specification version of the protocol, MUST also support all prior specification versions of the protocol. Every implementation of the protocol MUST clearly indicate the most recent specification version to which it is conformant, using the version URLs above.

Message Header

Each protocol message has a fixed 8-byte header that MUST be encoded as if it were expressed by the following structure:

struct pvAccessHeader {
    byte magic;
    byte version;
    byte flags;
    byte messageCommand;
    int payloadSize;
};

The semantics of these message header components are given in the following table.

Table 9 pvAccess Header Members

Member

Description

magic

pvAccess protocol magic code. This MUST always be 0xCA.

version

Protocol version.

flags

Message flags.

messageCommand

Message command (i.e. create, get, put, process, etc.).

payloadSize

Message payload size (non-aligned, in bytes).

Table 10 pvAccess Header Flags Description

bit

Value

Description

0

0

Application message

0

1

Control message

1,2,3

0

Unused, MUST be 0

5, 4

00

Not segmented message

5, 4

01

First message (of segmented messages)

5, 4

10

Last message (of segmented messages)

5, 4

11

Middle message (of segmented messages)

6

0

Message sent by client

6

1

Message sent by server

7

0

Little endian byte order

7

1

Big endian byte order

Between two segmented messages of the same set there MUST NOT be any other application message than the segmented message of the same set. Control messages are allowed to be in-between.

Alignment offset MUST be preserved between segmented messages, i.e. if the last sent byte of a segmented message is misaligned by 6 bytes to the 64-bit aligned start of the message reference point, then the next segmented message needs to insert 6 padding bytes at the start of the next segmented message payload.

Application Messages

This section describes the message payloads for application messages. Each subsection describes a single message command (pvAccessHeader.messageCommand).

“request” means a message sent by a client, and “response” means a message sent by a server. Is this specifically in response to the client request? If so, as written “response” does not say that!

In order to understand specific application messages it is helpful to be familiar with the EPICS V4 pvAccess Programmers Reference.

Most application messages below relate to the management of process variable channels. A process variable, or PV, is a dynamical quantity and its associated local processing semantics, as understood by process control systems. pvAccess has been designed to specifically integrate with process control systems to provide an efficient interconnect for systems involved in the exchange of PV related information. Agent systems connect to a process control computer (via pvAccess) hosting PVs, by opening a “Channel” to each PV of interest. A channel is the temporal connection between pvAccess agents, with respect to one process variable.

All application message MUST be sent over the data transmission transport unless explicitly specified. TCP/IP is the transport in the reference implementation. A response message MUST be sent over the same transport as that on which the request was received.

CMD_BEACON (0x00)

Servers MUST broadcast or multicast beacons over UDP. Beacons are be used to announce the appearance and continued presence of servers. Clients may use Beacons to detect when new servers appear, and may use this information to more quickly retry unanswered CMD_SEARCH messages.

struct beaconMessage {
    byte[12] guid;
    byte flags;
    byte beaconSequenceId;
    short changeCount;
    byte[16] serverAddress;
    short serverPort;
    string protocol;
    FieldDesc serverStatusIF;
    [if serverStatusIF != NULL_TYPE_CODE] PVField serverStatus;
};
Table 11 Beacon Message Members

Member

Description

guid

Server GUID (Globally Unique Identifier). MUST change every restart.

flags

reserved

beaconSequenceId

Beacon sequence ID (counter w/ rollover). Can be used to detect UDP routing problems.

changeCount

Count (w/ rollover) that changes every time server’s list of channels changes.

serverAddressIPv6

Server address (e.g. for IP transports IPv6 or IPv6 encoded IPv4 address).

serverPort

Server port (e.g. for IP transport socket port where server is listening).

protocol

Protocol/transport name (e.g. “tcp” for standard pvAccess TCP/IP communication).

serverStatusIF

Optional server status Field description, NULL_TYPE_CODE MUST be used indicate absence of data.

serverStatus

Optional server data.

When a pvAccess server is started it MUST begin emitting beacons. Clients MUST monitor all beacons. A beacon received from an as yet unknown serverAddress:serverPort MUST be interpreted as indicating that a new server has come online. A beacon with the same serverAdddress:serverPort address as one already received but has different globally unique ID (guid), MUST be interpreted as indicating that the server was restarted. In both cases a client SHOULD boost searching of not yet found channels. A client SHOUD also boost searching of not yet found channels when changeCount changes (this indicates that the server might host new channels). A client MAY disconnect old connections or wait until connection loss is detected (on failed Echo message send).

Each server transport instance SHOULD emit its own beacons. For example, if a server supports data transmission over TCP/IP and UDP/IP then these SHOULD both emit beacons. If the instances are tightly coupled, i.e. they have the same lifecycle and share the same channels, then only one server MAY emit beacons.

Due to the fact that UDP does not guarantee delivery, a server MUST send several beacons to notify that it is alive (e.g. 15 beacons with 1Hz period). After a longer period it MAY stop sending them, however it is recommended that it SHOULD continue merely with a low rate (e.g. one beacon per minute) to report serverStatus.

Existing PVA server implementations send one beacon every 15 seconds for the first 5 minutes after startup. After running for 5 minutes, they lower the beacon period to once every 180 seconds (3 minutes).

Beacons SHOULD not be used to report connection-valid status.

CMD_CONNECTION_VALIDATION (0x01)

The Connection Validation message has two different formats depending on Flags[Direction].

A Connection Validation Request message MUST be the first application message sent from the server to a client when a TCP/IP connection is established (after a Set byte order Control message). The client MUST NOT send any messages on the connection until it has received a connection validation message from the server.

The connection validation request and connection validation response messages are defined as follows:

// Server to Client
struct connectionValidationRequest {
    int serverReceiveBufferSize;
    short serverIntrospectionRegistryMaxSize;
    string[] authNZ;                        // list of supported authNZ;
};

// Client to Server
struct connectionValidationResponse {
    int clientReceiveBufferSize;
    short clientIntrospectionRegistryMaxSize;
    short connectionQos;
    string authNZ;                          // selected authNZ plugin;
    // Optional, content depends on authNZ
    FieldDesc dataIF;
    PVField data;
};

In the connectionValidationRequest, the server lists the support authentication methods. Currently supported are “anonymous”, “ca”, “x509”. In the connectionValidationResponse, the client selects one of these. For “anonymous” or “x509”, no further detail is required and the FieldDesc is 0xFF for the ‘null’ type code with no PVField. For “ca”, a structure with string elements “user” and “host” needs to follow.

Table 12 Connection Validation Request Message Members

Member

Description

serverReceiveBufferSize

Server receive buffer size in bytes.

serverReceiveSocketBufferSize

Server socket buffer size in bytes.

serverIntrospectionRegistryMaxSize

Maximum number of introspection registry entries server is able to handle.

authNZ

List of supported authentication modes

Table 13 Connection Validation Response Message Members

Member

Description

clientReceiveBufferSize

Client receive buffer size in bytes.

clientReceiveSocketBufferSize

Client socket buffer size in bytes.

clientIntrospectionRegistryMaxSize

Maximum number of introspection registry entries client is able to handle.

connectionQoS

Connection QoS parameters.

Table 14 Connection QoS Parameters Description

bit

Description

0-6

Priority level [0-100].

7

Unused, MUST be 0.

8

Low-latency priority.

9

Throughput priority.

10

Enable compression.

11-15

Unused, MUST be 0.

Each Quality of Service (QoS) parameter value REQUIRES a separate TCP/IP connection. If the Low-latency priority bit is set, this indicates clients should attempt to minimize latency if they have the capacity to do so. If the Throughput priority bit is set, this indicates a client similarly should attempt to maximize throughput. How this is achieved is implementation defined. The Compression bit enables compression for the connection (Which compression? From which support layer?). A matter for a future version of the specification should be whether a streaming mode algorithm should be specified.

CMD_ECHO (0x02)

An Echo diagnostic message is usually sent to check if TCP/IP connection is still valid.

struct echoRequest {
    byte[] somePayload;
};

struct echoResponse {
    byte[] samePayloadAsInRequest;
};
Table 15 Echo request message members

Member

Description

somePayload

Arbitrary payload content, can be empty.

Table 16 Echo response message members

Member

Description

samePayloadAsInRequest

Same paylaod as in request message.

Version 1 servers do not support the payload and will always send an empty reply. Version 2 servers return the payload.

CMD_SEARCH (0x03)

A channel “search request” message SHOULD be sent over UDP/IP, however UDP congestion control SHOULD be implemented in this case. A server MUST accept this message also over TCP/IP.

struct searchRequest {
    int searchSequenceID;
    byte flags; // 0-bit for replyRequired, 7-th bit for "sent as unicast" (1)/"sent as broadcast/multicast" (0)

    byte[3] reserved;

    // if not provided (or zero), the same transport is used for responses
    // needs to be set when local broadcast (multicast on loop interface) is done
    byte[16] responseAddress; // e.g. IPv6 address in case of IP based transport, UDP
    short responsePort;       // e.g. socket port in case of IP based transport

    string[] protocols;

    struct {
        int searchInstanceID;
        string channelName;
    } channels[];
};
Table 17 Search request message members

Member

Description

searchSequenceID

Search sequence ID (counter w/ rollover), can be used by congestion control algorithms.

replyRequired

0x01 to force server to respond even if it does not host channel(s), 0x00 otherwise.

protocol

A set of allowed protocols to respond (“tcp”, “tls”). Unrestricted if array is empty.

searchInstanceID

ID to be used to associate response with the following channel name.

channelName

Non-empty channel name, maximum length of 500 characters.

The protocol “tcp” indicates that the client would like to then continue the data communication via a plain TCP connection. “tls” indicates that the client can also support an SSL/TLS TCP connection.

Note that the element count for protocol uses the normal size encoding, i.e. unsigned 8-bit integer 1 for one supported protocol. The element count for the channels array, however, always uses an unsigned 16 bit integer. This choice is based on the reference implementations which append channel names to the network buffer and update the count. With normal size encoding, an increment to 254 would change the count from requiring 1 byte to 3 bytes, shifting already added channel names.

The response to a search request is defined as messageCommand 0x04, see below.

As mentioned, servers always accept CMD_SEARCH via TCP. The environment variable EPICS_PVA_NAME_SERVERS configures a client to use a list of IP addresses for name lookup via TCP. The client connects to each IP (and optional “:port”) listed as a name server. Upon connection, the server will send the byte order and validation request messages. After the server and client complete this exchange, the client may send CMD_SEARCH. If the channel is known, the server will reply with CMD_SEARCH_RESPONSE via the same TCP connection.

CMD_SEARCH_RESPONSE (0x04)

A search response message MUST be sent as the response to a specific search request (0x03) message.

struct searchResponse {
    byte[12] guid;          
    int searchSequenceID;
    byte[16] serverAddress; // e.g. IPv6 address in case of IP based transport 
    short serverPort;       // e.g. socket port in case of IP based transport
    string protocol;
    boolean found;
    int[] searchInstanceIDs;
};
Table 18 Search response message members

Member

Description

searchSequenceID

Search sequence ID, same as specified in search request.

found

Flag indicating whether response contains IDs of found or not found channels.

serverAddressIPv6

Server address (e.g. in case of IP transport IP or IPv6 encoded IPv4 address).

serverPort

Server port (e.g. in case of IP transport socket port where server is listening).

protocol

Protocol name, “tcp” for standard pvAccess TCP/IP communication, “tls” for secure TCP

searchInstanceIDs

IDs, associated with names in the request, relevant to this response.

A client MUST examine the protocol member field to verify it supports the given exchange protocol; if not, the search response is ignored.

The count for the number of searchInstanceIDs elements is always sent as an unsigned 16 bit integer, not using the default size encoding.

If the serverAddressIPv6 is non-zero, it specifies the TCP connection information that the client should use for further communication, i.e., to create a channel and perform get/put/… operations. If the address is all zero, and the exchange is via UDP, the client should use the address from which the UDP reply was received as the server address. If the address is all zero, and the exchange is via TCP, the client should use that same TCP connection for further communication.

CMD_AUTHNZ (0x05)

struct authNZRequest {
    FieldDesc dataIF;
    [if dataIF != NULL_TYPE_CODE] PVField data;
};

struct authNZResponse {
    FieldDesc dataIF;
    [if dataIF != NULL_TYPE_CODE] PVField data;
};

CMD_ACL_CHANGE (0x06)

This is a placeholder message code not used by existing peers.

// TODO new message code (from server) 0x06
struct aclChange {
    int clientChannelID;
    struct {
        int requestID;  // invalid ID is 0 (means for channel)
        BitSet[] rights;   // get has only one bit-set (readRights), put-get has 2 (read and write), channel has one (allowed/dissallowed request)
    } changes[];
};

CMD_CREATE_CHANNEL (0x07)

A channel provides a communication path between a client and a server hosted “process variable.”

Each channel instance MUST be bound only to one connection.

struct createChannelRequest {
    short count;
    struct {
        int clientChannelID;
        string channelName;
    } channels[];
};

struct createChannelResponse {
    int clientChannelID;
    int serverChannelID;
    Status status;
    // [if status.type == OK | WARNING] short accessRights; // never used
};
Table 19 Create channel request message members

Member

Description

clientChannelID

Client generated channel ID.

channelName

Name of the channel to be created, non-empty and maximum length of 500 characters.

The createChannelRequest.channels array starts with a short count, not using the normal size encoding. Current PVA server implementations only support requests for creating a single channel, i.e. the count must be 1.

Table 20 Create channel response (per channel) message members

Member

Description

clientChannelID

Client generated channel ID, same as in request

serverChannelID

Server generated channel ID.

status

Completion status.

accessRights

Access rights (TBD).

Note

A server MUST store the clientChannelID and respond with its value in a destroyChannelMessage when a channel destroy request is requested, see below. A client uses the serverChannelID value for all subsequent requests on the channel. Agents SHOULD NOT make any assumptions about how given IDs are generated. IDs MUST be unique within a connection and MAY be recycled after a channel is disconnected.

CMD_DESTROY_CHANNEL (0x08)

A “destroy channel” message is sent by a client to a server to destroy a channel that was previously created (with a create channel message).

A server may also send this message to the client when the channel is no longer available. Examples include a PVA gateway that sends this message from its server side when it lost a channel on its client side.

struct destroyChannelRequest {
    int serverChannelID;
    int clientChannelID;
};

struct destroyChannelResponse {
    int serverChannelID;
    int clientChannelID;
};
Table 21 Destroy channel request

Member

Description

serverChannelID

Server generated channel ID, same as in create response.

clientChannelID

Client generated channel ID, same as in create request.

Table 22 Destroy channel response

Member

Description

serverChannelID

Server generated channel ID, same as in create response.

clientChannelID

Client generated channel ID, same as in create request.

If the request (clientChannelID, serverChannelID) pair does not match, the server MUST respond with an error status. The server MAY break its response into several messages.

Note

A server MUST send this message to a client to notify the client about server-side initiated channel destruction. Subsequently, a client MUST mark such channels as disconnected. If the client’s interest in the process variable continues, it MUST start sending search request messages for the channel.

CMD_CONNECTION_VALIDATED (0x09)

Sent from Client to Server to indicate the completion of an Authentication handshake.

struct connectionValidated {
    Status status;
};

CMD_GET (0x0A)

A “channel get” set of messages are used to retrieve (get) data from the channel.

struct channelGetRequestInit {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x08 for INIT;
    FieldDesc pvRequestIF;
    PVField pvRequest;
};

struct channelGetResponseInit {
    int requestID;
    byte subcommand;
    Status status;
    [if status.type == OK | WARNING] FieldDesc pvStructureIF;
};
Table 23 Channel get init request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Client generated request ID.

subcommand

0x08

pvRequestIF

pvRequest Field description.

pvRequest

pvRequest structure.

Table 24 Channel get init response

Member

Description

requestID

Request ID, same as in request message.

subcommand

0x08, same as in request message.

status

Completion status.

pvStructureIF

pvStructure (data container) Field description.

After a get request is successfully initialized, the client can issue actual get request(s).

struct channelGetRequest {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x00 or 0x40 for GET; additional 0x10 mask for DESTROY;
};

struct channelGetResponse {
    int requestID;
    byte subcommand;
    Status status;
    [if status.type == OK | WARNING] BitSet changedBitSet;
    [if status.type == OK | WARNING] PVField pvStructureData;
};
Table 25 Channel get request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in init message.

subcommand

0x00 for GET, additional 0x10 mask for DESTROY.

Table 26 Channel get response

Member

Description

requestID

Request ID, same as in request message.

subcommand

Same as in request message.

status

Completion status.

changedBitSet

Changed BitSet for pvStructureData.

pvStructureData

Data structure.

Most implementations send a 0x00 subcommand to GET data, but based on the original protocol documentation 0x40 is also in use.

Note

If the DESTROY mask is applied, the server MUST destroy the request after the get response and the client MUST do the same after it receives the response.

CMD_PUT (0x0B)

A “channel put” set of messages are used to set (put) data to the channel.

struct channelPutRequestInit {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x08;
    FieldDesc pvRequestIF;
    PVField pvRequest;
};

struct channelPutResponseInit {
    int requestID;
    byte subcommand;
    Status status;
    [if status.type == OK | WARNING] FieldDesc pvPutStructureIF;
};
Table 27 Channel put init request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Client generated request ID.

subcommand

0x08

pvRequestIF

pvRequest Field description.

pvRequest

pvRequest structure.

Table 28 Channel put init response

Member

Description

requestID

Request ID, same as in request message.

subcommand

0x08, same as in request message.

status

Completion status.

pvPutStructureIF

pvPutStructure (data container) Field description.

After a put request is successfully initialized, the client can issue actual put request(s) on the channel.

struct channelPutRequest {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x00 for PUT; 0x10 mask for DESTROY;
    BitSet toPutBitSet;
    PVField pvPutStructureData;
};

struct channelPutResponse {
    int requestID;
    byte subcommand;
    Status status;
};
Table 29 Channel put request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in init message.

subcommand

0x00 for PUT, additional 0x10 mask for DESTROY.

toPutBitSet

To-put BitSet for pvPutStructureData.

pvPutStructureData

Data to put structure.

Table 30 Channel put response

Member

Description

requestID

Request ID, same as in request message.

subcommand

Same as in request message.

status

Completion status.

A “get-put” request retrieves the remote put structure. This MAY be used by user applications to show data that was set the last time by the application.

struct channelGetPutRequest {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x40;
};

struct channelGetPutResponse {
    int requestID;
    byte subcommand;
    Status status;
    [if status.type == OK | WARNING]
        BitSet returnedDataBitSet;
        PVField pvStructureData;
};
Table 31 Channel get put request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in init message.

subcommand

0x40.

Table 32 Channel get put response

Member

Description

requestID

Request ID, same as in request message.

subcommand

Same as in request message.

status

Completion status.

returnedDataBitSet

Which fields are provided in data.

pvStructureData

The returned data.

CMD_PUT_GET (0x0C)

A “channel put-get” set of messages are used to set (put) data to the channel and then immediately retrieve data from the channel. Channels are usually “processed” or “updated” by their host between put and get, so that the get reflects changes in the process variable’s state.

struct channelPutGetRequestInit {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x08;
    FieldDesc pvRequestIF;
    PVField pvRequest;
};

struct channelPutGetResponseInit {
    int requestID;
    byte subcommand;
    Status status;
    [if status.type == OK | WARNING] FieldDesc pvPutStructureIF;
    [if status.type == OK | WARNING] FieldDesc pvGetStructureIF;
};
Table 33 Channel put-get init request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Client generated request ID.

subcommand

0x08

pvRequestIF

pvRequest Field description.

pvRequest

pvRequest structure.

Table 34 Channel put-get init response

Member

Description

requestID

Request ID, same as in request message.

subcommand

0x08, same as in request message.

status

Completion status.

pvPutStructureIF

pvPutStructure (data container) Field description.

pvGetStructureIF

pvGetStructure (data container) Field description.

After a put-get request is successfully initialized, the client can issue actual put-get request(s) on the channel.

struct channelPutGetRequest {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x00 for PUT_GET; 0x10 mask for DESTROY;
    BitSet toPutBitSet;
    PVField pvPutStructureData;
};

struct channelPutGetResponse {
    int requestID;
    byte subcommand;
    Status status;
    [if status.type == OK | WARNING] PVField pvGetStructureData;
};
Table 35 Channel put-get request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in init message.

subcommand

0x00 for PUT_GET, additional 0x01 mask for DESTROY.

toPutBitSet

To-put BitSet for pvPutStructureData.

pvPutStructureData

Data to put structure.

Table 36 Channel put-get response

Member

Description

requestID

Request ID, same as in request message.

subcommand

Same as in request message.

status

Completion status.

pvGetStructureData

Get data structure.

A “get-put” request retrieves the remote put structure. This MAY be used by user applications to show data that was set the last time by the application.

struct channelGetPutRequest {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x80;
};

struct channelGetPutResponse {
    int requestID;
    byte subcommand;
    Status status;
    [if status.type == OK | WARNING] PVField pvPutStructureData;
};
Table 37 Channel get put request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in init message.

subcommand

0x80.

Table 38 Channel get put response

Member

Description

requestID

Request ID, same as in request message.

subcommand

Same as in request message.

status

Completion status.

pvPutStructureData

Remote put data structure.

A “get-get” request retrieves remote get structure. This MAY be used by user applications to show data that was retrieved the last time.

struct channelGetGetRequest {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x40;
};

struct channelGetGetResponse {
    int requestID;
    byte subcommand;
    Status status;
    [if status.type == OK | WARNING] PVField pvGetStructureData;
};
Table 39 Channel get get request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in init message.

subcommand

0x40.

Table 40 Channel get get response

Member

Description

requestID

Request ID, same as in request message.

subcommand

Same as in request message.

status

Completion status.

pvGetStructureData

Remote get data structure.

CMD_MONITOR (0x0D)

The “channel monitor” set of messages are used by client agents to indicate that they wish to be asynchronously informed of changes in the state or values of the process variable of a channel.

Setup

Starting with a valid serverChannelID (cf. Create Channel message), a client first sends a channelMonitorRequest with subcommand==0x08 or 0x88 (if using the pipeline protocol). The client also chooses a requestID, and provides a pvRequest structure.

The server responds with a channelMonitorResponse having subcommand==0x08 and a Status indicating whether the Channel supports subscriptions, and that the provided pvRequest is valid.

If the Status is success (OK or WARNING), then a the subscription data Structure is described and the subscription is established.

The subscription is initially in the Stopped state. In this state the Server must not send any updates.

Normal Operation

After a monitor subscription is established either peer may send non-init messages (subcommand&0xF7) asynchronously.

A Client may send a channelMonitorRequest which performs up to three actions.

  1. subcommand&0x80 indicates an acknowledgement (increment) to the pipeline flow control window.

  2. subcommand&0x44==0x44 Changes the subscription state from Stopped to Running. subcommand&0x44==0x04 Changes the subscription state from Running to Stopped.

  3. subcommand&0x10 requests that the subscription be terminated.

A Server subscription update is a channelMonitorResponse with subcommand==0x00 or 0x10. If 0x10 then this update is the last update, and the subscription has ended.

The changedBitSet lists all elements of the channel data that has changed, i.e. the following pvStructureData contains only the serialization for those changed elements. Note that the changedBitSet may address the same element more than once. For example, a bitset {0, 1, 2} indicates that the complete structure has changed (bit 0), and additionally indicates a change in elements 1 and 2, which might be the first two elements of that structure. The pvStructureData will only contain the complete structure data once, it will not repeat data for elements 1 and 2, since they are already contained in the serialized data addressed by bit 0.

pvRequest options

standard options

  1. record._options.queueSize

  2. record._options.pipeline

  3. record._options.ackAny

Pipeline protocol option

Usage of the pipeline protocol option requires both sides to agree and maintain a flow control window counter indicating the number of subscription updates which the Server is may send without receiving another acknowledgement from the Client.

This option is exercised used if the pvRequest includes the field ‘record._options.pipeline’ having a value convertible to boolean true. If this field is not present, or not convertible to true, then the Server may send subscription updates without restriction.

The flow control window counter is established by the client in the initial channelMonitorRequest message. If subcommand==0x08, the initial count is zero. If subcommand==0x88, then the initial count is provided by the ‘nfree’ message field.

The Server may send a subscription update as long as the flow control counter is non-zero. Each time an update is sent by the server, and received by the client, the counter is decremented.

The client may send a channelMonitorRequest with subcommand&0x80 and a ‘nfree’ count which is added to the counter.

Acknowledgement Algorithm

In this way, the client can manage the rate at which the server can send update.

A suggested implementation is for the client to maintain a predetermined buffer capacity. This size is send as the initial window size (counter). This buffer fills as subscription updates are received, and it is update data is consumed.

Entries in this buffer may be in one of three states.

  1. Free.

  2. In Use

  3. Un-acknowledged

Transitions are:

  1. Free -> In Use when a subscription update is received

  2. In Use -> Un-acknowledged when the update data has been consumed

  3. Un-acknowledged -> Free when an acknowledgement message is sent

The flow control window counter should match the number of Free entries.

The ‘nfree’ count in an acknowledgement message should never exceed the number of Un-acknowledged entries.

For reasons of efficiency, it is recommended not to send an acknowledgement message each time an entries transitions Un-acknowledged -> Free. A suggested default is to send an acknowledgement when the number of Un-acknowledged exceeds half of the total buffer capacity.

TODO: describe ‘record._options.ackAny’ option.

Request Encoding (Client -> Server)

struct channelMonitorRequest {
    int serverChannelID;
    int requestID;
    byte subcommand;
    if subcommmand&0x08 { // Init
        StructureDesc pvRequestIF;
        PVStructure pvRequest;
        if subcommand&0x80 { // pipeline support
            int nfree; // initial window size
        }
    } else {
        if subcommand&0x80 { // pipeline support
            int nfree; // increment window size
        }
        if subcommand&0x04 {
            if subcommand&0x40 {
                // subscription start
            } else {
                // subscription stop
            }
        }
        if subcommand&0x10 {
            // last request (requestID released)
        }
    }
};

Response Encoding (Server -> Client)

struct channelMonitorResponse {
    int requestID;
    byte subcommand;
    if subcommmand&0x08 { // Init
        Status status;
        if status.type == OK | WARNING {
            FieldDesc pvStructureIF;
        }
    } else {
        if subcommand&0x10 {
            Status status;
            if ! payloadBuffer.empty() {
                BitSet changedBitSet;
                PVField pvStructureData;
                BitSet overrunBitSet;
            }
            // final update (requestID released)
        } else { // normal update
            BitSet changedBitSet;
            PVField pvStructureData;
            BitSet overrunBitSet;
        }
    }
};

CMD_ARRAY (0x0E)

A “channel array” set of messages are used to handle remote array values. Requests allow a client agent to: retrieve (get) and set (put) data from/to the array, and to change the array’s length (number of valid elements in the array).

struct channelArrayRequestInit {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x08;
    FieldDesc pvRequestIF;
    PVField pvRequest;
};

struct channelArrayResponseInit {
    int requestID;
    byte subcommand;
    Status status;
    [if status.type == OK | WARNING] FieldDesc pvArrayIF;
};
Table 41 Channel array init request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Client generated request ID.

subcommand

0x08

pvRequestIF

pvRequest Field description.

pvRequest

pvRequest structure.

Table 42 Channel array init response

Member

Description

requestID

Request ID, same as in request message.

subcommand

0x08, same as in request message.

status

Completion status.

pvArrayIF

pvArray (data container) Field description.

After an array request is successfully initialized, the client can issue the actual array request(s).

struct channelGetArrayRequest {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x40 mask for GET; 0x10 mask for DESTROY;
    size offset;
    size count;
};

struct channelGetArrayResponse {
    int requestID;
    byte subcommand;
    Status status;
    [if status.type == OK | WARNING] PVField pvArrayData;
};
Table 43 Channel array get request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in init message.

subcommand

0x40 for GET, additional 0x10 mask for DESTROY.

offset

Offset from the beginning of the array.

count

Number of elements requested, 0 means form offset to the end of the array.

Table 44 Channel array get response

Member

Description

requestID

Request ID, same as in request message.

subcommand

Same as in request message.

status

Completion status.

pvArrayData

Data array.

struct channelPutArrayRequest {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x00 mask for PUT; 0x10 mask for DESTROY;
    size offset;
    PVField pvArrayData;
};

struct channelPutArrayResponse {
    int requestID;
    byte subcommand;
    Status status;
};
Table 45 Channel array put request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in init message.

subcommand

0x00 for PUT, additional 0x10 mask for DESTROY.

offset

Offset from the beginning of the array.

pvArrayData

Subarray to be put.

Table 46 Channel array put response

Member

Description

requestID

Request ID, same as in request message.

subcommand

Same as in request message.

status

Completion status.

/// TODO GetLength is missing, fix the codes \!\!\!

struct channelSetLengthRequest {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x80 mask for SET_LENGTH; 0x10 mask for DESTROY;
    size length;
};

struct channelSetLengthResponse {
    int requestID;
    byte subcommand;
    Status status;
};
Table 47 Channel array set length request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in init message.

subcommand

0x40 for GET, additional 0x10 mask for DESTROY.

length

New length.

Table 48 Channel array set length response

Member

Description

requestID

Request ID, same as in request message.

subcommand

Same as in request message.

status

Completion status.

CMD_DESTROY_REQUEST (0x0F)

A “destroy request” messages is used destroy any request instance, i.e. an instance with requestID.

// destroys any request with given requestID
struct destroyRequest {
    int serverChannelID;
    int requestID;
};
Table 49 Destroy request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in request init message.

CMD_PROCESS (0x10)

A “channel process” set of messages are used to indicate to the server that the computation actions associated with a channel should be executed. In the language of EPICS, this means that the channel should be “processed”.

struct channelProcessRequestInit {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x08;
    FieldDesc pvRequestIF;
    [if serverStatusIF != NULL_TYPE_CODE] PVField pvRequest;
};

struct channelProcessResponseInit {
    int requestID;
    byte subcommand;
    Status status;
};
Table 50 Channel process init request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Client generated request ID.

subcommand

0x08

pvRequestIF

Optional pvRequest Field description, NULL_TYPE_CODE is none.

pvRequest

Optional pvRequest structure.

Table 51 Channel process init response

Member

Description

requestID

Request ID, same as in request message.

subcommand

0x08, same as in request message.

status

Completion status.

After a process request is successfully initialized, the client can issue the actual process request(s).

struct channelProcessRequest {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x00 mask for PROCESS; 0x10 mask for DESTROY;
};

struct channelProcessResponse {
    int requestID;
    byte subcommand;
    Status status;
};
Table 52 Channel process request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in init message.

subcommand

0x00 for PROCESS, additional 0x10 mask for DESTROY.

Table 53 Channel process response

Member

Description

requestID

Request ID, same as in request message.

subcommand

Same as in request message.

status

Completion status.

CMD_GET_FIELD (0x11)

Thus message is used to retrieve a channel’s type introspection data, i.e. a description of all the channel’s fields and their data types.

struct channelGetFieldRequest {
    int serverChannelID;
    int requestID;
    string subFieldName;  // entire record if empty
};

struct channelGetFieldResponse {
    int requestID;
    Status status;
    [if status.type == OK | WARNING] FieldDesc subFieldIF;
};
Table 54 Get channel introspection data request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Client generated request ID.

subFieldName

Name of the subfield to get or entire record if empty.

Table 55 Get channel introspection data response

Member

Description

requestID

Request ID, same as in request message.

status

Completion status.

subFieldIF

Requested field introspection data.

CMD_MESSAGE (0x12)

A “message” message is used by a server to provide to a client human readable text regarding the status of a specific request. This message MUST NOT be used to report request completion status.

struct message {
    int requestID;
    byte messageType; // info = 0, warning = 1, error = 2, fatalError = 3
    string message;
};
Table 56 Message response

Member

Description

requestID

Request ID.

messageType

Message type enum.

message

Message.

CMD_MULTIPLE_DATA (0x13)

This message code never used, and considered deprecated.

CMD_RPC (0x14)

The “channel RPC” set of messages are used to provide remote procedure call (RPC) support over pvAccess.

struct channelRPCRequestInit {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x08;
    FieldDesc pvRequestIF;
    PVField pvRequest;
};

struct channelRPCResponseInit {
    int requestID;
    byte subcommand;
    Status status;
};
Table 57 Channel RPC init request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Client generated request ID.

subcommand

0x08

pvRequestIF

pvRequest Field description.

pvRequest

pvRequest structure.

Table 58 Channel RPC init response

Member

Description

requestID

Request ID, same as in request message.

subcommand

0x08, same as in request message.

status

Completion status.

After a RPC request is successfully initialized, the client can issue actual RPC request(s).

struct channelRPCRequest {
    int serverChannelID;
    int requestID;
    byte subcommand = 0x00 mask for RPC; 0x10 mask for DESTROY;
    FieldDesc pvStructureIF;
    PVField pvStructureData;
};

struct channelRPCResponse {
    int requestID;
    byte subcommand;
    Status status;
    [if status.type == OK | WARNING] FieldDesc pvResponseIF;
    [if status.type == OK | WARNING] PVField pvResponseData;
};
Table 59 Channel RPC request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in init message.

subcommand

0x00 for RPC, additional 0x10 mask for DESTROY.

pvStructureIF

pvStructureData Field description.

pvStructureData

Argument data structure.

Table 60 Channel RPC response

Member

Description

requestID

Request ID, same as in request message.

subcommand

Same as in request message.

status

Completion status.

pvResponseIF

pvResponseDataField description.

pvResponseData

Response data structure.

CMD_CANCEL_REQUEST (0x15)

A “cancel request” messages is used cancel any pending request, i.e. an instance with requestID.

// cancel any request with given requestID
struct cancelRequest {
    int serverChannelID;
    int requestID;
};
Table 61 Cancel request

Member

Description

serverChannelID

Server generated channel ID, same as in create channel response.

requestID

Request ID, same as in request init message.

CMD_ORIGIN_TAG (0x16)

When a client or server receives a packet containing a Search message with flagged “sent as unicast” it may resend this as a multicast to “224.0.0.128” through the loopback interface (“127.0.0.1”). A forwarded packet must change Search messages flagged “sent as unicast” to “send as broadcast”, and prefix the packet with an Origin Tag message containing the address to which the receiving socket was bound. This may be “0.0.0.0”, an interface address, or a local broadcast address depending on the host OS.

A server which wishes to receive forwarded unicast Search messages should listen for “224.0.0.128” through the loopback interface. aka. join group “224.0.0.128” on interface “127.0.0.1”. Received packets should be handled in one of three ways.

  1. A packet which is prefixed with an Origin Tag message containing a forwarderAddress which matches one or more of a server’s socket bind addresses shall be processed as if it was received through each matching socket. At exception to this is that a forwarded message must never be re-forwarded, even if containing Search messages flagged as “sent as unicast”.

  2. If the host OS (like Windows) does not support receiving only multicast messages, then any packet not prefixed with an Origin Tag, and containing a Search message flagged “sent as unicast” should be forwarded.

  3. Other packets must be ignored.

A forwarderAddress is considered to match a server’s socket bind address if a socket bound to either address could have received the original packet. This is an OS dependent process. A suggested start point is to consider a match if either forwarderAddress or socket bind address is “0.0.0.0” (INADDR_ANY). Identical forwarderAddress and bind address also match.

// Indicate who forwarded the search request
struct originTag {
    byte[16] forwarderAddress;
};

Control Messages

This section describes the message payloads for control messages. Each subsection describes a single message command (pvAccessHeader.messageCommand).

Control messages have no payload and are used internally by the protocol, for instance to handle byte order management and flow control.

The payload size field contains control message specific values.

Mark Total Byte Sent (0x00)

Note that this message type has so far not been used.

The payload size field holds the value of the total bytes sent. The client SHOULD respond with an acknowledgment control message (0x01) as soon as possible.

Acknowledge Total Bytes Received (0x01)

Note that this message type has so far not been used.

The payload size field holds the acknowledge value of total bytes received. This must match the previously received marked value as described above.

Set byte order (0x02)

The 7-th bit of a header flags field indicates the server’s selected byte order for the connection on which this message was received. Client MUST encode all the messages sent to the server via this connection using this byte order.
The client’s decoding byte order for messages received from the server depends on the payload size field value as follows:

Table 62 Client Decoding

Payload Size Field Value

Meaning

0x00000000

Client MUST decode all the messages received via this connection using server’s selected byte order.

0xFFFFFFFF

Client MUST decode all the messages sent received this connection as indicated by each message byte order flag.

Note

Existing implementations have been found to ignore the “payload size”. They decode each received message based on the byte order bit in the message header flags field, i.e., they always behave as per “payload size” = 0xFFFFFFFF.

This MUST be the first message sent by a server when connection is established. For connection-less protocols this message is not sent and byte order is determined per message using its byte order flag.

Note

This message is byte order independent.

Echo request (0x03)

Diagnostic/test echo message. The receiver should respond with an Echo response (0x04) message with the same payload size field value.

Echo response (0x04)

Response to a echo request. The payload size field contains the same value as in the request message.