Esta página aún no está traducida; se muestra en inglés.
DMR bench testing on the SDR bench
How to test the DMR work (the board's modem driver behind hal/hal_dmr_modem.h, the call stack in core/dmr/call/,
the AMBE FEC and vocoder hosting, the audio path) on the bench: the rig, the tools, and the cases a person runs at the
radio.
Status words as in docs/spec/gotchas.md: "on air" = checked with the SDR or another radio.
A radio's checklist of required HIL tests is tools/bringup.py list --radio <id>
(tests/hil/README.md). The cases here are the manual procedures and what
the HIL tests don't script yet.
1. The rig
| Part | What |
|---|---|
| Radio under test | A radio with RadioFoundry, on the bench, on USB: driven by the debug link (tools/rfoundry_debug.py, the HIL tests) or its keys; the board's diagnostics page |
| Bench board | A board that serves the bench line protocol (TCP 7373): it builds and sends DMR bursts as jobs, decodes what it receives into burst records, and sends and receives FM. Given as --bench-api HOST[:PORT] or $RFOUNDRY_BENCH_API |
| Second bench board (optional) | The receive side (--bench-api-rx, $RFOUNDRY_BENCH_API_RX). A half-duplex board can't hear while it transmits |
The test channel is the rig's (--dmr-freq / --dmr-cc: tests/hil/README.md, "The rig's configuration"). It must be
inside the board's transmit list and receive window.
2. The tools
All in tools/bench/, MIT.
| Tool | What |
|---|---|
bench_line.py |
Client of the bench line protocol. bench_line.py HOST[:PORT] info shows the board; run bench_tx ARGS... sends one job |
mmdvm_hotspot.py |
The radio as an MMDVM modem over USB CDC (or the optional MMDVM UDP transport): configure simplex or SFR, poll status, log what it sends up; our extensions: command 0xD5 (SFR experiment switches) and the SFR counters at the end of GET_STATUS. Needs pyserial |
dmr_packet.py |
Reassembles the data packets in a listen job's JSON lines and decodes the IP in them |
dmr_cach.py |
The CACH and short LC, from the standard |
dmr_bench.py |
The DMR TX checks the HIL tests share (check_tx, check_modem_calls), their limits and a board's overrides |
sdrmon.py |
The carrier floor and off-slot residual of a power envelope |
Burst analysis of what the radio sends comes from the receive board's records through the HIL harness (tests/hil/README.md).
3. The radio receives
The bench board sends with bench_line.py HOST run bench_tx ARGS...; the user reads the diagnostics page and the main
screen. Each transmission is a known stimulus: source 9990301, AMBE silence unless stated. Many of these are also
automated in tests/hil (test_dmr_rx, test_dmr_call_features, test_dmr_data). A board refuses an option it
doesn't do (unsupported).
| Case | Job | Radio should show | Pass |
|---|---|---|---|
| R1 group voice | voice --dst TG --superframes 3 |
+18 voice bursts, 8 headers, 3 terminators, CRC errors unchanged, the channel's CC, sync MS; call 9990301 -> TG | All counted, call shown and ended by the terminator |
| R2 private | voice --private --dst <radio ID> |
Private call from 9990301 | Shown; not shown when sent to another ID |
| R3 late entry | voice --late 8 --superframes 5 (no header, first 8 bursts dropped) |
Call acquired from the embedded LC | Right caller (not a stale LC) within ~1 s; no call started by a lone burst |
| R4 back to back | voice --superframes 2 --calls 3 --gap-ms 60 |
Three calls, callers alternate | None merged or lost |
| R5 no terminator | voice --superframes 2 --terminators 0 |
Call ends by time-out | Ends 0.3-0.8 s after the last burst; slot ticks keep counting |
| R6 wrong CC | voice --burst-cc N (N not the radio's color code) |
No call, no audio | Never counted as voice for us |
| R7 CSBK | csbk --count 4 --opcode 1F --dst <radio ID> |
+5 CSBKs; with the data service, a call alert | Counted with good CRC |
| R8 data | data --dst <radio ID> --octets 40 |
2 CSBK + 1 data header + 4 rate 1/2 blocks | Counted with good CRC |
| R9 confirmed data | data --confirmed |
Data received | Data counted |
| R10 BS sync | voice --family bs |
Sync family BS | BS reported (no CACH: not a repeater outbound) |
| R11 TS1/TS2 sync | voice --family ts1, then ts2 |
Sync family TS1, then TS2 | Both reported |
| R12 long call | voice --superframes 50 (18 s) |
One call, +300 voice bursts | No restart, no SYNC_LOST, CRC errors unchanged |
| R13 emergency / privacy | voice --emergency; voice --service-options 40 --pi |
Emergency shown; PI call not played without a key | As stated |
| R14 talker alias | voice --superframes 8 --talker-alias 'RadioFoundry bench modem' |
Alias shown | Within ~2 s; the call LC stays right |
4. Voice quality
tests/hil/test_dmr_audio_smoke.py runs in every bench pass (tests/hil/README.md, Default bench pass). RX: the
bench's recording to the call the radio's channel listens to. TX: the voice layer's test signal (RADIO op 33) in place
of the mic, and the bench's recording played back to the radio.
| Direction | Pass |
|---|---|
| RX | voice.rx_peak >= 1000, frames not one frame repeated (voice.rx_repeats) |
| TX | Distinct, non-silent frames on air, and the played-back recording decodes to audio on the radio |
Missing prerequisites with the radio and bench present fail; they don't skip.
Decoding AMBE to audio on the test host needs an AMBE+2 vocoder, and this project ships none (README,
docs/CLEANROOM.md). Options: a DVSI hardware vocoder on USB (ThumbDV / DV3000 class, AMBE-3000 chip), or an open
decoder the tester installs locally, never vendored here. Independent of any vocoder, the radio's own decoder judges a
call (voice.rx_peak, the radio's own over played back to it).
5. Hotspot and SFR
test_hotspot covers the MMDVM protocol and test_hotspot_sfr the repeat on air. By hand: mmdvm_hotspot.py --sfr
turns SFR on and logs what the radio sends up, and mmdvm_hotspot.py --debug sends our 0xD5 experiment switches and
prints the SFR counters from GET_STATUS.