Field Guide · term

Also known as: DMO, direct mode operation, TETRA direct mode

TETRA DMO (Direct Mode Operation) is TETRA’s infrastructure-less peer-to-peer mode: two radios talk directly with no base station or control channel between them.12 A transmitting station sends a Direct Mode Synchronisation Burst (DSB) to let the other radios acquire, then a train of Direct Mode Normal Bursts (DNB) carrying the call. Because there is no trunking layer, the trunked-mode ingestion path — hunt a control channel, follow grants — does not apply; a DMO receiver instead camps a direct-mode channel, detects the DSB, and follows the burst train.

DSB (acquire) freq-corr SCH/S120 bits sync tr BKN2 216 DNB (call) × N BKN1 216 norm tr BKN2 216 BKN1 … same π/4-DQPSK, training sequences and scrambler as TMO — only field layout differs
A DMO transmission opens with a DSB (frequency correction, a 120-bit SCH/S, sync training sequence and a 216-bit block) then continues as a train of DNBs, each two 216-bit blocks around the normal training sequence.

A reused physical layer

The DMO air interface reuses the trunked-mode (TMO) physical layer wholesale: identical π/4-DQPSK at 18 ksym/s, 25 kHz channels, 255-symbol (14.167 ms) TDMA timeslots, the four-slot frame / 18-frame multiframe, the same normal and synchronisation training sequences, and the same 32-tap scrambler polynomial (colour code 0 for the SCH/S and SCH/H of a DSB, exactly as TMO scrambles its BSCH). So the receiver, sync-word correlation and channel-coding machinery are shared between the two modes — only the burst field layout differs, which is the one thing DMO needs to add.

The channel coding is likewise not a new code family: DMO’s SCH/S, SCH/H, SCH/F and TCH/S run the same per-channel chains as their TMO logical-channel counterparts, so the existing decoders handle them once the blocks are sliced, de-rotated and descrambled. The only DMO-specific coding rules are the colour-0 seed for the DSB signalling blocks and the field boundaries below.

The two burst kinds

Burst Layout (relative to training-sequence lead dibit L)
DSB (sync) 40-dibit frequency correction · 60-dibit SCH/S (120 type-5 bits, BKN1) · 19-dibit sync training sequence · 108-dibit BKN2 (216 bits)
DNB (normal) 108-dibit BKN1 (216 bits) · 11-dibit normal training sequence · 108-dibit BKN2 (216 bits)

The DSB is the acquisition burst: its frequency-correction field lets a cold receiver lock, and its SCH/S (the 120-bit block ahead of the sync training sequence) carries the synchronisation PDU — the DM colour code and the master’s slot/frame numbering used to anchor the DNB traffic that follows. The SCH/S decodes exactly like a TMO BSCH (colour 0). The DNB is the payload burst: its two 216-bit blocks carry either TCH/S speech (decoded to the two 137-bit ACELP frames by the shared TCH/S chain) or SCH/F short-data signalling — a receiver tells them apart by which decode’s CRC passes. The block boundaries relative to the training-sequence lead dibit are not the same as TMO’s NDB, so DMO needs its own slicer.

Configuring a DMO system

A DMO channel is decoded by setting a system’s protocol: tetra-dmo (aliases dmo / tetra_dmo) and pointing control_channels at the direct-mode frequency — the daemon camps that frequency rather than hunting, locks on the first DSB, auto-recovers the DM colour code, and records the DNB voice train. An optional tetra_colour_code overrides the auto-recovery when the traffic colour is known.

trunking:
  systems:
    - name: DMO
      protocol: tetra-dmo
      control_channels: [438900000]
      # tetra_colour_code: 3   # optional; 0/omitted = auto-recover the DM colour

Scope and honesty

GopherTrunk decodes DMO end to end in the daemon: newTETRADMOPipeline (internal/scanner/ccdecoder/pipelines_dmo.go) locks on the DSB SCH/S, recovers the DM colour code, and grants; a same-carrier voice chain (runTETRADMOVoiceChain, internal/voice/composer/tetra_dmo_voice.go) decodes the DNB TCH/S speech — both hard- and soft-decision (the same ~2× yield lever the TMO traffic path gets) — through the clean-room ACELP vocoder to a recording. The DM call-control protocol that rides in SCH/S / SCH/F — source and destination SSI, group, call type — is EN 300 396-3, a separate specification, and is not yet decoded, so a DMO call is recorded without a talkgroup/party identity (it files under group 0). And while the decode chain is validated offline (synthetic round-trips + TestTETRADMOReplay on captures) and with a synthetic full-daemon lock test, it has not yet been A/B’d against a real on-air DMO capture through the full daemon — the standing lesson (#764/#771) is that synthetic round-trips can pass while on-air decode fails, so treat DMO voice as functional-but-unverified-on-air until that A/B lands.

Relevance to SDR

internal/radio/tetra/dmo.go defines the DMBurstKind (DSB/DNB), the burst geometry, and the ExtractDMBursts / ExtractDMBurstsSoft slicers that correlate the training sequences under all four residual π/4-DQPSK rotations; dmo_stream.go wraps them in a bounded sliding-window DMStreamExtractor for the live daemon.

A DNB detection on its own is not evidence of traffic, and treating it as such is a trap worth understanding. The DNB training sequence is only 11 dibits and is matched at tolerance 2 under eight filters (two sequences × four rotations), so the number of sequences that match by chance is Σ_{k≤2} C(11,k)·3^k = 529 out of 4^11, giving ≈1.0 × 10⁻³ per dibit position across the eight — about 18 false DNBs per second at the 18 kdibit/s symbol rate. Since a DMO channel is silent between transmissions, that is what the detector reports almost all of the time. dmo_grid.go’s DMSlotGrid is the discriminator: a real transmission comes from one radio on one clock, so every one of its bursts lands on the 255-dibit timeslot grid and all its DNB leads share a single residue mod 255, whereas false alarms are uniform across all 255. The residue is learned from the stream rather than derived from a hardcoded burst offset, so a wrong constant cannot silently stop DMO from granting; the latch is dropped when the burst train ends so the next transmission re-votes. The 19-dibit DSB detector needs no such gate — its false-alarm rate is ~0.007/s and it must still pass the SCH/S CRC.

dmo_decode.go maps the sliced blocks onto the shared decoders — DecodeDMSCHS (via the BSCH chain), DecodeDMSCHH (via SCH/HD), DecodeDMSCHF, and DMBurstTCHSpeech / DMBurstTCHSpeechSoft (via the TCH/S chain) — de-rotating and descrambling with the DM colour code (recovered by RecoverDMColourCode) before each decode.

Sources

  1. Terrestrial Trunked Radio — Wikipedia, on the TETRA standard and its direct mode. 

  2. Direct mode operation — Wikipedia, on infrastructure-less direct radio-to-radio operation. 

See also