meshcore 2.3.0__tar.gz → 2.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. {meshcore-2.3.0 → meshcore-2.3.2}/PKG-INFO +1 -1
  2. {meshcore-2.3.0 → meshcore-2.3.2}/pyproject.toml +1 -1
  3. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/reader.py +2 -3
  4. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/serial_cx.py +4 -0
  5. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/tcp_cx.py +4 -0
  6. meshcore-2.3.2/tests/unit/test_path_discovery_response.py +45 -0
  7. meshcore-2.3.2/tests/unit/test_serial_connection.py +31 -0
  8. {meshcore-2.3.0 → meshcore-2.3.2}/.github/python-test.yml +0 -0
  9. {meshcore-2.3.0 → meshcore-2.3.2}/.gitignore +0 -0
  10. {meshcore-2.3.0 → meshcore-2.3.2}/LICENSE +0 -0
  11. {meshcore-2.3.0 → meshcore-2.3.2}/README.md +0 -0
  12. {meshcore-2.3.0 → meshcore-2.3.2}/examples/.pubsub_example.py.swp +0 -0
  13. {meshcore-2.3.0 → meshcore-2.3.2}/examples/ble_chat.py +0 -0
  14. {meshcore-2.3.0 → meshcore-2.3.2}/examples/ble_pin_pairing_example.py +0 -0
  15. {meshcore-2.3.0 → meshcore-2.3.2}/examples/ble_private_key_export.py +0 -0
  16. {meshcore-2.3.0 → meshcore-2.3.2}/examples/ble_sign_example.py +0 -0
  17. {meshcore-2.3.0 → meshcore-2.3.2}/examples/ble_stats.py +0 -0
  18. {meshcore-2.3.0 → meshcore-2.3.2}/examples/ble_t1000_chan_msg.py +0 -0
  19. {meshcore-2.3.0 → meshcore-2.3.2}/examples/ble_t1000_custom_vars.py +0 -0
  20. {meshcore-2.3.0 → meshcore-2.3.2}/examples/ble_t1000_infos.py +0 -0
  21. {meshcore-2.3.0 → meshcore-2.3.2}/examples/ble_t1000_msg.py +0 -0
  22. {meshcore-2.3.0 → meshcore-2.3.2}/examples/ble_t1000_msg_retries.py +0 -0
  23. {meshcore-2.3.0 → meshcore-2.3.2}/examples/ble_t1000_set_cv.py +0 -0
  24. {meshcore-2.3.0 → meshcore-2.3.2}/examples/chan_recv_with_path.py +0 -0
  25. {meshcore-2.3.0 → meshcore-2.3.2}/examples/connection_events_example.py +0 -0
  26. {meshcore-2.3.0 → meshcore-2.3.2}/examples/mepo_mc_gps.py +0 -0
  27. {meshcore-2.3.0 → meshcore-2.3.2}/examples/pubsub_example.py +0 -0
  28. {meshcore-2.3.0 → meshcore-2.3.2}/examples/rf_packet_monitor.py +0 -0
  29. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_battery_monitor.py +0 -0
  30. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_channel_manager.py +0 -0
  31. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_chat.py +0 -0
  32. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_contacts.py +0 -0
  33. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_infos.py +0 -0
  34. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_meshcore_ollama.py +0 -0
  35. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_msg.py +0 -0
  36. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_pingbot.py +0 -0
  37. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_repeater_status.py +0 -0
  38. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_repeater_telemetry.py +0 -0
  39. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_rss_bot.py +0 -0
  40. {meshcore-2.3.0 → meshcore-2.3.2}/examples/serial_trace.py +0 -0
  41. {meshcore-2.3.0 → meshcore-2.3.2}/examples/tcp_chat.py +0 -0
  42. {meshcore-2.3.0 → meshcore-2.3.2}/examples/tcp_login_status.py +0 -0
  43. {meshcore-2.3.0 → meshcore-2.3.2}/examples/tcp_mchome_contacts.py +0 -0
  44. {meshcore-2.3.0 → meshcore-2.3.2}/examples/tcp_mchome_infos.py +0 -0
  45. {meshcore-2.3.0 → meshcore-2.3.2}/examples/tcp_mchome_msg.py +0 -0
  46. {meshcore-2.3.0 → meshcore-2.3.2}/examples/tcp_mchome_readmsgs.py +0 -0
  47. {meshcore-2.3.0 → meshcore-2.3.2}/pytest.ini +0 -0
  48. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/__init__.py +0 -0
  49. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/ble_cx.py +0 -0
  50. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/commands/__init__.py +0 -0
  51. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/commands/base.py +0 -0
  52. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/commands/binary.py +0 -0
  53. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/commands/contact.py +0 -0
  54. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/commands/control_data.py +0 -0
  55. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/commands/device.py +0 -0
  56. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/commands/messaging.py +0 -0
  57. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/connection_manager.py +0 -0
  58. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/events.py +0 -0
  59. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/lpp_json_encoder.py +0 -0
  60. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/meshcore.py +0 -0
  61. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/meshcore_parser.py +0 -0
  62. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/packets.py +0 -0
  63. {meshcore-2.3.0 → meshcore-2.3.2}/src/meshcore/parsing.py +0 -0
  64. {meshcore-2.3.0 → meshcore-2.3.2}/tests/README.md +0 -0
  65. {meshcore-2.3.0 → meshcore-2.3.2}/tests/test_ble_connection.py +0 -0
  66. {meshcore-2.3.0 → meshcore-2.3.2}/tests/test_ble_pin_pairing.py +0 -0
  67. {meshcore-2.3.0 → meshcore-2.3.2}/tests/test_meshcore_ble_pin.py +0 -0
  68. {meshcore-2.3.0 → meshcore-2.3.2}/tests/unit/test_commands.py +0 -0
  69. {meshcore-2.3.0 → meshcore-2.3.2}/tests/unit/test_events.py +0 -0
  70. {meshcore-2.3.0 → meshcore-2.3.2}/tests/unit/test_private_key_export.py +0 -0
  71. {meshcore-2.3.0 → meshcore-2.3.2}/tests/unit/test_reader.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcore
