20 Commits
Author SHA1 Message Date
cortandClaude Opus 5 395378a87a Correct protocol.md against the implementation
The connection flow described a handshake the code never performed: MSTCL
as the login challenge (it is a shutdown notice), RPTA as the accept (the
constant is never sent), no RPTK acknowledgment, and state names that did
not exist. The keepalive section contradicted itself, describing an "MSTP"
command answered with RPTACK.

Rewrite it from the code. The challenge is RPTACK + salt, the accept is
RPTACK + repeater_id, and every handshake step is shown with its reply.
Fix the ID width claim: repeater IDs are 4 bytes, but the radio and
talkgroup IDs inside DMRD are 3. Document DMRD as a 53-byte structure with
a 55-byte wire length, which is what the parser actually requires.

Add what was missing: MSTCL, MSTNAK, and DMRA as commands, the RPTK hash
construction, the ID-takeover challenge, RPTO's trust gating and UNIT=,
voice-vs-data stream classification, and the outbound client role.

Soften two claims the code does not enforce. RPTO does not require the
connected state, and any packet from the registered address refreshes
liveness, so disconnect lands at max_missed times the sweep interval
rather than timeout_duration.

The outbound path logged "waiting for MSTCL..." while correctly waiting
for RPTACK + salt — the same confusion the document had. Group the
four-byte command prefixes in constants.py and record what they are for,
since HBlink4 only uses RPTP and the rest read as dead code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 06:56:41 -05:00
cortandClaude Opus 4.7 89c506a224 docs: audit and refresh ahead of merge to main
Documentation cleanup pass across the tree, driven by the upcoming merge
of the dmrd-translation branch to main.

Deletions (obsolete / superseded):
- docs/user_csv_automation_proposal.md — implemented as dashboard/user_db.py
- docs/QUICK_TEST_REFERENCE.md — stale test counts, referenced a
  TEST_COVERAGE.md that no longer exists
- user.old.csv — development backup artifact (also added user.old* and
  user.bak* to .gitignore)

Release notes renumbered to the 4.x series (file kept 1.x-labelled from
a prior numbering scheme that predated the 4.1.0 release):
- docs/RELEASE_NOTES_v1.5.md   -> docs/RELEASE_NOTES_v4.5.md
- docs/RELEASE_NOTES_v1.6.1.md -> docs/RELEASE_NOTES_v4.6.1.md
- Also fixed a stray "v1.5+" -> "v4.5+" in stream_tracking_diagrams.md

Content fixes where docs contradicted code or were stale:
- docs/dmrd_translation.md: replaced the "Payload blanking" section with
  "Link Control rewriting" describing VHEAD/VTERM full-LC and voice-burst
  EMB_LC re-encoding via dmr_utils3.bptc
- docs/connecting_to_hblink4.md: cross-reference updated to match
- docs/protocol.md: corrected call-type bit direction (0=Group,
  1=Private/Unit — previously reversed), replaced "Bits 0-3: Reserved"
  with actual dtype_vseq semantics, updated translation-doc link
- readme.md: "Built on Twisted" -> asyncio (Twisted was removed in the
  outbound-connection release); expanded docs index to include routing,
  DMRD translation, diagrams, TODO, and OpenBridge analysis; added DMRD
  translation to the features list
- docs/stream_tracking.md: StreamState snippet now shows lc_base and
  lc_cache fields added for LC rewriting
- scripts/README.md: noted that dashboard/user_db.py is the primary
  refresh path; script remains as manual fallback
- dashboard/user_db.py: dropped the doctring reference to the deleted
  proposal file

Note: dmrd-translation branch remains in active development but is
fully functional as of this commit. Tests: 75/75 pass (pre-existing
test_access_control.py failures are unrelated and predate this branch).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 07:52:37 -05:00
cortandClaude Opus 4.7 32286ae1ed feat: RPTO slot/TGID translation and outbound rf_src override
Trusted repeaters can now declare per-entry slot/TGID translation rules in
their RPTO (OPTIONS) string, plus an optional single-ID rf_src override for
outbound group voice.

Grammar (operator-facing, goes into MMDVM.ini / DMRGateway.ini):
  TS1 = entry[,entry...]
  TS2 = entry[,entry...]
  SRC = radio_id
  entry = net_tgid_spec[:local_slot[:local_tgid]]
  net_tgid_spec: N | N-M (range, specificity 2) | N (exact, specificity 3)
  local_slot: 1 | 2 | * (preserve net slot)
  local_tgid: N | * (preserve matched net tgid)

Wildcards on the network side (*, N*) are rejected at parse time to keep
the hot path O(1). Ranges expand to concrete map entries at RPTO parse
time (capped at 10,000 tgids). Most-specific rule wins on collision;
losers are dropped with a warning.

