Skip to content

5 Customising a Horus Binary v2 Packet

Mark Jessop edited this page Sep 4, 2021 · 8 revisions

The Horus Binary v2 format expands the payload ID space from 8 to 16-bits (for 65535 possible payload IDs), and allows for 9 bytes of user-customisable payload data. How these 9 bytes are used is up to the payload designer, but needs to be described in a way that allows the Horus Binary decoder to interpret the bytes, and produce a UKHAS-compliant telemetry sentence suitable for uploading to the Habitat database (and hence displayed on the HabHub tracker).

Horus Binary v2 Packet Format Re-cap

The Horus Binary v2 packet format (prior to forward-error correction) is as follows:

Byte No. Data Type Size (bytes) Description
0 uint16 2 Payload ID (0-65535)
2 uint16 2 Sequence Number
4 uint8 1 Time-of-day (Hours)
5 uint8 1 Time-of-day (Minutes)
6 uint8 1 Time-of-day (Seconds)
7 float 4 Latitude
11 float 4 Longitude
15 uint16 2 Altitude (m)
17 uint8 1 Speed (kph)
18 uint8 1 Satellites
19 int8 1 Temperature (deg C)
20 uint8 1 Battery Voltage
21 ??? 9 Custom data
30 uint16 2 CRC16-CCITT Checksum

Note that while the majority of the packet format is fixed, there are 9 bytes available to the user to include data from other sensors. 9 bytes might not sound like a lot, but if you're conservative with your data types, you can fit quite a lot in here!

Interpreting the Custom Data Section

The information necessary for interpreting the custom data section is contained with custom_field_list.json. Each payload making use of the custom data area needs to have an entry in this file (matching the callsign allocated in payload_id_list.txt), otherwise the custom data area is ignored when packet parsing is performed.

An example entry in this file is shown below:

"HORUSTEST": {
    "struct": "<BbBfH",
    "fields": [
        ["cutdown_battery_voltage", "battery_5v_byte"],
        ["external_temperature", "none"],
        ["test_counter", "none"],
        ["test_float_field", "none"],
        ["test_int_field", "none"]
    ]
},

The entry is named with the payload's callsign (in this case HORUSTEST), which must match the entry in payload_id_list.txt.

struct

The struct entry tells the decoder how to interpret the 9 bytes, and is a Python struct 'format string'. The text <BbBfH might look a bit arcane, but is a shorthand way of describing packed binary data types.

The first character indicates the endianness of the multi-byte data types used (e.g. big-endian = most-significant or little-endian = least-significant byte sent first). < represents little-endian, and > represents big-endian.

Some common data types that we would expect within high-altitude balloon telemetry are represented by the following characters:

  • B - Unsigned 8-bit integer (0 - 255)
  • b - Signed 8-bit integer (-128 - 127)
  • H - Unsigned 16-bit integer (0-65535)
  • h - Signed 16-bit integer (-32768 - 32767)
  • f - 32-bit Floating-point number.
  • x - A pad byte - not interpreted.

For the HORUSTEST example, the string is indicating that the 9 bytes contain:

  • < - Little-endian ordered data (for multi-byte data types - common on most modern platforms)
  • B - Byte 1 is a unsigned 8-bit integer (0 - 255).
  • b - Byte 2 is a signed 8-bit integer (-128 - 127).
  • B - Byte 3 is a unsigned 8-bit integer.
  • f - Bytes 4-7 are a 32-bit floating point number.
  • H - Bytes 8-9 are a unsigned 16-bit integer (0-65535)

So as an example, if the custom byte area contained the data 0AD87910069E3F162C, this would be interpreted as values (10, -40, 121, 1.2345600128173828, 11286).

fields

While the struct entry tells us how to split the bytes into different fields, we would like to provide some information as to what each of the fields are, and potentially do some post-processing of the field data. For each field that is decoded by the struct definition, we need to have an entry in the fields section. Each entry consists of a field name (e.g. 'external_temperature'), and a value with indicates if any additional post-processing is done to the data. The following values are supported:

  • none - No additional post-processing of the value. The value is converted to a string using standard Python type conversion (e.g. str(value) )
  • battery_5v_byte - Interpret an unsigned 8-bit integer as a battery voltage, where 0 = 0v, 255 = 5.0V, with linear steps in between.

Additional post-processing functions can be added if necessary - these would need to be added to delegates.py - please let me know what you need!

Testing Packet Parsing

TODO

Requesting an Update to horusdemodlib

TODO

Clone this wiki locally