From 748bb5b1910188407a1004f2c607b536428701c9 Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Tue, 7 Oct 2025 06:13:19 -0400 Subject: [PATCH] Rewrite NXDN Dibit PN95 Code and allow custom seed value; #318 --- .../cygwin_bat/complete_usage_options.txt | 4 +- include/dsd.h | 3 +- src/dsd_main.c | 13 ++++- src/nxdn_deperm.c | 56 +++++++++++++------ src/nxdn_frame.c | 4 +- 5 files changed, 58 insertions(+), 22 deletions(-) diff --git a/examples/cygwin_bat/complete_usage_options.txt b/examples/cygwin_bat/complete_usage_options.txt index 8ff3818..1525892 100644 --- a/examples/cygwin_bat/complete_usage_options.txt +++ b/examples/cygwin_bat/complete_usage_options.txt @@ -1,4 +1,4 @@ -Build Version: AW 2025-182-g24c1dd9 +Build Version: AW 2025-197-gf3b89f1 MBElib Version: 1.3.4 CODEC2 Support Enabled @@ -137,6 +137,8 @@ Decoder options: Advanced Decoder options: -X Manually Set P2 Parameters (WACN, SYSID, CC/NAC) (-X BEE00ABC123) + -* Manually Set NXDN PN95 Dibit Scrambler Seed (1-511) + (-* 261) -D Manually Set TIII DMR Location Area n bit len (0-10)(10 max) (Value defaults to max n bit value for site model size) (Setting 0 will show full Site ID, no area/subarea) diff --git a/include/dsd.h b/include/dsd.h index e11c6f8..1038917 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -898,6 +898,7 @@ typedef struct uint8_t nxdn_sacch_frame_segcrc[4]; uint8_t nxdn_alias_block_number; char nxdn_alias_block_segment[4][4][8]; + uint16_t nxdn_pn95_seed; //site/srv/cch info char nxdn_location_category[14]; @@ -1281,7 +1282,7 @@ void ncursesClose (); //new NXDN Functions start here! void nxdn_frame (dsd_opts * opts, dsd_state * state); -void nxdn_descramble (uint8_t dibits[], int len); +void nxdn_pn95_dibit_scrambler(dsd_state * state, uint8_t * dibits, int len); //nxdn deinterleaving/depuncturing functions void nxdn_deperm_facch (dsd_opts * opts, dsd_state * state, uint8_t bits[144]); void nxdn_deperm_sacch (dsd_opts * opts, dsd_state * state, uint8_t bits[60]); diff --git a/src/dsd_main.c b/src/dsd_main.c index b64bcdb..d9fa776 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -1214,6 +1214,7 @@ memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment)); state->nxdn_alias_block_number = 0; memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment)); + state->nxdn_pn95_seed = 228; //default value //site/srv/cch info state->nxdn_location_site_code = 0; @@ -1526,6 +1527,8 @@ printf ("Advanced Decoder options:\n"); printf (" -X Manually Set P2 Parameters (WACN, SYSID, CC/NAC)\n"); printf (" (-X BEE00ABC123)\n"); + printf (" -* Manually Set NXDN PN95 Dibit Scrambler Seed (1-511)\n"); + printf (" (-* 261)\n"); printf (" -D Manually Set TIII DMR Location Area n bit len (0-10)(10 max)\n"); printf (" (Value defaults to max n bit value for site model size)\n"); printf (" (Setting 0 will show full Site ID, no area/subarea)\n"); @@ -1906,7 +1909,7 @@ exitflag = 0; - while ((c = getopt (argc, argv, "~yhaepPqs:t:v:z:i:o:d:c:g:n:w:B:C:R:f:m:u:x:A:S:M:G:D:L:V:U:YK:b:H:X:NQ:WrlZTF@:!:01:2:345:6:7:89:Ek:I:J:O")) != -1) + while ((c = getopt (argc, argv, "~yhaepPqs:t:v:z:i:o:d:c:g:n:w:B:C:R:f:m:u:x:A:S:M:G:D:L:V:U:YK:b:H:X:NQ:WrlZTF@:!:01:2:345:6:7:8*:9:Ek:I:J:O")) != -1) { switch (c) @@ -2217,7 +2220,15 @@ if (state.R > 0x7FFF) state.R = 0x7FFF; //disable keyloader in case user tries to use this and it at the same time state.keyloader = 0; + fprintf (stderr, "NXDN Scrambler Key set to: %05d;", state.R); break; + + case '*': + sscanf (optarg, "%hu", &state.nxdn_pn95_seed); + if (state.nxdn_pn95_seed > 0x1FF) state.nxdn_pn95_seed = 0x1FF; + else if (state.nxdn_pn95_seed == 0) state.nxdn_pn95_seed = 228; + fprintf (stderr, "NXDN PN9 Seed Value set to: %03d;", state.nxdn_pn95_seed); + break; case 'H': //new handling for 10/32/64 Char Key diff --git a/src/nxdn_deperm.c b/src/nxdn_deperm.c index baf0f0a..f0fba3d 100644 --- a/src/nxdn_deperm.c +++ b/src/nxdn_deperm.c @@ -25,26 +25,48 @@ #include "dsd.h" #include "nxdn_const.h" -//NOTE: Descrambling was having an issue without a value inside the brackets, but only when -//the PARITY table was disabled, was this due to a memory issue or overflow? -static const uint8_t scramble_t[182] = { //values are the position values we need to invert in the descramble - 2, 5, 6, 7, 10, 12, 14, 16, 17, 22, 23, 25, 26, 27, 28, 30, 33, 34, 36, 37, 38, 41, 45, 47, - 52, 54, 56, 57, 59, 62, 63, 64, 65, 66, 67, 69, 70, 73, 76, 79, 81, 82, 84, 85, 86, 87, 88, - 89, 92, 95, 96, 98, 100, 103, 104, 107, 108, 116, 117, 121, 122, 125, 127, 131, 132, 134, - 137, 139, 140, 141, 142, 143, 144, 145, 147, 151, 153, 154, 158, 159, 160, 162, 164, 165, - 168, 170, 171, 174, 175, 176, 177, 181 -}; - - -//decoding functions here -void nxdn_descramble(uint8_t dibits[], int len) +void nxdn_pn95_dibit_scrambler(dsd_state * state, uint8_t * dibits, int len) { - for (int i=0; inxdn_pn95_seed; //default value is 228 / 0xE4 + + //debug hard set + // lfsr = 261; + + uint16_t bit = 0; + uint8_t pN95[182]; memset (pN95, 0, sizeof(pN95)); + + for (int i = 0; i < len; i++) { - if (scramble_t[i] >= len) - break; - dibits[scramble_t[i]] ^= 0x2; // invert sign of scrambled dibits + //before feedback, take the bit + pN95[i] = lfsr & 1; + + //since this is right shift, the taps are 0 and 4, and not 8 and 4 (9,5) + bit = ((lfsr >> 4) ^ (lfsr >> 0)) & 1; + lfsr >>= 1; + lfsr |= (bit << 8); + } + + //convert the pN sequence to a scramble table + uint8_t scramble_table[182]; memset(scramble_table, 0, sizeof(scramble_table)); + int k = 0; + for (int i = 0; i < len; i++) + { + if (pN95[i] == 1) + scramble_table[k++] = i; + } + + //the entries into the scramble_table are the dibits (symbols) that are inverted + for (int i = 0; i < k; i++) + { + dibits[scramble_table[i]] ^= 0x2; + dibits[scramble_table[i]] &= 0x3; + } + + //debug, make sure we don't overflow dibits array + // fprintf (stderr, " PN95: K: %d; Len: %d; ", k, len); + } void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144]) diff --git a/src/nxdn_frame.c b/src/nxdn_frame.c index 3d13590..cbdd13c 100644 --- a/src/nxdn_frame.c +++ b/src/nxdn_frame.c @@ -90,7 +90,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) //collect lich bits first, if they are good, then we can collect the rest of them for (int i = 0; i < 8; i++) lich_dibits[i] = dbuf[i] = getDibit(opts, state); - nxdn_descramble (lich_dibits, 8); + nxdn_pn95_dibit_scrambler (state, lich_dibits, 8); lich = 0; for (int i=0; i<8; i++) lich |= (lich_dibits[i] >> 1) << (7-i); @@ -343,7 +343,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state) dbuf[i+8] = getDibit(opts, state); } - nxdn_descramble (dbuf, 182); //sizeof(dbuf) + nxdn_pn95_dibit_scrambler (state, dbuf, 182); //seperate our dbuf (dibit_buffer) into individual bit array for (int i = 0; i < 182; i++)