From 0f5612fdd46d2849ab22077718eff2144e6e9c1b Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Sat, 9 Mar 2024 19:38:09 -0500 Subject: [PATCH] M17 - Simple BRT Encoder; Setup for PKT Encoder; --- include/dsd.h | 4 ++ src/dsd_main.c | 39 ++++++++++++- src/m17.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 190 insertions(+), 9 deletions(-) diff --git a/include/dsd.h b/include/dsd.h index d938fb2..3202422 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -271,6 +271,8 @@ typedef struct int msize; int playfiles; int m17encoder; + int m17encoderbrt; + int m17encoderpkt; int delay; int use_cosine_filter; int unmute_encrypted_p25; @@ -1016,6 +1018,8 @@ void processYSF(dsd_opts * opts, dsd_state * state); //YSF void processM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR) void processM17LSF(dsd_opts * opts, dsd_state * state); //M17 (LSF) void encodeM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR) encoder +void encodeM17BRT(dsd_opts * opts, dsd_state * state); //M17 (BRT) encoder +void encodeM17PKT(dsd_opts * opts, dsd_state * state); //M17 (PKT) encoder void processP2(dsd_opts * opts, dsd_state * state); //P2 void processTSBK(dsd_opts * opts, dsd_state * state); //P25 Trunking Single Block void processMPDU(dsd_opts * opts, dsd_state * state); //P25 Multi Block PDU (SAP 0x61 FMT 0x15 or 0x17 for Trunking Blocks) diff --git a/src/dsd_main.c b/src/dsd_main.c index 251e3e7..b9d318c 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -626,6 +626,8 @@ initOpts (dsd_opts * opts) opts->msize = 1024; //15 default, max is 1024, much cleaner data decodes on Phase 2 cqpsk at max opts->playfiles = 0; opts->m17encoder = 0; + opts->m17encoderbrt = 0; + opts->m17encoderpkt = 0; opts->delay = 0; opts->use_cosine_filter = 1; opts->unmute_encrypted_p25 = 0; @@ -1288,6 +1290,11 @@ usage () printf (" Example: dsd-fme -fZ -i tcp -8 -o pulse -N 2> m17encoderlog.ans\n"); printf (" Run M17 Encoding, listening to default tcp input, without internal decode/playback and output to 48k/1 analog output device\n"); printf ("\n"); + printf (" -fB M17 BERT Encoder\n"); + printf (" Example: dsd-fme -fB -6 m17bert.wav\n"); + printf (" -fP M17 Packet Encoder\n"); + printf (" Example: dsd-fme -fP -6 m17pkt.wav (NOTE: WIP)\n"); + printf ("\n"); printf ("Decoder options:\n"); printf (" -fa Auto Detection\n"); printf (" -ft TDMA Trunking P25p1 Control and Voice, P25p2 Trunked Channels, and DMR\n"); @@ -2387,13 +2394,27 @@ main (int argc, char **argv) fprintf(stderr, "Notice: M17 cannot autodetect polarity. \n Use -xz option if Inverted Signal expected.\n"); fprintf(stderr, "Decoding only M17 frames.\n"); } - else if (optarg[0] == 'Z') //Captial Z to Run the M17 encoder + else if (optarg[0] == 'Z') //Captial Z to Run the M17 STR encoder { opts.m17encoder = 1; opts.pulse_digi_rate_out = 48000; opts.pulse_digi_out_channels = 1; sprintf (opts.output_name, "M17 Encoder"); } + else if (optarg[0] == 'B') //Captial B to Run the M17 BRT encoder + { + opts.m17encoderbrt = 1; + opts.pulse_digi_rate_out = 48000; + opts.pulse_digi_out_channels = 1; + sprintf (opts.output_name, "M17 BERT"); + } + else if (optarg[0] == 'P') //Captial P to Run the M17 PKT encoder + { + opts.m17encoderpkt = 1; + opts.pulse_digi_rate_out = 48000; + opts.pulse_digi_out_channels = 1; + sprintf (opts.output_name, "M17 Packet"); + } break; //don't mess with the modulations unless you really need to case 'm': @@ -2951,6 +2972,22 @@ main (int argc, char **argv) encodeM17STR(&opts, &state); } + else if (opts.m17encoderbrt == 1) + { + opts.pulse_digi_rate_out = 8000; + //open any outputs, if not already opened + if (opts.audio_out_type == 0) openPulseOutput(&opts); + encodeM17BRT(&opts, &state); + } + + else if (opts.m17encoderpkt == 1) + { + opts.pulse_digi_rate_out = 8000; + //open any outputs, if not already opened + if (opts.audio_out_type == 0) openPulseOutput(&opts); + encodeM17PKT(&opts, &state); + } + else { diff --git a/src/m17.c b/src/m17.c index ecfef26..376b9b8 100644 --- a/src/m17.c +++ b/src/m17.c @@ -1118,7 +1118,7 @@ void encodeM17RF (dsd_opts * opts, dsd_state * state, uint8_t * input, int type) } //Preamble (just repeat the preamble 12 times to make 192 symbols) - if (type == 33) //B Pattern prepends ??? (last symbol opposite of first symbol to prevent zero-crossing) + if (type == 33) //B Pattern prepends BRT (last symbol opposite of first symbol to prevent zero-crossing) { for (i = 0; i < 192; i++) output_dibits[i] = (m17_preamble_b[ (i*2+0)%16 ] << 1) + (m17_preamble_b[ (i*2+1)%16 ] << 0); @@ -1144,18 +1144,18 @@ void encodeM17RF (dsd_opts * opts, dsd_state * state, uint8_t * input, int type) output_dibits[i] = (m17_str_fs[i*2+0] << 1) + (m17_str_fs[i*2+1] << 0); } - if (type == 3) //PKT - { - for (i = 0; i < 8; i++) - output_dibits[i] = (m17_pkt_fs[i*2+0] << 1) + (m17_pkt_fs[i*2+1] << 0); - } - - if (type == 4) //BRT + if (type == 3) //BRT { for (i = 0; i < 8; i++) output_dibits[i] = (m17_brt_fs[i*2+0] << 1) + (m17_brt_fs[i*2+1] << 0); } + if (type == 4) //PKT + { + for (i = 0; i < 8; i++) + output_dibits[i] = (m17_pkt_fs[i*2+0] << 1) + (m17_pkt_fs[i*2+1] << 0); + } + //load rest of frame (if not preamble, EOT marker, or dead air) if (type < 5) { @@ -1210,6 +1210,10 @@ void encodeM17RF (dsd_opts * opts, dsd_state * state, uint8_t * input, int type) // fprintf (stderr, " %d", baseband[i]); // } + //debug insert random 'noise' into the baseband audio + // for (i = 0; i < 40; i++) + // baseband[i] -= rand()& 0x7FFF; + //dead air type, output to all enabled formats zero sample to simulate dead air //NOTE: 25 rounds is approximately 1 second even, seems optimal if (type == 99) @@ -2084,3 +2088,139 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) free(samp2); } + +//encode and create audio of a Project M17 BERT signal +void encodeM17BRT(dsd_opts * opts, dsd_state * state) +{ + + //NOTE: BERT will not use the nucrses terminal, + //just strictly for making a BERT test signal + + uint8_t nil[368]; //empty array + memset (nil, 0, sizeof(nil)); + + int i, j, k, x; //basic utility counters + + //send dead air with type 99 + for (i = 0; i < 25; i++) + encodeM17RF (opts, state, nil, 99); + + //send preamble_b for the BERT frame + encodeM17RF (opts, state, nil, 33); + + //BERT - 197 bits generated from a PRBS9 Generator + uint8_t m17_b1[201]; memset (m17_b1, 0, sizeof(m17_b1)); + + uint16_t lfsr = 1; //starting value of the LFSR + uint16_t bit = 1; //result bit of taps XOR + m17_b1[0] = 1; + + while (!exitflag) + { + + //Generate sequence (if doing 197 at a time) + // for (j = 0; j < 197; j++) + // { + // bit = ( (lfsr >> 8) ^ (lfsr ^ 4) ) & 1; + // lfsr = (lfsr << 1) | bit; + // m17_b1[j] = bit; + // } + + //BERT (reversed sequence for output) + uint8_t m17_b1r[208]; memset (m17_b1r, 0, sizeof(m17_b1r)); + + //BERT (after Convolutional Encode) + uint8_t m17_b1c[402]; memset (m17_b1c, 0, sizeof(m17_b1c)); + + //BERT (after P2 Puncturing) + uint8_t m17_b2p[368]; memset (m17_b2p, 0, sizeof(m17_b2p)); + + //BERT (Interleaved Bits) + uint8_t m17_b3i[368]; memset (m17_b3i, 0, sizeof(m17_b3i)); + + //BERT (Scrambling Applied) + uint8_t m17_b4s[368]; memset (m17_b4s, 0, sizeof(m17_b4s)); + + simple_conv_encoder (m17_b1, m17_b1c, 201); //197+4 + + //use the P2 puncture to...puncture and collapse the BERT Frame + k = 0; x = 0; + for (i = 0; i < 34; i++) + { + m17_b2p[k++] = m17_b1c[x++]; + m17_b2p[k++] = m17_b1c[x++]; + m17_b2p[k++] = m17_b1c[x++]; + m17_b2p[k++] = m17_b1c[x++]; + m17_b2p[k++] = m17_b1c[x++]; + //quit early on last set of i when 368 k bits reached + //index from 0 to 367,so 368 is breakpoint with k++ + if (k == 368) break; + m17_b2p[k++] = m17_b1c[x++]; + m17_b2p[k++] = m17_b1c[x++]; + m17_b2p[k++] = m17_b1c[x++]; + m17_b2p[k++] = m17_b1c[x++]; + m17_b2p[k++] = m17_b1c[x++]; + m17_b2p[k++] = m17_b1c[x++]; + x++; + } + + //debug K and X bit positions + fprintf (stderr, " K: %d; X: %d", k, x); + + //interleave the bit array using Quadratic Permutation Polynomial + //function π(x) = (45x + 92x^2 ) mod 368 + for (i = 0; i < 368; i++) + { + x = ((45*i)+(92*i*i)) % 368; + m17_b3i[x] = m17_b2p[i]; + } + + //scramble/randomize the frame + for (i = 0; i < 368; i++) + m17_b4s[i] = (m17_b3i[i] ^ m17_scramble[i]) & 1; + + //debug insert 3 random bit flip in the finished BERT frame + // int rnd1 = rand()%368; + // int rnd2 = rand()%368; + // int rnd3 = rand()%368; + // m17_b4s[rnd1] ^= 1; + // m17_b4s[rnd2] ^= 1; + // m17_b4s[rnd3] ^= 1; + + //----------------------------------------- + + fprintf (stderr, "\n M17 BERT (ENCODER): "); + + //reverse the sequence and shift so it appears correct on display + for (i = 0; i < 197; i++) + m17_b1r[i+3] = m17_b1[196-i]; + + //Dump Output of the BERT array (reversed and shifted sequence) + for (i = 0; i < 25; i++) + fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&m17_b1r[i*8], 8)); + + //convert bit array into symbols and RF/Audio + encodeM17RF (opts, state, m17_b4s, 3); + + //advance sequence if doing 1 bit each BERT frame + bit = ( (lfsr >> 8) ^ (lfsr ^ 4) ) & 1; + lfsr = (lfsr << 1) | bit; + + //shift the array once and put the result bit into the zero position + //NOTE: The endian-ness of this may be opposite of what is expected + for (j = 1; j < 197; j++) + m17_b1[197-j] = m17_b1[197-j-1]; + m17_b1[0] = bit; + + //end sequence advancement + + } +} + +//encode and create audio of a Project M17 PKT signal +void encodeM17PKT(dsd_opts * opts, dsd_state * state) +{ + UNUSED(opts); UNUSED(state); + //TODO: This whole thing + fprintf (stderr, "\n M17 Packet (ENCODER): "); +} \ No newline at end of file