Runtime:
- RepeaterState grows inbound_map / outbound_map (inverses) and a single
  tx_src_override.
- _check_inbound_routing translates local -> network before the ACL check
  so subscriptions stay in one vocabulary.
- _calculate_stream_targets uses each target's outbound_map to run the
  slot-busy / hang-time check against the slot the packet will actually
  occupy on air.
- _forward_stream (and the outbound->local forwarding path) rewrite
  bytes 5-7 (rf_src via override), 8-10 (tgid), 11-14 (repeater id for
  outbound targets), and the slot bit in byte 15. Data-sync frames
  (frame_type==2) get bytes 20-52 zeroed so MMDVMHost's BPTC decode
  fails and it falls back to the rewritten DMRD header; voice frames
  keep AMBE vocoder bits intact.
- Untranslated repeaters pay zero overhead (empty-dict short-circuits).
- Unit/private calls are still rejected upstream; SRC= has a defensive
  group-only gate regardless.
- Mid-stream RPTO logs a warning and applies new rules immediately;
  in-flight streams finish on their cached routing.

Validated via parser unit tests (exact/range/collision/error cases, NAT
grammar, specificity precedence) and module imports. NOT yet validated
on live DMR traffic — that's what this branch is for.

Docs:
- docs/dmrd_translation.md: full feature reference (new)
- docs/configuration.md: trust + RPTO extensions section
- docs/connecting_to_hblink4.md: operator Options= examples for
  MMDVMHost / DMRGateway (Pi-Star/WPSD references stripped — out of scope)
- docs/protocol.md: extended RPTO grammar note

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:55:24 -05:00
Cort Buffington f3e2fe96e1 Revise HomeBrew DMR protocol documentation
Clarify the HomeBrew DMR protocol implementation details and correct errors in the keepalive mechanism. Update the table formatting for configuration data fields and DMRD packet structure.
2025-10-05 11:27:01 -05:00
cort e7d5eb4cea docs: Add RPTO (Repeater Options) command documentation to protocol.md
- Document RPTO message format and purpose
- Explain talkgroup negotiation and intersection logic
- Note that server config is master allow list
- Include examples of RPTO usage and filtering
- Completes protocol documentation for all implemented commands
2025-10-05 11:21:47 -05:00
cort 26a84ad67a Update documentation: mark terminator detection complete, clarify LC extraction goals, add comprehensive TODO list
- Created docs/TODO.md with 11 prioritized features
- Clarified LC extraction rationale: needed for stream forwarding with ID modification, not for current read-only ops
- Updated all docs to reflect completed terminator detection (60ms via packet header flags)
- Removed outdated TODO comments about sync pattern extraction
- Updated IMPLEMENTATION_SUMMARY.md with completion status
- Updated hang_time.md, protocol.md, lc_extraction.md with current state
- Updated readme.md feature list and documentation links
- Updated hblink.py comments to reference docs/TODO.md
2025-10-02 16:44:24 -05:00
cort efda9b02b6 Implement fast terminator detection (200ms inactivity threshold)
- Add fast terminator detection: when new stream tries to start, check if current stream inactive >200ms
- If inactive >200ms, end old stream immediately and allow new one (provides ~200ms turnaround)
- Add end_reason field to stream_end events ('fast_terminator' or 'timeout')
- Update dashboard to display end_reason in event log
- Mark sync pattern terminator detection as TODO (not yet working, needs investigation)
- Mark LC extraction from sync frames as TODO (may need FEC decoding)
- Update all documentation to reflect new approach
- Remove negative language about 'limitations' - frame as TODO items instead

This provides acceptable fast turnaround (~200ms) without needing to decode ETSI sync
patterns, which don't appear to match in Homebrew protocol packets (may need FEC or
other decoding that requires investigation).
2025-10-02 11:10:49 -05:00
cort fcd6214288 Fix three critical issues found in testing
1. Fixed call_type logic inversion:
   - Was: call_type_bit == 1 → private (WRONG)
   - Now: call_type_bit == 1 → group (CORRECT per Homebrew protocol)
   - Bit 6 of _bits field: 0=private, 1=group

2. Added data sync terminator detection:
   - Was only detecting voice terminators (0xD5DD7DF75D55)
   - Now also detects data terminators (0x7DFFD5F55D5F)
   - Fixes issue where frame_type=2 streams showed 'timeout' instead of 'terminator'

3. Improved dashboard event log formatting:
   - Added proper display for hang_time_expired events
   - Shows 'Hang time expired: Repeater X slot Y'

Testing revealed: Group voice calls were using Data Sync terminators, not
Voice Sync terminators. Both patterns now supported.
2025-10-02 10:33:36 -05:00
cort 08f0abd96a Fix dashboard issues: call type detection and hang time cleanup
Critical fixes:
- Fixed call_type showing 'unknown' by using Homebrew packet metadata (byte 15, bit 6)
  instead of waiting for LC extraction
