Summary
The companion firmware's RX-log serial hook (MyMesh::logRxRaw, PUSH_CODE_LOG_RX_DATA = 0x88) silently drops any overheard packet whose raw length exceeds MAX_FRAME_SIZE - 3 (173 bytes). The radio itself receives and repeats packets up to MAX_TRANS_UNIT (255 bytes), so packets in the 174–255 byte range are handled normally on-air but never reach a host application over the serial/BLE companion link. There is no truncation and no error frame — the packet just never appears in the RX log.
Where
examples/companion_radio/MyMesh.cpp:
void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) {
if (_serial->isConnected() && len + 3 <= MAX_FRAME_SIZE) { // <-- 3-byte header: code + snr + rssi
int i = 0;
out_frame[i++] = PUSH_CODE_LOG_RX_DATA;
out_frame[i++] = (int8_t)(snr * 4);
out_frame[i++] = (int8_t)(rssi);
memcpy(&out_frame[i], raw, len);
i += len;
_serial->writeFrame(out_frame, i);
}
// else: packet silently discarded
}
Relevant constants (src/MeshCore.h, src/helpers/BaseSerialInterface.h):
| Constant |
Value |
Meaning |
MAX_TRANS_UNIT |
255 |
max on-air packet the radio receives/repeats |
MAX_PACKET_PAYLOAD |
184 |
max packet payload |
MAX_PATH_SIZE |
64 |
max accumulated path bytes |
MAX_FRAME_SIZE |
176 |
companion serial frame size |
So the RX-log frame can carry a raw packet of at most 176 - 3 = 173 bytes, well below the 255-byte packet the node otherwise processes.
Why it bites in practice
A packet's path grows as it floods through the mesh — every repeater appends its hash (1–3 bytes per hop depending on path_hash_mode, up to MAX_PATH_SIZE = 64). A group/channel text message that fits comfortably when first transmitted can therefore cross the 173-byte threshold after enough hops, at which point every downstream node that overhears it stops reporting it in the RX log even though it still receives and repeats it.
Concretely, for a GRP_TXT packet the raw length is 6 (header + transport codes + path_len) + path_len + pkt_payload. With a ~160–180 byte payload (long bot/status messages are common on busy channels) the packet exceeds 173 bytes after only a handful of hops, and beyond ~10–17 hops it is essentially never logged.
Impact
Any host-side tooling that relies on the RX log (e.g. packet observers, MQTT bridges, routing/path analyzers) sees a systematic blind spot: exactly the long, many-hop packets — the most interesting ones for route analysis — are the ones missing. This looks like "some messages have no path/echo information" to the user, with no indication anything was dropped.
Observed downstream in a companion host app (mc-webui): long channel messages relayed over 8–17 hops consistently produce zero RX-log echoes, while short messages on the same channel are logged normally. Reconstructing the packet host-side confirms the packet hash matches — the packet was real and on-air — but the firmware never emitted a 0x88 frame for it.
Suggested fixes (any one)
- Truncate instead of drop — forward the first
MAX_FRAME_SIZE - 3 bytes and signal truncation (e.g. a flag byte or a length field), so hosts at least see the header + path even if the tail of the payload is clipped. For path/route analysis the header and path bytes are what matter most, and those live at the front of the packet.
- Raise
MAX_FRAME_SIZE for the companion link to accommodate MAX_TRANS_UNIT + header (i.e. ≥ 258), so any legitimately-received packet can always be forwarded. This is the cleanest fix if serial/BLE buffer sizes allow it.
- At minimum, document the limitation and/or emit a lightweight "packet too large for RX log (len=N)" notice so hosts can surface it rather than silently losing data.
Happy to test a patch on ESP32 (WiFi companion) hardware.
Summary
The companion firmware's RX-log serial hook (
MyMesh::logRxRaw,PUSH_CODE_LOG_RX_DATA = 0x88) silently drops any overheard packet whose raw length exceedsMAX_FRAME_SIZE - 3(173 bytes). The radio itself receives and repeats packets up toMAX_TRANS_UNIT(255 bytes), so packets in the 174–255 byte range are handled normally on-air but never reach a host application over the serial/BLE companion link. There is no truncation and no error frame — the packet just never appears in the RX log.Where
examples/companion_radio/MyMesh.cpp:Relevant constants (
src/MeshCore.h,src/helpers/BaseSerialInterface.h):MAX_TRANS_UNITMAX_PACKET_PAYLOADMAX_PATH_SIZEMAX_FRAME_SIZESo the RX-log frame can carry a raw packet of at most
176 - 3 = 173bytes, well below the 255-byte packet the node otherwise processes.Why it bites in practice
A packet's
pathgrows as it floods through the mesh — every repeater appends its hash (1–3 bytes per hop depending onpath_hash_mode, up toMAX_PATH_SIZE = 64). A group/channel text message that fits comfortably when first transmitted can therefore cross the 173-byte threshold after enough hops, at which point every downstream node that overhears it stops reporting it in the RX log even though it still receives and repeats it.Concretely, for a GRP_TXT packet the raw length is
6 (header + transport codes + path_len) + path_len + pkt_payload. With a ~160–180 byte payload (long bot/status messages are common on busy channels) the packet exceeds 173 bytes after only a handful of hops, and beyond ~10–17 hops it is essentially never logged.Impact
Any host-side tooling that relies on the RX log (e.g. packet observers, MQTT bridges, routing/path analyzers) sees a systematic blind spot: exactly the long, many-hop packets — the most interesting ones for route analysis — are the ones missing. This looks like "some messages have no path/echo information" to the user, with no indication anything was dropped.
Observed downstream in a companion host app (mc-webui): long channel messages relayed over 8–17 hops consistently produce zero RX-log echoes, while short messages on the same channel are logged normally. Reconstructing the packet host-side confirms the packet hash matches — the packet was real and on-air — but the firmware never emitted a
0x88frame for it.Suggested fixes (any one)
MAX_FRAME_SIZE - 3bytes and signal truncation (e.g. a flag byte or a length field), so hosts at least see the header + path even if the tail of the payload is clipped. For path/route analysis the header and path bytes are what matter most, and those live at the front of the packet.MAX_FRAME_SIZEfor the companion link to accommodateMAX_TRANS_UNIT + header(i.e. ≥ 258), so any legitimately-received packet can always be forwarded. This is the cleanest fix if serial/BLE buffer sizes allow it.Happy to test a patch on ESP32 (WiFi companion) hardware.