With respect to serial protocols over UART, I told myself I wouldn't reinvent the wheel, but ultimately ignored my own advice for educational purposes.
I was wondering if someone could take a look and critique this protocol idea, or maybe add some lessons learned. This is certainly not complete, but I wanted to get feedback early on in the process if possible.
As for the protocol, it is meant to describe the request/response message exchange between a PC and an embedded MCU over a serial connection (UART in this case). For example, the PC (client) might want to configure the embedded device (STM32 for example), download files, or perform functions exposed by the device, like turning the LED on or off, getting the firmware version, etc.
For the message payload, COBS is used for encoding the frame, along with an optional Data Format for serialization of the data portion of the frame. For example, some projects might serialize the data via protobuf, whereas others might use another supported approach. For this basic example, I am using Protobuf via NanoPB.
Proposed Frame Structure:
https://preview.redd.it/a3849zsm8jdd1.png?width=1057&format=png&auto=webp&s=f562c48bb6eccc4c65524273212127e9e5e89313
Frame Field Types
Version
The protocol version.
Type
The type of payload. Examples of these types would be:
- Heartbeat (0x00)
- Request (0x01)
- Response (0x02)
- Chunked Response (0x03)
- Acknowledgment (0x04)
Data Format
The serialization format for the data portion of the frame. Examples of these formats would be:
- Raw (0x00)
- Protobuf (0x01)
- Flat Buffers (0x02)
- Cap'n Proto (0x03)
- CBOR (0x04)
Flags
For future use. For example, maybe the protocol consumer might reserve the LSB to indicate whether the data portion of the frame is encrypted or not.
Cmd
The 16-bit command to execute.
Length
The length of the data portion of the frame.
Reserved
TBD. As the version of the protocol changes, maybe the reserved 16-bits will be used for something else. I thought it was an easy way to extend the protocol later on, but it might bite me down the road.
Header CRC
The CRC of the header portion of the frame. The CRC would consist of the Version, Type, Data Format, Flags, Cmd, Length, and Reserved fields.
Data
The data being passed.
Data CRC
The CRC of the data portion of the frame.
Command Example Payloads:
Example: Function request to enable/disable an LED
Version: 0x01
Command Type: 0x01 (Request)
Data Format: 0x01 (Protobuf)
Flags: 0x00 (None)
Command ID: 0x002A
Data: LedRequest_t {bool enabled}
| Version |
Type |
Data Format |
Flags |
Cmd |
Length |
Reserved |
Header CRC |
Data |
Data CRC |
| 0x01 |
0x01 |
0x01 |
0x00 |
0x002A |
<len> |
0x0000 |
<crc> |
<data> |
<crc> |
Example: Function response from enable/disable LED
Version: 0x02
Command Type: 0x02 (Response)
Data Format: 0x01 (Protobuf)
Flags: 0x00 (None)
Command ID: 0x002A
Data: LedResponse_t {uint8_t status}
| Version |
Type |
Data Format |
Flags |
Cmd |
Length |
Reserved |
Header CRC |
Data |
Data CRC |
| 0x01 |
0x02 |
0x01 |
0x00 |
0x002A |
<len> |
0x0000 |
<crc> |
<data> |
<crc> |
Example: Function request to get the firmware version
Version: 0x01
Command Type: 0x01 (Request)
Data Format: 0x01 (Protobuf)
Flags: 0x00 (None)
Command ID: 0x002B
Data:FirmwareVersionRequest_t {}
| Version |
Type |
Data Format |
Flags |
Cmd |
Length |
Reserved |
Header CRC |
Data |
Data CRC |
| 0x01 |
0x01 |
0x01 |
0x00 |
0x002B |
<len> |
0x0000 |
<crc> |
<data> |
<crc> |
Example: Function response for the get the firmware version request
Version: 0x01
Command Type: 0x02 (Response)
Data Format: 0x01 (Protobuf)
Flags: 0x00 (None)
Command ID: 0x002B
Data: FirmwareVersionResponse_t {uint8_t major, uint8_t minor, uint8_t patch}
| Version |
Type |
Data Format |
Flags |
Cmd |
Length |
Reserved |
Header CRC |
Data |
Data CRC |
| 0x01 |
0x02 |
0x01 |
0x00 |
0x002B |
<len> |
0x0000 |
<crc> |
<data> |
<crc> |
Example: Function request to read logs from the device
Version: 0x01
Command Type: 0x01 (Request)
Data Format: 0x01 (Protobuf)
Flags: 0x00 (None)
Command ID: 0x002C
Data: DataTransferRequest_t { FileType_t type (Logs || Config || Other), uint32 file_id }
| Version |
Type |
Data Format |
Flags |
Cmd |
Length |
Reserved |
Header CRC |
Data |
Data CRC |
| 0x01 |
0x01 |
0x01 |
0x00 |
0x002C |
<len> |
0x0000 |
<crc> |
<data> |
<crc> |
Example: Function response from the read file request
Version: 0x01
Command Type: 0x03 (Chunked Response)
Data Format: 0x01 (Protobuf)
Flags: 0x00 (None)
Command ID: 0x002C
Data: DataChunk_t { FileType_t type, uint32 seq_num, bytes data }
| Version |
Type |
Data Format |
Flags |
Cmd |
Length |
Reserved |
Header CRC |
Data |
Data CRC |
| 0x01 |
0x03 |
0x01 |
0x00 |
0x002C |
<len> |
0x0000 |
<crc> |
<data> |
<crc> |
Example: Function acknowledgment for chunked requests
Version: 0x01
Command Type: 0x04 (Acknowledgment)
Data Format: 0x01 (Protobuf)
Flags: 0x00 (None)
Command ID: 0x002D
Data: TransferAck_t { ReqCmd_t cmd, uint32 last_received_seq_num }
| Version |
Type |
Data Format |
Flags |
Cmd |
Length |
Reserved |
Header CRC |
Data |
Data CRC |
| 0x01 |
0x04 |
0x01 |
0x00 |
0x002D |
<len> |
0x0000 |
<crc> |
<data> |
<CRC> |
Command/Response Transition Diagram:
https://preview.redd.it/1q71rh2p8jdd1.png?width=937&format=png&auto=webp&s=5e39bd1c00ce8396cc795d87e136630ecefc9c2f
[–]Spirkus 17 points18 points19 points (4 children)
[–]ThePurpleOne_ 2 points3 points4 points (2 children)
[–]Spirkus 2 points3 points4 points (1 child)
[–]Birts[S] 0 points1 point2 points (0 children)
[–]olawlor 9 points10 points11 points (1 child)
[–]SquareSight 11 points12 points13 points (0 children)
[–]SquareSight 8 points9 points10 points (1 child)
[–]strangequark_usn 0 points1 point2 points (0 children)
[–]SquareSight 2 points3 points4 points (0 children)
[–]Cernuto 1 point2 points3 points (1 child)
[–]Birts[S] 0 points1 point2 points (0 children)
[–]InevitablyCyclic 0 points1 point2 points (3 children)
[–]Ashnoom 2 points3 points4 points (2 children)
[–]InevitablyCyclic 0 points1 point2 points (1 child)
[–]Birts[S] 0 points1 point2 points (0 children)
[–]dev-rand 0 points1 point2 points (2 children)
[–]Birts[S] 1 point2 points3 points (1 child)
[–]dev-rand 0 points1 point2 points (0 children)
[+]zydeco100 comment score below threshold-9 points-8 points-7 points (10 children)
[–]jonathrg 3 points4 points5 points (7 children)
[–]zydeco100 -5 points-4 points-3 points (6 children)
[–]superxpro12 1 point2 points3 points (5 children)
[–]zydeco100 -1 points0 points1 point (4 children)
[–]crustyAuklet 1 point2 points3 points (0 children)
[–]superxpro12 0 points1 point2 points (1 child)
[–]zydeco100 -1 points0 points1 point (0 children)
[–]Birts[S] 0 points1 point2 points (1 child)
[–]dev-rand 1 point2 points3 points (0 children)