Timed Sample Protocols

Timed Sample protocols cover a collection of common Opcodes, but with differing underlying sample data types. The opcodes, and their intended usage is described below in Opcodes. The purpose of this common protocol approach is to create a group of components, which allow information about the manner in which the data was gathered/generated to be sent in-line with the sample data itself. Therefore allowing a single port to be used to contextualise the samples present upon it.

The protocol was developed for use with Software Defined Radios (SDRs), with the intention of providing a standardised way to pass information related to the capture, or transmission of samples, (e.g. timestamps, driving discrete IO or GPS position).

Transitioning of Opcodes

Opcodes in OpenCPI are capable of being changed at any point without any specific buffer length being required. However there is a general assumption that the most used opcode will be that of Sample. Therefore optimisation of actions affecting this opcode is to be considered a higher priority than other operations.

Operations such as Flush and Discontinuity are zero length messages (ZLM’s). There is no data transferred with these operations, instead entering this opcode should be seen as sufficient evidence that this event has occurred.

Opcodes

Sample

Sample opcode is used for transferring samples. The underlying type used within this opcode is the basis of that protocol name, and the suffix attached to the name of any components which have been designed to handle only a single protocol format. If a component has different input and output types on their primary ports, then both protocols are mentioned in the suffix. A component which handles data in a protocol-agnostic manner (i.e. protocol-less) does not have any protocol suffix in its name.

The following formats are currently supported:

The endianness of protocol defaults to host ordered, however note that this can be explicitly defined within a worker’s OWD.

Time

Time of the first sample in the next sample message, with subsequent samples being continuous and captured on a time delta defined by sample interval. If data is not continuous, then the timestamp might stop reflecting the actual time of reception/transmission, therefore after a Discontinuity it is advised to resend the time.

On a receive path, time generally is related to either the time the signal was received at the signal port, or the time at which digitisation occurred (both of these relate to a time in the past).

On a transmit path, time is generally related to the time that a signal is to be transmitted. As this time is generally in the future relative to the processing time, if a timestamp earlier than the current time is seen, this is taken as a request to transmit straight away. Additionally if a platform does not undertake any processing of timestamps on the transmit path, then this will also lead to samples being transmitted straight away.

If a platform sets this timestamp directly (i.e. not set directly by an application), then any transmit or receive reference point should be clearly documented.

Time format is defined as being GPS time. Note that there is an offset between GPS and UTC timestamps; GPS being based on an invariant clock, whereas UTC might have discontinuities due to leap seconds. The differences are summarised in this stack exchange answer.

Components which discard or insert samples should update time messages so that any forwarded time messages are correctly related to the next sample message output by the component. Where a decimation has occurred (i.e. a discarding of samples) then the component should relate the timestamp to the first sub-sample of the next sample (ideally a group delay would also be provided to allow any additional alignment). Note that this insertion or discarding behaviour will also have an effect on the sample interval.

Time is stored as an unsigned Q32.64 fixed point value, where the seconds argument is the value before the decimal point and the fraction argument is the value after the decimal point. This leads to the smallest representable value being \(\approx 5.4 \times 10^{-20}\) seconds. Using just the 40 most significant bits of the fractional part gives accuracy to \(\approx 0.9095\) picoseconds.

Time messages contain 12 bytes of data.

  <operation name="time">
    <argument name="fraction" type="ulonglong"/>
    <argument name="seconds" type="ulong"/>
  </operation>

Sample Interval

The sample interval is the time between sample points (i.e. the reciprocal of the sample rate). It has the same format as the Time operation to allow direct addition of sample interval values to time values.

Components which discard or insert samples, (i.e. change the sampling rate), must update the sample interval so that the value sent from the component is a true reflection of the sampling rate output by the component. Sample interval is stored as an unsigned Q32.64 fixed point value, where the seconds argument is the value before the decimal point and the fraction argument is the value after the decimal point.

Sample interval messages contain 12 bytes of data.

  <operation name="sample_interval">
    <argument name="fraction" type="ulonglong"/>
    <argument name="seconds" type="ulong"/>
  </operation>

Flush

Instructs a component to flush all internal buffers within that component. This should lead to all input data received before this message being processed and outputted without the need for additional input data. Internal buffers are often flushed by feeding in zeros.

Once all data has been flushed (if there are any internal buffers to clear) the flush message must be forwarded on. Generally the flush length is tied to the size of these internal buffers, however some components opt for this to instead be controlled by a property.

Some platforms also use a flush to mark the completion of a transmission burst. On these platforms a flush message reaching the DAC has the additional meaning that any switching or amplifiers might be set back into a low power state.

Flush is a ZLM opcode.

<operation name="flush"/>

Discontinuity

Indicates that the next sample message is discontinuous from the previous sample message. A discontinuity implies that there is a gap in time, or processing context between the samples before and after the discontinuity message. As an example a component which is framing samples into the payload of a communication system protocol may output a discontinuity after each frame/packet, to mark the completion of that frame.

Discontinuity messages are interpreted as a requirement to reset any internal buffers, as the samples following this opcode do not have a close relationship to the samples preceding this message.

Discontinuity is a ZLM opcode.

<operation name="discontinuity"/>

Metadata

Additional information relating to the sample messages. The id argument stores an ID value for the type of metadata message. Each ID value is unique to a type of metadata. The value argument is the metadata value associated with the ID.

The id values are not globally defined, therefore it is up to the application developer to ensure that id values are unique within a given application. Workers must make the best possible effort to maintain the alignment of metadata messages within sample values of sample messages.

Note that while the aggregate size of the fields within a metadata message are the same as that of the sample interval and time messages, due to how data structures within OpenCPI are formed, there is additional padding within a metadata message (leading to a metadata message filling 16 bytes).

  <operation name="metadata">
    <argument name="id" type="ulong"/>
    <argument name="value" type="ulonglong"/>
  </operation>

Additional Information About Opcode Usage

Group Delay

Group delay is the phase (time) distortion that certain operations cause upon a signal, these calculations are normally related to filtering or calculations which accumulate an output value over multiple incoming samples. Depending upon the calculation a group delay can be linear, or frequency dependent. Some components within this project provide a property to allow the correction of any group delay. This is enacted as a subtraction from any incoming time opcodes (therefore is not a frequency dependent correction).

To align with the time and sample interval messages, the group delay is also defined as a Q32.64 formatted field.

Zero Length Messages

Opcodes which do not have any associated data are called zero length messages (ZLMs) within the OpenCPI framework. Examples of these are the Flush and Discontinuity opcodes.

Within an HDL worker context ZLMs only make use of a subset of the port signals: There is no data, therefore the byte_enable and valid signals are also not used (as these relate only to operations which contain data).

End of File

An end of file (EOF) flag is used to mark the point when no further data is capable of being processed without the worker being initialised. The EOF flag generally should only be set when the opcode is set to 0, and there is no active message (i.e. the previous message buffer has been sent).

Components can use the EOF flag like a flush message, in order to ensure any data left within internal buffers is processed before the component forwards on the EOF flag.