3 Commits
Author SHA1 Message Date
Cort BuffingtonandClaude Sonnet 4.6 e511b4992c Port hblink3 ACL system to dmrlink3
- const.py: add ID_MIN, ID_MAX, PEER_MAX constants
- config.py: port merge_ranges(), acl_build(), acl_check(), process_acls()
  from hblink3; parse USE_ACL/SUB_ACL in [GLOBAL] and REG_ACL per system
- dmrlink.py: import acl_check; gate master_reg_req() with per-system REG_ACL
- bridge.py: remove old file-based build_acl() and allow_sub closure; remove
  -s/--sub-acl CLI arg; call process_acls(CONFIG); use acl_check() with
  global SUB_ACL in group_voice()
- dmrlink-SAMPLE.cfg: document and add USE_ACL, SUB_ACL, REG_ACL entries

ACL semantics: REG_ACL is per-master-system (ignored on peers, which cannot
control who registers on their upstream master); SUB_ACL is global and gates
source IDs from propagating through the bridge. No TGID ACLs — bridge rules
already control TGID propagation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 18:03:14 -05:00
Cort BuffingtonandClaude Sonnet 4.6 d38ba50720 Protocol correctness pass from ipsc2hbpc/ipsc2hbp consultation
- const.py: rename CALL_MON_NACK→REPEATER_BLOCKED, UNKNOWN_COLLISION→
  CALL_INTERRUPT_REQ; add seven previously-unknown opcodes (SYSTEM_MAP_REQ/
  REPLY, UNKNOWN_9E, WIRELINE, REMOTE_PROG_REQ/REPLY, OPCODE_0xF0); replace
  BURST_DATA_TYPE dict with integer constants; add GV field offset constants
  (GV_BURST_TYPE_OFF, GV_RTP_TS_OFF, GV_BE_FLAG, GV_BE_LC_FLCO_OFF, etc.)

- dmrlink.py: fix _ts calculation bug (was returning 1 or 33; now correctly
  returns 1 or 2); use burst_type for GROUP_VOICE timeslot detection
  (HEAD/TERM read call_info; SLOT_VOICE reads burst_type bit 7 per protocol);
  master now sends PEER_LIST_REPLY immediately after MASTER_REG_REPLY without
  waiting for PEER_LIST_REQ; peer now sends PEER_LIST_REQ immediately on
  receiving MASTER_REG_REPLY; master sends DE_REG_REPLY and broadcasts updated
  peer list on DE_REG_REQ; peer_list_req sends only to requester (not
  broadcast); master watchdog: any packet from a registered peer refreshes
  keepalive timestamp; new opcodes dispatched at DEBUG instead of error

- bridge.py: replace seq_id-based call boundary detection with per-TS
  call_start tracking using VOICE_HEAD/VOICE_TERM burst types; XPR8400
  firmware churns seq_id every superframe when Talker Alias is interleaved,
  making it unreliable as a call boundary indicator

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 13:18:47 -05:00
Cort BuffingtonandClaude Sonnet 4.6 ce191c2b34 Initial port: Python 3 / asyncio reimplementation of dmrlink
Full port of dmrlink (Python 2 / Twisted) to Python 3 with asyncio, aligned
with the HBlink3 2026_cleanup branch style.

- const.py:  merged ipsc_const + ipsc_mask, all bytes literals corrected for Py3
- log.py:    root-logger config matching HBlink3 log.py
- config.py: configparser Py3 port; bytes built with bytes([]) / bytes.fromhex()
- dmrlink.py: full asyncio IPSC protocol engine; ReportServer (NDJSON/TCP)
  replaces Twisted DatagramProtocol, LoopingCall, NetstringReceiver, and pickle
- bridge.py: asyncio port of confbridge.py, renamed to match HBlink3 convention;
  BridgeReportServer adds NDJSON bridge/call-event streaming
- dashboard/: FastAPI + WebSocket dashboard adapted for IPSC data shapes
  (MASTER/PEER mode, PEERS dict, bridge_event call log)
- requirements.txt, pyproject.toml: package metadata

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 12:41:31 -05:00