- Fixed hang time never ending by emitting hang_time_expired event when hang time
  actually expires in HBlink4
- Dashboard now handles hang_time_expired event and clears slot display

Improvements:
- Removed color_code from dashboard events (RF air interface only, not needed by server)
- Updated protocol.md to clarify color code is for RF only
- Removed unused remove_stream_delayed() method from dashboard
- Logo increased 20% (60px -> 72px)

Design principle documented: Prefer Homebrew protocol metadata over LC extraction
for information available in packet headers (call type, timeslot, IDs, etc.)
2025-10-02 10:25:09 -05:00
cort a1c31f0358 Implement DMR voice terminator sync pattern detection
IMPLEMENTATION:
- Add DMR sync pattern constants to constants.py
  - Voice header: 0x755FD7DF75F7
  - Voice terminator: 0xD5DD7DF75D55
  - Data header/terminator patterns defined
- Implement _is_dmr_terminator() with sync pattern matching
  - Checks bytes 20-25 for terminator pattern
  - Returns True for voice terminators, False otherwise
  - Data terminators not yet implemented (TODO)
- Stream ends immediately when terminator detected
  - ~60ms after PTT release (primary detection)
  - Timeout fallback still available (2.0s)

TESTING:
- Add test_terminator_detection.py with 5 tests
  - test_voice_terminator_detection (PASS)
  - test_voice_header_not_terminator (PASS)
  - test_voice_frame_not_sync (PASS)
  - test_short_packet_not_terminator (PASS)
  - test_data_sync_not_implemented (PASS)
- All 36 tests passing (31 previous + 5 new)

DOCUMENTATION:
- Update IMPLEMENTATION_SUMMARY.md
  - Mark terminator detection as implemented
  - Update test counts (36 total)
  - Move from Known Limitations to completed
- Update protocol.md with correct sync patterns
- Clarify voice vs data terminator status

BENEFITS:
- Fast slot turnaround in normal operation
- Reduces slot unavailability from 2s to ~60ms
- Better spectrum efficiency
- Production ready for voice traffic
2025-10-01 18:02:23 -05:00
cort 114f2f22b7 Add DMR stream tracking with terminator detection and hang time
Features:
- Implement per-slot stream tracking for connected repeaters
- Add DMR terminator frame detection infrastructure
- Implement hang time to prevent slot hijacking during conversations
- Add two-tier stream end detection (terminator frame + timeout fallback)
- Add talkgroup filtering based on repeater configuration

Stream Management:
- StreamState dataclass for tracking active transmissions
- Per-slot (1 & 2) independent stream management
- Stream contention detection and first-come-first-served handling
- Automatic stream cleanup with configurable timeouts

Configuration:
- stream_timeout: 2.0s fallback for lost terminator frames
- stream_hang_time: 10-20s slot reservation after stream ends
- Updated config_sample.json with examples

Documentation:
- docs/stream_tracking.md: Stream management technical details
- docs/stream_tracking_diagrams.md: Visual flow diagrams (ASCII)
- docs/hang_time.md: Hang time feature explanation
- docs/protocol.md: Added DMRD packet structure and terminator details
- docs/configuration.md: Updated with stream management parameters
- readme.md: Updated features list

Tests:
- tests/test_stream_tracking.py: Stream tracking validation
- tests/test_hang_time.py: Hang time functionality tests

Implementation Notes:
- Terminator detection infrastructure in place (_is_dmr_terminator stub)
- Sync pattern decoding to be implemented in future
- No traffic forwarding yet (tracking only)
- All diagrams use ASCII characters for perfect alignment
2025-10-01 15:59:25 -05:00
Cort Buffington b81c600a3a adding warning to incorrect information on the Internet 2025-09-01 11:53:31 -05:00
Cort Buffington 5754f43b8b Improve Protocol description 2025-09-01 11:44:44 -05:00
Cort Buffington 8b55d8c418 Fixing my intern's screw ups with respect to keepalives 2025-09-01 09:49:42 -05:00
Cort Buffington 0aabe71d56 fixing ping/pong handling 2025-09-01 09:29:28 -05:00
Cort Buffington 7178dd567b enhance repeater timeout handling and logging for MSTP commands 2025-09-01 09:20:55 -05:00
Cort Buffington 403061f698 added additional protocol documentation 2025-09-01 08:09:16 -05:00
Cort Buffington 6ef0053610 change state names for more readability 2025-08-31 09:45:16 -05:00
Cort Buffington 170f6468eb fixed radio ID parsing mistake. 2025-08-30 20:38:16 -05:00
Cort Buffington 81dbdce2b7 Changed "master" to "server" in several places to reflect the new architecture of HBlink4.
Added a file explaining the protocol itself.
2025-08-30 12:46:57 -05:00