feat!: mux-py on DongLoRa Protocol v2 with tag-aware dispatch
The 1.0 Python mux, mirroring the Rust donglora-mux 1.0 one-for-one and implementing the full §13 multi-client semantics on the DongLoRa Protocol v2 wire format.
* Structural rewrite. donglora_mux/{daemon,intercept,session,tagmap}.py replace the 601-line __init__.py monolith.
* Tag-aware dispatch. TagMapper with skip-zero allocation and per-client bulk drop on disconnect. Multiple clients can have commands in flight concurrently; the single-oneshot response slot is gone.
* Full §13.2 multi-client SET_CONFIG semantics. Tracks (client_id, modulation) lock owner and synthesizes OK(APPLIED/MINE), OK(ALREADY_MATCHED/OTHER), or OK(LOCKED_MISMATCH/OTHER).
* TX loopback fan-out (§13.4). On TX_DONE(TRANSMITTED) the mux synthesizes an RX frame with origin = LOCAL_LOOPBACK for every connected client except the transmitter.
* Async ERR(EFRAME) fan-out: tag-0 framing errors are broadcast to all clients.
* Per-client TX cache on ClientSession so the loopback fan-out does not need the sender to re-buffer.
* Socket and serial fcntl.flock to prevent multiple mux instances from fighting over the same dongle or socket path.
* 500 ms keepalive matching PROTOCOL.md §3.4 (2x margin on the 1 s inactivity timer), replacing the 5 s cadence from 0.x.
* Clean SIGINT / SIGTERM shutdown: per-client handler tasks are tracked and cancelled, so blocked reader.read() calls no longer pin the event loop open.
This commit is contained in:
12 files changed
+1693
-694
No files matched your search
+9
-6
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "donglora-mux"
|
||||
version = "0.2.0"
|
||||
version = "1.0.0"
|
||||
description = "DongLoRa USB Multiplexer — share one dongle with multiple applications"
|
||||
license = "MIT"
|
||||
requires-python = ">=3.10"
|
||||
@@ -8,16 +8,18 @@ readme = "README.md"
|
||||
authors = [{ name = "Stephen Waits", email = "steve@waits.net" }]
|
||||
keywords = ["lora", "radio", "usb", "multiplexer"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Development Status :: 4 - Beta",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Topic :: Communications :: Ham Radio",
|
||||
"Topic :: System :: Hardware",
|
||||
]
|
||||
dependencies = [
|
||||
"donglora",
|
||||
"cobs",
|
||||
"pyserial",
|
||||
# DongLoRa Protocol v2 wire primitives — encode_frame, decode_frame, Command/DeviceMessage
|
||||
# parsers, SetConfigResult, RxEvent, etc. Pinned tightly; the mux knows
|
||||
# intimate details about the v1.0 shape and will break if the protocol
|
||||
# moves.
|
||||
"donglora>=1.0.0,<2.0.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
@@ -28,7 +30,7 @@ Repository = "https://github.com/donglora/mux-py"
|
||||
Homepage = "https://github.com/donglora/mux-py"
|
||||
|
||||
[dependency-groups]
|
||||
dev = ["ruff", "pytest", "pytest-cov"]
|
||||
dev = ["ruff", "pytest", "pytest-cov", "pytest-asyncio"]
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
@@ -50,3 +52,4 @@ known-first-party = ["donglora", "donglora_mux"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
asyncio_mode = "auto"
|
||||
Reference in new issue
Block a user