Objects had no header dependencies, so changing a shared header (here
config.h gaining a field) left stale objects linked against the old
struct layout: ipsc.o read the mode and master address at the wrong
offsets and the bridge came up as an IPSC peer. Generate .d files with
-MMD -MP and include them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IPSC->HBP: PVT_VOICE (0x81) was dropped. It uses the GROUP_VOICE layout,
so it now goes through the same path: DMRD gets the private-call flag
and the LC is FLCO 3. Late entry anchors on a burst E carrying FLCO 3.
HBP->IPSC: the HBP header LC was already copied verbatim, so radios saw
private calls, but the packets went out as GROUP_VOICE. The opcode now
follows the LC's FLCO, and the fallback LCs (late entry, orphan
terminator) honour the HBP private-call flag.
No on/off setting: the translator carries private calls; the network
server decides who may make them. Confirmed private calls are not
supported.
Tests replay a PVT_VOICE call captured from a MOTOTRBO repeater and an
HBP private call captured from HBlink3, full and late entry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Feature-for-feature, config-for-config port of the Python ipsc2hbp IPSC↔HBP
translator to dependency-free C11 (links only libc).
- src/dmr/: self-contained DMR DSP/FEC library (BPTC(196,96), embedded LC,
AMBE 49<->72, RS(12,9), Hamming, Golay), validated bit-for-bit against
dmr_utils3 via golden vectors.
- src/: config (in-tree TOML parser), logging, poll() event loop, UDP,
SHA-1/SHA-256/HMAC, IPSC master/peer protocol, HBP client, call translator.
- Single-threaded event loop mirrors the original asyncio design.
- tests/: DSP self-test + byte-for-byte translator parity vs the Python
reference (IPSC->HBP DMRD and HBP->IPSC GROUP_VOICE).
make && make test both pass; integration-tested against the fake peer/master.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>