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. including optional OpenBridge/FBP peer sections.
- `FreeDmrProcess`: starts and stops `bridge_master.py`. - `FreeDmrProcess`: starts and stops `bridge_master.py`.
- `HbpRepeater`: UDP HBP client emulator with login, ping, packet send, stream - `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, - `FbpPeer`: UDP FBP v5 peer emulator with signed packet sends, keepalive,
version negotiation, STUN and source-quench control helpers. version negotiation, STUN and source-quench control helpers.
- `UdpBlackBoxScenario`: process plus two-master loopback topology with - `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 target. When AllStar is disabled it reports busy; when enabled it enters
AllStar mode and schedules reset. It should not create or retune reflector AllStar mode and schedules reset. It should not create or retune reflector
state or announce a dial-a-TG link. state or announce a dial-a-TG link.
- Dial-a-TG default-reflector configuration bugs: startup and live options reload - Dial-a-TG default-dial configuration bugs: startup and live options reload
should use the same prohibited default-reflector targets. Reserved/control should use the same prohibited default targets. Reserved/control targets such
targets such as `6`, `7`, and AllStar control target `8` should not create an as `6`, `7`, and AllStar control target `8` should not create an active
active default TS2 reflector at startup. The FreeDMR policy cap should match default reflector at startup. `DEFAULT_DIAL_TS1` and `DEFAULT_DIAL_TS2` are
RF dial-a-TG handling: `999999` is valid and higher default reflectors are the canonical per-slot defaults; deprecated `DEFAULT_REFLECTOR`, `DIAL` and
rejected. Invalid default-reflector options should disable any existing `StartRef` remain TS2 compatibility aliases. The FreeDMR policy cap should
default reflector for the current session rather than preserving stale TS2 TG9 match RF dial-a-TG handling: `999999` is valid and higher defaults are
reflector state. Invalid startup defaults should be logged and should not rejected. Invalid default options should disable any existing default for the
create bridge state; the in-memory effective default should normalize to `0` current session rather than preserving stale TG9 reflector state. Invalid
without writing back to the config file. System-wide defaults are intended for startup defaults should be logged and should not create bridge state; the
sparing use; client requested settings are preferential. 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 - Static TG configuration bugs: startup and live options reload should reject
prohibited local/control TGs consistently on both TS1 and TS2 after parsing the 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 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 - Client options parsing bugs: malformed independent numeric fields such as
`IDENTTG=A`, `VOICE=A`, or `SINGLE=A` should not abort otherwise valid session `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`. 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 Empty `DIAL` / `DEFAULT_REFLECTOR` is equivalent to `0` and means no TS2
reflector. Invalid `TIMER` values should be logged and should not block valid default reflector. Invalid `TIMER` values should be logged and should not
static TG changes, which should use the current effective timer. block valid static TG changes, which should use the current effective timer.
- Voice ident override bugs: `OVERRIDE_IDENT_TG` should be parsed before packet - Voice ident override bugs: `OVERRIDE_IDENT_TG` should be parsed before packet
generation. Valid positive TGs below all-call are used as the destination; 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 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. data-only state.
- Voice LC rewrite boundary bugs: embedded-LC rewrite should apply only to voice - 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 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 - HBP group/VCSBK rate-control bugs: same-timestamp packet bursts should not
raise during local packet-rate calculation before duplicate/drop handling can raise during local packet-rate calculation before duplicate/drop handling can
run. run.
@ -334,10 +343,11 @@ Implemented:
and alias downloads disabled. The generated config supports scenario-level and alias downloads disabled. The generated config supports scenario-level
knobs for global ACL fields, static TG lists and optional FBP peers. knobs for global ACL fields, static TG lists and optional FBP peers.
- Black-box HBP coverage for static routing, global ACL startup parsing, - Black-box HBP coverage for static routing, global ACL startup parsing,
data/control payload preservation, sequence wrap, duplicate sequence `0` data/control payload preservation, same-TG voice embedded-LC payload
suppression, terminator lifecycle suppression, recorded fixture replay, burst preservation, in-call Talker Alias/GPS log observability, sequence wrap,
loss and duplicate UDP profiles, and local generated prompt output for duplicate sequence `0` suppression, terminator lifecycle suppression, recorded
dial-a-TG reserved controls. 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 - 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 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 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, destination TG or unit ID, stream ID, sequence, frame type, call type,
dtype/voice sequence, payload bytes and optional frame delay. dtype/voice sequence, payload bytes and optional frame delay.
- Synthetic fixtures build canonical `DMRD` payload bytes from `PacketSpec`. - 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 - Recorded fixture support is not implemented yet. When added, fixtures should
keep raw bytes plus sidecar metadata describing expected decoded fields and keep raw bytes plus sidecar metadata describing expected decoded fields and
allowed rewrite regions. 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 test claiming login, HMAC, UDP parsing or real cadence coverage belongs in the
UDP layer. UDP layer.
- Minimal synthetic voice payloads may not be sufficient for scenarios that - Minimal synthetic voice payloads may not be sufficient for scenarios that
assert full LC encoding. Recorded fixtures or carefully generated payloads assert full packet audio behaviour. Full LC and slot type codec behaviour is
should be used for those cases. 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 - Embedded LC can carry information such as embedded GPS and talker alias. The
current harness protects against accidental mutation of data/control packets, current harness protects same-TG carry-over and standalone codec behavior, but
but it does not yet verify future source-to-destination embedded-LC carry-over. does not yet verify selective embedded-LC rewrite/preservation on TG-mapped
streams.
- Generated prompt interruption is covered in both layers for state and - Generated prompt interruption is covered in both layers for state and
UDP-visible routing. The harness still does not prove RF-side audio behavior 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 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 - 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 only the slot bit while preserving source ID, destination TG, peer ID, stream
ID and packet bytes outside the expected header bit. ID and packet bytes outside the expected header bit.
- Deterministic dial-a-TG tests verify that TS1 private calls create, retune, - Deterministic dial-a-TG tests verify that private-call control is slot-local:
disconnect and query TS2 reflector state without emitting network traffic. 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 - Deterministic generated-prompt tests verify first-packet prompt state, prompt
cancellation when real HBP voice wins the same slot, and embedded-LC rewrite cancellation when real HBP voice wins the same slot, and embedded-LC rewrite
for late entry after cancellation. 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 - Deterministic reserved control-range tests verify that TS1 private calls to
`4001..4999` do not create or retune reflector bridges and report busy rather `4001..4999` do not create or retune reflector bridges and report busy rather
than linked. than linked.
- Deterministic echo-target tests verify that TS1 private call `9990` creates - Deterministic echo-target tests verify that TS1 private call `9990` is an
and activates the TS2 reflector state and announces a link. intentional linkable echo/test target and announces a link without creating an
FBP route target.
- Deterministic information-service tests verify that `9991..9999` schedules - Deterministic information-service tests verify that `9991..9999` schedules
both the requested AMBE file and the generic silence prompt without creating a both the requested AMBE file and the generic silence prompt without creating a
reflector. reflector.
- Deterministic policy-range tests verify that `999999` is still linkable while - Deterministic policy-range tests verify that `999999` is still linkable while
`1000000` does not create or retune reflector state and reports busy rather `1000000` does not create or retune reflector state and reports busy rather
than linked. than linked.
- Deterministic default-reflector tests verify that startup rejects reserved - Deterministic default-dial tests verify that startup rejects reserved control
control targets `6`, `7`, and `8`, while still allowing a linkable default targets `6`, `7`, and `8`, while still allowing linkable
reflector target to create an active TS2 reflector. They also verify `DEFAULT_DIAL_TS1` and `DEFAULT_DIAL_TS2` targets to create active per-slot
`999999` remains valid and startup/options reject default reflector targets reflectors. Deprecated `DEFAULT_REFLECTOR`, `DIAL` and `StartRef` remain TS2
above that policy cap, with invalid options disabling any active default aliases. These tests also verify `999999` remains valid and startup/options
reflector state and invalid startup defaults producing a warning while 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`. normalizing runtime state to `0`.
- Deterministic static-TG configuration tests verify that startup rejects - Deterministic static-TG configuration tests verify that startup rejects
prohibited TS1 and TS2 static TGs after integer parsing, rejects invalid IDs 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 prohibition. They also verify whitespace normalization and token-level
skipping of invalid static TG tokens while valid tokens still apply. skipping of invalid static TG tokens while valid tokens still apply.
- Deterministic options parser tests verify malformed independent numeric fields - Deterministic options parser tests verify malformed independent numeric fields
do not block valid DIAL/static fields, boolean-like options reject values other do not block valid default-dial/static fields, boolean-like options reject
than `0` or `1`, empty `DIAL` disables default reflector state, and invalid values other than `0` or `1`, empty `DIAL` disables TS2 default reflector
`TIMER` values are logged without blocking valid static TG changes. state, and invalid `TIMER` values are logged without blocking valid static TG
changes.
- Deterministic voice-ident tests verify override destination selection for - Deterministic voice-ident tests verify override destination selection for
valid string TGs, empty/false overrides, malformed values, control TGs, and valid string TGs, empty/false overrides, malformed values, control TGs, and
all-call. 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 hotspot proxy environment boolean parser so Docker settings such as
`FDPROXY_IPV6=0` disable the feature. `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 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. It verifies these state changes are scoped to the receiving master system.
Status query `5000` reports one active reflector and does not repair stale Status query `5000` reports one active reflector and does not repair stale
multi-active state. 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 prompt without creating reflector state. The current FreeDMR dial-a-TG policy
cap is covered: `999999` remains linkable and higher targets report busy rather 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 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 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 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`. 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 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 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 static TGs are still created. Static TG option parsing also covers simple
whitespace normalization and token-level skipping of invalid tokens so valid 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 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 `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 using the current effective timer. Voice ident override coverage verifies valid
override TGs are used, empty/false overrides use all-call, and malformed, 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. 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, 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 FBP-to-HBP and FBP-to-FBP forwarding so voice embedded-LC rewrite does not mutate
VCSBK/control payload bytes. 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 OBP group voice rate-drop coverage verifies per-stream packet-rate protection is
calculated from elapsed stream duration rather than the absolute stream start calculated from elapsed stream duration rather than the absolute stream start
timestamp. OBP voice lifecycle coverage verifies a voice terminator marks the 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 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 loopback-only test config. It emulates HBP repeaters and FBP/OpenBridge peer
servers over UDP, performs HBP login, sends signed packets/control messages, and 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 Current UDP scenarios cover HBP registration/config handshake, static TG
routing, global `USE_ACL: False` startup parsing observed through packet routing, global `USE_ACL: False` startup parsing observed through packet
admission, data-sync/control payload preservation, modulo-256 voice sequence admission, data-sync/control payload preservation, same-TG voice embedded-LC
wrap, sequence `0` duplicate suppression, voice terminator suppression of late 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 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 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 to another master. They now also cover FBP v5 static TG routing in both

Loading…
Cancel
Save

Powered by TurnKey Linux.