mirror of
https://github.com/n0mjs710/ipsc2hbpc.git
synced 2026-11-08 04:18:24 +00:00
IPSC->HBP: send MMDVMHost silence for AMBE frames the repeater flags bad
The repeater sets a per-AMBE-frame "bad voice" flag when it could not correct the frame on RF receive (confirmed OTA on a weak signal). We re-encoded those frames with fresh, valid FEC, so they reached HBP looking good. MMDVMHost replaces uncorrectable frames with silence, so substitute its DMR_SILENCE_DATA frame for each flagged frame. No FEC repair is added in the HBP->IPSC direction: MMDVMHost already corrects every RF frame or replaces it with silence before it reaches the network, so HBP never carries damaged frames. Tests: new bad-voice check; synthetic parity inputs had the flag bits set at random, cleared them (the reference ignores those bits, output unchanged). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
667c1a559b
commit
ec83237268
4 files changed
+70
-13
No files matched your search
@@ -57,6 +57,13 @@
|
||||
#define GV_BURST_TYPE_OFF 30
|
||||
#define GV_PAYLOAD_OFF 31
|
||||
#define GV_MIN_LEN 31
|
||||
#define GV_AMBE_OFF 33 /* 19-byte AMBE field: three 49-bit frames at bits 0, 50, 100 */
|
||||
/* Repeater-set "bad voice" flags, one per AMBE frame (uncorrectable on RF receive):
|
||||
* frame 1 = data[32] bit 0; frames 2/3 = bits 49/99 of the AMBE field. */
|
||||
#define GV_BAD1_OFF 32
|
||||
#define GV_BAD1_MSK 0x01
|
||||
#define GV_BAD2_BIT 49
|
||||
#define GV_BAD3_BIT 99
|
||||
#define GV_BE_FLAG 0x16 /* data[32] value identifying burst E (carries reassembled LC repeat) */
|
||||
#define GV_BE_LC_FLCO_OFF 56 /* FLCO of the reassembled LC repeat carried only on burst E */
|
||||
#define FLCO_GROUP 0x00 /* Group Voice Channel User (real call identity); 0x04-0x08 = TA/GPS */
|
||||
|
||||
+13
-4
@@ -102,6 +102,10 @@ static void rand4(uint8_t out[4])
|
||||
if (getrandom(out, 4, 0) != 4) { out[0]=rand(); out[1]=rand(); out[2]=rand(); out[3]=rand(); }
|
||||
}
|
||||
|
||||
/* 72-bit AMBE silence frame from MMDVMHost DMR_SILENCE_DATA; replaces frames the
|
||||
* repeater flagged bad (IPSC->HBP). */
|
||||
static const uint8_t AMBE_SILENCE_MMDVM[9] = {0xB9,0xE8,0x81,0x52,0x61,0x73,0x00,0x2A,0x6B};
|
||||
|
||||
/* precompute 19-byte IPSC AMBE payload of three silence frames */
|
||||
static void make_ambe_silence(uint8_t out[19])
|
||||
{
|
||||
@@ -424,11 +428,16 @@ void translator_ipsc_voice_received(translator *tr, const uint8_t *data, int len
|
||||
* bytes on a TA superframe); all AMBE is forwarded under the locked identity. */
|
||||
if (len < 52) { LOGW(LOGN, "SLOT_VOICE too short for AMBE: %d bytes", len); return; }
|
||||
|
||||
dmr_bit raw[152]; dmr_bytes_to_bits(data + 33, 19, raw);
|
||||
dmr_bit raw[152]; dmr_bytes_to_bits(data + GV_AMBE_OFF, 19, raw);
|
||||
dmr_bit a1_72[72], a2_72[72], a3_72[72];
|
||||
dmr_ambe_49_to_72(raw + 0, a1_72);
|
||||
dmr_ambe_49_to_72(raw + 50, a2_72);
|
||||
dmr_ambe_49_to_72(raw + 100, a3_72);
|
||||
dmr_bit *a72[3] = {a1_72, a2_72, a3_72};
|
||||
int bad[3] = {data[GV_BAD1_OFF] & GV_BAD1_MSK, raw[GV_BAD2_BIT], raw[GV_BAD3_BIT]};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (bad[i]) dmr_bytes_to_bits(AMBE_SILENCE_MMDVM, 9, a72[i]);
|
||||
else dmr_ambe_49_to_72(raw + 50 * i, a72[i]);
|
||||
}
|
||||
if (bad[0] || bad[1] || bad[2])
|
||||
LOGD(LOGN, "IPSC bad AMBE ts=%d flags=%d%d%d — sent as silence", ts, bad[0], bad[1], bad[2]);
|
||||
int pos = tr->out_frame_pos[ts] % 6;
|
||||
dmr_bit embed[48]; build_embed(tr, ts, pos, embed);
|
||||
dmr_bit fb[264]; int at=0;
|
||||
|
||||
+8
-8
@@ -1,16 +1,16 @@
|
||||
1 1 800004c317052f9b8100005b02000043e200000000000000100000000000010000000000000000000000000000000000000000000000
|
||||
1 10 800004c317052f9b8100005b02000043e2000000000000001000000000000a000000070e151c232a31383f464d545b626970777e0000
|
||||
1 10 800004c317052f9b8100005b02000043e2000000000000001000000000000a0000858c939aa1a8afb6bdc4cbd2d9e0e7eef5fc030000
|
||||
1 10 800004c317052f9b8100005b02000043e2000000000000001000000000000a00000a11181f262d343b424950575e656c737a81880000
|
||||
1 10 800004c317052f9b8100005b02000043e2000000000000001000000000000a000000070e151c232a31383f464d445b626970777e0000
|
||||
1 10 800004c317052f9b8100005b02000043e2000000000000001000000000000a0000858c939aa1a8afb6bdc4cbd2c9e0e7eef5fc030000
|
||||
1 10 800004c317052f9b8100005b02000043e2000000000000001000000000000a00000a11181f262d343b424950574e656c737a81880000
|
||||
1 10 800004c317052f9b8100005b02000043e2000000000000001000000000000a00008f969da4abb2b9c0c7ced5dce3eaf1f8ff060d0000
|
||||
1 10 800004c317052f9b8100005b02000043e2000000000000001000000000000a0016141b222930373e454c535a61686f767d848b920000
|
||||
1 10 800004c317052f9b8100005b02000043e2000000000000001000000000000a000099a0a7aeb5bcc3cad1d8dfe6edf4fb020910170000
|
||||
1 10 800004c317052f9b8100005b02000043e2000000000000001000000000000a000099a0a7aeb5bc83cad1d8dfe6edf4fb020910170000
|
||||
1 2 800004c317052f9b8100005b02000043e200000000000000100000000000020000000000000000000000000000000000000000000000
|
||||
1 1 800004c317102f9be500000902000043e200000000000000100000000000010000000000000000000000000000000000000000000000
|
||||
1 10 800004c317112f9be500000902000043e2000000000000001000000000000a000000050a0f14191e23282d32373c41464b50555a0000
|
||||
1 10 800004c317112f9be500000902000043e2000000000000001000000000000a000000050a0f14191e23282d32372c41464b50555a0000
|
||||
1 10 800004c317112f9be500000902000043e2000000000000001000000000000a000073787d82878c91969ba0a5aaafb4b9bec3c8cd0000
|
||||
1 10 800004c317122f9be500000902000043e2000000000000001000000000000a0000e6ebf0f5faff04090e13181d22272c31363b400000
|
||||
1 10 800004c317122f9be500000902000043e2000000000000001000000000000a0000595e63686d72777c81868b90959a9fa4a9aeb30000
|
||||
1 10 800004c317132f9be500000902000043e2000000000000001000000000000a0016ccd1d6dbe0e5eaeff4f9fe03080d12171c21260000
|
||||
1 10 800004c317132f9be500000902000043e2000000000000001000000000000a00003f44494e53585d62676c71767b80858a8f94990000
|
||||
1 10 800004c317122f9be500000902000043e2000000000000001000000000000a0000595e63686d72377c81868b90859a9fa4a9aeb30000
|
||||
1 10 800004c317132f9be500000902000043e2000000000000001000000000000a0016ccd1d6dbe0e5aaeff4f9fe03080d12171c21260000
|
||||
1 10 800004c317132f9be500000902000043e2000000000000001000000000000a00003f44494e53581d62676c71766b80858a8f94990000
|
||||
1 2 800004c317132f9be500000902000043e200000000000000100000000000020000000000000000000000000000000000000000000000
|
||||
+42
-1
@@ -8,6 +8,7 @@
|
||||
#include "../src/translate.h"
|
||||
#include "../src/config.h"
|
||||
#include "../src/eventloop.h"
|
||||
#include "../src/dmr/dmr.h"
|
||||
|
||||
/* ---- captured DMRD output ---- */
|
||||
#define MAXCAP 64
|
||||
@@ -114,7 +115,47 @@ int main(void)
|
||||
}
|
||||
if (fi) fclose(fi);
|
||||
if (fr) fclose(fr);
|
||||
translator_free(tr);
|
||||
|
||||
/* ---- bad-voice flags (IPSC->HBP): flagged AMBE frames become MMDVMHost silence ---- */
|
||||
static const uint8_t SIL[9] = {0xB9,0xE8,0x81,0x52,0x61,0x73,0x00,0x2A,0x6B};
|
||||
static const int want[2][3] = {{1,1,1}, {0,1,0}}; /* per voice frame: flagged? */
|
||||
int bad_fails = 0;
|
||||
tr = translator_new(&cfg, loop);
|
||||
translator_set_protocols(tr, (struct ipsc *)1, (struct hbp *)1);
|
||||
ncap = 0;
|
||||
fi = fopen("tests/parity_in.txt", "r");
|
||||
for (int k = 0; k < 3 && fi && fgets(line, sizeof line, fi); k++) {
|
||||
int ts, bt; char hex[400];
|
||||
if (sscanf(line, "%d %d %399s", &ts, &bt, hex) != 3) continue;
|
||||
uint8_t raw[400]; int n = unhex(hex, raw);
|
||||
if (k >= 1) {
|
||||
const int *w = want[k - 1];
|
||||
if (w[0]) raw[32] |= 0x01;
|
||||
if (w[1]) raw[33 + 49 / 8] |= (uint8_t)(0x80 >> (49 % 8));
|
||||
if (w[2]) raw[33 + 99 / 8] |= (uint8_t)(0x80 >> (99 % 8));
|
||||
}
|
||||
translator_ipsc_voice_received(tr, raw, n, ts, bt);
|
||||
}
|
||||
if (fi) fclose(fi);
|
||||
if (ncap != 3) { fprintf(stderr, "FAIL bad-voice: expected 3 DMRD, got %d\n", ncap); bad_fails++; }
|
||||
for (int v = 0; v < 2 && v + 1 < ncap; v++) {
|
||||
dmr_bit b[264]; dmr_bytes_to_bits(cap[v + 1] + 20, 33, b);
|
||||
dmr_bit f[3][72];
|
||||
memcpy(f[0], b, 72);
|
||||
memcpy(f[1], b + 72, 36); memcpy(f[1] + 36, b + 156, 36);
|
||||
memcpy(f[2], b + 192, 72);
|
||||
dmr_bit s[72]; dmr_bytes_to_bits(SIL, 9, s);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int is_sil = memcmp(f[i], s, sizeof s) == 0;
|
||||
if (is_sil != want[v][i]) {
|
||||
fprintf(stderr, "FAIL bad-voice: voice %d frame %d silence=%d, want %d\n", v, i + 1, is_sil, want[v][i]);
|
||||
bad_fails++;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("Bad-voice flags (IPSC->HBP): %d failures\n", bad_fails);
|
||||
|
||||
translator_free(tr); ev_free(loop);
|
||||
return (fails || in_fails) ? 1 : 0;
|
||||
return (fails || in_fails || bad_fails) ? 1 : 0;
|
||||
}
|
||||
Reference in new issue
Block a user