This document defines the binary communication protocol used to facilitate and unify the interaction between different Harp devices, and between computers or other controllers and Harp devices. It was designed with efficiency and ease of parsing in mind.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
The Harp Binary Protocol SHOULD be used for all exchanges between a Controller and a Device. The Controller is typically a computer, or a server. The Device is typically a data acquisition or actuator microcontroller.
Exchanges of data using the protocol are based on messages addressed to specific registers, as defined in the Device Interface.
Note
The Harp Binary Protocol uses Little-Endian byte ordering.
All Harp messages MUST follow the structure below, specifying the minimal amount of information for a well-defined exchange of data.
| Harp Message |
|---|
| MessageType |
| Length |
| ExtendedLength* |
| Address |
| Port |
| PayloadType |
| Timestamp* |
| Payload |
| Checksum |
Note
Fields marked with * can be included or omitted under specific conditions. Check the corresponding section for details.
Specifies the type and other operation flags of the Harp message. The structure of this byte MUST follow the below specification:
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | Error | 0 | Type | |
Specifies the type of the Harp message.
| Value | Description |
|---|---|
1 (Read) |
Read the contents of the register with the specified Address |
2 (Write) |
Write the contents to the register with the specified Address |
3 (Event) |
Send the contents of the register with the specified Address |
When this flag is set, the message represents an error reply sent from the Device to a request from the Controller. This flag SHOULD NOT be set in any other messages. This flag SHALL NOT be set in any messages sent from the Controller to the Device.
Specifies the number of bytes (U8) after this field that are still available and need to be read to complete the Harp message. If one byte is not enough to express the length of the message, the Length field MUST be set to 255. In this case the ExtendedLength field MUST be included.
Specifies the number of bytes (U16) after this field that are still available and need to be read to complete the Harp message. If this field is used, the Length field MUST be set to 255.
Specifies the address of the register to which the message payload refers to.
Specifies the origin or destination Device of a Harp message, to be used when a hub Device is mediating access to several Devices. If the field is unused or if it refers to the Device itself, its value MUST be 0xFF.
Indicates the type of data available in Payload. The structure of this byte MUST follow the below specification:
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|
| IsSigned | IsFloat | 0 | HasTimestamp | Size | |||
Specifies the size of each word in Payload.
| Value | Description |
|---|---|
| 1 | 8 bits |
| 2 | 16 bits |
| 4 | 32 bits |
| 8 | 64 bits |
If the Harp message contains a timestamp, this bit MUST be set. In this case the fields Seconds and Microseconds MUST be included in the message.
This bit indicates whether Payload encodes fractional values. If the bit is not set, the payload contains integers.
Note
The bit [IsFloat] MUST NOT be set with 8-bit or 16-bit sized payloads.
This bit indicates whether Payload encodes integers with signal. If the bit is not set, the payload contains unsigned integers.
Note
The bits [IsFloat] and [IsSigned] MUST NOT be set simultaneously.
Specifies the value of the Device Harp clock. If the HasTimestamp flag is set, the following fields MUST be present before the message payload.
Specifies the number of whole seconds (U32) in the Harp Timestamp.
Specifies the fractional part of the Harp Timestamp (U16) encoded as the number of microseconds divided by 32.
Note
The full timestamp information, in seconds, can be retrieved using the formula:
Timestamp = Seconds + Microseconds * 32e-6
The contents of the Harp message.
The sum of all bytes (U8) contained in the other fields of the Harp message structure. The receiver of the message MUST calculate its own checksum from all received bytes and compare it against the received value in this field. If the two values do not match, the Harp message SHOULD be discarded.
Below we present technical notes and reference implementation examples for some of the protocol features.
The following pseudo-code snippet illustrates how to check for the Error flag in the MessageType field:
int errorMask = 0x08;
if (MessageType & errorMask)
{
printf(“Error detected.\n”);
}The following pseudo-code snippet illustrates how all possible PayloadType values are defined.
int isUnsigned = 0x00;
int isSigned = 0x80;
int isFloat = 0x40;
int hasTimestamp = 0x10;
enum PayloadType
{
U8 = (isUnsigned | 1),
S8 = (isSigned | 1),
U16 = (isUnsigned | 2),
S16 = (isSigned | 2),
U32 = (isUnsigned | 4),
S32 = (isSigned | 4),
U64 = (isUnsigned | 8),
S64 = (isSigned | 8),
Float = (isFloat | 4),
Timestamp = hasTimestamp,
TimestampedU8 = (hasTimestamp | U8),
TimestampedS8 = (hasTimestamp | S8),
TimestampedU16 = (hasTimestamp | U16),
TimestampedS16 = (hasTimestamp | S16),
TimestampedU32 = (hasTimestamp | U32),
TimestampedS32 = (hasTimestamp | S32),
TimestampedU64 = (hasTimestamp | U64),
TimestampedS64 = (hasTimestamp | S64),
TimestampedFloat = (hasTimestamp | Float)
}Bit masking can be used to check whether time information is available, regardless of the payload type:
int hasTimestamp = 0x10;
if (PayloadType & hasTimestamp)
{
printf(“Time information is available in the Harp message payload.\n”);
}Example of how to calculate the Checksum in C:
unsigned char Checksum = 0;
int i = 0;
for (; i < Length + 1; i++)
{
Checksum += HarpMessage(i);
}The Payload field can contain a single value, or an array of values of the same type. The first step to parse these payloads is to first find the number of values contained in the Payload field. The following code example demonstrates how to calculate the array length for both timestamped and non-timestamped payloads:
int arrayLength;
int hasTimestamp = 0x10;
int sizeMask = 0x0F;
if (PayloadType & hasTimestamp)
{
// Harp message with time information
arrayLength = (Length – 10) / (PayloadType & sizeMask )
}
else
{
// Harp message without time information
arrayLength = (Length – 4) / (PayloadType & sizeMask )
}-
v0.1
- First draft.
-
v0.2
- Changed Event Command to 3.
-
v0.3
- Cleaned up document and added C code examples.
- First release.
-
v1.0
- Updating naming of the protocol fields, etc, to latest naming review.
- Major release.
-
v1.1
- Corrected [
PayloadType] list on page 2.
- Corrected [
-
v1.2
- Changed device naming to Controller and Peripheral.
-
v1.3
- Minor corrections.
-
v1.4.0
- Refactor documentation to markdown format.
- Minor typo corrections.
- Improve clarity of some sections.
- Adopt semantic versioning.
-
v1.4.1
- Remove table of contents to avoid redundancy with doc generators.
- Avoid using verbatim literals in titles.
- Change device naming to Controller and Device.
-
v1.5.0
- Add requirements language.
- Changed naming of Command to Request.
- Clarify request-reply contract and add event stream patterns.
- Avoid scattering of message specification features.
- Discourage the use of polymorphic register behavior.