Skip to content

Sending and receiving raw_data not working as expected #85

@JohannesFriedrich

Description

@JohannesFriedrich

Summary

Two bugs prevented send_raw_data from working correctly end-to-end:

  1. messaging.py – The command frame sent to the firmware was missing the mandatory path_len byte, causing every call to return ERR_CODE_UNSUPPORTED_CMD.
  2. reader.py – The incoming PUSH_CODE_RAW_DATA frame was parsed incorrectly: a reserved byte was not skipped and only 4 payload bytes were read, silently truncating any payload longer than 3 bytes.

Fix 1 – commands/messaging.py: wrong frame format for CMD_SEND_RAW_DATA

Root cause:
The firmware expects the frame 0x19 | path_len (1 byte, signed int8) | path (path_len bytes) | payload (≥ 4 bytes) – see MyMesh.cpp (companion_radio example).

The old implementation sent b"\x19" + payload, skipping path_len entirely. The firmware read payload[0] as path_len (e.g. 0x3D = 61), then checked 2 + 61 + 4 ≤ frame_lengthFALSEwriteUnsupportedCmdFrame().

Additionally, the firmware responds with writeOKFrame() (RESP_CODE_OK = 0x00) on success, not with PUSH_CODE_MSG_SENT. The old code awaited EventType.MSG_SENT, so a successful send was never resolved.

Before:

data = b"\x19" + bytes(payload)
return await self.send(data, [EventType.MSG_SENT, EventType.ERROR])

After:

data = bytes([0x19, len(path)]) + path + bytes(payload)
return await self.send(data, [EventType.OK, EventType.ERROR])

Fix 2 – reader.py: PUSH_CODE_RAW_DATA frame not parsed correctly

Root cause:
The firmware pushes [0x84, SNR×4 (int8), RSSI (int8), 0xFF (reserved), payload…] – the fourth byte is a reserved 0xFF placeholder (possibly path_len in a future firmware version).

The old code called dbuf.read(4) after RSSI, which consumed [0xFF, payload[0], payload[1], payload[2]] – the reserved byte ended up in the payload hex string and the last payload byte was dropped.

Before:

res["RSSI"] = int.from_bytes(dbuf.read(1), byteorder="little", signed=True)
res["payload"] = dbuf.read(4).hex()

After:

res["RSSI"] = int.from_bytes(dbuf.read(1), byteorder="little", signed=True)
dbuf.read(1)  # skip reserved byte (0xFF, possibly path_len in future)
res["payload"] = dbuf.read().hex()  # read all remaining payload bytes

Notes

  • Flood mode (path_len < 0) is explicitly unsupported in the current firmware and raises ERR_CODE_UNSUPPORTED_CMD. Only direct routing (path_len ≥ 0) is supported.
  • The minimum payload size of 4 bytes is enforced by the firmware (len > 1 + path_len + 4).

I

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions