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; }