Wait for CHANNEL_DATA_RECV in get_msg()

The companion protocol lists PACKET_CHANNEL_DATA_RECV (0x1B) as an
answer to GET_MESSAGE (0x0A). PR #88 added the CHANNEL_DATA_RECV
event and parser, but get_msg() still waited only for
CONTACT_MSG_RECV, CHANNEL_MSG_RECV, ERROR and NO_MORE_MSGS. When the
next queued message is a channel datagram, get_msg() therefore ignored
the device's answer and returned ERROR (reason "timeout") after
default_timeout, which also stops the auto-fetch loop.

Add CHANNEL_DATA_RECV to the expected events and cover it with a test
that runs a real CHANNEL_DATA_RECV frame through MessageReader and
EventDispatcher.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Maxwell Burton
2026-10-02 17:03:17 +00:00
co-authored by Claude Sonnet 5.5
parent e84f9a32b7
commit 9f22c05b0c
2 changed files with 46 additions and 0 deletions
+45
View File
@@ -12,6 +12,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
from meshcore.events import Event, EventType, EventDispatcher
from meshcore.reader import MessageReader
from meshcore.packets import PacketType, CommandType
from meshcore.commands.messaging import MessagingCommands
# ---------------------------------------------------------------------------
@@ -489,6 +490,50 @@ async def test_channel_data_recv_widened_data_type():
assert evt.payload["payload"] == ""
@pytest.mark.asyncio
async def test_get_msg_returns_channel_data_recv():
"""get_msg() resolves on CHANNEL_DATA_RECV instead of timing out.
The companion protocol lists PACKET_CHANNEL_DATA_RECV (0x1B) as an answer
to GET_MESSAGE (0x0A). When the next queued message is a channel datagram
the device answers with that frame, and get_msg() must return it rather
than an ERROR event with reason "timeout".
"""
dispatcher = EventDispatcher()
await dispatcher.start()
reader = MessageReader(dispatcher)
commands = MessagingCommands()
commands.dispatcher = dispatcher
frame = bytes([
PacketType.CHANNEL_DATA_RECV.value,
0x10, # SNR
0x00, 0x00, # reserved
0x01, # channel_idx
0xFF, # path_len direct
0x23, 0x01, # data_type = 0x0123 (little-endian)
0x04, # data_len
0xDE, 0xAD, 0xBE, 0xEF, # payload
])
async def device(data):
# The device answers GET_MESSAGE with the queued channel datagram.
assert data == b"\x0a"
await reader.handle_rx(bytearray(frame))
commands._sender_func = device
try:
result = await commands.get_msg(timeout=2.0)
finally:
await dispatcher.stop()
assert result.type == EventType.CHANNEL_DATA_RECV
assert result.payload["channel_idx"] == 1
assert result.payload["data_type"] == 0x0123
assert result.payload["payload"] == "deadbeef"
# ---------------------------------------------------------------------------
# Wire-format parity bundle: AUTOADD_CONFIG (max_hops trailing byte)
# ---------------------------------------------------------------------------