From 8c343137201c0b6cb70fc45eb04065bda250618c Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Sun, 13 Jul 2025 11:32:15 -0400 Subject: [PATCH] NXDN: #299 Additional check for LICH "offbits" that should all be 1's as sync condition; Add 7-bit Parity Check for known DCR Lich ("RICH") Codes; Make Tweaks to Help Incorporate Lich Parity and Offbits into NXDN Sync Determination; --- src/nxdn_frame.c | 77 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/src/nxdn_frame.c b/src/nxdn_frame.c index 19daee4..6bc888a 100644 --- a/src/nxdn_frame.c +++ b/src/nxdn_frame.c @@ -25,7 +25,8 @@ #include "dsd.h" #include "nxdn_const.h" -#include +// #define NXDN_DEBUG_LICH //print LICH debug info on err on payload == 1 +#define NXDN_LICH_OFFBITS //use the offbits to help determine sync status (disable if bad signal / bad sample) void nxdn_frame (dsd_opts * opts, dsd_state * state) { @@ -94,13 +95,49 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) lich = 0; for (int i=0; i<8; i++) lich |= (lich_dibits[i] >> 1) << (7-i); - lich_parity_received = lich & 1; - lich_parity_computed = ((lich >> 7) + (lich >> 6) + (lich >> 5) + (lich >> 4)) & 1; - lich = lich >> 1; - if (lich_parity_received != lich_parity_computed && lich != 0x4A) //may disable this if it causes issues + //debug lich as a 16-bit value (with encoding "dividing") + uint8_t lich_bits[16]; memset(lich_bits, 0, sizeof(lich_bits)); + for (int i=0; i<8; i++) { - if (opts->payload == 1) fprintf(stderr, " Lich Parity Error %02X\n", lich); - state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly + lich_bits[(i*2)+0] = (lich_dibits[i] >> 1) & 1; + lich_bits[(i*2)+1] = (lich_dibits[i] >> 0) & 1; + } + uint16_t lich_bits_hex = (uint16_t)ConvertBitIntoBytes(lich_bits, 16); + UNUSED(lich_bits_hex); + + //debug look at the "off bits" of the encoded lich, should be all 1's (8) + //disble this code if sync issues arise, this may not be ideal of marginal signal + uint8_t lich_off_hex = 0; + for (int i=0; i<8; i++) + lich_off_hex += lich_bits[(i*2)+1]; + #ifdef NXDN_LICH_OFFBITS + if (lich_off_hex < 7) //allow up to 1 bit error + { + #ifdef NXDN_DEBUG_LICH + if (opts->payload == 1) + fprintf(stderr, " Lich Off Bit Fill Error: %d / 8; \n", lich_off_hex); + #endif + // state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly + goto END; + } + #endif + + uint8_t lich_full = lich; + lich_parity_received = lich & 1; + lich_parity_computed = ((lich_full >> 7) + (lich_full >> 6) + (lich_full >> 5) + (lich_full >> 4)) & 1; + lich = lich_full >> 1; + + //special cases on DCR where parity is computed over 7 bits, and not 4 bits + if (lich == 0x4A || lich == 0x48 || lich == 0x46) + lich_parity_computed = ((lich_full >> 7) + (lich_full >> 6) + (lich_full >> 5) + (lich_full >> 4) + (lich_full >> 3) + (lich_full >> 2) + (lich_full >> 1)) & 1; + + if (lich_parity_received != lich_parity_computed) + { + #ifdef NXDN_DEBUG_LICH + if (opts->payload == 1) + fprintf(stderr, " Lich Parity Error %02X / %04X\n", lich_full, lich_bits_hex); + #endif + // state->lastsynctype = -1; goto END; } @@ -114,8 +151,11 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) //all inbound lich are even value (lsb is set to 0 for inbound direction) if (lich % 2 == 0 && opts->p25_trunk == 1) { - if (opts->payload == 1) fprintf(stderr, " Simplex/Inbound NXDN lich on trunking system - type 0x%02X\n", lich); - state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly + #ifdef NXDN_DEBUG_LICH + if (opts->payload == 1) + fprintf(stderr, " Simplex/Inbound NXDN lich on trunking system - type 0x%02X\n", lich); + #endif + // state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly goto END; } @@ -243,11 +283,14 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) break; default: - if (opts->payload == 1) fprintf(stderr, " false sync or unsupported NXDN lich type 0x%02X\n", lich); + #ifdef NXDN_DEBUG_LICH + if (opts->payload == 1) + fprintf(stderr, " false sync or unsupported NXDN lich type L: %02X / LH: %04X\n", lich, lich_bits_hex); + #endif //reset the sacch field, we probably got a false sync and need to wipe or give a bad crc memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment)); memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc)); - state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly + // state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly voice = 0; goto END; break; @@ -264,8 +307,10 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) { printFrameSync (opts, state, "IDAS D ", 0, "-"); } + #ifdef NXDN_DEBUG_LICH if (opts->payload == 1) - fprintf (stderr, "L: %02X; ", lich); + fprintf (stderr, "L: %02X / LH: %04X; ", lich, lich_bits_hex); + #endif } else if (sacch2) { @@ -273,8 +318,10 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) { printFrameSync (opts, state, "JPN DCR", 0, "-"); } + #ifdef NXDN_DEBUG_LICH if (opts->payload == 1) - fprintf (stderr, "L: %02X; ", lich); + fprintf (stderr, "L: %02X / LH: %04X; ", lich, lich_bits_hex); + #endif } else if (voice || facch || sacch || facch2 || udch || cac) { @@ -283,8 +330,10 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) printFrameSync (opts, state, "NXDN48 ", 0, "-"); } else printFrameSync (opts, state, "NXDN96 ", 0, "-"); + #ifdef NXDN_DEBUG_LICH if (opts->payload == 1) - fprintf (stderr, "L: %02X; ", lich);; + fprintf (stderr, "L: %02X / LH: %04X; ", lich, lich_bits_hex); + #endif } //now that we have a good LICH, we can collect all of our dibits