USB Serial¶
FRAME FORMAT · > AND < · 16-BIT LENGTH · 176 BYTES
The serial link is the transport without a radio, without a PIN code and without a network: a cable to a computer. It is also the transport whose format is easiest to read, and that format is the same as with BLE and WiFi. This chapter describes the frame byte by byte and the state machine that pulls it out of the byte stream.
[!NOTE] Source. This page has been verified against the firmware itself:
MeshCorev1.16.0, commit03b6ef4, 28 July 2026 — filessrc/helpers/ArduinoSerialInterface.cpp,src/helpers/ArduinoSerialInterface.handsrc/helpers/BaseSerialInterface.h.
One interface, three implementations¶
Everything a companion app exchanges with a node passes through
BaseSerialInterface. It knows only two functions:
src/helpers/BaseSerialInterface.h r.16-20
virtual bool isConnected() const = 0;
virtual bool isWriteBusy() const = 0;
virtual size_t writeFrame(const uint8_t src[], size_t len) = 0;
virtual size_t checkRecvFrame(uint8_t dest[]) = 0;
ArduinoSerialInterface, SerialBLEInterface and SerialWifiInterface
implement those three. Which one ends up in the firmware is a build choice;
see WiFi as a Companion Link.
The frame size is the same for all three:
src/helpers/BaseSerialInterface.h r.5
#define MAX_FRAME_SIZE 176 // +4 for transport codes (region scoping)
176 bytes, with the comment that four more are added for transport codes. What those transport codes are is in Regions and Scopes.
The frame the node sends¶
Three header bytes, then the payload:
src/helpers/ArduinoSerialInterface.cpp r.24-37
size_t ArduinoSerialInterface::writeFrame(const uint8_t src[], size_t len) {
if (len > MAX_FRAME_SIZE) {
// frame is too big!
return 0;
}
uint8_t hdr[3];
hdr[0] = '>';
hdr[1] = (len & 0xFF); // LSB
hdr[2] = (len >> 8); // MSB
_serial->write(hdr, 3);
return _serial->write(src, len);
}
| Byte | Value | Meaning |
|---|---|---|
| 0 | > (0x3E) |
node → computer |
| 1 | length low | LSB first |
| 2 | length high | MSB |
| 3… | payload | at most 176 bytes |
Direction sits in the start byte. The node sends with > and listens for
<: a frame going the other way therefore starts with a different
character. That is not encryption, but it makes it impossible to
accidentally read your own output as input.
A frame larger than 176 bytes is not truncated but not sent at all —
writeFrame() then returns zero.
The state machine on the receiving side¶
Bytes arrive one at a time, so the receiver is a state machine with four states:
IDLE ── sees '<' ───▶ HDR_FOUND
HDR_FOUND ── length LSB ─▶ LEN1_FOUND
LEN1_FOUND ── length MSB ─▶ LEN2_FOUND (or back to IDLE on length 0)
LEN2_FOUND ── payload ────▶ frame done, back to IDLE
Two details are worth noting:
src/helpers/ArduinoSerialInterface.cpp r.59-68
default:
if (rx_len < MAX_FRAME_SIZE) {
rx_buf[rx_len] = (uint8_t)c; // rest of frame will be discarded if > MAX
}
rx_len++;
if (rx_len >= _frame_len) { // received a complete frame?
if (_frame_len > MAX_FRAME_SIZE) _frame_len = MAX_FRAME_SIZE; // truncate
memcpy(dest, rx_buf, _frame_len);
_state = RECV_STATE_IDLE; // reset state, for next frame
return _frame_len;
}
An overlong frame is read in full but only kept up to 176 bytes; the rest
disappears. The counter keeps running so the state machine is at the right
point in the stream once the frame ends. And an announced length of zero
sends the machine straight back to IDLE — an empty frame does not exist.
There is no connection detection¶
src/helpers/ArduinoSerialInterface.cpp r.16-18
bool ArduinoSerialInterface::isConnected() const {
return true; // no way of knowing, so assume yes
}
A serial port has no concept of a connection. The firmware therefore always says yes. With BLE and WiFi it is different: there is a counterpart that connects and drops away, and there the interface does track it. See BLE Architecture.
Sources¶
Firmware, commit 03b6ef4 (v1.16.0, 28 July 2026):
src/helpers/ArduinoSerialInterface.cpp—writeFrame(),checkRecvFrame()and the four statessrc/helpers/BaseSerialInterface.h— the shared interface andMAX_FRAME_SIZE
Related in this documentation:
- WiFi as a Companion Link — the same frame over TCP
- BLE Architecture — the same frame over BLE
- Regions and Scopes — the four transport code bytes the comment refers to
- The Hardware of a Node — where this part sits
Translated from Dutch by Anthropic Claude