Skip to content

Commit 4d81c05

Browse files
committed
protocol(p25): honor explicit FDMA IDENs in frequency mapping
1 parent e4c309f commit 4d81c05

3 files changed

Lines changed: 41 additions & 7 deletions

File tree

src/protocol/p25/p25_frequency.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ process_channel_to_freq(dsd_opts* opts, dsd_state* state, int channel) {
6666
int type = state->p25_chan_type[iden] & 0xF;
6767
// OP25-derived slots-per-carrier by channel type
6868
static const int slots_per_carrier[16] = {1, 1, 1, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
69-
// Derive division only when TDMA iden is known. This matches OP25, which
70-
// only divides the channel by tdma when an IDEN_UP_TDMA has populated the
71-
// table. Without that knowledge, treat channel as FDMA (denom=1).
69+
// Derive division only when TDMA iden is known. Explicit IDEN hints take
70+
// precedence over the system-level TDMA fallback so mixed P1/P2 systems do
71+
// not halve explicitly FDMA channel numbers.
7272
int denom = 1;
73-
if ((state->p25_chan_tdma[iden] & 0x1) != 0) {
73+
int explicit_hint = state->p25_chan_tdma_explicit[iden];
74+
int use_tdma_denom = (explicit_hint == 2 || (explicit_hint == 0 && (state->p25_chan_tdma[iden] & 0x1) != 0));
75+
if (use_tdma_denom) {
7476
if (type < 0 || type > 15) {
7577
fprintf(stderr, "\n P25 FREQ: unknown iden type %d (iden %d)", type, iden);
7678
return 0;
@@ -80,7 +82,7 @@ process_channel_to_freq(dsd_opts* opts, dsd_state* state, int channel) {
8082
fprintf(stderr, "\n P25 FREQ: invalid slots/carrier for type %d", type);
8183
return 0;
8284
}
83-
} else {
85+
} else if (explicit_hint != 1) {
8486
// Fallback: if the system is known to carry Phase 2 (TDMA) voice but
8587
// we have not yet seen an IDEN_UP_TDMA for this iden, assume 2
8688
// slots/carrier. This avoids early mis-tunes where a TDMA grant
@@ -150,11 +152,13 @@ p25_format_chan_suffix(const dsd_state* state, uint16_t chan, int slot_hint, cha
150152
int type = state->p25_chan_type[iden] & 0xF;
151153
static const int slots_per_carrier[16] = {1, 1, 1, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
152154
int denom = 1;
153-
if ((state->p25_chan_tdma[iden] & 0x1) != 0) {
155+
int explicit_hint = state->p25_chan_tdma_explicit[iden];
156+
int use_tdma_denom = (explicit_hint == 2 || (explicit_hint == 0 && (state->p25_chan_tdma[iden] & 0x1) != 0));
157+
if (use_tdma_denom) {
154158
if (type >= 0 && type <= 15) {
155159
denom = slots_per_carrier[type];
156160
}
157-
} else if (state->p25_sys_is_tdma == 1) {
161+
} else if (explicit_hint != 1 && state->p25_sys_is_tdma == 1) {
158162
// Conservative fallback when TDMA IDEN not yet learned
159163
denom = 2;
160164
}

tests/protocol/p25/test_p25_format_chan_suffix.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,18 @@ main(void) {
6666
p25_format_chan_suffix(&st3, ch, -1, buf, sizeof buf);
6767
rc |= expect_eq_str("fallback denom=2", buf, " (FDMA 0003 S2)");
6868

69+
// Case 4: Explicit FDMA must not show a TDMA suffix even if the system has
70+
// Phase 2 voice and the legacy TDMA bit is stale.
71+
static dsd_state st4;
72+
memset(&st4, 0, sizeof st4);
73+
st4.p25_sys_is_tdma = 1;
74+
st4.p25_chan_tdma[id] = 1;
75+
st4.p25_chan_tdma_explicit[id] = 1;
76+
st4.p25_chan_type[id] = 3;
77+
ch = (uint16_t)((id << 12) | 0x000A);
78+
memset(buf, 0, sizeof buf);
79+
p25_format_chan_suffix(&st4, ch, -1, buf, sizeof buf);
80+
rc |= expect_eq_str("explicit fdma suffix empty", buf, "");
81+
6982
return rc;
7083
}

tests/protocol/p25/test_p25_freq_fallback_tdma.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,22 @@ main(void) {
8181
long want = 851000000 + 3 * 100 * 125; // 851.0375 MHz
8282
rc |= expect_eq_long("fallback denom2", f, want);
8383

84+
// Explicit FDMA must override both the TDMA system hint and any stale TDMA
85+
// bit for this IDEN. Otherwise mixed P1/P2 systems can tune halfway between
86+
// real FDMA channels.
87+
static dsd_state st_fdma;
88+
memset(&st_fdma, 0, sizeof st_fdma);
89+
st_fdma.p25_sys_is_tdma = 1;
90+
st_fdma.p25_chan_tdma[id] = 1;
91+
st_fdma.p25_chan_tdma_explicit[id] = 1;
92+
st_fdma.p25_chan_type[id] = 3;
93+
st_fdma.p25_base_freq[id] = 851000000 / 5;
94+
st_fdma.p25_chan_spac[id] = 100;
95+
96+
chan = (id << 12) | 0x000A;
97+
f = process_channel_to_freq(&opts, &st_fdma, chan);
98+
want = 851000000 + 10 * 100 * 125; // FDMA denom=1
99+
rc |= expect_eq_long("explicit fdma no fallback", f, want);
100+
84101
return rc;
85102
}

0 commit comments

Comments
 (0)