From 53a256bee869c515c7c2132f38cbce5d0843ba85 Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Tue, 3 Feb 2026 02:57:02 -0500 Subject: [PATCH] NXDN: Rework code for the FACCH1 duplicate message check post NXDN Viterbi overhaul; Use static array to hold facch1 message after recovery and compare when LICH type calls for 2 individual FACCH1 messages in an NXDN frame; Zero out facch1_storage on SACCH or SCCH decode (happens first) and after potential comparison time in FACCH1 decode; --- include/dsd.h | 2 +- src/nxdn_deperm.c | 27 +++++++++++++++++++++++++-- src/nxdn_frame.c | 14 +++++++++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/include/dsd.h b/include/dsd.h index c846506..ca414cc 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -1272,7 +1272,7 @@ void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t * dbuf); //All-in-One NXDN Soft Decision Viterbi Function based on libM17 uint32_t nxdn_soft_decision_viterbi(uint8_t * bits, const uint16_t * interleave, uint8_t * puncture, int d_len, int p_len, int num_bytes, int offset, uint8_t * viterbi_bits, uint8_t * viterbi_bytes); //NXDN Conventional and Type-C -void nxdn_facch1(dsd_opts * opts, dsd_state * state, uint8_t * bits); +void nxdn_facch1(dsd_opts * opts, dsd_state * state, uint8_t * bits, uint8_t frame); void nxdn_sacch(dsd_opts * opts, dsd_state * state, uint8_t * bits); void nxdn_cac(dsd_opts * opts, dsd_state * state, uint8_t * bits); void nxdn_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t * bits, uint8_t type); diff --git a/src/nxdn_deperm.c b/src/nxdn_deperm.c index 030e70a..b2ffb9b 100644 --- a/src/nxdn_deperm.c +++ b/src/nxdn_deperm.c @@ -339,10 +339,16 @@ uint8_t facch1_puncture[4] = {1,0,1,1}; uint8_t facch2_puncture[14] = {1,1,1,0,1,1,1,1,1,1,1,0,1,1}; uint8_t cac_puncture[14] = {1,1,1,0,1,1,1,1,1,1,1,0,1,1}; +//facch1 storage, for duplicate message check +static uint8_t facch1_storage[12] = {0}; + //sacch soft decision making void nxdn_sacch(dsd_opts * opts, dsd_state * state, uint8_t * bits) { + //erase facch1 storage (facch1 only happens along with a sacch/scch frame) + memset(facch1_storage, 0, sizeof(facch1_storage)); + uint8_t crc = 1; //value computed by crc6 on payload uint8_t check = 0; //value pulled from last 6 bits int sf = 0; @@ -575,7 +581,7 @@ void nxdn_sacch(dsd_opts * opts, dsd_state * state, uint8_t * bits) } -void nxdn_facch1(dsd_opts * opts, dsd_state * state, uint8_t * bits) +void nxdn_facch1(dsd_opts * opts, dsd_state * state, uint8_t * bits, uint8_t frame) { uint16_t crc = 0; @@ -606,8 +612,22 @@ void nxdn_facch1(dsd_opts * opts, dsd_state * state, uint8_t * bits) check = check | viterbi_bits[80+i]; } + //duplicate frame check if frame == 2 + uint8_t duplicate = 0; + if (frame == 2) + { + if (memcmp(facch1_storage, viterbi_bytes, 12) == 0) + duplicate = 1; + } - if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, viterbi_bits); + //erase facch1 storage + memset(facch1_storage, 0, sizeof(facch1_storage)); + + //store facch1 message viterbi bytes if frame == 1 + if (frame == 1) + memcpy(facch1_storage, viterbi_bytes, sizeof(facch1_storage)); + + if (crc == check && duplicate == 0) NXDN_Elements_Content_decode(opts, state, 1, viterbi_bits); // else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, viterbi_bits); if (opts->payload == 1) @@ -750,6 +770,9 @@ void nxdn_cac(dsd_opts * opts, dsd_state * state, uint8_t * bits) void idas_scch(dsd_opts * opts, dsd_state * state, uint8_t * bits, uint8_t direction) { + //erase facch1 storage (facch1 only happens along with a sacch/scch frame) + memset(facch1_storage, 0, sizeof(facch1_storage)); + fprintf (stderr, "%s", KYEL); fprintf (stderr, " SCCH"); diff --git a/src/nxdn_frame.c b/src/nxdn_frame.c index a24edb4..3466086 100644 --- a/src/nxdn_frame.c +++ b/src/nxdn_frame.c @@ -556,9 +556,17 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) if (sacch) nxdn_sacch(opts, state, sacch_bits); if (cac) nxdn_cac(opts, state, cac_bits); - //TODO: Redo duplicate facch check inside decoder? storage for facch message? - if (facch & 1) nxdn_facch1(opts, state, facch_bits_a); - if (facch & 2) nxdn_facch1(opts, state, facch_bits_b); + //Duplicate facch check inside decoder. store and compare for facch message, depending on passed frame value + if (facch == 3) + { + if (facch & 1) nxdn_facch1(opts, state, facch_bits_a, 1); + if (facch & 2) nxdn_facch1(opts, state, facch_bits_b, 2); + } + else //facch1 steals, or single facch only messages + { + if (facch & 1) nxdn_facch1(opts, state, facch_bits_a, 0); + if (facch & 2) nxdn_facch1(opts, state, facch_bits_b, 0); + } //Seperated UDCH user data from facch2 data if (udch) nxdn_facch2_udch(opts, state, facch2_bits, 0);