Universal Serial Parser (USP) Guide

There are many machines and sensors which emit streams of data over a serial interface, and can get some control commands over this same interface.

The purpose of the Universal Serial Parser (USP) service on Octave is to accept this data from a serial interface on the edge device and make it available in the resources tree so it can be interpreted in an edge action script in order to extract valuable information. The service provides also the capability to send commands via this same serial interface.

The service is exposed as any other Octave service (modbus, canopen, io).
It will be receiving a configuration from the cloud and exposes resources to read and write data from the serial link

📘

Firmware Version

This feature is available from edge firmware 3.0.0.

Interfaces Description

  • /usp/config : configuration of the service
  • /usp/value : decoded message according to the configuration
  • /usp/write : message to be sent over the serial interface

Configuration

The configuration of the service is done writing a JSON document to /usp/config resource:

{
  "uart": "UART0" | ... | "UARTn",   // String, Mandatory
  "frame_timeout": 0.5,              // Timeout in seconds. After waiting this amount of time without completing a message, reset the accumulation state and the parser state machine
    
  // Framing of serial data: choose one of the 3 strategies:
  "framing": {
      "delimiter":["0D0A","20"],// Accumulate bytes on the serial port until matching one of the specified separators. Delimiter is to be written as an Hex string
    // or
      "fixed": 34,// Accumulate the number of specified bytes
    // or
      "lenfield" : {"start":2, "size":2, "bigendian":true, "offset":0}, // Accumulate bytes based on a length field which define the number of byte to accumulate
  }
}

and also assigning the uart being owned by the usp service in the /io/config resource : "own":"usp".
example:

{
   "devs":[
      {
         "conf":[
            {
               "baud":"38400",
               "bits":"8",
               "flow":"N",
               "own":"usp",
               "pair":"N",
               "std":"232",
               "stop":"1",
               "type":"UART1",
               "wire":"2"
            }
         ],
         "type":"serial"
      }
   ]
}

3 strategies are available to adapt to the way messages are framed on the serial link:

  • delimiter: the service looks for one of the matching delimiters defined in the configuration. A delimiter is the hexadecimal representation of 1 to 4 bytes. All the data read on the serial link are accumulated in a buffer, and when the delimiter is found, the service writes the content of the buffer to the variable /usp/value. The delimiter is included in the data reported.
  • fixed: the service reads from the serial link a fixed amount of bytes defined in the configuration and stores the data in a buffer. Once the number is reached, the service writes the content of the buffer to the variable /usp/value.
  • lenfield: this configuration is made to match protocols providing the length of the frame at a fixed position. The configuration must indicate : the position of the length field in the frame (start), the size of the length field (size), the encoding of the length field (bigendian set to true or false), the offset (offset), which is a value to be added to the read length field, in order to add trailing bytes (eg. CRC bytes). Once the number "length field value" + "offset" is reached, the service writes the content of the buffer to the variable /usp/value.

Sending data

In order to send data, you have to write a JSON document to /usp/write resource.

Example:

{
	"data":[1,6,145],       //bytes to send
	"answer_timeout":0.2	  //(optional) timeout in seconds for the response frame
}

The data entry contains the bytes that must be sent on the serial link.
These data must be formatted either as an integer array: each integer value represents a byte (0-225).
The answer_timeout entry is optional. It allows the user to configure a timeout between the end of the sent frame and the start of the next received frame.

Receiving data

When data bytes are received they are parsed (or counted) according to the framing strategy.
When a frame is considered complete, it is pushed to the /usp/value resource.
If the frame_timeout time has elapsed after the first received byte without having completed the frame, the received bytes get pushed in the resource, along with a timeout error.

Example:

{
	"data": [1,6,145],      	//bytes received
	"error": "frame_timeout"	//error information, absent if no error. Possible values are "answer_timeout" or "frame_timeout"
}