3
- Version: 2.3.0
3
+ Version: 2.3.2
4
4
  Summary: Base classes for communicating with meshcore companion radios
5
5
  Project-URL: Homepage, https://github.com/fdlamotte/meshcore_py
6
6
  Project-URL: Issues, https://github.com/fdlamotte/meshcore_py/issues
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "meshcore"
7
- version = "2.3.0"
7
+ version = "2.3.2"
8
8
  authors = [
9
9
  { name="Florent de Lamotte", email="florent@frizoncorrea.fr" },
10
10
  { name="Alex Wolden", email="awolden@gmail.com" },
@@ -26,7 +26,6 @@ class MessageReader:
26
26
  self.pending_binary_requests: Dict[str, Dict[str, Any]] = {} # tag -> {request_type, expires_at}
27
27
 
28
28
  self.packet_parser = MeshcorePacketParser()
29
- self.decrypt_channels = True
30
29
 
31
30
  @property
32
31
  def decrypt_channels(self):
@@ -828,13 +827,13 @@ class MessageReader:
828
827
  res["pubkey_pre"] = dbuf.read(6).hex()
829
828
  opl = dbuf.read(1)[0]
830
829
  opl_hlen = ((opl & 0xc0) >> 6) + 1
831
- opl = opl & 0xbf
830
+ opl = opl & 0x3f
832
831
  res["out_path_len"] = opl
833
832
  res["out_path_hash_len"] = opl_hlen
834
833
  res["out_path"] = dbuf.read(opl*opl_hlen).hex()
835
834
  ipl = dbuf.read(1)[0]
836
835
  ipl_hlen = ((ipl & 0xc0) >> 6) + 1
837
- ipl = ipl & 0xbf
836
+ ipl = ipl & 0x3f
838
837
  res["in_path_len"] = ipl
839
838
  res["in_path_hash_len"] = ipl_hlen
840
839
  res["in_path"] = dbuf.read(ipl*ipl_hlen).hex()
@@ -79,6 +79,10 @@ class SerialConnection:
79
79
  idx = data.find(b"\x3e")
80
80
  if idx < 0: # no start of frame
81
81
  return
82
+ # Discard any leading junk bytes before the actual frame marker.
83
+ # Some radios interleave console/debug text on the same UART, so
84
+ # valid companion frames may begin at an offset inside the chunk.
85
+ data = data[idx:]
82
86
  self.header = data[0:1]
83
87
  data = data[1:]
84
88
 
@@ -73,6 +73,10 @@ class TCPConnection:
73
73
  idx = data.find(b"\x3e")
74
74
  if idx < 0: # no start of frame
75
75
  return
76
+ # Discard any leading junk bytes before the actual frame marker.
77
+ # Some radios interleave console/debug text on the same UART, so
78
+ # valid companion frames may begin at an offset inside the chunk.
79
+ data = data[idx:]
76
80
  self.header = data[0:1]
77
81
  data = data[1:]
78
82
 
@@ -0,0 +1,45 @@
1
+ import pytest
2
+
3
+ from meshcore.events import EventType
4
+ from meshcore.reader import MessageReader
5
+
6
+ pytestmark = pytest.mark.asyncio
7
+
8
+
9
+ class MockDispatcher:
10
+ def __init__(self):
11
+ self.dispatched_events = []
12
+
13
+ async def dispatch(self, event):
14
+ self.dispatched_events.append(event)
15
+
16
+
17
+ async def test_path_discovery_response_decodes_3byte_paths():
18
+ dispatcher = MockDispatcher()
19
+ reader = MessageReader(dispatcher)
20
+
21
+ packet = bytearray.fromhex(
22
+ "8d" # PacketType.PATH_DISCOVERY_RESPONSE
23
+ "00" # Reserved byte
24
+ "112233445566" # 6-byte contact public-key prefix
25
+ "82" # Outbound path descriptor: mode=2 (3-byte hops), hop_count=2
26
+ "a1a2a3b1b2b3" # Outbound path bytes: 2 hops * 3 bytes each
27
+ "81" # Inbound path descriptor: mode=2 (3-byte hops), hop_count=1
28
+ "c1c2c3" # Inbound path bytes: 1 hop * 3 bytes
29
+ )
30
+
31
+ await reader.handle_rx(packet)
32
+
33
+ matching = [e for e in dispatcher.dispatched_events if e.type == EventType.PATH_RESPONSE]
34
+ assert len(matching) == 1
35
+
36
+ payload = matching[0].payload
37
+ assert payload["pubkey_pre"] == "112233445566"
38
+
39
+ assert payload["out_path_hash_len"] == 3
40
+ assert payload["out_path_len"] == 2
41
+ assert payload["out_path"] == "a1a2a3b1b2b3"
42
+
43
+ assert payload["in_path_hash_len"] == 3
44
+ assert payload["in_path_len"] == 1
45
+ assert payload["in_path"] == "c1c2c3"
@@ -0,0 +1,31 @@
1
+ import asyncio
2
+
3
+ import pytest
4
+
5
+ from meshcore.serial_cx import SerialConnection
6
+
7
+
8
+ class RecordingReader:
9
+ def __init__(self):
10
+ self.frames = []
11
+
12
+ async def handle_rx(self, data):
13
+ self.frames.append(bytes(data))
14
+
15
+
16
+ @pytest.mark.asyncio
17
+ async def test_handle_rx_discards_leading_junk_before_frame_start():
18
+ conn = SerialConnection("/dev/null", 115200)
19
+ reader = RecordingReader()
20
+ conn.set_reader(reader)
21
+
22
+ payload = b"\x00\x01\x02\x53"
23
+ frame = b"\x3e" + len(payload).to_bytes(2, "little") + payload
24
+
25
+ conn.handle_rx(b"junk bytes\r\n" + frame)
26
+ await asyncio.sleep(0)
27
+
28
+ assert reader.frames == [payload]
29
+ assert conn.header == b""
30
+ assert conn.inframe == b""
31
+ assert conn.frame_expected_size == 0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes