Bug fixes in dial, implement dial on both slots, tidy up voice prompts,

improve ebm_lc handling, allow Talker Alias and in-call GPS to transit FreeDMR.
master
Simon 2 weeks ago
parent 562d86f949
commit d86623180a

File diff suppressed because it is too large Load Diff

@ -38,7 +38,9 @@ The harness code is split as follows:
including optional OpenBridge/FBP peer sections.
- `FreeDmrProcess`: starts and stops `bridge_master.py`.
- `HbpRepeater`: UDP HBP client emulator with login, ping, packet send, stream
send, and capture support.
send, and capture support. The initial login challenge is retried for a
bounded startup window so subprocess startup work does not race the first
test packet.
- `FbpPeer`: UDP FBP v5 peer emulator with signed packet sends, keepalive,
version negotiation, STUN and source-quench control helpers.
- `UdpBlackBoxScenario`: process plus two-master loopback topology with
@ -125,17 +127,19 @@ for rule timeout checks without sleeping.
target. When AllStar is disabled it reports busy; when enabled it enters
AllStar mode and schedules reset. It should not create or retune reflector
state or announce a dial-a-TG link.
- Dial-a-TG default-reflector configuration bugs: startup and live options reload
should use the same prohibited default-reflector targets. Reserved/control
targets such as `6`, `7`, and AllStar control target `8` should not create an
active default TS2 reflector at startup. The FreeDMR policy cap should match
RF dial-a-TG handling: `999999` is valid and higher default reflectors are
rejected. Invalid default-reflector options should disable any existing
default reflector for the current session rather than preserving stale TS2 TG9
reflector state. Invalid startup defaults should be logged and should not
create bridge state; the in-memory effective default should normalize to `0`
without writing back to the config file. System-wide defaults are intended for
sparing use; client requested settings are preferential.
- Dial-a-TG default-dial configuration bugs: startup and live options reload
should use the same prohibited default targets. Reserved/control targets such
as `6`, `7`, and AllStar control target `8` should not create an active
default reflector at startup. `DEFAULT_DIAL_TS1` and `DEFAULT_DIAL_TS2` are
the canonical per-slot defaults; deprecated `DEFAULT_REFLECTOR`, `DIAL` and
`StartRef` remain TS2 compatibility aliases. The FreeDMR policy cap should
match RF dial-a-TG handling: `999999` is valid and higher defaults are
rejected. Invalid default options should disable any existing default for the
current session rather than preserving stale TG9 reflector state. Invalid
startup defaults should be logged and should not create bridge state; the
in-memory effective default should normalize to `0` without writing back to
the config file. System-wide defaults are intended for sparing use; client
requested settings are preferential.
- Static TG configuration bugs: startup and live options reload should reject
prohibited local/control TGs consistently on both TS1 and TS2 after parsing the
configured TG strings to integers. Invalid IDs at or above `16777215` should
@ -146,9 +150,9 @@ for rule timeout checks without sleeping.
- Client options parsing bugs: malformed independent numeric fields such as
`IDENTTG=A`, `VOICE=A`, or `SINGLE=A` should not abort otherwise valid session
options in the same string. `VOICE` and `SINGLE` accept only `0` or `1`.
Empty `DIAL` / `DEFAULT_REFLECTOR` is equivalent to `0` and means no default
reflector. Invalid `TIMER` values should be logged and should not block valid
static TG changes, which should use the current effective timer.
Empty `DIAL` / `DEFAULT_REFLECTOR` is equivalent to `0` and means no TS2
default reflector. Invalid `TIMER` values should be logged and should not
block valid static TG changes, which should use the current effective timer.
- Voice ident override bugs: `OVERRIDE_IDENT_TG` should be parsed before packet
generation. Valid positive TGs below all-call are used as the destination;
empty or false override values use all-call; malformed, out-of-range, or
@ -197,7 +201,12 @@ for rule timeout checks without sleeping.
data-only state.
- Voice LC rewrite boundary bugs: embedded-LC rewrite should apply only to voice
bursts B-E and must not mutate data-sync/control payload bytes while forwarding
over HBP or FBP paths.
over HBP or FBP paths. Same-TG voice forwarding should preserve burst payload
bytes so embedded Talker Alias/GPS-like LC can traverse; target-TG mapped
forwarding should still regenerate embedded LC for the rewritten TG.
- Embedded-LC observability bugs: accepted in-call Talker Alias and GPS LC cycles
should be decoded with the standalone MMDVMHost-style embedded-LC codec and
logged without changing packet routing or mutation behaviour.
- HBP group/VCSBK rate-control bugs: same-timestamp packet bursts should not
raise during local packet-rate calculation before duplicate/drop handling can
run.
@ -334,10 +343,11 @@ Implemented:
and alias downloads disabled. The generated config supports scenario-level
knobs for global ACL fields, static TG lists and optional FBP peers.
- Black-box HBP coverage for static routing, global ACL startup parsing,
data/control payload preservation, sequence wrap, duplicate sequence `0`
suppression, terminator lifecycle suppression, recorded fixture replay, burst
loss and duplicate UDP profiles, and local generated prompt output for
dial-a-TG reserved controls.
data/control payload preservation, same-TG voice embedded-LC payload
preservation, in-call Talker Alias/GPS log observability, sequence wrap,
duplicate sequence `0` suppression, terminator lifecycle suppression, recorded
fixture replay, burst loss and duplicate UDP profiles, and local generated
prompt output for dial-a-TG reserved controls.
- Black-box FBP coverage for enhanced keepalive/version setup, static TG routing
from HBP to FBP and from FBP to HBP, BCKA gating of enhanced HBP-to-FBP
forwarding, BCSQ source-quench suppression, invalid BCSQ rejection, BCST STUN
@ -476,6 +486,22 @@ fixture readers once recorded fixtures are added:
destination TG or unit ID, stream ID, sequence, frame type, call type,
dtype/voice sequence, payload bytes and optional frame delay.
- Synthetic fixtures build canonical `DMRD` payload bytes from `PacketSpec`.
- `freedmr_dmr_codec.py` is a standalone codec proving ground for protocol
helpers before they are linked into packet routing. Its first scope is
MMDVMHost-style embedded LC encode/decode with Hamming(16,11,4), column parity
and 5-bit checksum validation. It now also covers full LC header/terminator
BPTC generation, RS(12,9) LC parity masks, a small LC classifier and
Golay(20,8,7) slot type encode/decode correction. TA/GPS logging fixtures are
generated through this module so the logging path sees valid embedded-LC
cycles rather than hand-coded bit slices. The module also exposes
legacy-compatible LC generation function names used by
`bridge_master.py`, `bridge.py` and `mk_voice.py`, plus compatible
`voice_head_term()` and `voice()` decode helpers used by `bridge_master.py`
and `bridge.py`. Synthetic group voice LC fallback is generated through this
module with normal service options (`0x00`); decoded inbound LC bytes remain
the source of truth when a real voice header is available. Active runtime
byte/alias helpers are FreeDMR-owned in `utils.py`; remaining `dmr_utils3`
imports are limited to legacy/lab tools unless those tools are updated later.
- Recorded fixture support is not implemented yet. When added, fixtures should
keep raw bytes plus sidecar metadata describing expected decoded fields and
allowed rewrite regions.
@ -516,11 +542,13 @@ Assertions should be grouped by intent:
test claiming login, HMAC, UDP parsing or real cadence coverage belongs in the
UDP layer.
- Minimal synthetic voice payloads may not be sufficient for scenarios that
assert full LC encoding. Recorded fixtures or carefully generated payloads
should be used for those cases.
assert full packet audio behaviour. Full LC and slot type codec behaviour is
covered in the standalone codec layer, while recorded fixtures or carefully
generated payloads should still be used for packet-path scenarios.
- Embedded LC can carry information such as embedded GPS and talker alias. The
current harness protects against accidental mutation of data/control packets,
but it does not yet verify future source-to-destination embedded-LC carry-over.
current harness protects same-TG carry-over and standalone codec behavior, but
does not yet verify selective embedded-LC rewrite/preservation on TG-mapped
streams.
- Generated prompt interruption is covered in both layers for state and
UDP-visible routing. The harness still does not prove RF-side audio behavior
or how a physical repeater/radio reacts to an abandoned prompt without a
@ -539,8 +567,9 @@ Assertions should be grouped by intent:
- Deterministic cross-slot routing tests verify that TS1-to-TS2 routing rewrites
only the slot bit while preserving source ID, destination TG, peer ID, stream
ID and packet bytes outside the expected header bit.
- Deterministic dial-a-TG tests verify that TS1 private calls create, retune,
disconnect and query TS2 reflector state without emitting network traffic.
- Deterministic dial-a-TG tests verify that private-call control is slot-local:
TS1 controls TS1 reflector state, TS2 controls TS2 reflector state, and TS1 no
longer retunes TS2.
- Deterministic generated-prompt tests verify first-packet prompt state, prompt
cancellation when real HBP voice wins the same slot, and embedded-LC rewrite
for late entry after cancellation.
@ -556,20 +585,22 @@ Assertions should be grouped by intent:
- Deterministic reserved control-range tests verify that TS1 private calls to
`4001..4999` do not create or retune reflector bridges and report busy rather
than linked.
- Deterministic echo-target tests verify that TS1 private call `9990` creates
and activates the TS2 reflector state and announces a link.
- Deterministic echo-target tests verify that TS1 private call `9990` is an
intentional linkable echo/test target and announces a link without creating an
FBP route target.
- Deterministic information-service tests verify that `9991..9999` schedules
both the requested AMBE file and the generic silence prompt without creating a
reflector.
- Deterministic policy-range tests verify that `999999` is still linkable while
`1000000` does not create or retune reflector state and reports busy rather
than linked.
- Deterministic default-reflector tests verify that startup rejects reserved
control targets `6`, `7`, and `8`, while still allowing a linkable default
reflector target to create an active TS2 reflector. They also verify
`999999` remains valid and startup/options reject default reflector targets
above that policy cap, with invalid options disabling any active default
reflector state and invalid startup defaults producing a warning while
- Deterministic default-dial tests verify that startup rejects reserved control
targets `6`, `7`, and `8`, while still allowing linkable
`DEFAULT_DIAL_TS1` and `DEFAULT_DIAL_TS2` targets to create active per-slot
reflectors. Deprecated `DEFAULT_REFLECTOR`, `DIAL` and `StartRef` remain TS2
aliases. These tests also verify `999999` remains valid and startup/options
reject targets above that policy cap, with invalid options disabling active
default state and invalid startup defaults producing a warning while
normalizing runtime state to `0`.
- Deterministic static-TG configuration tests verify that startup rejects
prohibited TS1 and TS2 static TGs after integer parsing, rejects invalid IDs
@ -578,9 +609,10 @@ Assertions should be grouped by intent:
prohibition. They also verify whitespace normalization and token-level
skipping of invalid static TG tokens while valid tokens still apply.
- Deterministic options parser tests verify malformed independent numeric fields
do not block valid DIAL/static fields, boolean-like options reject values other
than `0` or `1`, empty `DIAL` disables default reflector state, and invalid
`TIMER` values are logged without blocking valid static TG changes.
do not block valid default-dial/static fields, boolean-like options reject
values other than `0` or `1`, empty `DIAL` disables TS2 default reflector
state, and invalid `TIMER` values are logged without blocking valid static TG
changes.
- Deterministic voice-ident tests verify override destination selection for
valid string TGs, empty/false overrides, malformed values, control TGs, and
all-call.

@ -32,8 +32,31 @@ the factory-held database object with parameterized inserts. It also covers the
hotspot proxy environment boolean parser so Docker settings such as
`FDPROXY_IPV6=0` disable the feature.
Standalone DMR codec coverage verifies the new `freedmr_dmr_codec.py` helpers
before they are wired into packet forwarding. These tests cover MMDVMHost-style
embedded LC encode/decode, Hamming(16,11,4) single-bit correction,
uncorrectable error rejection, checksum-checked round trips, DMR payload
embedded-LC slice helpers, full LC header/terminator BPTC generation, RS(12,9)
LC parity masks, group/unit LC classification, and Golay(20,8,7) slot type
encode/decode correction. Synthetic group voice LC generation defaults to
normal service options (`0x00`) and keeps the HBLink `0x20` value only as an
explicit legacy constant. The full LC, routing-style embedded LC, voice
header/terminator and voice burst fixtures are fixed byte/bit vectors captured
from known-good behaviour, so these tests no longer need `dmr_utils3`.
Runtime LC generation and the voice header/terminator and burst decode helpers
used by `bridge_master.py` and `bridge.py` now use compatibility functions in
`freedmr_dmr_codec.py`. Active runtime helper functions such as `bytes_3()`,
`bytes_4()`, `int_id()` and `get_alias()` are provided by FreeDMR `utils.py`.
The deterministic suite includes dial-a-TG coverage. It verifies that private
calls from TS1 can create, retune, disconnect and query the TS2 reflector state.
calls from TS1 create, retune, disconnect and query TS1 reflector state, while
private calls from TS2 control TS2 reflector state. TS1 no longer controls TS2.
Default dial-a-TG startup and OPTIONS handling is covered through canonical
per-slot `DEFAULT_DIAL_TS1` and `DEFAULT_DIAL_TS2`; deprecated
`DEFAULT_REFLECTOR`, `DIAL` and `StartRef` remain TS2 compatibility aliases.
It also covers late-entry synthetic LC fallback: streams without a decodable
voice header fabricate normal group voice LC bytes, while streams with a real
voice header preserve the decoded LC service-options byte unchanged.
It verifies these state changes are scoped to the receiving master system.
Status query `5000` reports one active reflector and does not repair stale
multi-active state.
@ -46,20 +69,20 @@ are covered as scheduling both the requested AMBE file and the generic silence
prompt without creating reflector state. The current FreeDMR dial-a-TG policy
cap is covered: `999999` remains linkable and higher targets report busy rather
than linked. Private dial-a-TG timeout coverage verifies private unit calls do
not emit unmatched `GROUP VOICE,END,RX` lifecycle events. Startup default-reflector handling is covered so reserved/control
not emit unmatched `GROUP VOICE,END,RX` lifecycle events. Startup default-dial handling is covered so reserved/control
targets `6`, `7`, and `8` are rejected, `999999` is accepted, and higher targets
are rejected. Invalid default-reflector options disable the effective TS2 TG9
are rejected. Invalid default-dial options disable the effective slot TG9
default reflector for the session; invalid startup defaults are logged and do
not create bridge state, with the in-memory effective default normalized to `0`.
A linkable target can still create an active TS2 default reflector. Static TG startup and options handling is
A linkable target can still create an active per-slot default reflector. Static TG startup and options handling is
covered so prohibited local/control TGs are rejected consistently on both TS1
and TS2, and invalid IDs at or above `16777215` are rejected while linkable
static TGs are still created. Static TG option parsing also covers simple
whitespace normalization and token-level skipping of invalid tokens so valid
tokens in the same TS1 or TS2 list still apply. Client options parsing covers
malformed independent numeric fields so valid DIAL/static fields still apply,
malformed independent numeric fields so valid default-dial/static fields still apply,
`VOICE` and `SINGLE` accept only `0`/`1`, and empty `DIAL` disables the default
reflector. Invalid `TIMER` values are logged and static TG changes continue
TS2 reflector. Invalid `TIMER` values are logged and static TG changes continue
using the current effective timer. Voice ident override coverage verifies valid
override TGs are used, empty/false overrides use all-call, and malformed,
control, or all-call override values are logged and fall back to all-call.
@ -108,6 +131,12 @@ handling can run.
Data-sync control payload preservation is covered across HBP-to-HBP, HBP-to-FBP,
FBP-to-HBP and FBP-to-FBP forwarding so voice embedded-LC rewrite does not mutate
VCSBK/control payload bytes.
Voice embedded-LC preservation is covered across HBP-to-HBP, HBP-to-FBP,
FBP-to-HBP and FBP-to-FBP same-TG forwarding. Those tests assert voice bursts
B-E keep their DMR payload bytes unless the target TG is intentionally rewritten.
Embedded-LC observability coverage verifies accepted in-call Talker Alias and
GPS LC cycles are decoded through the standalone validated codec to system log
messages without changing packet routing or mutation behaviour.
OBP group voice rate-drop coverage verifies per-stream packet-rate protection is
calculated from elapsed stream duration rather than the absolute stream start
timestamp. OBP voice lifecycle coverage verifies a voice terminator marks the
@ -163,12 +192,17 @@ behavior, and `rule_timer_loop()` clears disconnected FBP-only route targets.
The UDP harness starts `bridge_master.py` as a subprocess with a generated
loopback-only test config. It emulates HBP repeaters and FBP/OpenBridge peer
servers over UDP, performs HBP login, sends signed packets/control messages, and
captures outbound UDP packets.
captures outbound UDP packets. The HBP login helper retries the initial login
challenge for a short startup window because `bridge_master.py` can spend time
loading aliases, keys and voice assets before Twisted has bound the loopback UDP
sockets.
Current UDP scenarios cover HBP registration/config handshake, static TG
routing, global `USE_ACL: False` startup parsing observed through packet
admission, data-sync/control payload preservation, modulo-256 voice sequence
wrap, sequence `0` duplicate suppression, voice terminator suppression of late
admission, data-sync/control payload preservation, same-TG voice embedded-LC
payload preservation, in-call Talker Alias/GPS log observability,
modulo-256 voice sequence wrap, sequence `0` duplicate suppression, voice
terminator suppression of late
same-stream packets, recorded HBP fixture replay, and a dial-a-TG reserved
control private call that emits a local TG9 TS2 prompt without leaking traffic
to another master. They now also cover FBP v5 static TG routing in both

Loading…
Cancel
Save

Powered by TurnKey Linux.