2 Commits
Author SHA1 Message Date
Cort BuffingtonandClaude Sonnet 4.6 94e145ec7c trunk: STATUS is {}; routing core skips TX/RX writes for trunk systems
A TRUNK system carries an arbitrary number of simultaneous streams, so
the previous TS-keyed STATUS dict was semantically wrong and never
actually read by any code (contention checks are bypassed for trunk
targets via TRUNKS list).

- trunk.py TRUNK.__init__: self.STATUS = {} with explanatory comment
- bridge.py bridgeIPSC.group_voice: wrap post-transmit TX state writes
  in `if _target['SYSTEM'] not in TRUNKS` — trunk targets have no TS
  slots to write into, and the values would never be consulted
- bridge.py bridgeTRUNK.group_voice: same TX guard + remove the final
  two RX state writes (self.STATUS[_ts]['RX_TGID/RX_TIME']) that would
  KeyError against the now-empty STATUS dict

13 new tests in tests/test_trunk_status.py all pass.  The 33
pre-existing failures in test_bridge.py / test_protocol.py (missing
SUB_ACL in test helpers) are unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 17:42:24 -05:00
Cort BuffingtonandClaude Sonnet 4.6 8d5307f4c3 Add Trunk v2: server-to-server IPSC bridge with stream ID and fast TGID filter
Introduces a new TRUNK system type that carries full IPSC GROUP_VOICE
payloads between two DMRlink3 instances without the IPSC registration/
keepalive machinery or the two-timeslot repeater restriction.

Wire format: 6-byte prefix (4-byte random stream ID + 2-byte reserved
flags) prepended to the unmodified IPSC payload from the routing core.
Stream IDs are generated at VOICE_HEAD boundaries, eliminating reliance
on the IPSC sequence number (which breaks monotonicity when Talker Alias
alternates between LC and TA fragments).  Loop prevention uses a bounded
deque of locally-generated stream IDs.  Authentication is by source
IP+port validation only, consistent with the amateur radio context.

Fast TGID ingress filter: built from bridge rules at startup so packets
for TGIDs with no route on this server are dropped before the routing
engine is invoked.  TRUNK systems are automatically added to the TRUNKS
contention-bypass list by bridge.py.

New: trunk.py (TRUNK base class, wire protocol, stream tracking)
Modified: config.py (TRUNK section parsing, non-breaking fallback)
Modified: dmrlink.py (_systems_snapshot TRUNK guard, mk_ipsc_systems skip)
Modified: bridge.py (bridgeTRUNK, mk_trunk_systems, TGID filter, auto-TRUNKS)
Modified: dmrlink-SAMPLE.cfg (TRUNK system type documentation)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 16:57:59 -05:00