From 5f969bf4aa88572a29e55c9fe7a6c8d4539306f1 Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Sat, 2 Mar 2024 19:26:48 -0500 Subject: [PATCH] M17 - Cleanup; Audio Tweaks; Fix Conv; Misc; --- src/dsd_ncurses.c | 3 +- src/m17.c | 147 +++++++++++++++++++++++----------------------- 2 files changed, 75 insertions(+), 75 deletions(-) diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index 0c06bb6..73ad58b 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -2550,8 +2550,9 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (opts->mod_c4fm == 1) printw ("[C4FM]"); if (opts->mod_gfsk == 1) printw ("[GFSK]"); printw ( "[%d] \n", (48000*opts->wav_interpolator)/state->samplesPerSymbol); + if (opts->m17encoder == 1) printw ("| Encoding: [%s] ", opts->output_name); + if (opts->m17encoder == 1) printw ("(\\) \n"); printw ("| Decoding: [%s] ", opts->output_name); - if (opts->m17encoder == 1) printw ("(\\) Toggle TX; "); if (opts->aggressive_framesync == 0) printw ("CRC/(RAS) "); //debug -- troubleshoot voice tuning after grant on DMR CC, subsequent grant may not tune because tuner isn't available if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1) printw ("Tuner Locked "); diff --git a/src/m17.c b/src/m17.c index 0b55e39..5520c8e 100644 --- a/src/m17.c +++ b/src/m17.c @@ -235,6 +235,9 @@ int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t * lich_bits) lich_counter = (uint8_t)ConvertBitIntoBytes(&lich_decoded[40], 3); //lich_cnt lich_reserve = (uint8_t)ConvertBitIntoBytes(&lich_decoded[43], 5); //lich_reserved + //sanity check to prevent out of bounds + if (lich_counter > 5) lich_counter = 5; + if (err == 0) fprintf (stderr, "LC: %d/6 ", lich_counter+1); else fprintf (stderr, "LICH G24 ERR"); @@ -853,7 +856,7 @@ void simple_conv_encoder (uint8_t * input, uint8_t * output, int len) uint8_t d3 = 0; uint8_t d4 = 0; - for (i = 0U; i < len; i++) + for (i = 0; i < len; i++) { d = input[i]; @@ -870,15 +873,14 @@ void simple_conv_encoder (uint8_t * input, uint8_t * output, int len) } } -//dibits-symbols map (TX) -const int8_t symbol_map[4]={+1, +3, -1, -3}; +//dibits-symbols map +const int8_t symbol_map[4] = {+1, +3, -1, -3}; -//encode and create audio of a Project M17 STR signal +//encode and create audio of a Project M17 Stream signal void encodeM17STR(dsd_opts * opts, dsd_state * state) { - //TODO: Cleanup Tons of Unused Arrays and Variables - //TODO: Switch to M17 Viterbi Decoder? + //TODO: Finish creating audio of the encoded signal //Enable frame, TX and Ncurses Printer opts->frame_m17 = 1; @@ -888,23 +890,21 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) ncursesOpen(opts, state); //User Defined Variables - uint8_t can = 7; - //numerical representation of dst and src after encoding, or special/reserved value + uint8_t can = 7; //channel access number + //numerical representation of dst and src after b40 encoding, or special/reserved value unsigned long long int dst = 0; unsigned long long int src = 0; - //DST and SRC Callsign Data (up to 9 characters in the b40 array) - char d40[] = "ABCDEFGHI"; UNUSED(d40); //DST - char s40[] = "IHGFEDCBA"; UNUSED(s40); //SRC + //DST and SRC Callsign Data (pick up to 9 characters from the b40 char array) + char d40[] = "BROADCAST"; //DST + char s40[] = "DSD-FME "; //SRC //end User Defined Variables - int i, j, k, x; //basic utility counters - short sample = 0; - size_t nsam = 160; //number of samples to be read in (default is for codec2 3200 bps) - size_t nbit = 64; //number of bits in each frame + int i, j, k, x; //basic utility counters + short sample = 0; //individual audio sample from source + size_t nsam = 160; //number of samples to be read in (default is for codec2 3200 bps) #ifdef USE_CODEC2 nsam = codec2_samples_per_frame(state->codec2_3200); - nbit = codec2_bits_per_frame(state->codec2_3200); #endif short * samp1 = malloc (sizeof(short) * nsam); @@ -916,30 +916,26 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) int fsn, eot = 0; //frame sequence number and eot bit int lich_cnt = 0; //lich frame number counter - uint8_t m17_lich[48]; UNUSED(m17_lich); //48-bit LICH (chunk+lich_cnt+reserved bits) - uint8_t lsf_chunk[6][48]; UNUSED(lsf_chunk); //40 bit chunks of link information spread across 6 frames - uint8_t lsf_chunkr[6][48]; UNUSED(lsf_chunkr); //reverse order bits - uint8_t m17_lsf[240]; UNUSED(m17_lsf); //the complete LSF + uint8_t lsf_chunk[6][48]; //40 bit chunks of link information spread across 6 frames + uint8_t m17_lsf[240]; //the complete LSF - memset (m17_lich, 0, sizeof(m17_lich)); memset (lsf_chunk, 0, sizeof(lsf_chunk)); - memset (lsf_chunkr, 0, sizeof(lsf_chunkr)); memset (m17_lsf, 0, sizeof(m17_lsf)); //NOTE: Most lich and lsf_chunk bits can be pre-set before the while loop, //only need to refresh the lich_cnt value and golay (no meta/IV/enc) - uint16_t lsf_dt = 2; //voice (3200bps) - uint16_t lsf_et = 0; UNUSED(lsf_et); - uint16_t lsf_es = 0; UNUSED(lsf_es); + uint16_t lsf_dt = 2; //voice (3200bps) + uint16_t lsf_et = 0; //encryption type + uint16_t lsf_es = 0; //encryption sub-type uint16_t lsf_cn = can; //can value - uint16_t lsf_rs = 0; UNUSED(lsf_rs); + uint16_t lsf_rs = 0; //reserved bits - uint16_t lsf_fi = 0; //16-bit frame information - lsf_fi = (lsf_dt << 1) + (lsf_cn << 7); + //compose the 16-bit frame information from the above sub elements + uint16_t lsf_fi = 0; + lsf_fi = (lsf_dt << 1) + (lsf_et << 3) + (lsf_es << 5) + (lsf_cn << 7) + (lsf_rs << 11); for (i = 0; i < 16; i++) m17_lsf[96+i] = (lsf_fi >> 15-i) & 1; - //TODO: Only the below if not reserved values "BROADCAST", "ALL", etc - + //TODO: Only encode CSD if not a reserved value //Convert base40 CSD to numerical values (lifted from libM17) for(i = strlen((const char*)d40)-1; i >= 0; i--) { @@ -966,10 +962,11 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) } //end CSD conversion + //load dst and src values into the LSF for (i = 0; i < 48; i++) m17_lsf[i] = (dst >> 47ULL-(unsigned long long int)i) & 1; for (i = 0; i < 48; i++) m17_lsf[i+48] = (src >> 47ULL-(unsigned long long int)i) & 1; - //compute the CRC16 for LSF + //pack and compute the CRC16 for LSF uint16_t crc_cmp = 0; uint8_t lsf_packed[30]; memset (lsf_packed, 0, sizeof(lsf_packed)); @@ -979,14 +976,10 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) //attach the crc16 bits to the end of the LSF data for (i = 0; i < 16; i++) m17_lsf[224+i] = (crc_cmp >> 15-i) & 1; - - - fprintf (stderr, "M17 Voice Stream Encoding: %ld Samples and %ld Bits Per Frame (3200 bps); ", nsam, nbit); - while (!exitflag) //while the software is running { - //read some audio samples from mic and load them into an audio buffer + //read some audio samples from source and load them into an audio buffer //NOTE: Reconfigured to use default 48k input, take 1 out of every 6 samples (Codec2 is 8k encoder) if (opts->audio_in_type == 0) //pulse audio { @@ -1039,7 +1032,7 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) } } - else if (opts->audio_in_type == 5) //OSS, testing working + else if (opts->audio_in_type == 5) //OSS { for (i = 0; i < nsam; i++) { @@ -1090,7 +1083,7 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) } } - else if (opts->audio_in_type == 3) + else if (opts->audio_in_type == 3) //RTL { #ifdef USE_RTLSDR for (i = 0; i < nsam; i++) @@ -1108,9 +1101,18 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) cleanupAndExit(opts, state); voice2[i] = sample; } + opts->rtl_rms = rtl_return_rms(); #endif } + //decimate audio input (default 100% on mic is WAY TOO LOUD for the encoder, fine tune in volume control) + for (i = 0; i < 160; i++) + { + //NOTE: Use + and - in ncurses to fine tune manually + voice1[i] *= (float)state->aout_gain/ (float)25.0f; + voice2[i] *= (float)state->aout_gain/ (float)25.0f; + } + //convert out audio input into CODEC2 (3200bps) 8 byte data stream uint8_t vc1_bytes[8]; memset (vc1_bytes, 0, sizeof(vc1_bytes)); uint8_t vc2_bytes[8]; memset (vc2_bytes, 0, sizeof(vc2_bytes)); @@ -1120,41 +1122,38 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) codec2_encode(state->codec2_3200, vc2_bytes, voice2); #endif - //start assembling our completed frame + //initialize and start assembling the completed frame - //STR frame sync pattern - 0xFF5D //-3, -3, -3, -3, +3, +3, -3, +3 - uint8_t m17_str_fs[16] = {1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1}; UNUSED(m17_str_fs); + //STR frame sync pattern - 0xFF5D (-3, -3, -3, -3, +3, +3, -3, +3) + uint8_t m17_str_fs[16] = {1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1}; //Data/Voice Portion of Stream Data Link Layer w/ FSN - uint8_t m17_v1[148]; memset (m17_v1, 0, sizeof(m17_v1)); UNUSED(m17_v1); + uint8_t m17_v1[148]; memset (m17_v1, 0, sizeof(m17_v1)); //Data/Voice Portion of Stream Data Link Layer w/ FSN (after Convolutional Encode) - uint8_t m17_v1c[296]; memset (m17_v1c, 0, sizeof(m17_v1c)); UNUSED(m17_v1c); + uint8_t m17_v1c[296]; memset (m17_v1c, 0, sizeof(m17_v1c)); //Data/Voice Portion of Stream Data Link Layer w/ FSN (after P2 Puncturing) - uint8_t m17_v1p[272]; memset (m17_v1p, 0, sizeof(m17_v1p)); UNUSED(m17_v1p); + uint8_t m17_v1p[272]; memset (m17_v1p, 0, sizeof(m17_v1p)); //LSF Chunk + LICH CNT of Stream Data Link Layer - uint8_t m17_l1[48]; memset (m17_l1, 0, sizeof(m17_l1)); UNUSED(m17_l1); + uint8_t m17_l1[48]; memset (m17_l1, 0, sizeof(m17_l1)); //LSF Chunk + LICH CNT of Stream Data Link Layer (after Golay 24,12 Encoding) - uint8_t m17_l1g[96]; memset (m17_l1g, 0, sizeof(m17_l1g)); UNUSED(m17_l1g); + uint8_t m17_l1g[96]; memset (m17_l1g, 0, sizeof(m17_l1g)); //Type 4c - Combined LSF Content Chuck and Voice/Data (96 + 272) - uint8_t m17_t4c[368]; memset (m17_t4c, 0, sizeof(m17_t4c)); UNUSED(m17_t4c); + uint8_t m17_t4c[368]; memset (m17_t4c, 0, sizeof(m17_t4c)); //Type 4i - Interleaved Bits - uint8_t m17_t4i[368]; memset (m17_t4i, 0, sizeof(m17_t4i)); UNUSED(m17_t4i); + uint8_t m17_t4i[368]; memset (m17_t4i, 0, sizeof(m17_t4i)); //Type 4s - Interleaved Bits with Scrambling Applied - uint8_t m17_t4s[368]; memset (m17_t4s, 0, sizeof(m17_t4s)); UNUSED(m17_t4s); - - //OTA Symbol Convertion (best variable type for this? int16?) - uint8_t m17_sym[184]; memset (m17_sym, 0, sizeof(m17_sym)); UNUSED(m17_sym); + uint8_t m17_t4s[368]; memset (m17_t4s, 0, sizeof(m17_t4s)); //insert the voice bytes into voice bits, and voice bits into v1 in their appropriate location - uint8_t v1_bits[64]; memset (v1_bits, 0, sizeof(v1_bits)); UNUSED(v1_bits); - uint8_t v2_bits[64]; memset (v2_bits, 0, sizeof(v2_bits)); UNUSED(v2_bits); + uint8_t v1_bits[64]; memset (v1_bits, 0, sizeof(v1_bits)); + uint8_t v2_bits[64]; memset (v2_bits, 0, sizeof(v2_bits)); k = 0; x = 0; for (j = 0; j < 8; j++) @@ -1178,10 +1177,9 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) //set current frame number as bits 1-15 of the v1 stream for (i = 0; i < 15; i++) m17_v1[i+1] = ( (uint8_t)(fsn >> 14-i) ) &1; - fsn++; //increment the frame sequence number //Use the convolutional encoder to encode the voice / data stream - simple_conv_encoder (m17_v1, m17_v1c, 144); //seems to be working now, or at least, the same bits before and after on the playback side + simple_conv_encoder (m17_v1, m17_v1c, 148); //was 144, not 144+4 //use the P2 puncture to...puncture and collapse the voice / data stream k = 0; x = 0; @@ -1193,13 +1191,12 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) m17_v1p[k++] = m17_v1c[x++]; m17_v1p[k++] = m17_v1c[x++]; m17_v1p[k++] = m17_v1c[x++]; - if (k == 272) break; //quit early on last set of i when 272 k bits reached m17_v1p[k++] = m17_v1c[x++]; - if (k == 272) break; //quit early on last set of i when 272 k bits reached m17_v1p[k++] = m17_v1c[x++]; - if (k == 272) break; //quit early on last set of i when 272 k bits reached + //quit early on last set of i when 272 k bits reached + //index from 0 to 271,so 272 is breakpoint with k++ + if (k == 272) break; m17_v1p[k++] = m17_v1c[x++]; - if (k == 272) break; //quit early on last set of i when 272 k bits reached m17_v1p[k++] = m17_v1c[x++]; m17_v1p[k++] = m17_v1c[x++]; x++; @@ -1209,8 +1206,6 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) for (i = 0; i < 272; i++) m17_t4c[i+96] = m17_v1p[i]; - //ignore the LSF/LICH reserved bits (unused currently) - //load up the lsf chunk for this cnt for (i = 0; i < 40; i++) lsf_chunk[lich_cnt][i] = m17_lsf[((lich_cnt)*40)+i]; @@ -1220,14 +1215,14 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) lsf_chunk[lich_cnt][41] = (lich_cnt >> 1) & 1; lsf_chunk[lich_cnt][42] = (lich_cnt >> 0) & 1; - //This is not M17 standard (yet), but use the LICH reserved bits to signal dt - lsf_chunk[lich_cnt][46] = (lsf_dt >> 1) & 1; - lsf_chunk[lich_cnt][47] = (lsf_dt >> 0) & 1; - //use the last 3 bits of reserved to signal the can value + //This is not M17 standard, but use the LICH reserved bits to signal can and dt lsf_chunk[lich_cnt][43] = (lsf_cn >> 2) & 1; lsf_chunk[lich_cnt][44] = (lsf_cn >> 1) & 1; lsf_chunk[lich_cnt][45] = (lsf_cn >> 0) & 1; + lsf_chunk[lich_cnt][46] = (lsf_dt >> 1) & 1; + lsf_chunk[lich_cnt][47] = (lsf_dt >> 0) & 1; + //encode with golay 24,12 and load into m17_lig Golay_24_12_encode (lsf_chunk[lich_cnt]+00, m17_l1g+00); Golay_24_12_encode (lsf_chunk[lich_cnt]+12, m17_l1g+24); @@ -1246,24 +1241,23 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) m17_t4i[x] = m17_t4c[i]; } - //scramble the frame + //scramble/randomize the frame for (i = 0; i < 368; i++) m17_t4s[i] = (m17_t4i[i] ^ m17_scramble[i]) & 1; //----------------------------------------- //decode stream with the M17STR_debug - if (state->m17encoder_tx == 1) //when enabled by user key press in ncurses + if (state->m17encoder_tx == 1) //when toggled on { - //Enable Carrier, synctype, etc state->carrier = 1; state->synctype = 8; - fprintf (stderr, "\n M17 STR (ENCODER): "); + fprintf (stderr, "\n M17 Stream (ENCODER): "); processM17STR_debug(opts, state, m17_t4s); //load bits inti a dibit array plus the framesync bits - uint8_t output_dibits[192]; memset (output_dibits, 0, sizeof(output_dibits)); UNUSED(output_dibits); + uint8_t output_dibits[192]; memset (output_dibits, 0, sizeof(output_dibits)); for (i = 0; i < 8; i++) output_dibits[i] = (m17_str_fs[i*2+0] << 1) + (m17_str_fs[i*2+1] << 0); @@ -1274,7 +1268,7 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) //Start working on converting the bitsream to an audio stream //convert to symbols @ 4800 bps - int output_symbols[192]; memset (output_symbols, 0, sizeof(output_symbols)); UNUSED(output_symbols); + int output_symbols[192]; memset (output_symbols, 0, sizeof(output_symbols)); for (i = 0; i < 192; i++) output_symbols[i] = symbol_map[output_dibits[i]]; @@ -1285,13 +1279,18 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) // if (i%24 == 0) fprintf (stderr, "\n"); // fprintf (stderr, " %d", output_symbols[i]); // } + UNUSED(output_symbols); //TODO: symbols to audio - //end by incrementing lich_cnt, reset on 6 + //increment lich_cnt, reset on 6 lich_cnt++; if (lich_cnt == 6) lich_cnt = 0; + //increment frame sequency number, trunc to maximum value + fsn++; + fsn &= 0x7FFF; + } //end if (state->m17encoder_tx) else //if not tx, reset values, drop carrier and sync @@ -1302,7 +1301,7 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) state->synctype = -1; } - //refresh ncurses printer + //refresh ncurses printer, if enabled if (opts->use_ncurses_terminal == 1) ncursesPrinter(opts, state);