TutoProto Protocol
This artificially made-up binary protocol is created specifically for use in IO Ninja tutorials. This protocol is, on the one hand, very simple and thus suitable for a tutorial, and on the other hand, follows the same principles as most real-world binary protocols. We’ll call our protocol TutoProto – a tutorial protocol.
As for the underlying transport, let’s assume TutoProto can work over TCP or Serial.
Header
Each TutoProto message is prefixed with a fixed header represented by the following struct:
struct TutoProtoHdr { uint8_t m_stx; uint8_t m_command : 4; uint8_t m_flags : 4; bigendian uint16_t m_id; bigendian uint16_t m_size; }
Header fields
| Field | Description |
|---|---|
| m_stx | STX character (the ‘signature’ of a packet start) |
| m_command | The code of a command |
| m_flags | Auxillary flags of the packet |
| m_id | Synchronization identifier for the sake of matching asynchronous commands and replies |
| m_size | Full size of the packet (including header and CRC) |
After the header, a command-specific payload follows, and then the packet is ended with the two bytes of a CRC16 checksum in the bigendian byte order.
The flags of a TutoProto packet are defined as such:
bitflag enum TutoProtoFlags: uint8_t { Reply, Error, }
| Flag | Description |
|---|---|
| Reply | This packet is a reply |
| Error | Command failed; TutoProtoHdr is followed by TutoProtoError |
Note
The use of bitflag enum-s in Jancy is a convenient way to define flags or options. First of all, they follow intuitive rules for bitwise operators (|, &, and ^). Secondly, the constants of a bitflag enum will be automatically assigned non-overlapping bit values. TutoProtoFlags.Reply will receive the value of 1, and TutoProtoFlags.Error will be 2 (if more flags are needed, they will go 4, 8, etc).
Visual attributes
We’ll be using this struct to display fields in packet templates and protocol analyzer, so let’s augment fields with additional display info attributes:
struct TutoProtoHdr { [ displayName = "STX" ] uint8_t m_stx; [ displayName = "Command", displayType = typeof(TutoProtoCommand) ] uint8_t m_command : 4; [ displayName = "Flags", displayType = typeof(TutoProtoFlags) ] uint8_t m_flags : 4; [ displayName = "ID" ] bigendian uint16_t m_id; [ displayName = "Size" ] bigendian uint16_t m_size; }
Commands & reply parameters
Let’s define TutoProto commands and their parameters.
enum TutoProtoCommand: uint8_t { GetVersion, Read, Write, }
| Command | Command parameters | Reply parameters |
|---|---|---|
| GetVersion | none | TutoProtoVersion |
| Read | TutoProtoRange |
data |
| Write | TutoProtoRange followed by data |
none |
Finally, here are the definitions of the command/reply-specific structures:
struct TutoProtoVersion { [ displayName = "Major" ] uint8_t m_major; [ displayName = "Minor" ] uint8_t m_minor; [ displayName = "Patch" ] uint8_t m_patch; } struct TutoProtoRange { [ displayName = "Offset", formatSpec = "0x%04X" ] bigendian uint32_t m_offset; [ displayName = "Length" ] bigendian uint16_t m_length; } struct TutoProtoError { [ displayName = "Error" ] bigendian uint32_t m_error; }