From fa47d0321bff33ad3c4d07653764ef41b8f430a3 Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Fri, 31 Oct 2025 05:58:45 -0400 Subject: [PATCH] Update and Strip Down M17 Features; #322 --- include/dsd.h | 56 +- src/dsd_audio.c | 8 +- src/dsd_frame.c | 17 +- src/dsd_frame_sync.c | 141 +- src/dsd_main.c | 306 +-- src/dsd_misc.c | 129 +- src/dsd_ncurses_handler.c | 17 +- src/dsd_ncurses_menu.c | 2 - src/dsd_ncurses_printer.c | 59 +- src/dsd_rigctl.c | 67 - src/m17.c | 3881 ++++++------------------------------- src/rtl_sdr_fm.cpp | 2 +- 12 files changed, 854 insertions(+), 3831 deletions(-) diff --git a/include/dsd.h b/include/dsd.h index c81af35..7ae09a6 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -357,10 +357,6 @@ typedef struct int ssize; int msize; int playfiles; - int m17encoder; - int m17encoderbrt; - int m17encoderpkt; - int m17decoderip; int delay; int use_cosine_filter; int unmute_encrypted_p25; @@ -414,7 +410,6 @@ typedef struct short int aggressive_framesync; int frame_m17; - int inverted_m17; FILE *symbolfile; int call_alert; @@ -431,12 +426,6 @@ typedef struct int udp_portno; char udp_hostname[1024]; - //M17 UDP for IP frame output - int m17_use_ip; //if enabled, open UDP and broadcast IP frame - int m17_portno; //default is 17000 - int m17_udp_sock; //actual UDP socket for M17 to send to - char m17_hostname[1024]; - //tcp socket for SDR++, etc int tcp_sockfd; int tcp_portno; @@ -953,15 +942,11 @@ typedef struct //M17 Storage uint8_t m17_lsf[360]; uint8_t m17_pkt[850]; - uint8_t m17_pbc_ct; //pbc packet counter uint8_t m17_str_dt; //stream contents unsigned long long int m17_dst; unsigned long long int m17_src; uint8_t m17_can; //can value that was decoded from signal - int m17_can_en; //can value supplied to the encoding side - int m17_rate; //sampling rate for audio input - int m17_vox; //vox enabled via RMS value char m17_dst_csd[20]; char m17_src_csd[20]; @@ -969,18 +954,22 @@ typedef struct char m17_src_str[50]; char m17_dst_str[50]; - uint8_t m17_meta[16]; //packed meta - uint8_t m17_enc; //enc type - uint8_t m17_enc_st; //scrambler or data subtye - int m17encoder_tx; //if TX (encode + decode) M17 Stream is enabled - int m17encoder_eot; //signal if we need to send the EOT frame + uint8_t m17_meta[16]; //packed meta + uint8_t m17_aes_iv[16]; //aes iv + uint8_t m17_enc; //enc type + uint8_t m17_enc_st; //scrambler or data subtye + + char m17_text_string[1024]; + char m17_gnss_string[1024]; + char m17_data_string[1024]; + char m17_meta_string[1024]; + + float m17_viterbi_err; //misc str storage char str50a[50]; char str50b[50]; char str50c[50]; - char m17dat[50]; //user supplied m17 data input string - char m17sms[800]; //user supplied sms text string //Codec2 #ifdef USE_CODEC2 @@ -1024,13 +1013,6 @@ typedef struct //M17 Sync Patterns #define M17_LSF "11113313" #define M17_STR "33331131" -//alternating with last symbol opposite of first symbol of LSF -#define M17_PRE "31313131" -#define M17_PIV "13131313" -#define M17_PRE_LSF "3131313133331131" //Preamble + LSF -#define M17_PIV_LSF "1313131311113313" //Preamble + LSF -#define M17_BRT "31331111" -#define M17_PKT "13113333" #define FUSION_SYNC "31111311313113131131" #define INV_FUSION_SYNC "13333133131331313313" @@ -1254,13 +1236,6 @@ void processDSTAR_HD (dsd_opts * opts, dsd_state * state); //DSTAR Header void processDSTAR_SD (dsd_opts * opts, dsd_state * state, uint8_t * sd); //DSTAR Slow Data void processYSF(dsd_opts * opts, dsd_state * state); //YSF void processM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR) -void processM17PKT(dsd_opts * opts, dsd_state * state); //M17 (PKT) -void processM17LSF(dsd_opts * opts, dsd_state * state); //M17 (LSF) -void processM17IPF(dsd_opts * opts, dsd_state * state); //M17 (IPF) -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 decodeM17PKT(dsd_opts * opts, dsd_state * state, uint8_t * input, int len); //M17 (PKT) decoder 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) @@ -1322,6 +1297,12 @@ void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsign void CNXDNConvolution_init(); //libM17 viterbi decoder + +//libm17 magic soft decision based viterbi +#define SYM_PER_PLD 184 +void slice_symbols(uint16_t out[2*SYM_PER_PLD], const float inp[SYM_PER_PLD]); +void randomize_soft_bits(uint16_t inp[SYM_PER_PLD*2]); +void reorder_soft_bits(uint16_t outp[SYM_PER_PLD*2], const uint16_t inp[SYM_PER_PLD*2]); uint32_t viterbi_decode(uint8_t* out, const uint16_t* in, const uint16_t len); uint32_t viterbi_decode_punctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, const uint16_t in_len, const uint16_t p_len); void viterbi_decode_bit(uint16_t s0, uint16_t s1, const size_t pos); @@ -1623,9 +1604,6 @@ int udp_socket_connect(dsd_opts * opts, dsd_state * state); int udp_socket_connectA(dsd_opts * opts, dsd_state * state); void udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data); void udp_socket_blasterA(dsd_opts * opts, dsd_state * state, size_t nsam, void * data); -int m17_socket_receiver(dsd_opts * opts, void * data); -int udp_socket_connectM17(dsd_opts * opts, dsd_state * state); -int m17_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data); //RC4 function prototypes void rc4_voice_decrypt (int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[]); diff --git a/src/dsd_audio.c b/src/dsd_audio.c index 4f67a84..cd46090 100644 --- a/src/dsd_audio.c +++ b/src/dsd_audio.c @@ -137,9 +137,11 @@ void openPulseInput(dsd_opts * opts) lt.maxlength = -1; lt.prebuf = -1; lt.tlength = -1; - if (opts->m17encoder == 1) - opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME4", PA_STREAM_RECORD, dev, "M17 Voice Input", &cc, NULL, <, &err); - else opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, <, &err); + // if (opts->m17encoder == 1) + // opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME4", PA_STREAM_RECORD, dev, "M17 Voice Input", &cc, NULL, <, &err); + // else opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, <, &err); + + opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, <, &err); if (err != 0) { diff --git a/src/dsd_frame.c b/src/dsd_frame.c index 8391062..5986711 100644 --- a/src/dsd_frame.c +++ b/src/dsd_frame.c @@ -262,21 +262,10 @@ processFrame (dsd_opts * opts, dsd_state * state) processYSF(opts, state); return; } - //M17 - else if ((state->synctype == 16) || (state->synctype == 9) || (state->synctype == 17) || (state->synctype == 8) || - (state->synctype == 76) || (state->synctype == 77) || (state->synctype == 86) || (state->synctype == 87) || - (state->synctype == 99) || (state->synctype == 98) ) + //M17 STR + else if (state->synctype == 16) { - if (state->synctype == 98 || state->synctype == 99) //preamble only - skipDibit(opts, state, 8); //skip dibits to prime the demodulator - else if (state->synctype == 16 || state->synctype == 17) - processM17STR(opts, state); - else if (state->synctype == 76 || state->synctype == 77) {} //Not available yet - // processM17BRT(opts, state); //Not available yet - else if (state->synctype == 86 || state->synctype == 87) - processM17PKT(opts, state); - else - processM17LSF(opts, state); + processM17STR(opts, state); return; } //P25 P2 diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c index c13e285..6248d42 100644 --- a/src/dsd_frame_sync.c +++ b/src/dsd_frame_sync.c @@ -162,7 +162,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state) char synctest20[21]; //YSF char synctest48[49]; //EDACS char synctest8[9]; //M17 - char synctest16[17]; //M17 Preamble char modulation[8]; char *synctest_p; char synctest_buf[10240]; //what actually is assigned to this, can't find its use anywhere? @@ -208,9 +207,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state) t = 0; synctest10[10] = 0; synctest[24] = 0; - synctest8[8] = 0; //M17, wasn't initialized or terminated (source of much pain and frustration in Cygwin) + synctest8[8] = 0; synctest12[12] = 0; - synctest16[16] = 0; //M17, wasn't initialized or terminated (source of much pain and frustration in Cygwin) synctest48[48] = 0; synctest32[32] = 0; synctest20[20] = 0; @@ -566,139 +564,24 @@ getFrameSync (dsd_opts * opts, dsd_state * state) } //end YSF sync - //M17 Sync -- Just STR and LSF for now - strncpy(synctest16, (synctest_p - 15), 16); + //M17 Sync -- Just STR strncpy(synctest8, (synctest_p - 7), 8); if(opts->frame_m17 == 1) { - //preambles will skip dibits in an attempt to prime the - //demodulator but not attempt any decoding - if (strcmp(synctest8, M17_PRE) == 0) + if (strcmp(synctest8, M17_STR) == 0) { - if (opts->inverted_m17 == 0) + printFrameSync (opts, state, "+M17 STR", synctest_pos + 1, modulation); + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + if (state->lastsynctype == 16) { - printFrameSync (opts, state, "+M17 PREAMBLE", synctest_pos + 1, modulation); - state->carrier = 1; - state->offset = synctest_pos; - state->max = ((state->max) + lmax) / 2; - state->min = ((state->min) + lmin) / 2; - state->lastsynctype = 98; - fprintf (stderr, "\n"); - return (98); - } - } - else if (strcmp(synctest8, M17_PIV) == 0) - { - if (opts->inverted_m17 == 1) - { - printFrameSync (opts, state, "-M17 PREAMBLE", synctest_pos + 1, modulation); - state->carrier = 1; - state->offset = synctest_pos; - state->max = ((state->max) + lmax) / 2; - state->min = ((state->min) + lmin) / 2; - state->lastsynctype = 99; - fprintf (stderr, "\n"); - return (99); - } - } - else if (strcmp(synctest8, M17_PKT) == 0) - { - if (opts->inverted_m17 == 0) - { - printFrameSync (opts, state, "+M17 PKT", synctest_pos + 1, modulation); - state->carrier = 1; - state->offset = synctest_pos; - state->max = ((state->max) + lmax) / 2; - state->min = ((state->min) + lmin) / 2; - if (state->lastsynctype == 86 || state->lastsynctype == 8) - { - state->lastsynctype = 86; - return (86); - } - state->lastsynctype = 86; - fprintf (stderr, "\n"); - } - // else //unknown, -BRT? - // { - // printFrameSync (opts, state, "-M17 BRT", synctest_pos + 1, modulation); - // state->carrier = 1; - // state->offset = synctest_pos; - // state->max = ((state->max) + lmax) / 2; - // state->min = ((state->min) + lmin) / 2; - // if (state->lastsynctype == 77) - // { - // state->lastsynctype = 77; - // return (77); - // } - // state->lastsynctype = 77; - // fprintf (stderr, "\n"); - // } - } - else if (strcmp(synctest8, M17_STR) == 0) - { - if (opts->inverted_m17 == 0) - { - printFrameSync (opts, state, "+M17 STR", synctest_pos + 1, modulation); - state->carrier = 1; - state->offset = synctest_pos; - state->max = ((state->max) + lmax) / 2; - state->min = ((state->min) + lmin) / 2; - if (state->lastsynctype == 16 || state->lastsynctype == 8) - { - state->lastsynctype = 16; - return (16); - } state->lastsynctype = 16; - fprintf (stderr, "\n"); - } - else - { - printFrameSync (opts, state, "-M17 LSF", synctest_pos + 1, modulation); - state->carrier = 1; - state->offset = synctest_pos; - state->max = ((state->max) + lmax) / 2; - state->min = ((state->min) + lmin) / 2; - if (state->lastsynctype == 99) - { - state->lastsynctype = 9; - return (9); - } - state->lastsynctype = 9; - fprintf (stderr, "\n"); - } - } - else if (strcmp(synctest8, M17_LSF) == 0) - { - if (opts->inverted_m17 == 1) - { - printFrameSync (opts, state, "-M17 STR", synctest_pos + 1, modulation); - state->carrier = 1; - state->offset = synctest_pos; - state->max = ((state->max) + lmax) / 2; - state->min = ((state->min) + lmin) / 2; - if (state->lastsynctype == 17 || state->lastsynctype == 9) - { - state->lastsynctype = 17; - return (17); - } - state->lastsynctype = 17; - fprintf (stderr, "\n"); - } - else - { - printFrameSync (opts, state, "+M17 LSF", synctest_pos + 1, modulation); - state->carrier = 1; - state->offset = synctest_pos; - state->max = ((state->max) + lmax) / 2; - state->min = ((state->min) + lmin) / 2; - if (state->lastsynctype == 98) - { - state->lastsynctype = 8; - return (8); - } - state->lastsynctype = 8; - fprintf (stderr, "\n"); + return (16); } + state->lastsynctype = 16; + fprintf (stderr, "\n"); } } //end M17 diff --git a/src/dsd_main.c b/src/dsd_main.c index 41e80d9..0662056 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -538,7 +538,6 @@ //M17 Storage memset (state->m17_lsf, 0, sizeof(state->m17_lsf)); memset (state->m17_pkt, 0, sizeof(state->m17_pkt)); - state->m17_pbc_ct = 0; state->m17_str_dt = 9; state->m17_dst = 0; @@ -552,13 +551,18 @@ state->m17_enc = 0; state->m17_enc_st = 0; memset(state->m17_meta, 0, sizeof(state->m17_meta)); - - //misc str storage - // sprintf (state->str50a, "%s", ""); - // memset (state->str50b, 0, 50*sizeof(char)); - // memset (state->str50c, 0, 50*sizeof(char)); - // memset (state->m17sms, 0, 800*sizeof(char)); - // sprintf (state->m17dat, "%s", ""); + memset(state->m17_aes_iv, 0, sizeof(state->m17_aes_iv)); + + memset(state->m17_text_string, 0, sizeof(state->m17_text_string)); + memset(state->m17_gnss_string, 0, sizeof(state->m17_gnss_string)); + memset(state->m17_data_string, 0, sizeof(state->m17_data_string)); + memset(state->m17_meta_string, 0, sizeof(state->m17_meta_string)); + sprintf (state->m17_text_string, "%s", ""); + sprintf (state->m17_gnss_string, "%s", ""); + sprintf (state->m17_data_string, "%s", ""); + sprintf (state->m17_meta_string, "%s", ""); + + state->m17_viterbi_err = 0.0f; //set float temp buffer to baseline memset (state->audio_out_temp_buf, 0.0f, sizeof(state->audio_out_temp_buf)); @@ -674,15 +678,10 @@ opts->uvquality = 3; opts->inverted_x2tdma = 1; // most transmitter + scanner + sound card combinations show inverted signals for this opts->inverted_dmr = 0; // most transmitter + scanner + sound card combinations show non-inverted signals for this - opts->inverted_m17 = 0; //samples from M17_Education seem to all be positive polarity (same from m17-tools programs) opts->mod_threshold = 26; opts->ssize = 128; //36 default, max is 128, much cleaner data decodes on Phase 2 cqpsk at max 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->m17decoderip = 0; opts->delay = 0; opts->use_cosine_filter = 1; opts->unmute_encrypted_p25 = 0; @@ -762,12 +761,6 @@ opts->udp_portno = 23456; //default port, same os OP25's sockaudio.py sprintf (opts->udp_hostname, "%s", "127.0.0.1"); - //M17 UDP Port and hostname - opts->m17_use_ip = 0; //if enabled, open UDP and broadcast IP frame - opts->m17_portno = 17000; //default is 17000 - opts->m17_udp_sock = 0; //actual UDP socket for M17 to send to - sprintf (opts->m17_hostname, "%s", "127.0.0.1"); - //tcp input options opts->tcp_sockfd = 0; opts->tcp_portno = 7355; //default favored by SDR++ @@ -1315,22 +1308,16 @@ //M17 Storage memset (state->m17_lsf, 0, sizeof(state->m17_lsf)); memset (state->m17_pkt, 0, sizeof(state->m17_pkt)); - state->m17_pbc_ct = 0; state->m17_str_dt = 9; //misc str storage // sprintf (state->str50a, "%s", ""); memset (state->str50b, 0, 50*sizeof(char)); memset (state->str50c, 0, 50*sizeof(char)); - memset (state->m17sms, 0, 800*sizeof(char)); - sprintf (state->m17dat, "%s", ""); state->m17_dst = 0; state->m17_src = 0; state->m17_can = 0; //can value that was decoded from signal - state->m17_can_en = -1; //can value supplied to the encoding side - state->m17_rate = 48000; //sampling rate for audio input - state->m17_vox = 0; //vox mode enabled on M17 encoder memset(state->m17_dst_csd, 0, sizeof(state->m17_dst_csd)); memset(state->m17_src_csd, 0, sizeof(state->m17_src_csd)); sprintf (state->m17_dst_str, "%s", ""); @@ -1338,10 +1325,19 @@ state->m17_enc = 0; state->m17_enc_st = 0; - state->m17encoder_tx = 0; - state->m17encoder_eot = 0; memset(state->m17_meta, 0, sizeof(state->m17_meta)); - + memset(state->m17_aes_iv, 0, sizeof(state->m17_aes_iv)); + + memset(state->m17_text_string, 0, sizeof(state->m17_text_string)); + memset(state->m17_gnss_string, 0, sizeof(state->m17_gnss_string)); + memset(state->m17_data_string, 0, sizeof(state->m17_data_string)); + memset(state->m17_meta_string, 0, sizeof(state->m17_meta_string)); + sprintf (state->m17_text_string, "%s", ""); + sprintf (state->m17_gnss_string, "%s", ""); + sprintf (state->m17_data_string, "%s", ""); + sprintf (state->m17_meta_string, "%s", ""); + + state->m17_viterbi_err = 0.0f; #ifdef USE_CODEC2 state->codec2_3200 = codec2_create(CODEC2_MODE_3200); @@ -1399,8 +1395,6 @@ printf (" rtl:dev:freq:gain:ppm:bw:sq:vol for rtl dongle (see below)\n"); printf (" tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)\n"); printf (" tcp:192.168.7.5:7355 for custom address and port \n"); - printf (" m17udp for M17 UDP/IP socket bind input (default host 127.0.0.1; default port 17000)\n"); - printf (" m17udp:192.168.7.8:17001 for M17 UDP/IP bind input (Binding Address and Port\n"); printf (" filename.bin for OP25/FME capture bin files\n"); printf (" filename.wav for 48K/1 wav files (SDR++, GQRX)\n"); printf (" filename.wav -s 96000 for 96K/1 wav files (DSDPlus)\n"); @@ -1423,8 +1417,6 @@ printf (" null for no audio output\n"); printf (" udp for UDP socket blaster output (default host 127.0.0.1; default port 23456)\n"); printf (" udp:192.168.7.8:23470 for UDP socket blaster output (Target Address and Port\n"); - printf (" m17udp for M17 UDP/IP socket blaster output (default host 127.0.0.1; default port 17000)\n"); - printf (" m17udp:192.168.7.8:17001 for M17 UDP/IP blaster output (Target Address and Port\n"); printf (" -d Create mbe data files, use this directory (TDMA version is experimental)\n"); printf (" -r Read/Play saved mbe data from file(s)\n"); printf (" -g Audio Digital Output Gain (Default: 0 = Auto; )\n"); @@ -1471,28 +1463,6 @@ printf (" Example: dsd-fme -fs -i rtl -C cap_plus_channel.csv -T\n"); printf (" Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:2\n"); printf ("\n"); - printf ("Encoder options:\n"); - printf (" -fZ M17 Stream Voice Encoder\n"); - printf (" Example: dsd-fme -fZ -M M17:9:DSD-FME:LWVMOBILE -i pulse -6 m17signal.wav -8 -N 2> m17encoderlog.txt\n"); - printf (" Run M17 Encoding, listening to pulse audio server, with internal decode/playback and output to 48k/1 wav file\n"); - printf ("\n"); - printf (" Example: dsd-fme -fZ -M M17:9:DSD-FME:LWVMOBILE -i tcp -o pulse -8 -N 2> m17encoderlog.txt\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 (" -fP M17 Packet Encoder\n"); - printf (" Example: dsd-fme -fP -M M17:9:DSD-FME:LWVMOBILE -6 m17pkt.wav -8 -S 'Hello World'\n"); - printf ("\n"); - printf (" -fB M17 BERT Encoder\n"); - printf (" Example: dsd-fme -fB -M M17:9:DSD-FME:LWVMOBILE -6 m17bert.wav -8\n"); - printf ("\n"); - printf (" -M M17 Encoding User Configuration String: M17:CAN:SRC:DST:INPUT_RATE:VOX (see examples above).\n"); - printf (" CAN 1-15; SRC and DST have to be no more than 9 UPPER base40 characters.\n"); - printf (" BASE40: ' ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.'\n"); - printf (" Input Rate Default is 48000; Use Multiples of 8000 up to 48000.\n"); - printf (" VOX Enabled on 1; (Default = 0)\n"); - printf (" Values not entered into the M17: string are set to default values.\n"); - // printf (" -S M17 Packet Encoder SMS String: No more than 772 chars, use single quotations (see example above).\n"); - // printf (" -S M17 Stream Encoder SMS String: No more than 48 chars, activates 1600 voice (best if broken into six 8 char chunks).\n"); printf ("Decoder options:\n"); printf (" -fa Auto Detection\n"); printf (" -fA Passive Analog Audio Monitor\n"); @@ -1504,7 +1474,6 @@ printf (" -fx Decode only X2-TDMA\n"); printf (" -fy Decode only YSF\n"); printf (" -fz Decode only M17*\n"); - printf (" -fU Decode only M17 UDP/IP Frame***\n"); printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n"); printf (" -fn Decode only NXDN96* (12.5 kHz)\n"); printf (" -fp Decode only ProVoice*\n"); @@ -1520,11 +1489,9 @@ printf (" -xx Expect non-inverted X2-TDMA signal\n"); printf (" -xr Expect inverted DMR signal\n"); printf (" -xd Expect inverted ICOM dPMR signal\n"); - printf (" -xz Expect inverted M17 signal\n"); printf ("\n"); printf (" * denotes frame types that cannot be auto-detected.\n"); printf (" ** Phase 2 Single Frequency may require user to manually set WACN/SYSID/CC parameters if MAC_SIGNAL not present.\n"); - printf (" *** configure UDP Input with -i m17:127.0.0.1:17000 \n"); printf ("\n"); printf ("Advanced Decoder options:\n"); printf (" -X Manually Set P2 Parameters (WACN, SYSID, CC/NAC)\n"); @@ -1545,7 +1512,6 @@ printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n"); printf (" -F Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n"); printf (" Enabling on some systems could lead to bad channel assignments/site data decoding if bad or marginal signal\n"); - printf (" -F Relax M17 LSF/PKT CRC Error Checking\n"); printf ("\n"); printf (" -b Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n"); printf (" (NOTE: This used to be the 'K' option! \n"); @@ -1841,9 +1807,6 @@ if (opts->udp_sockfdA) close (opts->udp_sockfdA); - if (opts->m17_udp_sock) - close (opts->m17_udp_sock); - //close MBE out files if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state); if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state); @@ -1921,7 +1884,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:8*:9: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: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) @@ -1935,7 +1898,7 @@ opts.call_alert = 1; break; - //Free'd up switches include: j, O, + //Free'd up switches include: j, M, // //make sure to put a colon : after each if they need an argument @@ -1956,20 +1919,6 @@ exit(0); break; - //Specify M17 encoder User Data (CAN, DST, SRC values) - //NOTE: Disabled QPSK settings by borrowing these switches (nobody probalby used them anyways) - case 'M': - strncpy(state.m17dat, optarg, 49); - state.m17dat[49] = '\0'; - break; - - // //Specify M17 encoder SMS Message (truncates at 772) - // case 'S': - // strncpy(state.m17sms, optarg, 772); - // state.m17sms[772] = '\0'; - // state.m17_str_dt = 3; //flip this so that STR encoder knows to use 1600 voice + data - // break; - //specify TG Hold value case 'I': sscanf (optarg, "%d", &state.tg_hold); @@ -3021,40 +2970,6 @@ //disable RRC filter for now opts.use_cosine_filter = 0; } - 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; - //filters disabled by default, use ncurses VBN switches - opts.use_lpf = 0; - opts.use_hpf = 0; - opts.use_pbf = 0; - opts.dmr_stereo = 0; - 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"); - } - else if (optarg[0] == 'U') //Captial U to Run the M17 UDP IPF decoder - { - opts.m17decoderip = 1; - opts.pulse_digi_rate_out = 8000; - opts.pulse_digi_out_channels = 1; - sprintf (opts.output_name, "M17 IP Frame"); - fprintf (stderr, "Decoding M17 UDP/IP Frames.\n"); - } break; //don't mess with the modulations unless you really need to case 'm': @@ -3154,11 +3069,6 @@ opts.inverted_dpmr = 1; fprintf (stderr, "Expecting inverted ICOM dPMR signals.\n"); } - else if (optarg[0] == 'z') - { - opts.inverted_m17 = 1; - fprintf (stderr, "Expecting inverted M17 signals.\n"); - } break; case 'r': @@ -3186,48 +3096,6 @@ openSerial (&opts, &state); } - if((strncmp(opts.audio_in_dev, "m17udp", 6) == 0)) //M17 UDP Socket Input - { - fprintf (stderr, "M17 UDP IP Frame Input: "); - char * curr; - - curr = strtok(opts.audio_in_dev, ":"); //should be 'm17' - if (curr != NULL) ; //continue - else goto M17ENDIN; //end early with preset values - - curr = strtok(NULL, ":"); //host address - if (curr != NULL) strncpy (opts.m17_hostname, curr, 1023); - - curr = strtok(NULL, ":"); //host port - if (curr != NULL) opts.m17_portno = atoi (curr); - - M17ENDIN: - fprintf (stderr, "%s:", opts.m17_hostname); - fprintf (stderr, "%d \n", opts.m17_portno); - } - - if((strncmp(opts.audio_out_dev, "m17udp", 6) == 0)) //M17 UDP Socket Output - { - fprintf (stderr, "M17 UDP IP Frame Output: "); - char * curr; - - curr = strtok(opts.audio_out_dev, ":"); //should be 'm17' - if (curr != NULL) ; //continue - else goto M17ENDOUT; //end early with preset values - - curr = strtok(NULL, ":"); //host address - if (curr != NULL) strncpy (opts.m17_hostname, curr, 1023); - - curr = strtok(NULL, ":"); //host port - if (curr != NULL) opts.m17_portno = atoi (curr); - - M17ENDOUT: - fprintf (stderr, "%s:", opts.m17_hostname); - fprintf (stderr, "%d \n", opts.m17_portno); - opts.m17_use_ip = 1; //tell the encoder to open the socket - opts.audio_out_type = 9; //set to null device - } - if((strncmp(opts.audio_in_dev, "tcp", 3) == 0)) //tcp socket input from SDR++ and others { fprintf (stderr, "TCP Direct Link: "); @@ -3625,134 +3493,12 @@ signal(SIGINT, handler); signal(SIGTERM, handler); - //read in any user supplied M17 CAN and/or CSD data - if((strncmp(state.m17dat, "M17", 3) == 0)) - { - //read in values - //string in format of M17:can:src_csd:dst_csd:input_rate - - //check and capatalize any letters in the CSD - for (int i = 0; state.m17dat[i]!='\0'; i++) - { - if(state.m17dat[i] >= 'a' && state.m17dat[i] <= 'z') - state.m17dat[i] = state.m17dat[i] -32; - } - - fprintf (stderr, "M17 User Data: "); - char * curr; - - // if((strncmp(state.m17dat, "M17", 3) == 0)) - // goto M17END; - - curr = strtok(state.m17dat, ":"); //should be 'M17' - if (curr != NULL) ; //continue - else goto M17END; //end early with preset values - - curr = strtok(NULL, ":"); //m17 channel access number - if (curr != NULL) - state.m17_can_en = atoi(curr); - - curr = strtok(NULL, ":"); //m17 src address - if (curr != NULL) - { - strncpy (state.str50c, curr, 9); //only read first 9 - state.str50c[9] = '\0'; - } - - curr = strtok(NULL, ":"); //m17 dst address - if (curr != NULL) - { - strncpy (state.str50b, curr, 9); //only read first 9 - state.str50b[9] = '\0'; - } - - curr = strtok(NULL, ":"); //m17 input audio rate - if (curr != NULL) - state.m17_rate = atoi(curr); - - curr = strtok(NULL, ":"); //m17 vox enable - if (curr != NULL) - state.m17_vox = atoi(curr); - - // curr = strtok(NULL, ":"); //moved to in and out methods - // if (curr != NULL) - // opts.m17_use_ip = atoi(curr); - - M17END: ; //do nothing - - //check to make sure can value is no greater than 15 (4 bit value) - if (state.m17_can_en > 15) - state.m17_can_en = 15; - - //if vox is greater than 1, assume user meant 'yes' and set to one - if (state.m17_vox > 1) - state.m17_vox = 1; - - //debug print m17dat string - // fprintf (stderr, " %s;", state.m17dat); - - fprintf (stderr, " M17:%d:%s:%s:%d;", state.m17_can_en, state.str50c, state.str50b, state.m17_rate); - if (state.m17_vox == 1) fprintf (stderr, "VOX;"); - fprintf (stderr, "\n"); - } - if (opts.playfiles == 1) { playMbeFiles (&opts, &state, argc, argv); } - else if (opts.m17encoder == 1) - { - //disable RRC filter for now - opts.use_cosine_filter = 0; - - opts.pulse_digi_rate_out = 8000; - - //open any inputs, if not alread opened, OSS input and output already handled - if (opts.audio_in_type == 0) openPulseInput(&opts); - - #ifdef USE_RTLSDR - else if(opts.audio_in_type == 3) - { - open_rtlsdr_stream(&opts); - opts.rtl_started = 1; - } - #endif - - //open any outputs, if not already opened - if (opts.audio_out_type == 0) openPulseOutput(&opts); - //All input and output now opened and handled correctly, so let's not break things by tweaking - 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) - { - //disable RRC filter for now - opts.use_cosine_filter = 0; - - 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 if (opts.m17decoderip == 1) - { - opts.pulse_digi_rate_out = 8000; - //open any outputs, if not already opened - if (opts.audio_out_type == 0) openPulseOutput(&opts); - processM17IPF(&opts, &state); - } - else { diff --git a/src/dsd_misc.c b/src/dsd_misc.c index cafba49..dc2898b 100644 --- a/src/dsd_misc.c +++ b/src/dsd_misc.c @@ -591,4 +591,131 @@ long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as rms = (long int)sqrt((p-err) / len); if (rms < 0) rms = 150; return rms; -} \ No newline at end of file +} + +//same as symbol levels in m17.h (m17-fme version) +const int8_t symbol_list[4]={-3, -1, +1, +3}; + +/** + * @brief Slice payload symbols into soft dibits. + * Input (RRC filtered baseband sampled at symbol centers) + * should be already normalized to {-3, -1, +1 +3}. + * @param out Soft valued dibits (type-4). + * @param inp Array of 184 floats (1 sample per symbol). + */ +void slice_symbols(uint16_t out[2*SYM_PER_PLD], const float inp[SYM_PER_PLD]) +{ + + for(uint8_t i=0; i=symbol_list[3]) + { + out[i*2+1]=0xFFFF; + } + else if(inp[i]>=symbol_list[2]) + { + out[i*2+1]=-(float)0xFFFF/(symbol_list[3]-symbol_list[2])*symbol_list[2]+inp[i]*(float)0xFFFF/(symbol_list[3]-symbol_list[2]); + } + else if(inp[i]>=symbol_list[1]) + { + out[i*2+1]=0x0000; + } + else if(inp[i]>=symbol_list[0]) + { + out[i*2+1]=(float)0xFFFF/(symbol_list[1]-symbol_list[0])*symbol_list[1]-inp[i]*(float)0xFFFF/(symbol_list[1]-symbol_list[0]); + } + else + { + out[i*2+1]=0xFFFF; + } + + //bit 1 + if(inp[i]>=symbol_list[2]) + { + out[i*2]=0x0000; + } + else if(inp[i]>=symbol_list[1]) + { + out[i*2]=0x7FFF-inp[i]*(float)0xFFFF/(symbol_list[2]-symbol_list[1]); + } + else + { + out[i*2]=0xFFFF; + } + } +} + +/** + * @brief Soft logic NOT. + * + * @param a Input A. + * @return uint16_t Output = not A. + */ +uint16_t soft_bit_NOT(const uint16_t a) +{ + return 0xFFFFU-a; +} + +//randomizing pattern +const uint8_t rand_seq[46]= +{ + 0xD6, 0xB5, 0xE2, 0x30, 0x82, 0xFF, 0x84, 0x62, 0xBA, 0x4E, 0x96, 0x90, 0xD8, 0x98, 0xDD, 0x5D, 0x0C, 0xC8, 0x52, 0x43, 0x91, 0x1D, 0xF8, + 0x6E, 0x68, 0x2F, 0x35, 0xDA, 0x14, 0xEA, 0xCD, 0x76, 0x19, 0x8D, 0xD5, 0x80, 0xD1, 0x33, 0x87, 0x13, 0x57, 0x18, 0x2D, 0x29, 0x78, 0xC3 +}; + +/** + * @brief Randomize type-4 soft bits. + * + * @param inp Input 368 soft type-4 bits. + */ +void randomize_soft_bits(uint16_t inp[SYM_PER_PLD*2]) +{ + for(uint16_t i=0; i>(7-(i%8)))&1) //flip bit if '1' + { + inp[i]=soft_bit_NOT(inp[i]); + } + } +} + +//interleaver pattern +const uint16_t intrl_seq[SYM_PER_PLD*2]= +{ + 0, 137, 90, 227, 180, 317, 270, 39, 360, 129, 82, 219, 172, 309, 262, 31, + 352, 121, 74, 211, 164, 301, 254, 23, 344, 113, 66, 203, 156, 293, 246, 15, + 336, 105, 58, 195, 148, 285, 238, 7, 328, 97, 50, 187, 140, 277, 230, 367, + 320, 89, 42, 179, 132, 269, 222, 359, 312, 81, 34, 171, 124, 261, 214, 351, + 304, 73, 26, 163, 116, 253, 206, 343, 296, 65, 18, 155, 108, 245, 198, 335, + 288, 57, 10, 147, 100, 237, 190, 327, 280, 49, 2, 139, 92, 229, 182, 319, + 272, 41, 362, 131, 84, 221, 174, 311, 264, 33, 354, 123, 76, 213, 166, 303, + 256, 25, 346, 115, 68, 205, 158, 295, 248, 17, 338, 107, 60, 197, 150, 287, + 240, 9, 330, 99, 52, 189, 142, 279, 232, 1, 322, 91, 44, 181, 134, 271, + 224, 361, 314, 83, 36, 173, 126, 263, 216, 353, 306, 75, 28, 165, 118, 255, + 208, 345, 298, 67, 20, 157, 110, 247, 200, 337, 290, 59, 12, 149, 102, 239, + 192, 329, 282, 51, 4, 141, 94, 231, 184, 321, 274, 43, 364, 133, 86, 223, + 176, 313, 266, 35, 356, 125, 78, 215, 168, 305, 258, 27, 348, 117, 70, 207, + 160, 297, 250, 19, 340, 109, 62, 199, 152, 289, 242, 11, 332, 101, 54, 191, + 144, 281, 234, 3, 324, 93, 46, 183, 136, 273, 226, 363, 316, 85, 38, 175, + 128, 265, 218, 355, 308, 77, 30, 167, 120, 257, 210, 347, 300, 69, 22, 159, + 112, 249, 202, 339, 292, 61, 14, 151, 104, 241, 194, 331, 284, 53, 6, 143, + 96, 233, 186, 323, 276, 45, 366, 135, 88, 225, 178, 315, 268, 37, 358, 127, + 80, 217, 170, 307, 260, 29, 350, 119, 72, 209, 162, 299, 252, 21, 342, 111, + 64, 201, 154, 291, 244, 13, 334, 103, 56, 193, 146, 283, 236, 5, 326, 95, + 48, 185, 138, 275, 228, 365, 318, 87, 40, 177, 130, 267, 220, 357, 310, 79, + 32, 169, 122, 259, 212, 349, 302, 71, 24, 161, 114, 251, 204, 341, 294, 63, + 16, 153, 106, 243, 196, 333, 286, 55, 8, 145, 98, 235, 188, 325, 278, 47 +}; + +/** + * @brief Reorder (interleave) 368 soft bits. + * + * @param outp Reordered soft bits. + * @param inp Input soft bits. + */ +void reorder_soft_bits(uint16_t outp[SYM_PER_PLD*2], const uint16_t inp[SYM_PER_PLD*2]) +{ + for(uint16_t i=0; im17encoder == 0) //don't allow menu if using M17 encoder - ncursesMenu (opts, state); - } + ncursesMenu (opts, state); //use k and l keys to test tg hold toggles on slots 1 and slots 2 if (c == 107) //'k' key, hold tg on slot 1 for trunking purposes, or toggle clear @@ -233,7 +230,6 @@ uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c) opts->inverted_dpmr = 1; opts->inverted_x2tdma = 1; opts->inverted_ysf = 1; - opts->inverted_m17 = 1; } else { @@ -241,7 +237,6 @@ uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c) opts->inverted_dpmr = 0; opts->inverted_x2tdma = 0; opts->inverted_ysf = 0; - opts->inverted_m17 = 0; } } @@ -888,16 +883,6 @@ uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c) else opts->use_hpf_d = 0; } - if (opts->m17encoder == 1 && c == 92) //'\' key - toggle M17 encoder Encode + TX - { - if (state->m17encoder_tx == 0) state->m17encoder_tx = 1; - else state->m17encoder_tx = 0; - - //flag on the EOT marker to send last frame after toggling encoder to zero - if (state->m17encoder_tx == 0) state->m17encoder_eot = 1; - - } - if(opts->frame_provoice == 1 && c == 65) //'A' Key, toggle ESK mask 0xA0 { if (state->esk_mask == 0) state->esk_mask = 0xA0; diff --git a/src/dsd_ncurses_menu.c b/src/dsd_ncurses_menu.c index 5feeb30..2e3b099 100644 --- a/src/dsd_ncurses_menu.c +++ b/src/dsd_ncurses_menu.c @@ -1415,7 +1415,6 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) opts->inverted_dpmr = 1; opts->inverted_x2tdma = 1; opts->inverted_ysf = 1; - opts->inverted_m17 = 1; } else { @@ -1423,7 +1422,6 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) opts->inverted_dpmr = 0; opts->inverted_x2tdma = 0; opts->inverted_ysf = 0; - opts->inverted_m17 = 0; } } diff --git a/src/dsd_ncurses_printer.c b/src/dsd_ncurses_printer.c index e86e7c5..5c945e6 100644 --- a/src/dsd_ncurses_printer.c +++ b/src/dsd_ncurses_printer.c @@ -223,9 +223,6 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) printw ("| Symbol Float Input: %s \n", opts->audio_in_dev); } - if (opts->m17decoderip == 1 && opts->udp_sockfd) - printw ("| M17 UDP IP Frame Input: %s:%d \n", opts->m17_hostname, opts->m17_portno); - if (opts->audio_in_type == 8) { printw ("| TCP Signal Input: %s:%d; %d kHz; 1 Ch; ", opts->tcp_hostname, opts->tcp_portno, opts->wav_sample_rate/1000); @@ -336,25 +333,6 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } } - if (opts->m17encoder == 1) - { - printw ("| M17 Encoder:"); - if (state->m17encoder_tx == 1 && state->m17_vox == 0) printw (" Toggle TX (\\) ON ;"); - if (state->m17encoder_tx == 0 && state->m17_vox == 0) printw (" Toggle TX (\\) OFF;"); - if (state->m17_vox == 1) printw (" Vox Mode;"); - printw (" Input Gain (/|*): %02.0f%% ", opts->audio_gainA); - - if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |"); - if (opts->use_hpf == 1) printw ("HP|"); else printw (" |"); - if (opts->use_pbf == 1) printw ("PB|"); else printw (" |"); - if (opts->audio_in_type != 3 && state->m17_vox == 1) printw ( " SQL: %04ld : %04d;", opts->rtl_rms, opts->rtl_squelch_level); - printw ("\n"); - - } - - if (opts->m17_use_ip == 1) - printw ("| M17 UDP IP Frame Output: %s:%d \n", opts->m17_hostname, opts->m17_portno); - if (opts->mbe_out_dir[0] != 0 && opts->dmr_stereo == 0) { printw ("| Writing MBE data files to directory %s\n", opts->mbe_out_dir); @@ -561,7 +539,6 @@ 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] \n", opts->output_name); printw ("| Decoding: [%s] ", opts->output_name); 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 @@ -654,20 +631,22 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) printw ("\n"); printw ("| "); - //fill in any extra info, like Meta (IV, etc) if (state->m17_enc == 1) { - printw (" Scrambler - Type: %d", state->m17_enc_st); + attron(COLOR_PAIR(1)); + printw ("Scrambler - Type: %d", state->m17_enc_st); + attron(COLOR_PAIR(3)); } if (state->m17_enc == 2) { attron(COLOR_PAIR(1)); - printw ("AES-CTR - IV: "); - //display packed meta as IV + printw ("AES-CTR IV: "); + //display AES IV for (i = 0; i < 16; i++) - printw ("%02X", state->m17_meta[i]); + printw ("%02X", state->m17_aes_iv[i]); + attron(COLOR_PAIR(3)); } if (state->m17_enc == 3) @@ -676,6 +655,30 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } printw ("\n"); + printw ("| "); + + //decoded elements from stream + char shortm17[72]; + memset(shortm17, 0, sizeof(shortm17)); + strncpy (shortm17, state->m17_text_string, 70); + shortm17[71] = 0; + printw ("META TEXT: %s", shortm17); + + printw ("\n"); + printw ("| "); + memset(shortm17, 0, sizeof(shortm17)); + strncpy (shortm17, state->m17_gnss_string, 70); + shortm17[71] = 0; + printw ("META GNSS: %s", shortm17); + + printw ("\n"); + printw ("| "); + memset(shortm17, 0, sizeof(shortm17)); + strncpy (shortm17, state->m17_data_string, 70); + shortm17[71] = 0; + printw ("MISC DATA: %s", shortm17); + + printw ("\n"); } diff --git a/src/dsd_rigctl.c b/src/dsd_rigctl.c index d80e789..832149a 100644 --- a/src/dsd_rigctl.c +++ b/src/dsd_rigctl.c @@ -32,7 +32,6 @@ void error(char *msg) { struct sockaddr_in address; struct sockaddr_in addressA; -struct sockaddr_in addressM17; // // Connect @@ -324,18 +323,6 @@ void udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * if (err < nsam) fprintf (stderr, "\n UDP Underflow %ld", err); //I'm not even sure if this is possible } -int m17_socket_receiver(dsd_opts * opts, void * data) -{ - size_t err = 0; - struct sockaddr_in cliaddr; - socklen_t len = sizeof(cliaddr); - - //receive data from socket - err = recvfrom(opts->udp_sockfd, data, 1000, 0, (struct sockaddr * ) & address, &len); //was MSG_WAITALL, but that seems to be = 256 - - return err; -} - //Analog UDP port on +2 of normal open socket void udp_socket_blasterA(dsd_opts * opts, dsd_state * state, size_t nsam, void * data) { @@ -353,20 +340,6 @@ void udp_socket_blasterA(dsd_opts * opts, dsd_state * state, size_t nsam, void * if (err < nsam) fprintf (stderr, "\n UDP Underflow %ld", err); //I'm not even sure if this is possible } -int m17_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data) -{ - UNUSED(state); - unsigned long long int err = 0; - - //See notes in m17.c on line ~3395 regarding usage - - //send audio or data to socket - err = sendto(opts->m17_udp_sock, data, nsam, 0, (const struct sockaddr * ) & addressM17, sizeof(struct sockaddr_in)); - //RETURN Value should be ACKN or NACK, or PING, or PONG - - return (err); -} - int udp_socket_connect(dsd_opts * opts, dsd_state * state) { UNUSED(state); @@ -447,46 +420,6 @@ int udp_socket_connectA(dsd_opts * opts, dsd_state * state) return 0; } -int udp_socket_connectM17(dsd_opts * opts, dsd_state * state) -{ - UNUSED(state); - - long int err = 0; - err = opts->m17_udp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (err < 0) - { - fprintf (stderr, " UDP Socket Error %ld\n", err); - return (err); - } - - // Don't think this is needed, but doesn't seem to hurt to keep it here either - int broadcastEnable = 1; - err = setsockopt(opts->m17_udp_sock, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)); - if (err < 0) - { - fprintf (stderr, " UDP Broadcast Set Error %ld\n", err); - return (err); - } - - memset((char * ) & addressM17, 0, sizeof(addressM17)); - addressM17.sin_family = AF_INET; - err = addressM17.sin_addr.s_addr = inet_addr(opts->m17_hostname); - if (err < 0) //error in this context reports back 32-bit inet_addr reversed order byte pairs - { - fprintf (stderr, " UDP inet_addr Error %ld\n", err); - return (err); - } - - addressM17.sin_port = htons(opts->m17_portno); - if (err < 0) - { - fprintf (stderr, " UDP htons Error %ld\n", err); - return (err); - } - - return 0; -} - void return_to_cc (dsd_opts * opts, dsd_state * state) { //extra safeguards due to sync issues with NXDN diff --git a/src/m17.c b/src/m17.c index 702c5ea..c57bbe7 100644 --- a/src/m17.c +++ b/src/m17.c @@ -1,12 +1,12 @@ /*------------------------------------------------------------------------------- * m17.c - * M17 Decoder and Encoder + * M17 Decoder (simplified version) * * m17_scramble Bit Array from SDR++ * CRC16, CSD encoder from libM17 / M17-Implementations (thanks again, sp5wwp) * * LWVMOBILE - * 2024-03 DSD-FME Florida Man Edition + * 2025-10 DSD-FME Florida Man Edition *-----------------------------------------------------------------------------*/ #include "dsd.h" @@ -46,10 +46,12 @@ uint8_t p1[62] = { 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1 }; +//p2 puncture +static uint8_t p2[12] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}; + uint8_t p3[62] = {1, 1, 1, 1, 1, 1, 1, 0}; -//from M17_Implementations / libM17 -- sp5wwp -- should have just looked here to begin with -//this setup looks very similar to the OP25 variant of crc16, but with a few differences (uses packed bytes) +//from M17_Implementations / libM17 -- sp5wwp uint16_t crc16m17(const uint8_t *in, const uint16_t len) { uint32_t crc = 0xFFFF; //init val @@ -132,22 +134,485 @@ void M17decodeCSD(dsd_state * state, unsigned long long int dst, unsigned long l } -void M17decodeLSF(dsd_state * state) +//NOTE: Current state of DSD-FME is Stripped Down and Simplied M17 stream decoder, only META is passed here +//so, basically, Meta Text, Meta GNSS, Arbitrary Data, and any other Meta only decodes, no packet data SMS, etc +void decodeM17PKT(dsd_opts * opts, dsd_state * state, uint8_t * input, int len) { + //Decode the completed packet + UNUSED(opts); UNUSED(state); int i; + uint8_t protocol = input[0]; + fprintf (stderr, " Protocol:"); + if (protocol == 0x00) fprintf (stderr, " Raw;"); + else if (protocol == 0x01) fprintf (stderr, " AX.25;"); + else if (protocol == 0x02) fprintf (stderr, " APRS;"); + else if (protocol == 0x03) fprintf (stderr, " 6LoWPAN;"); + else if (protocol == 0x04) fprintf (stderr, " IPv4;"); + else if (protocol == 0x05) fprintf (stderr, " SMS;"); + else if (protocol == 0x06) fprintf (stderr, " Winlink;"); + else if (protocol == 0x09) fprintf (stderr, " OTA Key Delivery;"); //m17-fme non standard packet data + else if (protocol == 0x80) fprintf (stderr, " Meta Text Data V2;"); //internal format only from meta + else if (protocol == 0x81) fprintf (stderr, " Meta GNSS Position Data;"); //internal format only from meta + else if (protocol == 0x82) fprintf (stderr, " Meta Text Data V3;"); //internal format only from meta + else if (protocol == 0x91) fprintf (stderr, " PDU GNSS Position Data;"); //PDU Version of GNSS + else if (protocol == 0x98) fprintf (stderr, " Meta Extended CSD;"); //internal format only from meta + else if (protocol == 0x99) fprintf (stderr, " 1600 Arbitrary Data;"); //internal format only from 1600 + else fprintf (stderr, " Res/Unk: %02X;", protocol); //any received but unknown protocol type + + //check for encryption, if encrypted, skip decode and report as encrypted + if (protocol == 0x09) {} //allow OTAKD passthrough (not encrypted ever) + else if (protocol >= 0x80 && protocol <= 0x83) {} //allow META passthrough (not encrypted ever) + else if (state->m17_enc != 0) + { + fprintf (stderr, " *Encrypted*"); + goto PKT_END; + } + + //simple UTF-8 SMS Decoder + if (protocol == 0x05) + { + fprintf (stderr, "\n SMS: "); + for (i = 1; i < len; i++) + { + fprintf (stderr, "%c", input[i]); + + //add line break to keep it under 80 columns + if ( (i%71) == 0 && i != 0) + fprintf (stderr, "\n "); + } + } + + //Extended Call Sign Data (depreciated in Version 3.0, but leaving for older soft/samples, etc) + else if (protocol == 0x98) + { + //NOTE: If doing a shift addition like this, make sure ALL values have (unsigned long long int) in front of it, not just the ones that 'needed' it + unsigned long long int src = ((unsigned long long int)input[1] << 40ULL) + ((unsigned long long int)input[2] << 32ULL) + ((unsigned long long int)input[3] << 24ULL) + ((unsigned long long int)input[4] << 16ULL) + ((unsigned long long int)input[5] << 8ULL) + ((unsigned long long int)input[6] << 0ULL); + unsigned long long int dst = ((unsigned long long int)input[7] << 40ULL) + ((unsigned long long int)input[8] << 32ULL) + ((unsigned long long int)input[9] << 24ULL) + ((unsigned long long int)input[10] << 16ULL) + ((unsigned long long int)input[11] << 8ULL) + ((unsigned long long int)input[12] << 0ULL); + char cf1[10]; memset (cf1, 0, 10*sizeof(char)); + char cf2[10]; memset (cf2, 0, 10*sizeof(char)); + fprintf (stderr, " CF1: "); //Contextual CF1 + for (i = 0; i < 9; i++) + { + char c = b40[src % 40]; + fprintf (stderr, "%c", c); + cf1[i] = c; + src = src / 40; + } + if (dst != 0) //if used + { + fprintf (stderr, " CF2: "); //Contextual CF2 + for (i = 0; i < 9; i++) + { + char c = b40[dst % 40]; + fprintf (stderr, "%c", c); + cf2[i] = c; + dst = dst / 40; + } + } + + sprintf (state->m17_data_string, "Extended CSD - CF1: %s; CF2: %s;", cf1, cf2); + } + + //GNSS Positioning (version 2.0 spec) + else if (protocol == 0x81) + { + //Decode GNSS Elements + uint8_t data_source = (input[1] >> 4); + uint8_t station_type = (input[1] & 0xF); + uint8_t validity = (input[2] >> 4); + uint8_t radius = (input[2] >> 1) & 0x7; + uint16_t bearing = ((input[2] & 0x1) << 8) + input[3]; + uint32_t latitude = (input[4] << 16) + (input[5] << 8) + input[6]; + uint32_t longitude = (input[7] << 16) + (input[8] << 8) + input[9]; + uint16_t altitude = (input[10] << 8) + input[11]; + uint16_t speed = (input[12] << 4) + (input[13] >> 4); + uint16_t reserved = ((input[13] & 0xF) << 8) + input[14]; + + //signed-ness and two's complement (needs to be tested and verified) + double lat_sign = +1.0; + if (latitude & 0x800000) + { + if (latitude > 0x800000) + { + latitude &= 0x7FFFFF; + latitude = 0x800000 - latitude; + } + + lat_sign = -1.0f; + } + + double lon_sign = 1.0f; + if (longitude & 0x800000) + { + if (longitude > 0x800000) + { + longitude &= 0x7FFFFF; + longitude = 0x800000 - longitude; + } + + lon_sign = -1.0f; + } + + //decoding calculation + double lat_float = ((double)latitude * 90.0f) / 8388607.0f * lat_sign; + double lon_float = ((double)longitude * 180.0f) / 8388607.0f * lon_sign; + + float radius_float = powf(2.0f, radius); + float speed_float = ((float)speed * 0.5f); + float altitude_float = ((float)altitude * 0.5f) - 500.0f; + + char deg_glyph[4]; + sprintf (deg_glyph, "%s", "°"); + + if (validity & 0x8) + fprintf (stderr, "\n GPS: (%f, %f);", lat_float, lon_float); + else fprintf (stderr, "\n GPS Not Valid;"); + + if (validity & 0x4) + fprintf (stderr, " Altitude: %.1f m;", altitude_float); + + if (validity & 0x2) + { + fprintf (stderr, " Speed: %.1f km/h;", speed_float); + fprintf (stderr, " Bearing: %d%s;", bearing, deg_glyph); + } + + if (validity & 0x1) + fprintf (stderr, "\n Radius: %.1f;", radius_float); + + if (reserved) + fprintf (stderr, " Reserved: %03X;", reserved); + + if (data_source == 0) fprintf (stderr, " M17 Client;"); + else if (data_source == 1) fprintf (stderr, " OpenRTX;"); + else fprintf (stderr, " Other Data Source: %0X;", data_source); + + if (station_type == 0) fprintf (stderr, " Fixed Station;"); + else if (station_type == 1) fprintf (stderr, " Mobile Station;"); + else if (station_type == 2) fprintf (stderr, " Handheld;"); + else fprintf (stderr, " Reserved Station Type: %0X;", station_type); + + char st[4]; + if (station_type == 0) sprintf (st, "FS"); + else if (station_type == 1) sprintf (st, "MS"); + else if (station_type == 2) sprintf (st, "HH"); + else sprintf (st, "%02X", station_type); + + //TODO: This to ncurses display? + sprintf (state->m17_gnss_string, "(%f, %f); Alt: %.1f; Spd: %.1f; Ber: %d; St: %s;", + lat_float, lon_float, altitude_float, speed_float, bearing, st); + + //now it is okay to change the protocol to 0x81 + if (protocol == 0x91) //PDU variant of GNSS + protocol = 0x81; + + } + + //Meta Text Messages Version 2.0 (4-segment with bitmapping) + else if (protocol == 0x80) + { + + uint8_t bitmap_len = (input[1] >> 4); + uint8_t bitmap_segment = input[1] & 0xF; + uint8_t segment_len = 1; + uint8_t segment_num = 1; + + //convert bitmap to actual values + if (bitmap_len == 0x1) + segment_len = 1; + else if (bitmap_len == 0x3) + segment_len = 2; + else if (bitmap_len == 0x7) + segment_len = 3; + else if (bitmap_len == 0xF) + segment_len = 4; + else segment_len = 1; //if none of these, then treat this like a single segment w/ len 1 + + //convert bitmap to actual values + if (bitmap_segment == 0x1) + segment_num = 1; + else if (bitmap_segment == 0x2) + segment_num = 2; + else if (bitmap_segment == 0x4) + segment_num = 3; + else if (bitmap_segment == 0x8) + segment_num = 4; + else segment_num = 1; //if none of these, then treat this like a single segment w/ len 1 + + //show Control Byte Len and Segment Values on Meta Text + fprintf (stderr, " %d/%d; ", segment_num, segment_len); + // if (super->opts.payload_verbosity > 0) + { + for (i = 2; i < len; i++) + fprintf (stderr, "%c", input[i]); + } + + //copy current segment into m17_text_string + int ptr = (segment_num-1)*13; + memcpy (state->m17_text_string+ptr, input+2, 13*sizeof(char)); + + //NOTE: there is no checkdown to see if all segments have arrived or not + //terminate the string on completion, dump completed string + if (segment_len == segment_num) + { + state->m17_text_string[ptr+13] = 0; + fprintf (stderr, "\n Complete Meta Text: %s", state->m17_text_string); + } + + //TODO: This + //send to event_log_writer + // if (segment_len == segment_num) + // event_log_writer (super, state->m17_text_string, protocol); + + } + + //Meta Text Messages Version 3.0 (15-segment sequential) + else if (protocol == 0x82) + { + + uint8_t segment_len = (input[1] >> 4) & 0xF; + uint8_t segment_num = (input[1] >> 0) & 0xF; + + //show Control Byte Len and Segment Values on Meta Text + fprintf (stderr, " %d/%d; ", segment_num, segment_len); + // if (super->opts.payload_verbosity > 0) + { + for (i = 2; i < len; i++) + fprintf (stderr, "%c", input[i]); + } + + //copy current segment into .dat + int ptr = (segment_num-1)*13; + memcpy (state->m17_text_string+ptr, input+2, 13*sizeof(char)); + + //NOTE: there is no checkdown to see if all segments have arrived or not + //terminate the string on completion, dump completed string + if (segment_len == segment_num) + { + state->m17_text_string[ptr+13] = 0; + fprintf (stderr, "\n Complete Meta Text: %s", state->m17_text_string); + } + + //TODO: This + // //send to event_log_writer + // if (segment_len == segment_num) + // event_log_writer (super, state->m17_text_string, protocol); + + } + + //1600 Arbitrary Data as Text String + else if (protocol == 0x99) + { + + sprintf (state->m17_data_string, "%s", ""); + + fprintf (stderr, " "); + for (i = 1; i < len; i++) + fprintf (stderr, "%c", input[i]); + + memcpy (state->m17_data_string, input+1, len); + + //todo: this + // event_log_writer (super, state->m17_data_string, protocol); + + } + + //Any Other Raw Data as Hex + else + { + fprintf (stderr, " "); + for (i = 1; i < len; i++) + fprintf (stderr, "%02X", input[i]); + } + + PKT_END: ; //do nothing + +} + +void decode_lsf_v3_contents(dsd_state * state) +{ + + unsigned long long int lsf_dst = (unsigned long long int)ConvertBitIntoBytes(&state->m17_lsf[0], 48); + unsigned long long int lsf_src = (unsigned long long int)ConvertBitIntoBytes(&state->m17_lsf[48], 48); + + //LSF Verison 3.0 Type Field + uint16_t lsf_type = (uint16_t)convert_bits_into_output(&state->m17_lsf[96], 16); + + //LSF Type Field broken into its sub fields + uint16_t payload_contents = (lsf_type >> 12) & 0xF; + uint16_t encryption_type = (lsf_type >> 9) & 0x7; + uint16_t signature = (lsf_type >> 8) & 0x1; + uint16_t meta_contents = (lsf_type >> 4) & 0xF; + uint16_t can = (lsf_type >> 0) & 0xF; + + //store this so we can reference it for playing voice and/or decoding data, dst/src etc + state->m17_str_dt = payload_contents; + state->m17_dst = lsf_dst; + state->m17_src = lsf_src; + state->m17_can = can; + + fprintf (stderr, "\n"); + + fprintf (stderr, " CAN: %d", can); + M17decodeCSD(state, lsf_dst, lsf_src); + + if (payload_contents == 0x1) fprintf (stderr, " Stream Data"); + else if (payload_contents == 0x2) fprintf (stderr, " Voice (3200bps)"); + else if (payload_contents == 0x3) fprintf (stderr, " Voice (1600bps)"); + else if (payload_contents == 0xF) fprintf (stderr, " Packet Data"); + else fprintf (stderr, " Reserved: %X", payload_contents); + + if (signature) fprintf (stderr, " Signed (secp256r1);"); + + //compatibility shim for current code and call history / event log (remove later if redone) + if (payload_contents != 0 && payload_contents < 4) + state->m17_str_dt = payload_contents; + else if (payload_contents == 0xF) + state->m17_str_dt = 20; + + //decode encryption_type (to maintain a level of backwards compatibility, + //the old encryption type and subtype values will be used only for encryption) + if (encryption_type != 0) + { + fprintf (stderr, "\n ENC:"); + + if (encryption_type == 0x1) + { + fprintf (stderr, " Scrambler (8-bit);"); + state->m17_enc = 1; + state->m17_enc_st = 0; + } + else if (encryption_type == 0x2) + { + fprintf (stderr, " Scrambler (16-bit);"); + state->m17_enc = 1; + state->m17_enc_st = 1; + } + else if (encryption_type == 0x3) + { + fprintf (stderr, " Scrambler (24-bit);"); + state->m17_enc = 1; + state->m17_enc_st = 2; + } + + else if (encryption_type == 0x4) + { + fprintf (stderr, " AES-CTR (128-bit);"); + state->m17_enc = 2; + state->m17_enc_st = 0; + } + else if (encryption_type == 0x5) + { + fprintf (stderr, " AES-CTR (192-bit);"); + state->m17_enc = 2; + state->m17_enc_st = 1; + } + else if (encryption_type == 0x6) + { + fprintf (stderr, " AES-CTR (256-bit);"); + state->m17_enc = 2; + state->m17_enc_st = 2; + } + + else if (encryption_type == 0x7) + { + fprintf (stderr, " Reserved Enc (0x7);"); + state->m17_enc = 3; + state->m17_enc_st = 3; + } + + if (encryption_type > 0x3 && encryption_type <= 0x6) + { + fprintf (stderr, " IV: "); + for (int i = 0; i < 16; i++) + fprintf (stderr, "%02X", state->m17_aes_iv[i]); + } + + } + else + { + state->m17_enc = 0; + state->m17_enc_st = 0; + } + + //pack meta bits either meta, or AES IV, depending on encryption type + if (meta_contents != 0xF) + { + for (int i = 0; i < 14; i++) + state->m17_meta[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[(i*8)+112], 8); + } + else if (meta_contents == 0xF) + { + memset(state->m17_meta, 0, sizeof(state->m17_meta)); + for (int i = 0; i < 14; i++) + state->m17_aes_iv[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[(i*8)+112], 8); + } + + //using meta_sum in case some byte fields, particularly meta[0], are zero + uint32_t meta_sum = 0; + for (int i = 0; i < 14; i++) + meta_sum += state->m17_meta[i]; + + //Decode Meta Data when meta_contents available and meta sum is not zero + if (meta_contents != 0 && meta_contents != 0xF && meta_sum != 0) + { + uint8_t meta[15]; meta[0] = meta_contents + 0x80; //add identifier for pkt decoder + for (int i = 0; i < 14; i++) meta[i+1] = state->m17_meta[i]; + fprintf (stderr, "\n "); + //Note: We don't have opts here, so in the future, if we need it, we will need to pass it here + decodeM17PKT (NULL, state, meta, 15); //decode META + } + + //Payload Dump on LSF Type + // if (opts->payload == 1) opts not passed here + { + fprintf (stderr, "\n"); + fprintf (stderr, " FT: %04X;", lsf_type); + fprintf (stderr, " PAY: %X;", payload_contents); + fprintf (stderr, " ENC: %X;", encryption_type); + fprintf (stderr, " SIG: %X;", signature); + fprintf (stderr, " META: %X;", meta_contents); + } + +} + +void decode_lsf_v2_contents(dsd_state * state) +{ + unsigned long long int lsf_dst = (unsigned long long int)ConvertBitIntoBytes(&state->m17_lsf[0], 48); unsigned long long int lsf_src = (unsigned long long int)ConvertBitIntoBytes(&state->m17_lsf[48], 48); uint16_t lsf_type = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[96], 16); //this is the way the manual/code expects you to read these bits - // uint8_t lsf_ps = (lsf_type >> 0) & 0x1; + // uint8_t lsf_ps = (lsf_type >> 0) & 0x1; //not referenced since we just do the embedded LSF in Stream Frame here uint8_t lsf_dt = (lsf_type >> 1) & 0x3; uint8_t lsf_et = (lsf_type >> 3) & 0x3; uint8_t lsf_es = (lsf_type >> 5) & 0x3; uint8_t lsf_cn = (lsf_type >> 7) & 0xF; uint8_t lsf_rs = (lsf_type >> 11) & 0x1F; + //decode behavior debug + // lsf_rs |= 0x10; + + //ECDSA signature included + uint8_t is_signed = 0; + + //Seperate the Signed bit from the reserved field, shift right once + if (lsf_rs & 1) + { + is_signed = 1; + lsf_rs >>= 1; + } + + //if this field is not zero, then this is not a standard V2.0 or older spec'd LSF type, + //if proposed LSF TYPE field changes occur, this region will be 0 for V2.0, and not 0 for newer + if (lsf_rs != 0) + { + fprintf (stderr, " Unknown LSF TYPE;"); //V3.0 in future spec? + goto LSF_END; + } + //store this so we can reference it for playing voice and/or decoding data, dst/src etc state->m17_str_dt = lsf_dt; state->m17_dst = lsf_dst; @@ -156,10 +621,6 @@ void M17decodeLSF(dsd_state * state) fprintf (stderr, "\n"); - //packet or stream - // if (lsf_ps == 0) fprintf (stderr, " P-"); - // if (lsf_ps == 1) fprintf (stderr, " S-"); - fprintf (stderr, " CAN: %d", lsf_cn); M17decodeCSD(state, lsf_dst, lsf_src); @@ -169,69 +630,96 @@ void M17decodeLSF(dsd_state * state) if (lsf_dt == 3) fprintf (stderr, " Voice (1600bps)"); if (lsf_rs != 0) fprintf (stderr, " RS: %02X", lsf_rs); - fprintf (stderr, "\n"); - if (lsf_et != 0) fprintf (stderr, " ENC:"); - if (lsf_et == 2) fprintf (stderr, " AES-CTR"); - if (lsf_et == 1) fprintf (stderr, " Scrambler - %d", lsf_es); + + // fprintf (stderr, "\n"); //do we need this? + + if (lsf_et != 0) fprintf (stderr, "\n ENC:"); + if (lsf_et == 1) + { + fprintf (stderr, " Scrambler"); + if (lsf_es == 0) + fprintf (stderr, " (8-bit);"); + else if (lsf_es == 1) + fprintf (stderr, " (16-bit);"); + else if (lsf_es == 2) + fprintf (stderr, " (24-bit);"); + } + if (lsf_et == 2) + { + fprintf (stderr, " AES"); + if (lsf_es == 0) + fprintf (stderr, " 128;"); + else if (lsf_es == 1) + fprintf (stderr, " 192;"); + else if (lsf_es == 2) + fprintf (stderr, " 256;"); + } + + if (is_signed) + fprintf (stderr, " Signed (secp256r1);"); state->m17_enc = lsf_et; state->m17_enc_st = lsf_es; - if (lsf_rs != 0) + //pack meta bits either meta, or AES IV, depending on encryption type + if (lsf_et == 0) { - if (lsf_rs == 0x10) - fprintf (stderr, " OTAKD Data Packet;"); - else if (lsf_rs == 0x11) - { - fprintf (stderr, " OTAKD Embedded LSF;\n"); - goto LSF_END; - } + memset(state->m17_aes_iv, 0, sizeof(state->m17_aes_iv)); + for (int i = 0; i < 14; i++) + state->m17_meta[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[(i*8)+112], 8); + } + else if (lsf_et == 2) + { + memset(state->m17_meta, 0, sizeof(state->m17_meta)); + for (int i = 0; i < 14; i++) + state->m17_aes_iv[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[(i*8)+112], 8); } - - //compare incoming META/IV value on AES, if timestamp 32-bits are not within a time 5 minute window, then throw a warning - // long long int epoch = 1577836800LL; //Jan 1, 2020, 00:00:00 UTC - // uint32_t tsn = ( (time(NULL)-epoch) & 0xFFFFFFFF); //current LSB 32-bit value - // uint32_t tsi = (uint32_t)ConvertBitIntoBytes(&state->m17_lsf[112], 32); //OTA LSB 32-bit value - // uint32_t dif = abs(tsn-tsi); - // if (lsf_et == 2 && dif > 3600) fprintf (stderr, " \n Warning! Time Difference > %d secs; Potential NONCE/IV Replay!\n", dif); - - //debug - // fprintf (stderr, "TSN: %ld; TSI: %ld; DIF: %ld;", tsn, tsi, dif); - - //pack meta bits into 14 bytes - for (i = 0; i < 14; i++) - state->m17_meta[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[(i*8)+112], 8); //using meta_sum in case some byte fields, particularly meta[0], are zero uint32_t meta_sum = 0; - for (i = 0; i < 14; i++) + for (int i = 0; i < 14; i++) meta_sum += state->m17_meta[i]; //Decode Meta Data when not ENC (if meta field is populated with something) if (lsf_et == 0 && meta_sum != 0) { uint8_t meta[15]; meta[0] = lsf_es + 0x80; //add identifier for pkt decoder - for (i = 0; i < 14; i++) meta[i+1] = state->m17_meta[i]; + + //re-map older values to newer internal values + //Extended CSD currently removed from 3.0, so just map it to depreciated new value of 0x98 + if (meta[0] == 0x82) + meta[0] = 0x98; + + for (int i = 0; i < 14; i++) + meta[i+1] = state->m17_meta[i]; + fprintf (stderr, "\n "); //Note: We don't have opts here, so in the future, if we need it, we will need to pass it here decodeM17PKT (NULL, state, meta, 15); //decode META } - //if no Meta (debug) - // if (lsf_et == 0 && meta_sum == 0) - // fprintf (stderr, " Meta Null; "); - if (lsf_et == 2) { fprintf (stderr, " IV: "); - for (i = 0; i < 16; i++) - fprintf (stderr, "%02X", state->m17_meta[i]); + for (int i = 0; i < 16; i++) + fprintf (stderr, "%02X", state->m17_aes_iv[i]); } LSF_END: ; //do nothing } +//gate function to determine if this is v2, or v3, and proceed accordingly +void M17decodeLSF(dsd_state * state) +{ + uint16_t lsf_type = (uint16_t)convert_bits_into_output(&state->m17_lsf[96], 16); + uint16_t version_check = lsf_type >> 12; + + if (version_check == 0) + decode_lsf_v2_contents(state); + else decode_lsf_v3_contents(state); +} + int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t * lich_bits) { int i, j, err; @@ -338,7 +826,7 @@ int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t * lich_bits) return err; } -void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload) +void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload, uint8_t lich_cnt) { int i; @@ -351,13 +839,6 @@ void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload voice2[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+64], 8); } - //TODO: Add some decryption methods - if (state->m17_enc != 0) - { - //process scrambler or AES-CTR decryption - //(no AES-CTR right now, Scrambler should be easy enough) - } - if (opts->payload == 1) { fprintf (stderr, "\n CODEC2: "); @@ -381,6 +862,15 @@ void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload short prev; int j; + //look at current viterbi error / cost metric, + //if exceeds threshold, substitute silence frame + if (state->m17_viterbi_err >= 25.0f) + { + uint64_t silence = 0x010004002575DDF2; + for (int i = 0; i < 8; i++) + voice1[i] = (silence >> (56ULL-(i*8))) & 0xFF; + } + codec2_decode(state->codec2_1600, samp1, voice1); //hpf_d on codec2 sounds better than not on those .rrc samples @@ -457,16 +947,23 @@ void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload #endif - //handle arbitrary data - uint8_t adata[9]; adata[0] = 0x89; //set so pkt decoder will rip these out as just utf-8 chars - for (i = 0; i < 8; i++) - adata[i+1] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+64], 8); + //Arbitrary Data Storage Across Superframe - //look and see if the payload has stuff in it first, if not, then run this - if (adata[1] != 0 || adata[2] != 0 || adata[3] != 0 || adata[4] != 0 || adata[5] != 0 || adata[6] != 0 || adata[7] != 0 || adata[8] != 0) + //sanity check + if (lich_cnt > 5) + lich_cnt = 5; + + //append incoming arbitrary data segment to pdu_sf array + memcpy (state->dmr_pdu_sf[0]+(lich_cnt*64), payload+64, 64); + + if (lich_cnt == 5) { + //6 x 8 octets, plus one protocol octet + uint8_t adata[49]; adata[0] = 0x99; + pack_bit_array_into_byte_array (state->dmr_pdu_sf[0], adata+1, 48); fprintf (stderr, "\n"); //linebreak - decodeM17PKT (opts, state, adata, 9); //decode Arbitrary Data as UTF-8 + decodeM17PKT (opts, state, adata, 48); //decode Arbitrary Data as UTF-8 + memset (state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0])); } } @@ -483,13 +980,6 @@ void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t * payload voice2[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+64], 8); } - //TODO: Add some decryption methods - if (state->m17_enc != 0) - { - //process scrambler or AES-CTR decryption - //(no AES-CTR right now, Scrambler should be easy enough) - } - if (opts->payload == 1) { fprintf (stderr, "\n CODEC2: "); @@ -515,6 +1005,18 @@ void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t * payload short prev; int j; + //look at current viterbi error / cost metric, + //if exceeds threshold, substitute silence frame + if (state->m17_viterbi_err >= 25.0f) + { + uint64_t silence = 0x010009439CE42108; + for (int i = 0; i < 8; i++) + { + voice1[i] = (silence >> (56ULL-(i*8))) & 0xFF; + voice2[i] = (silence >> (56ULL-(i*8))) & 0xFF; + } + } + codec2_decode(state->codec2_3200, samp1, voice1); codec2_decode(state->codec2_3200, samp2, voice2); @@ -620,107 +1122,74 @@ void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t * payload } -void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t * m17_bits) +void prepare_str(dsd_opts * opts, dsd_state * state, float * sbuf) { + int i; + uint16_t soft_bit[2*SYM_PER_PLD]; //raw frame soft bits + uint16_t d_soft_bit[2*SYM_PER_PLD]; //deinterleaved soft bits + uint8_t viterbi_bytes[31]; //packed viterbi return bytes + uint32_t error = 0; //viterbi error - int i, k, x; - uint8_t m17_punc[275]; //25 * 11 = 275 - memset (m17_punc, 0, sizeof(m17_punc)); - for (i = 0; i < 272; i++) - m17_punc[i] = m17_bits[i+96]; - - //depuncture the bits - uint8_t m17_depunc[300]; //25 * 12 = 300 - memset (m17_depunc, 0, sizeof(m17_depunc)); - k = 0; x = 0; - for (i = 0; i < 25; i++) - { - m17_depunc[k++] = m17_punc[x++]; - m17_depunc[k++] = m17_punc[x++]; - m17_depunc[k++] = m17_punc[x++]; - m17_depunc[k++] = m17_punc[x++]; - m17_depunc[k++] = m17_punc[x++]; - m17_depunc[k++] = m17_punc[x++]; - m17_depunc[k++] = m17_punc[x++]; - m17_depunc[k++] = m17_punc[x++]; - m17_depunc[k++] = m17_punc[x++]; - m17_depunc[k++] = m17_punc[x++]; - m17_depunc[k++] = m17_punc[x++]; - m17_depunc[k++] = 0; - } - - //setup the convolutional decoder - uint8_t temp[300]; - uint8_t s0; - uint8_t s1; - uint8_t m_data[28]; - uint8_t trellis_buf[144]; - memset (trellis_buf, 0, sizeof(trellis_buf)); - memset (temp, 0, sizeof (temp)); - memset (m_data, 0, sizeof (m_data)); - - for (i = 0; i < 296; i++) - temp[i] = m17_depunc[i] << 1; - - CNXDNConvolution_start(); - for (i = 0; i < 148; i++) - { - s0 = temp[(2*i)]; - s1 = temp[(2*i)+1]; - - CNXDNConvolution_decode(s0, s1); - } - - CNXDNConvolution_chainback(m_data, 144); - - //144/8 = 18, last 4 (144-148) are trailing zeroes - for(i = 0; i < 18; i++) - { - trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1; - trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1; - trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1; - trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1; - trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1; - trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1; - trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1; - trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1; - } - - //load m_data into bits for either data packets or voice packets + uint8_t stream_bits[144]; //128+16 uint8_t payload[128]; uint8_t end = 9; uint16_t fn = 0; + + memset(soft_bit, 0, sizeof(soft_bit)); + memset(d_soft_bit, 0, sizeof(d_soft_bit)); + memset(viterbi_bytes, 0, sizeof(viterbi_bytes)); + + memset (stream_bits, 0, sizeof(stream_bits)); memset (payload, 0, sizeof(payload)); - end = trellis_buf[0]; - fn = (uint16_t)ConvertBitIntoBytes(&trellis_buf[1], 15); + //libm17 magic + //slice symbols to soft dibits + slice_symbols(soft_bit, sbuf); - //insert fn bits into meta 14 and meta 15 for Initialization Vector - state->m17_meta[14] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[1], 7); - state->m17_meta[15] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[8], 8); + //derandomize + randomize_soft_bits(soft_bit); - if (opts->payload == 1) - fprintf (stderr, " FSN: %05d", fn); + //deinterleave + reorder_soft_bits(d_soft_bit, soft_bit); + + //viterbi + error = viterbi_decode_punctured(viterbi_bytes, d_soft_bit+96, p2, 272, 12); + + //track viterbi error / cost metric + state->m17_viterbi_err = (float)error/(float)0xFFFF; + + //load viterbi_bytes into bits for either data packets or voice packets + unpack_byte_array_into_bit_array(viterbi_bytes+1, stream_bits, 18); //18*8 = 144 + + end = stream_bits[0]; + fn = (uint16_t)convert_bits_into_output(&stream_bits[1], 15); + + //insert fn bits into aes_iv 14 and meta 15 for Initialization Vector + state->m17_aes_iv[14] = (uint8_t)convert_bits_into_output(&stream_bits[1], 7); + state->m17_aes_iv[15] = (uint8_t)convert_bits_into_output(&stream_bits[8], 8); + + //Frame Number + fprintf (stderr, " FN: %04X", fn); + + //viterbi error + fprintf (stderr, " Ve: %1.1f; ", (float)error/(float)0xFFFF); if (end == 1) fprintf (stderr, " END;"); for (i = 0; i < 128; i++) - payload[i] = trellis_buf[i+16]; + payload[i] = stream_bits[i+16]; if (state->m17_str_dt == 2) M17processCodec2_3200(opts, state, payload); else if (state->m17_str_dt == 3) - M17processCodec2_1600(opts, state, payload); - else if (state->m17_str_dt == 1) fprintf (stderr, " DATA;"); - else if (state->m17_str_dt == 0) fprintf (stderr, " RES;"); - // else fprintf (stderr, " UNK;"); + M17processCodec2_1600(opts, state, payload, fn%6); - if (opts->payload == 1 && state->m17_str_dt < 2) + if (opts->payload == 1 && state->m17_str_dt != 2 && state->m17_str_dt != 3) { fprintf (stderr, "\n STREAM: "); for (i = 0; i < 18; i++) - fprintf (stderr, "[%02X]", (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8)); + fprintf (stderr, "[%02X]", (uint8_t)ConvertBitIntoBytes(&stream_bits[i*8], 8)); } } @@ -729,15 +1198,17 @@ void processM17STR(dsd_opts * opts, dsd_state * state) { int i, x; - //overflow/memory issue returns in Cygwin for...reasons... - uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits) + + uint8_t dbuf[184]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits) + float sbuf[184]; //float symbol buffer uint8_t m17_rnd_bits[368]; //368 bits that are still scrambled (randomized) uint8_t m17_int_bits[368]; //368 bits that are still interleaved - uint8_t m17_bits[368]; //368 bits that have been de-interleaved and de-scramble + uint8_t m17_bits[368]; //368 bits that have been de-interleaved and de-scramble uint8_t lich_bits[96]; int lich_err = -1; memset (dbuf, 0, sizeof(dbuf)); + memset (sbuf, 0, sizeof(sbuf)); memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits)); memset (m17_int_bits, 0, sizeof(m17_int_bits)); memset (m17_bits, 0, sizeof(m17_bits)); @@ -754,6 +1225,16 @@ void processM17STR(dsd_opts * opts, dsd_state * state) m17_rnd_bits[i*2+1] = (dbuf[i] >> 0) & 1; } + //convert dbuf into a symbol array + for (i = 0; i < 184; i++) + { + if (dbuf[i] == 0) sbuf[i] = +1.0f; + else if (dbuf[i] == 1) sbuf[i] = +3.0f; + else if (dbuf[i] == 2) sbuf[i] = -1.0f; + else if (dbuf[i] == 3) sbuf[i] = -3.0f; + else sbuf[i] = +0.0f; + } + //descramble the frame for (i = 0; i < 368; i++) m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1; @@ -773,3111 +1254,9 @@ void processM17STR(dsd_opts * opts, dsd_state * state) lich_err = M17processLICH(state, opts, lich_bits); if (lich_err == 0) - M17prepareStream(opts, state, m17_bits); - - // if (lich_err != 0) state->lastsynctype = -1; //disable + prepare_str(opts, state, sbuf); //ending linebreak fprintf (stderr, "\n"); -} //end processM17STR - -//original version using nxdn convolutional decoder -void processM17LSF(dsd_opts * opts, dsd_state * state) -{ - - //NOTE: Works now with decisions based on previous bit, but still - //not quite as good as it needs to be, need better decision making on the punctured bit - - int i, j, k, x; - uint8_t dbuf[184]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits) - uint8_t m17_rnd_bits[368]; //368 bits that are still scrambled (randomized) - uint8_t m17_int_bits[368]; //368 bits that are still interleaved - uint8_t m17_bits[368]; //368 bits that have been de-interleaved and de-scrambled - uint8_t m17_depunc[500]; //488 bits after depuncturing - - memset (dbuf, 0, sizeof(dbuf)); - memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits)); - memset (m17_int_bits, 0, sizeof(m17_int_bits)); - memset (m17_bits, 0, sizeof(m17_bits)); - memset (m17_depunc, 0, sizeof(m17_depunc)); - - //load dibits into dibit buffer - for (i = 0; i < 184; i++) - dbuf[i] = (uint8_t) getDibit(opts, state); - - //convert dbuf into a bit array - for (i = 0; i < 184; i++) - { - m17_rnd_bits[i*2+0] = (dbuf[i] >> 1) & 1; - m17_rnd_bits[i*2+1] = (dbuf[i] >> 0) & 1; - } - - //descramble the frame - for (i = 0; i < 368; i++) - m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1; - - //deinterleave 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_bits[i] = m17_int_bits[x]; - } - - j = 0; k = 0; x = 0; - - // P1 Depuncture - for (i = 0; i < 488; i++) - { - //assign any puncture as a 0 - // if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++]; - // else m17_depunc[x++] = 0; - - - //seems to be better if we use the last bit as an educated guess on what the next bit should be - //this pseudo logic is based purely on 0xFFFFFFFFFF as Broadcast, and all zeroes as the Meta(IV) - - //DST, or META field - if (i < 48 || i > 96) - { - if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++]; - else if (m17_depunc[x-2] == 1) m17_depunc[x++] = 1; - else m17_depunc[x++] = 0; - } - else //any other field - { - if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++]; - else m17_depunc[x++] = 0; - } - - - - if (k == 61) k = 0; //61 -- should reset 8 times againt the array - - } - - //debug -- values seem okay at end of run - // fprintf (stderr, "K = %d; J = %d; X = %d", k, j, x); - - //debug deinterleaved bits - // fprintf (stderr, "\n DEINT: "); - // for (i = 0; i < 368; i++) - // fprintf (stderr, "%d,", m17_bits[i]); - - //debug depunctured bits - // fprintf (stderr, "\n DEPUNC: "); - // for (i = 0; i < 488; i++) - // fprintf (stderr, "%d,", m17_depunc[i]); - - //setup the convolutional decoder - uint8_t temp[500]; - uint8_t s0; - uint8_t s1; - uint8_t m_data[32]; - uint8_t trellis_buf[260]; //30*8 = 240 - memset (trellis_buf, 0, sizeof(trellis_buf)); - memset (temp, 0, sizeof (temp)); - memset (m_data, 0, sizeof (m_data)); - - for (i = 0; i < 488; i++) - temp[i] = m17_depunc[i] << 1; - - CNXDNConvolution_start(); - for (i = 0; i < 244; i++) - { - s0 = temp[(2*i)]; - s1 = temp[(2*i)+1]; - - CNXDNConvolution_decode(s0, s1); - } - - CNXDNConvolution_chainback(m_data, 240); - - //244/8 = 30, last 4 (244-248) are trailing zeroes - for(i = 0; i < 30; i++) - { - trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1; - trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1; - trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1; - trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1; - trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1; - trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1; - trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1; - trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1; - } - - memset (state->m17_lsf, 0, sizeof(state->m17_lsf)); - memcpy (state->m17_lsf, trellis_buf, 240); - - uint8_t lsf_packed[30]; - memset (lsf_packed, 0, sizeof(lsf_packed)); - - //need to pack bytes for the sw5wwp variant of the crc (might as well, may be useful in the future) - for (i = 0; i < 30; i++) - lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[i*8], 8); - - uint16_t crc_cmp = crc16m17(lsf_packed, 28); - uint16_t crc_ext = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[224], 16); - int crc_err = 0; - - if (crc_cmp != crc_ext) crc_err = 1; - - if (crc_err == 0) - M17decodeLSF(state); - else if (opts->aggressive_framesync == 0) - M17decodeLSF(state); - - if (opts->payload == 1) - { - fprintf (stderr, "\n LSF: "); - for (i = 0; i < 30; i++) - { - if (i == 15) fprintf (stderr, "\n "); - fprintf (stderr, "[%02X]", lsf_packed[i]); - } - fprintf (stderr, " (CRC CHK) E: %04X; C: %04X;", crc_ext, crc_cmp); - } - - if (crc_err == 1) fprintf (stderr, " CRC ERR"); - - //ending linebreak - fprintf (stderr, "\n"); - -} //end processM17LSF - -//original version using nxdn convolutional decoder, used for encoder debug -void processM17LSF_debug(dsd_opts * opts, dsd_state * state, uint8_t * m17_rnd_bits) -{ - - //NOTE: Same as OTA processM17LSF, sans dibit collection - - int i, j, k, x; - - uint8_t m17_int_bits[368]; //368 bits that are still interleaved - uint8_t m17_bits[368]; //368 bits that have been de-interleaved and de-scramble - uint8_t m17_depunc[500]; //488 bits after depuncturing - - memset (m17_int_bits, 0, sizeof(m17_int_bits)); - memset (m17_bits, 0, sizeof(m17_bits)); - memset (m17_depunc, 0, sizeof(m17_depunc)); - - //descramble the frame - for (i = 0; i < 368; i++) - m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1; - - //deinterleave 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_bits[i] = m17_int_bits[x]; - } - - j = 0; k = 0; x = 0; - - // P1 Depuncture - for (i = 0; i < 488; i++) - { - //assign any puncture as a 0 - // if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++]; - // else m17_depunc[x++] = 0; - - - //seems to be better if we use the last bit as an educated guess on what the next bit should be - //this pseudo logic is based purely on 0xFFFFFFFFFF as Broadcast, and all zeroes as the Meta(IV) - - //DST, or META field - if (i < 48 || i > 96) - { - if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++]; - else if (m17_depunc[x-2] == 1) m17_depunc[x++] = 1; - else m17_depunc[x++] = 0; - } - else //any other field - { - if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++]; - else m17_depunc[x++] = 0; - } - - - - if (k == 61) k = 0; //61 -- should reset 8 times againt the array - - } - - //setup the convolutional decoder - uint8_t temp[500]; - uint8_t s0; - uint8_t s1; - uint8_t m_data[32]; - uint8_t trellis_buf[260]; //30*8 = 240 - memset (trellis_buf, 0, sizeof(trellis_buf)); - memset (temp, 0, sizeof (temp)); - memset (m_data, 0, sizeof (m_data)); - - for (i = 0; i < 488; i++) - temp[i] = m17_depunc[i] << 1; - - CNXDNConvolution_start(); - for (i = 0; i < 244; i++) - { - s0 = temp[(2*i)]; - s1 = temp[(2*i)+1]; - - CNXDNConvolution_decode(s0, s1); - } - - CNXDNConvolution_chainback(m_data, 240); - - //244/8 = 30, last 4 (244-248) are trailing zeroes - for(i = 0; i < 30; i++) - { - trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1; - trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1; - trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1; - trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1; - trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1; - trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1; - trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1; - trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1; - } - - memset (state->m17_lsf, 0, sizeof(state->m17_lsf)); - memcpy (state->m17_lsf, trellis_buf, 240); - - uint8_t lsf_packed[30]; - memset (lsf_packed, 0, sizeof(lsf_packed)); - - //need to pack bytes for the sw5wwp variant of the crc (might as well, may be useful in the future) - for (i = 0; i < 30; i++) - lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[i*8], 8); - - uint16_t crc_cmp = crc16m17(lsf_packed, 28); - uint16_t crc_ext = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[224], 16); - int crc_err = 0; - - if (crc_cmp != crc_ext) crc_err = 1; - - if (crc_err == 0) - M17decodeLSF(state); - else if (opts->aggressive_framesync == 0) - M17decodeLSF(state); - - if (opts->payload == 1) - { - fprintf (stderr, "\n LSF: "); - for (i = 0; i < 30; i++) - { - if (i == 15) fprintf (stderr, "\n "); - fprintf (stderr, "[%02X]", lsf_packed[i]); - } - fprintf (stderr, " (CRC CHK) E: %04X; C: %04X;", crc_ext, crc_cmp); - } - - if (crc_err == 1) fprintf (stderr, " CRC ERR"); - -} //end processM17LSF_debug - -//this debug version using the libm17 viterbi decoder plus weight states -void processM17LSF_debug2(dsd_opts * opts, dsd_state * state, uint8_t * m17_rnd_bits) -{ - //Working: Switched to libM17 Viterbi Decoder, but the logic for weigted 'soft bits' - //isn't as well as it could be, really wants the symbol values to make estimations - - //TODO: See if noted above can be tweaked using dibit buffer values or something - - int i, j, k, x; - uint8_t m17_int_bits[368]; //368 bits that are still interleaved - uint16_t m17_bits[368]; //368 bits that have been de-interleaved and de-scrambled - uint16_t m17_depunc[488]; //488 weighted byte representation of bits after depuncturing - uint8_t lsf_bytes[31]; - uint8_t lsf_packed[30]; - uint32_t v_err = 0; //errors in viterbi decoder - UNUSED(v_err); - - memset (state->m17_lsf, 0, sizeof(state->m17_lsf)); - memset (m17_int_bits, 0, sizeof(m17_int_bits)); - memset (m17_bits, 0, sizeof(m17_bits)); - memset (m17_depunc, 0, sizeof(m17_depunc)); - memset (lsf_packed, 0, sizeof(lsf_packed)); - memset (lsf_bytes, 0, sizeof(lsf_bytes)); - - //descramble the frame - for (i = 0; i < 368; i++) - m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1; - - //deinterleave 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_bits[i] = m17_int_bits[x]; - } - - //P1 Depuncture & Add Weights - x = 0; - for (i = 0; i < 488; i++) - { - if (p1[i%61] == 1) - m17_depunc[i] = m17_bits[x++]; - else m17_depunc[i] = 0; - - if (m17_depunc[i]) - m17_depunc[i] = 0xFFFF; - else m17_depunc[i] = 0x7FFF; - } - - //debug -- fill all of the byte array - // memset (m17_depunc, 0xFFFF, sizeof(m17_depunc)); - - //debug - // fprintf (stderr, "\n depunc: \n"); - // for (i = 0; i < 488; i++) - // fprintf (stderr, " %04X", m17_depunc[i]); - - //use the libM17 Viterbi Decoder - uint16_t len = 488; - v_err = viterbi_decode(lsf_bytes, m17_depunc, len); - // v_err -= 3932040; //cost negation (double check this as well as unit, meaning, etc) - - //debug - // fprintf (stderr, "\n lsf_bytes: \n"); - // for (i = 0; i < 31; i++) - // fprintf (stderr, " %02X", lsf_bytes[i]); - - //copy + left shift one octet - memcpy (lsf_packed, lsf_bytes+1, 30); - - //Unpack bytes into m17_lsf bits - k = 0; - for (j = 0; j < 30; j++) - { - for (i = 0; i < 8; i++) - state->m17_lsf[k++] = (lsf_packed[j] >> (7-i)) & 1; - } - - uint16_t crc_cmp = crc16m17(lsf_packed, 28); - uint16_t crc_ext = (lsf_packed[28] << 8) + (lsf_packed[29] << 0); - int crc_err = 0; - - if (crc_cmp != crc_ext) crc_err = 1; - - if (crc_err == 0) - M17decodeLSF(state); - else if (opts->aggressive_framesync == 0) - M17decodeLSF(state); - - if (opts->payload == 1) - { - fprintf (stderr, "\n LSF: "); - for (i = 0; i < 30; i++) - { - if (i == 15) fprintf (stderr, "\n "); - fprintf (stderr, "[%02X]", lsf_packed[i]); - } - fprintf (stderr, " (CRC CHK) E: %04X; C: %04X;", crc_ext, crc_cmp); - // fprintf (stderr, " V Err: %d", v_err); - } - - if (crc_err == 1) fprintf (stderr, " CRC ERR"); - - //ending linebreak - // fprintf (stderr, "\n"); - -} //end processM17LSF_debug2 - -//debug M17STR for the encoder to pass bits into -void processM17STR_debug(dsd_opts * opts, dsd_state * state, uint8_t * m17_rnd_bits) -{ - - int i, x; - uint8_t m17_int_bits[368]; //368 bits that are still interleaved - uint8_t m17_bits[368]; //368 bits that have been de-interleaved and de-scrambled - uint8_t lich_bits[96]; - int lich_err = -1; - - memset (m17_int_bits, 0, sizeof(m17_int_bits)); - memset (m17_bits, 0, sizeof(m17_bits)); - memset (lich_bits, 0, sizeof(lich_bits)); - - //descramble the frame - for (i = 0; i < 368; i++) - m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1; - - //deinterleave 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_bits[i] = m17_int_bits[x]; - } - - for (i = 0; i < 96; i++) - lich_bits[i] = m17_bits[i]; - - //check lich first, and handle LSF chunk and completed LSF - lich_err = M17processLICH(state, opts, lich_bits); - - if (lich_err == 0) - M17prepareStream(opts, state, m17_bits); - - -} //end processM17STR_debug - -//simple convolutional encoder -void simple_conv_encoder (uint8_t * input, uint8_t * output, int len) -{ - int i, k = 0; - uint8_t g1 = 0; - uint8_t g2 = 0; - uint8_t d = 0; - uint8_t d1 = 0; - uint8_t d2 = 0; - uint8_t d3 = 0; - uint8_t d4 = 0; - - for (i = 0; i < len; i++) - { - d = input[i]; - - g1 = (d + d3 + d4) & 1; - g2 = (d + d1 + d2 + d4) & 1; - - d4 = d3; - d3 = d2; - d2 = d1; - d1 = d; - - output[k++] = g1; - output[k++] = g2; - } } - -//dibits-symbols map -const int8_t symbol_map[4] = {+1, +3, -1, -3}; - -//sample RRC filter for 48kHz sample rate -//alpha=0.5, span=8, sps=10, gain=sqrt(sps) -float m17_rrc[81] = -{ - -0.003195702904062073f, -0.002930279157647190f, -0.001940667871554463f, - -0.000356087678023658f, 0.001547011339077758f, 0.003389554791179751f, - 0.004761898604225673f, 0.005310860846138910f, 0.004824746306020221f, - 0.003297923526848786f, 0.000958710871218619f, -0.001749908029791816f, - -0.004238694106631223f, -0.005881783042101693f, -0.006150256456781309f, - -0.004745376707651645f, -0.001704189656473565f, 0.002547854551539951f, - 0.007215575568844704f, 0.011231038205363532f, 0.013421952197060707f, - 0.012730475385624438f, 0.008449554307303753f, 0.000436744366018287f, - -0.010735380379191660f, -0.023726883538258272f, -0.036498030780605324f, - -0.046500883189991064f, -0.050979050575999614f, -0.047340680079891187f, - -0.033554880492651755f, -0.008513823955725943f, 0.027696543159614194f, - 0.073664520037517042f, 0.126689053778116234f, 0.182990955139333916f, - 0.238080025892859704f, 0.287235637987091563f, 0.326040247765297220f, - 0.350895727088112619f, 0.359452932027607974f, 0.350895727088112619f, - 0.326040247765297220f, 0.287235637987091563f, 0.238080025892859704f, - 0.182990955139333916f, 0.126689053778116234f, 0.073664520037517042f, - 0.027696543159614194f, -0.008513823955725943f, -0.033554880492651755f, - -0.047340680079891187f, -0.050979050575999614f, -0.046500883189991064f, - -0.036498030780605324f, -0.023726883538258272f, -0.010735380379191660f, - 0.000436744366018287f, 0.008449554307303753f, 0.012730475385624438f, - 0.013421952197060707f, 0.011231038205363532f, 0.007215575568844704f, - 0.002547854551539951f, -0.001704189656473565f, -0.004745376707651645f, - -0.006150256456781309f, -0.005881783042101693f, -0.004238694106631223f, - -0.001749908029791816f, 0.000958710871218619f, 0.003297923526848786f, - 0.004824746306020221f, 0.005310860846138910f, 0.004761898604225673f, - 0.003389554791179751f, 0.001547011339077758f, -0.000356087678023658f, - -0.001940667871554463f, -0.002930279157647190f, -0.003195702904062073f -}; - -static float mem[81]; - -//convert bit array into symbols and RF/Audio -void encodeM17RF (dsd_opts * opts, dsd_state * state, uint8_t * input, int type) -{ - - //NOTE: Reorganized type numbers as following: - //Single Digit numbers 1,2,3,4 are LSF, STR, BRT, and PKT - //Double Digit numbers 11,33,55,99 are preamble, EOT, or Dead Air - - int i, j, k, x; - - //Preamble A - 0x7777 (+3, -3, +3, -3, +3, -3, +3, -3) - uint8_t m17_preamble_a[16] = {0,1,1,1, 0,1,1,1, 0,1,1,1, 0,1,1,1}; - - //Preamble B - 0xEEEE (-3, +3, -3, +3, -3, +3, -3, +3) - uint8_t m17_preamble_b[16] = {1,1,1,0, 1,1,1,0, 1,1,1,0, 1,1,1,0}; - - //EOT Marker - 0x555D - uint8_t m17_eot_marker[16] = {0,1,0,1, 0,1,0,1, 0,1,0,1, 1,1,0,1}; - - //LSF frame sync pattern - 0x55F7 +3, +3, +3, +3, -3, -3, +3, -3 - uint8_t m17_lsf_fs[16] = {0,1,0,1, 0,1,0,1, 1,1,1,1, 0,1,1,1}; - - //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}; - - //PKT frame sync pattern - 0x75FF (-3, -3, -3, -3, +3, +3, -3, +3) - uint8_t m17_pkt_fs[16] = {0,1,1,1, 0,1,0,1,1,1,1,1,1,1,1,1}; - - //BRT frame sync pattern - 0xDF55 (-3, +3, -3, -3, +3, +3, +3, +3) - uint8_t m17_brt_fs[16] = {1,1,0,1, 1,1,1,1, 0,1,0,1, 0,1,0,1}; - - //load bits into a dibit array plus the framesync bits - uint8_t output_dibits[192]; memset (output_dibits, 0, sizeof(output_dibits)); - - //Preamble (just repeat the preamble 12 times to make 192 symbols) - if (type == 11) //A Pattern prepends LSF (last symbol opposite of first symbol to prevent zero-crossing) - { - for (i = 0; i < 192; i++) - output_dibits[i] = (m17_preamble_a[ (i*2+0)%16 ] << 1) + (m17_preamble_a[ (i*2+1)%16 ] << 0); - } - - //Preamble (just repeat the preamble 12 times to make 192 symbols) - 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); - } - - //EOT Marker (just repeat the EOT marker 12 times to make 192 symbols) - if (type == 55) - { - for (i = 0; i < 192; i++) - output_dibits[i] = (m17_eot_marker[ (i*2+0)%16 ] << 1) + (m17_eot_marker[ (i*2+1)%16 ] << 0); - } - - //load frame sync pattern - if (type == 1) //LSF - { - for (i = 0; i < 8; i++) - output_dibits[i] = (m17_lsf_fs[i*2+0] << 1) + (m17_lsf_fs[i*2+1] << 0); - } - - if (type == 2) //Stream - { - for (i = 0; i < 8; i++) - output_dibits[i] = (m17_str_fs[i*2+0] << 1) + (m17_str_fs[i*2+1] << 0); - } - - 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) - { - for (i = 0; i < 184; i++) - output_dibits[i+8] = (input[i*2+0] << 1) + (input[i*2+1] << 0); - } - - //convert to symbols - int output_symbols[192]; memset (output_symbols, 0, 192*sizeof(int)); - for (i = 0; i < 192; i++) - output_symbols[i] = symbol_map[output_dibits[i]]; - - //symbols to audio - - //upsample 10x - int output_up[192*10]; memset (output_up, 0, 192*10*sizeof(int)); - for (i = 0; i < 192; i++) - { - for (j = 0; j < 10; j++) - output_up[(i*10)+j] = output_symbols[i]; - } - - //craft baseband with deviation + filter - short baseband[1920]; memset (baseband, 0, 1920*sizeof(short)); - - //simple, no filtering - if (opts->use_cosine_filter == 0) - { - for (i = 0; i < 1920; i++) - baseband[i] = output_up[i] * 7168.0f; - } - - //version w/ filtering lifted from M17_Implementations / libM17 - else if (opts->use_cosine_filter == 1) - { - - float mac = 0.0f; - x = 0; - for (i = 0; i < 192; i++) - { - mem[0] = (float)output_symbols[i] * 7168.0f; - - for (j = 0; j < 10; j++) - { - - mac = 0.0f; - - //calc the sum of products - for (k = 0; k < 81; k++) - mac += mem[k]*m17_rrc[k]*sqrtf(10.0); - - //shift the delay line right by 1 - for (k = 80; k > 0; k--) - mem[k] = mem[k-1]; - - mem[0] = 0.0f; - - baseband[x++] = (short)mac; - } - - } - } - - //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) - { - memset (output_dibits, 0xFF, sizeof(output_dibits)); //NOTE: 0xFF works better on bin files - memset (baseband, 0, 1920*sizeof(short)); - } - - //save symbols (dibits, actually) to symbol capture bin file format - if (opts->symbol_out_f) //use -c output.bin to use this format (default type for DSD-FME) - { - for (i = 0; i < 192; i++) - fputc (output_dibits[i], opts->symbol_out_f); - } - - //save symbol stream format (M17_Implementations), output to float values that m17-packet-decode can read - if (opts->use_dsp_output) //use -Q output.bin to use this format, will be placed in the DSP folder (reusing DSP) - { - FILE * pFile; //file pointer - pFile = fopen (opts->dsp_out_file, "a"); //append, not write - float val = 0; - for (i = 0; i < 192; i++) - { - val = (float)output_symbols[i]; - fwrite(&val, 4, 1, pFile); - } - fclose(pFile); - } - - //playing back signal audio into device/udp - //NOTE: Open the analog output device, use -8 - if (opts->monitor_input_audio == 1) - { - //Pulse Audio - if (opts->audio_out_type == 0) - pa_simple_write(opts->pulse_raw_dev_out, baseband, 1920*2, NULL); - - //UDP - if (opts->audio_out_type == 8) - udp_socket_blasterA (opts, state, 1920*2, baseband); - - //STDOUT or OSS 48k/1 - if (opts->audio_out_type == 1 || opts->audio_out_type == 5) - write (opts->audio_out_fd, baseband, 1920*2); - - } - - //if we have a raw signal wav file, write to it now - if (opts->wav_out_raw != NULL) - { - sf_write_short(opts->wav_out_raw, baseband, 1920); - sf_write_sync (opts->wav_out_raw); - } - - //NOTE: Internal voice decoding is disabled when tx audio over a hardware device, wav/bin still enabled - UNUSED(state); - -} - -//encode and create audio of a Project M17 Stream signal -void encodeM17STR(dsd_opts * opts, dsd_state * state) -{ - - //initialize RRC memory buffer - memset (mem, 0, 81*sizeof(float)); - - //set stream type value here so we can change 3200 or 1600 accordingly - uint8_t st = 2; //stream type: 0 = res; 1 = data; 2 = voice(3200); 3 = voice(1600) + data; - if (state->m17_str_dt == 3) st = 3; //this is set to 3 IF -S user text string is called at CLI - else st = 2; //otherwise, just use 32066 voice - - //IP Frame Things and User Variables for Reflectors, etc - uint8_t nil[368]; //empty array to send to RF during Preamble, EOT Marker, or Dead Air - memset (nil, 0, sizeof(nil)); - - //Enable frame, TX and Ncurses Printer - opts->frame_m17 = 1; - state->m17encoder_tx = 1; - - if (opts->use_ncurses_terminal == 1) - ncursesOpen(opts, state); - - //if using the ncurses terminal, disable TX on startup until user toggles it with the '\' key, if not vox enabled - if (opts->use_ncurses_terminal == 1 && state->m17encoder_tx == 1 && state->m17_vox == 0) - state->m17encoder_tx = 0; - - //User Defined Variables - int use_ip = 0; //1 to enable IP Frame Broadcast over UDP - int udpport = opts->m17_portno; //port number for M17 IP Frame (default is 17000) - //set at startup now via CLI, or use default if no user value specified - uint8_t reflector_module = 0x41; //'A', single letter reflector module A-Z, 0x41 is A - 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 (pick up to 9 characters from the b40 char array) - char d40[50] = "BROADCAST"; //DST - char s40[50] = "DSD-FME "; //SRC - //end User Defined Variables - - //configure User Defined Variables, if defined at CLI - if (state->m17_can_en != -1) //has a set value - can = state->m17_can_en; - - if (state->str50c[0] != 0) - sprintf (s40, "%s", state->str50c); - - if (state->str50b[0] != 0) - sprintf (d40, "%s", state->str50b); - - //if special values, then assign them - if (strcmp (d40, "BROADCAST") == 0) - dst = 0xFFFFFFFFFFFF; - if (strcmp (d40, "ALL") == 0) - dst = 0xFFFFFFFFFFFF; - //end - - 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 160 samples for codec2 3200 bps) - int dec = state->m17_rate / 8000; //number of samples to run before selecting a sample from source input - int sql_hit = 11; //squelch hits, hit enough, and deactivate vox - int eot_out = 1; //if we have already sent the eot out once - - //send dead air with type 99 - for (i = 0; i < 25; i++) - encodeM17RF (opts, state, nil, 99); - - //Open UDP port to default or user defined values, if enabled - int sock_err; - if (opts->m17_use_ip == 1) - { - // - sock_err = udp_socket_connectM17(opts, state); - if (sock_err < 0) - { - fprintf (stderr, "Error Configuring UDP Socket for M17 IP Frame :( \n"); - use_ip = 0; - opts->m17_use_ip = 0; - } - else use_ip = 1; - } - - //Standard IP Framing - uint8_t magic[4] = {0x4D, 0x31, 0x37, 0x20}; - uint8_t ackn[4] = {0x41, 0x43, 0x4B, 0x4E}; UNUSED(ackn); - uint8_t nack[4] = {0x4E, 0x41, 0x43, 0x4B}; UNUSED(nack); - uint8_t conn[11]; memset (conn, 0, sizeof(conn)); - uint8_t disc[10]; memset (disc, 0, sizeof(disc)); - uint8_t ping[10]; memset (ping, 0, sizeof(ping)); - uint8_t pong[10]; memset (pong, 0, sizeof(pong)); - uint8_t eotx[10]; memset (eotx, 0, sizeof(eotx)); - int udp_return = 0; UNUSED(udp_return); - uint8_t sid[2]; memset (sid, 0, sizeof(sid)); - uint8_t m17_ip_frame[432]; memset (m17_ip_frame, 0, sizeof(m17_ip_frame)); - uint8_t m17_ip_packed[54]; memset (m17_ip_packed, 0, sizeof(m17_ip_packed)); - uint16_t ip_crc = 0; - - //NONCE - time_t ts = time(NULL); //timestamp since epoch / "Unix Time" - srand(ts); //randomizer seed based on timestamp - - //Stream ID value - sid[0] = rand() & 0xFF; - sid[1] = rand() & 0xFF; - - //initialize a nonce (if ENC is required in future) - uint8_t nonce[14]; memset (nonce, 0, sizeof(nonce)); - //32bit LSB of the timestamp - nonce[0] = (ts >> 24) & 0xFF; - nonce[1] = (ts >> 16) & 0xFF; - nonce[2] = (ts >> 8) & 0xFF; - nonce[3] = (ts >> 0) & 0xFF; - //64-bit of rnd data - nonce[4] = rand() & 0xFF; - nonce[5] = rand() & 0xFF; - nonce[6] = rand() & 0xFF; - nonce[7] = rand() & 0xFF; - nonce[8] = rand() & 0xFF; - nonce[9] = rand() & 0xFF; - nonce[10] = rand() & 0xFF; - nonce[11] = rand() & 0xFF; - //The last two octets are the CTR_HIGH value (upper 16 bits of the frame number), - //but you would need to talk non-stop for over 20 minutes to roll it, so just using rnd - //also, using zeroes seems like it may be a security issue, so using rnd as a base - nonce[12] = rand() & 0xFF; - nonce[13] = rand() & 0xFF; - - #ifdef USE_CODEC2 - if (st == 2) - nsam = codec2_samples_per_frame(state->codec2_3200); - else if (st == 3) - nsam = codec2_samples_per_frame(state->codec2_1600); - else nsam = 160; //default to 160 if RES or DATA, even if we don't handle those - #endif - - short * samp1 = malloc (sizeof(short) * nsam); - short * samp2 = malloc (sizeof(short) * nsam); - - short voice1[nsam]; //read in xxx ms of audio from input source - short voice2[nsam]; //read in xxx ms of audio from input source - - //frame sequence number and eot bit - uint16_t fsn = 0; - uint8_t eot = 0; - uint8_t lich_cnt = 0; //lich frame number counter - - 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 (lsf_chunk, 0, sizeof(lsf_chunk)); - 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, nonce, and golay - uint16_t lsf_ps = 1; //packet or stream indicator bit - uint16_t lsf_dt = st; //stream type - 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; //reserved bits - - //compose the 16-bit frame information from the above sub elements - uint16_t lsf_fi = 0; - lsf_fi = (lsf_ps & 1) + (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; - - //Convert base40 CSD to numerical values (lifted from libM17) - - //Only if not already set to a reserved value - if (dst < 0xEE6B27FFFFFF) - { - for(i = strlen((const char*)d40)-1; i >= 0; i--) - { - for(j = 0; j < 40; j++) - { - if(d40[i]==b40[j]) - { - dst=dst*40+j; - break; - } - } - } - } - - if (src < 0xEE6B27FFFFFF) - { - for(i = strlen((const char*)s40)-1; i >= 0; i--) - { - for(j = 0; j < 40; j++) - { - if(s40[i]==b40[j]) - { - src=src*40+j; - break; - } - } - } - } - //end CSD conversion - - //Setup conn, disc, eotx, ping, pong values - conn[0] = 0x43; conn[1] = 0x4F; conn[2] = 0x4E; conn[3] = 0x4E; conn[10] = reflector_module; - disc[0] = 0x44; disc[1] = 0x49; disc[2] = 0x53; disc[3] = 0x43; - ping[0] = 0x50; ping[1] = 0x49; ping[2] = 0x4E; ping[3] = 0x47; - pong[0] = 0x50; pong[1] = 0x4F; pong[2] = 0x4E; pong[3] = 0x47; - eotx[0] = 0x45; eotx[1] = 0x4F; eotx[2] = 0x54; eotx[3] = 0x58; //EOTX is not Standard, but going to send / receive anyways - - //these values were not loaded correctly before, so just manually handle one and copy to others - conn[4] = (src >> 40UL) & 0xFF; conn[5] = (src >> 32UL) & 0xFF; conn[6] = (src >> 24UL) & 0xFF; - conn[7] = (src >> 16UL) & 0xFF; conn[8] = (src >> 8UL) & 0xFF; conn[9] = (src >> 0UL) & 0xFF; - for (i = 0; i < 6; i++) - { - disc[i+4] = conn[i+4]; ping[i+4] = conn[i+4]; - pong[i+4] = conn[i+4]; eotx[i+4] = conn[i+4]; - } - - //SEND CONN to reflector - if (use_ip == 1) - udp_return = m17_socket_blaster (opts, state, 11, conn); - - //TODO: Read UDP ACKN/NACK value, disable use_ip if NULL or nack return - - //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; - - //load the nonce from packed bytes to a bitwise iv array - uint8_t iv[112]; memset(iv, 0, sizeof(iv)); - k = 0; - for (j = 0; j < 14; j++) - { - for (i = 0; i < 8; i++) - iv[k++] = (nonce[j] >> (7-i))&1; - } - - //if AES enc employed, insert the iv into LSF - if (lsf_et == 2) - { - for (i = 0; i < 112; i++) - m17_lsf[i+112] = iv[i]; - } - - //pack and compute the CRC16 for LSF - uint16_t crc_cmp = 0; - uint8_t lsf_packed[30]; - memset (lsf_packed, 0, sizeof(lsf_packed)); - for (i = 0; i < 28; i++) - lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_lsf[i*8], 8); - crc_cmp = crc16m17(lsf_packed, 28); - - //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; - - //pack the CRC - for (i = 28; i < 30; i++) - lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_lsf[i*8], 8); - - //Craft and Send Initial LSF frame to be decoded - - //LSF w/ convolutional encoding (double check array sizes) - uint8_t m17_lsfc[488]; memset (m17_lsfc, 0, sizeof(m17_lsfc)); - - //LSF w/ P1 Puncturing - uint8_t m17_lsfp[368]; memset (m17_lsfp, 0, sizeof(m17_lsfp)); - - //LSF w/ Interleave - uint8_t m17_lsfi[368]; memset (m17_lsfi, 0, sizeof(m17_lsfi)); - - //LSF w/ Scrambling - uint8_t m17_lsfs[368]; memset (m17_lsfs, 0, sizeof(m17_lsfs)); - - //Use the convolutional encoder to encode the LSF Frame - simple_conv_encoder (m17_lsf, m17_lsfc, 244); - - //P1 puncture - x = 0; - for (i = 0; i < 488; i++) - { - if (p1[i%61] == 1) - m17_lsfp[x++] = m17_lsfc[i]; - } - - //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_lsfi[x] = m17_lsfp[i]; - } - - //scramble/randomize the frame - for (i = 0; i < 368; i++) - m17_lsfs[i] = (m17_lsfi[i] ^ m17_scramble[i]) & 1; - - //flag to determine if we send a new LSF frame for new encode - //only send once at the appropriate time when encoder is toggled on - int new_lsf = 1; - - while (!exitflag) //while the software is running - { - - //if not decoding internally, assign values for ncurses display - if (opts->monitor_input_audio == 1) - { - sprintf (state->m17_src_str, "%s", s40); - sprintf (state->m17_dst_str, "%s", d40); - state->m17_src = src; - state->m17_dst = dst; - state->m17_can = can; - state->m17_str_dt = lsf_dt; - state->m17_enc = lsf_et; - state->m17_enc_st = lsf_es; - for (i = 0; i < 16; i++) - state->m17_meta[i] = 0; - if (lsf_et == 2) - { - for (i = 0; i < 14; i++) - state->m17_meta[i] = nonce[i]; - for (i = 0; i < 8; i++) - { - state->m17_meta[14] <<= 1; - state->m17_meta[15] <<= 1; - state->m17_meta[14] += ((fsn >> 7) >> (7-i)) & 1; - state->m17_meta[15] += ((fsn >> 0) >> (7-i)) & 1; - } - } - } - - //read some audio samples from source and load them into an audio buffer - if (opts->audio_in_type == 0) //pulse audio - { - for (i = 0; i < nsam; i++) - { - for (j = 0; j < dec; j++) - pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL ); - voice1[i] = sample; //only store the 6th sample - } - - if (st == 2) - { - for (i = 0; i < nsam; i++) - { - for (j = 0; j < dec; j++) - pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL ); - voice2[i] = sample; //only store the 6th sample - } - } - } - - else if (opts->audio_in_type == 1) //stdin - { - int result = 0; - for (i = 0; i < nsam; i++) - { - for (j = 0; j < dec; j++) - result = sf_read_short(opts->audio_in_file, &sample, 1); - voice1[i] = sample; - if (result == 0) - { - sf_close(opts->audio_in_file); - fprintf (stderr, "Connection to STDIN Disconnected.\n"); - fprintf (stderr, "Closing DSD-FME.\n"); - exitflag = 1; - break; - } - } - - if (st == 2) - { - for (i = 0; i < nsam; i++) - { - for (j = 0; j < dec; j++) - result = sf_read_short(opts->audio_in_file, &sample, 1); - voice2[i] = sample; - if (result == 0) - { - sf_close(opts->audio_in_file); - fprintf (stderr, "Connection to STDIN Disconnected.\n"); - fprintf (stderr, "Closing DSD-FME.\n"); - exitflag = 1; - break; - } - } - } - } - - else if (opts->audio_in_type == 5) //OSS - { - for (i = 0; i < nsam; i++) - { - for (j = 0; j < dec; j++) - read (opts->audio_in_fd, &sample, 2); - voice1[i] = sample; - } - - if (st == 2) - { - for (i = 0; i < nsam; i++) - { - for (j = 0; j < dec; j++) - read (opts->audio_in_fd, &sample, 2); - voice2[i] = sample; - } - } - } - - else if (opts->audio_in_type == 8) //TCP - { - int result = 0; - for (i = 0; i < nsam; i++) - { - for (j = 0; j < dec; j++) - result = sf_read_short(opts->tcp_file_in, &sample, 1); - voice1[i] = sample; - if (result == 0) - { - sf_close(opts->tcp_file_in); - fprintf (stderr, "Connection to TCP Server Disconnected.\n"); - fprintf (stderr, "Closing DSD-FME.\n"); - exitflag = 1; - break; - } - } - - if (st == 2) - { - for (i = 0; i < nsam; i++) - { - for (j = 0; j < dec; j++) - result = sf_read_short(opts->tcp_file_in, &sample, 1); - voice2[i] = sample; - if (result == 0) - { - sf_close(opts->tcp_file_in); - fprintf (stderr, "Connection to TCP Server Disconnected.\n"); - fprintf (stderr, "Closing DSD-FME.\n"); - exitflag = 1; - break; - } - } - } - } - - else if (opts->audio_in_type == 3) //RTL - { - #ifdef USE_RTLSDR - for (i = 0; i < nsam; i++) - { - for (j = 0; j < dec; j++) - if (get_rtlsdr_sample(&sample, opts, state) < 0) - cleanupAndExit(opts, state); - sample *= opts->rtl_volume_multiplier; - voice1[i] = sample; - } - - if (st == 2) - { - for (i = 0; i < nsam; i++) - { - for (j = 0; j < dec; j++) - if (get_rtlsdr_sample(&sample, opts, state) < 0) - cleanupAndExit(opts, state); - sample *= opts->rtl_volume_multiplier; - voice2[i] = sample; - } - } - opts->rtl_rms = rtl_return_rms(); - #endif - } - - //read in RMS value for vox function; NOTE: will not work correctly SOCAT STDIO TCP due to blocking when no samples to read - if (opts->audio_in_type != 3) - opts->rtl_rms = raw_rms(voice1, nsam, 1) / 2; //dividing by two so mic isn't so sensitive on vox - - //low pass filter - if (opts->use_lpf == 1) - { - lpf (state, voice1, 160); - if (st == 2) - lpf (state, voice2, 160); - } - - //high pass filter - if (opts->use_hpf == 1) - { - hpf (state, voice1, 160); - if (st == 2) - hpf (state, voice2, 160); - } - - //passband filter - if (opts->use_pbf == 1) - { - pbf (state, voice1, 160); - if (st == 2) - pbf (state, voice2, 160); - } - - //manual gain control - if (opts->audio_gainA > 0.0f) - { - analog_gain (opts, state, voice1, 160); - if (st == 2) - analog_gain (opts, state, voice2, 160); - } - - //automatic gain control - else - { - agsm (opts, state, voice1, 160); - if (st == 2) - agsm (opts, state, voice2, 160); - } - - //NOTE: Similar to EDACS analog, if calculating raw rms here after filtering, - //anytime the walkie-talkie is held open but no voice, the center spike is removed, - //and counts against the squelch hits making vox mode inconsistent - // if (opts->audio_in_type != 3) - // opts->rtl_rms = raw_rms(voice1, 160, 1); - - //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)); - - #ifdef USE_CODEC2 - if (st == 2) - { - codec2_encode(state->codec2_3200, vc1_bytes, voice1); - codec2_encode(state->codec2_3200, vc2_bytes, voice2); - } - if (st == 3) - codec2_encode(state->codec2_1600, vc1_bytes, voice1); - #endif - - //Fill vc2_bytes with arbitrary data, UTF-8 chars (up to 48) - if (st == 3) - memcpy (vc2_bytes, state->m17sms+(lich_cnt*8), 8); - - //initialize and start assembling the completed frame - - //Data/Voice Portion of Stream Data Link Layer w/ FSN - 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)); - - //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)); - - //LSF Chunk + LICH CNT of Stream Data Link Layer - 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)); - - //Type 4c - Combined LSF Content Chuck and Voice/Data (96 + 272) - 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)); - - //Type 4s - Interleaved Bits with Scrambling Applied - 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)); - uint8_t v2_bits[64]; memset (v2_bits, 0, sizeof(v2_bits)); - - k = 0; x = 0; - for (j = 0; j < 8; j++) - { - for (i = 0; i < 8; i++) - { - v1_bits[k++] = (vc1_bytes[j] >> (7-i)) & 1; - v2_bits[x++] = (vc2_bytes[j] >> (7-i)) & 1; - } - } - - for (i = 0; i < 64; i++) - { - m17_v1[i+16] = v1_bits[i]; - m17_v1[i+16+64] = v2_bits[i]; - } - - //tally consecutive squelch hits based on RMS value, or reset - if (opts->rtl_rms > opts->rtl_squelch_level) sql_hit = 0; - else sql_hit++; //may eventually roll over to 0 again - - //if vox enabled, toggle tx/eot with sql_hit comparison - if (state->m17_vox == 1) - { - if (sql_hit > 10 && lich_cnt == 0) //licn_cnt 0 to prevent new LSF popping out - { - state->m17encoder_tx = 0; - // eot = 1; //same issue as observed in M17-FME - } - else - { - state->m17encoder_tx = 1; - eot = 0; - } - } - - //set end of tx bit on the exitflag (sig, results not gauranteed) or toggle eot flag (always triggers) - if (exitflag) eot = 1; - if (state->m17encoder_eot) eot = 1; - m17_v1[0] = (uint8_t)eot; //set as first bit of the stream - - //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; - - //Use the convolutional encoder to encode the voice / data stream - 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; - for (i = 0; i < 25; i++) - { - m17_v1p[k++] = m17_v1c[x++]; - m17_v1p[k++] = m17_v1c[x++]; - m17_v1p[k++] = m17_v1c[x++]; - m17_v1p[k++] = m17_v1c[x++]; - m17_v1p[k++] = m17_v1c[x++]; - m17_v1p[k++] = m17_v1c[x++]; - m17_v1p[k++] = m17_v1c[x++]; - m17_v1p[k++] = m17_v1c[x++]; - //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++]; - m17_v1p[k++] = m17_v1c[x++]; - m17_v1p[k++] = m17_v1c[x++]; - x++; - } - - //add punctured voice / data bits to the combined frame - for (i = 0; i < 272; i++) - m17_t4c[i+96] = m17_v1p[i]; - - //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]; - - //update lich_cnt in the current LSF chunk - lsf_chunk[lich_cnt][40] = (lich_cnt >> 2) & 1; - lsf_chunk[lich_cnt][41] = (lich_cnt >> 1) & 1; - lsf_chunk[lich_cnt][42] = (lich_cnt >> 0) & 1; - - //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_l1g - Golay_24_12_encode (lsf_chunk[lich_cnt]+00, m17_l1g+00); - Golay_24_12_encode (lsf_chunk[lich_cnt]+12, m17_l1g+24); - Golay_24_12_encode (lsf_chunk[lich_cnt]+24, m17_l1g+48); - Golay_24_12_encode (lsf_chunk[lich_cnt]+36, m17_l1g+72); - - //add lsf chunk to the combined frame - for (i = 0; i < 96; i++) - m17_t4c[i] = m17_l1g[i]; - - //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_t4i[x] = m17_t4c[i]; - } - - //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 toggled on - { - //Enable Carrier, synctype, etc - state->carrier = 1; - state->synctype = 8; - - //send LSF frame once, if new encode session - if (new_lsf == 1) - { - - fprintf (stderr, "\n M17 LSF (ENCODER): "); - if (opts->monitor_input_audio == 0) - processM17LSF_debug(opts, state, m17_lsfs); - else fprintf (stderr, " To Audio Out Device Type: %d; ", opts->audio_out_type); - - //convert bit array into symbols and RF/Audio - memset (nil, 0, sizeof(nil)); - encodeM17RF (opts, state, nil, 11); //Preamble - // for (i = 0; i < 2; i++) - encodeM17RF (opts, state, m17_lsfs, 1); //LSF - - //flag off after sending - new_lsf = 0; - - //flag to indicate to send one eot afterwards - eot_out = 0; - } - - fprintf (stderr, "\n M17 Stream (ENCODER): "); - if (opts->monitor_input_audio == 0) - processM17STR_debug(opts, state, m17_t4s); - else fprintf (stderr, " To Audio Out Device Type: %d; ", opts->audio_out_type); - - //show UDP if active - if (use_ip == 1 && lich_cnt != 5) - fprintf (stderr, " UDP: %s:%d", opts->m17_hostname, udpport); - - //debug RMS Value - if (state->m17_vox == 1) - { - fprintf (stderr, " RMS: %04ld", opts->rtl_rms); - fprintf (stderr, " SQL HIT: %d;", sql_hit); - } - - //debug show pulse input latency - // if (opts->audio_in_type == 0) - // { - // unsigned long long int latency = pa_simple_get_latency (opts->pulse_digi_dev_in, NULL); - // fprintf (stderr, " Latency: %05lld;", latency); - // } - - //convert bit array into symbols and RF/Audio - encodeM17RF (opts, state, m17_t4s, 2); - - //Contruct an IP frame using previously created arrays - memset (m17_ip_frame, 0, sizeof(m17_ip_frame)); - memset (m17_ip_packed, 0, sizeof(m17_ip_packed)); - - //add MAGIC - k = 0; - for (j = 0; j < 4; j++) - { - for (i = 0; i < 8; i++) - m17_ip_frame[k++] = (magic[j] >> (7-i)) &1; - } - - //add StreamID - for (j = 0; j < 2; j++) - { - for (i = 0; i < 8; i++) - m17_ip_frame[k++] = (sid[j] >> (7-i)) &1; - } - - //add the current LSF, sans CRC - for (i = 0; i < 224; i++) - m17_ip_frame[k++] = m17_lsf[i]; - - //add eot bit flag - m17_ip_frame[k++] = eot&1; - - //add current fsn value - for (i = 0; i < 15; i++) - m17_ip_frame[k++] = (fsn >> (14-i))&1; - - //voice and/or data payload - for (i = 0; i < 64; i++) - m17_ip_frame[k++] = v1_bits[i]; - - //voice and/or data payload - for (i = 0; i < 64; i++) - m17_ip_frame[k++] = v2_bits[i]; - - //pack current bit array into a byte array for a CRC check - for (i = 0; i < 52; i++) - m17_ip_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_ip_frame[i*8], 8); - ip_crc = crc16m17(m17_ip_packed, 52); - - //add CRC value to the ip frame - for (i = 0; i < 16; i++) - m17_ip_frame[k++] = (ip_crc >> (15-i))&1; - - //pack CRC into the byte array as well - for (i = 52; i < 54; i++) - m17_ip_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_ip_frame[i*8], 8); - - //Send packed IP frame to UDP port if enabled - if (use_ip == 1) - udp_return = m17_socket_blaster (opts, state, 54, m17_ip_packed); - - //increment lich_cnt, reset on 6 - lich_cnt++; - if (lich_cnt == 6) lich_cnt = 0; - - //increment frame sequency number, trunc to maximum value, roll nonce if needed - fsn++; - if (fsn > 0x7FFF) - { - fsn = 0; - nonce[13]++; - if (nonce[13] > 0xFF) - { - nonce[13] = 0; //roll over to zero of exceeds 0xFF - nonce[12]++; - nonce[12] &= 0xFF; //trunc for potential rollover (doesn't spill over) - } - } - - } //end if (state->m17encoder_tx) - - else //if not tx, reset values, drop carrier and sync - { - - //Send last IP Frame with EOT, pack this before resetting - memset (m17_ip_frame, 0, sizeof(m17_ip_frame)); - memset (m17_ip_packed, 0, sizeof(m17_ip_packed)); - - //add MAGIC - k = 0; - for (j = 0; j < 4; j++) - { - for (i = 0; i < 8; i++) - m17_ip_frame[k++] = (magic[j] >> (7-i)) &1; - } - - //add StreamID - for (j = 0; j < 2; j++) - { - for (i = 0; i < 8; i++) - m17_ip_frame[k++] = (sid[j] >> (7-i)) &1; - } - - //add the current LSF, sans CRC - for (i = 0; i < 224; i++) - m17_ip_frame[k++] = m17_lsf[i]; - - //add eot bit flag - m17_ip_frame[k++] = eot&1; - - //add current fsn value - for (i = 0; i < 15; i++) - m17_ip_frame[k++] = (fsn >> (14-i))&1; - - //voice and/or data payload - for (i = 0; i < 64; i++) - m17_ip_frame[k++] = v1_bits[i]; - - //voice and/or data payload - for (i = 0; i < 64; i++) - m17_ip_frame[k++] = v2_bits[i]; - - //pack current bit array into a byte array for a CRC check - for (i = 0; i < 52; i++) - m17_ip_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_ip_frame[i*8], 8); - ip_crc = crc16m17(m17_ip_packed, 52); - - //add CRC value to the ip frame - for (i = 0; i < 16; i++) - m17_ip_frame[k++] = (ip_crc >> (15-i))&1; - - //pack CRC into the byte array as well - for (i = 52; i < 54; i++) - m17_ip_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_ip_frame[i*8], 8); - - //reset - lich_cnt = 0; - fsn = 0; - state->carrier = 0; - state->synctype = -1; - - //update timestamp - ts = time(NULL); - - //update randomizer seed and SID - srand(ts); //randomizer seed based on time - - //update Stream ID - sid[0] = rand() & 0xFF; - sid[1] = rand() & 0xFF; - - //update nonce - nonce[0] = (ts >> 24) & 0xFF; - nonce[1] = (ts >> 16) & 0xFF; - nonce[2] = (ts >> 8) & 0xFF; - nonce[3] = (ts >> 0) & 0xFF; - nonce[4] = rand() & 0xFF; - nonce[5] = rand() & 0xFF; - nonce[6] = rand() & 0xFF; - nonce[7] = rand() & 0xFF; - nonce[8] = rand() & 0xFF; - nonce[9] = rand() & 0xFF; - nonce[10] = rand() & 0xFF; - nonce[11] = rand() & 0xFF; - nonce[12] = rand() & 0xFF; - nonce[13] = rand() & 0xFF; - - //load the nonce from packed bytes to a bitwise iv array - memset(iv, 0, sizeof(iv)); - k = 0; - for (j = 0; j < 14; j++) - { - for (i = 0; i < 8; i++) - iv[k++] = (nonce[j] >> (7-i))&1; - } - - //if AES enc employed, insert the iv into LSF - if (lsf_et == 2) //disable to allow the 0x69 repeating non-zero fill on RES - { - for (i = 0; i < 112; i++) m17_lsf[i+112] = iv[i]; - } - - //repack, new CRC, and update rest of lsf as well - memset (lsf_packed, 0, sizeof(lsf_packed)); - for (i = 0; i < 28; i++) - lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_lsf[i*8], 8); - crc_cmp = crc16m17(lsf_packed, 28); - - //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; - - //repack the CRC - for (i = 28; i < 30; i++) - lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_lsf[i*8], 8); - - //Recraft and Prepare New LSF frame for next encoding session - //this is primarily to make sure the LSF has the refreshed nonce - memset (m17_lsfc, 0, sizeof(m17_lsfc)); - memset (m17_lsfp, 0, sizeof(m17_lsfp)); - memset (m17_lsfi, 0, sizeof(m17_lsfi)); - memset (m17_lsfs, 0, sizeof(m17_lsfs)); - - //Use the convolutional encoder to encode the LSF Frame - simple_conv_encoder (m17_lsf, m17_lsfc, 244); - - //P1 puncture - x = 0; - for (i = 0; i < 488; i++) - { - if (p1[i%61] == 1) - m17_lsfp[x++] = m17_lsfc[i]; - } - - //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_lsfi[x] = m17_lsfp[i]; - } - - //scramble/randomize the frame - for (i = 0; i < 368; i++) - m17_lsfs[i] = (m17_lsfi[i] ^ m17_scramble[i]) & 1; - - //flush the last frame with the eot bit on - if (eot && !eot_out) - { - fprintf (stderr, "\n M17 Stream (ENCODER): "); - if (opts->monitor_input_audio == 0) - processM17STR_debug(opts, state, m17_t4s); - else fprintf (stderr, " To Audio Out Device Type: %d; ", opts->audio_out_type); - - //show UDP if active - if (use_ip == 1 && lich_cnt != 5) - fprintf (stderr, " UDP: %s:%d", opts->m17_hostname, udpport); - - //debug RMS Value - if (state->m17_vox == 1) - { - fprintf (stderr, " RMS: %04ld", opts->rtl_rms); - fprintf (stderr, " SQL HIT: %d;", sql_hit); - } - - //convert bit array into symbols and RF/Audio - encodeM17RF (opts, state, m17_t4s, 2); //Last Stream Frame - memset (nil, 0, sizeof(nil)); - encodeM17RF (opts, state, nil, 55); //EOT Marker - - //send dead air with type 99 - for (i = 0; i < 25; i++) - encodeM17RF (opts, state, nil, 99); - - //send IP Frame with EOT bit - if (use_ip == 1) - udp_return = m17_socket_blaster (opts, state, 54, m17_ip_packed); - - //SEND EOTX to reflector - if (use_ip == 1) - udp_return = m17_socket_blaster (opts, state, 10, eotx); - - //reset indicators - eot = 0; - eot_out = 1; - state->m17encoder_eot = 0; - } - - //flag on when restarting the encoder - new_lsf = 1; - - //flush decoder side meta last, primarily the last two octets with the lich_cnt in them - memset(state->m17_meta, 0, sizeof(state->m17_meta)); - - //flush decoder side lsf, may be redundant, but using to make sure no stale values loaded during debug - memset(state->m17_lsf, 0, sizeof(state->m17_lsf)); - - } - - //refresh ncurses printer, if enabled - if (opts->use_ncurses_terminal == 1) - ncursesPrinter(opts, state); - - //slot 1 - watchdog_event_history(opts, state, 0); - watchdog_event_current(opts, state, 0); - - } - - //SEND EOTX to reflector - // if (use_ip == 1) - // udp_return = m17_socket_blaster (opts, state, 10, eotx); - - //SEND DISC to reflector - if (use_ip == 1) - udp_return = m17_socket_blaster (opts, state, 10, disc); - - //free allocated memory - free(samp1); - free(samp2); - -} - -//encode and create audio of a Project M17 BERT signal -void encodeM17BRT(dsd_opts * opts, dsd_state * state) -{ - - //initialize RRC memory buffer - memset (mem, 0, 81*sizeof(float)); - - //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) -{ - - //initialize RRC memory buffer - memset (mem, 0, 81*sizeof(float)); - - uint8_t nil[368]; //empty array - memset (nil, 0, sizeof(nil)); - - int i, j, k, x; //basic utility counters - - //User Defined Variables - 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 (pick up to 9 characters from the b40 char array) - char d40[50] = "BROADCAST"; //DST - char s40[50] = "DSD-FME "; //SRC - - //Default - // char text[800] = "This is a simple SMS text message sent over M17 Packet Data."; - - //short - //NOTE: Working on full payload w/o padding - // char text[800] = "Lorem"; - - //medium - //NOTE: Fixed w/ the pad < 1, then add a block (not just if 0) - // char text[800] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; - - //large - //NOTE: Working on full payload w/o padding - char text[800] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; - - //Preamble of the Declaration of Independence (U.S.A.) - //NOTE: Fixed again with block != 31 check and manual terminator insertion into text byte 772 - // char text[] = "When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation. We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness.--That to secure these rights, Governments are instituted among Men, deriving their just powers from the consent of the governed, --That whenever any Form of Government becomes destructive of these ends, it is the Right of the People to alter or to abolish it, and to institute new Government, laying its foundation on such principles and organizing its powers in such form, as to them shall seem most likely to effect their Safety and Happiness. Prudence, indeed, will dictate that Governments long established should not be changed for light and transient causes; and accordingly all experience hath shewn, that mankind are more disposed to suffer, while evils are sufferable, than to right themselves by abolishing the forms to which they are accustomed. But when a long train of abuses and usurpations, pursuing invariably the same Object evinces a design to reduce them under absolute Despotism, it is their right, it is their duty, to throw off such Government, and to provide new Guards for their future security.--Such has been the patient sufferance of these Colonies; and such is now the necessity which constrains them to alter their former Systems of Government. The history of the present King of Great Britain is a history of repeated injuries and usurpations, all having in direct object the establishment of an absolute Tyranny over these States. To prove this, let Facts be submitted to a candid world."; - - //end User Defined Variables - - //configure User Defined Variables, if defined at CLI - if (state->m17_can_en != -1) //has a set value - can = state->m17_can_en; - - if (state->str50c[0] != 0) - sprintf (s40, "%s", state->str50c); - - if (state->str50b[0] != 0) - sprintf (d40, "%s", state->str50b); - - if (state->m17sms[0] != 0) - sprintf (text, "%s", state->m17sms); - - //if special values, then assign them - if (strcmp (d40, "BROADCAST") == 0) - dst = 0xFFFFFFFFFFFF; - if (strcmp (d40, "ALL") == 0) - dst = 0xFFFFFFFFFFFF; - - //end CLI Configuration - - //send dead air with type 99 - for (i = 0; i < 25; i++) - encodeM17RF (opts, state, nil, 99); - - //send preamble_a for the LSF frame - // encodeM17RF (opts, state, nil, 11); //don't need to send twice, had wrong type anyways - - //NOTE: PKT mode does not seem to have an IP format specified by M17 standard, - //so I will assume that you do not send PKT data over IP to a reflector - - uint8_t m17_lsf[240]; - memset (m17_lsf, 0, sizeof(m17_lsf)); - - //Setup LSF Variables, these are not sent in chunks like with voice - //but only once at start of PKT TX - uint16_t lsf_ps = 0; //packet or stream indicator bit - uint16_t lsf_dt = 1; //Data - 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; //reserved bits - uint8_t protocol = 5; //SMS Protocol - - //compose the 16-bit frame information from the above sub elements - uint16_t lsf_fi = 0; - lsf_fi = (lsf_ps & 1) + (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; - - //Convert base40 CSD to numerical values (lifted from libM17) - - //Only if not already set to a reserved value - if (dst < 0xEE6B27FFFFFF) - { - for(i = strlen((const char*)d40)-1; i >= 0; i--) - { - for(j = 0; j < 40; j++) - { - if(d40[i]==b40[j]) - { - dst=dst*40+j; - break; - } - } - } - } - - if (src < 0xEE6B27FFFFFF) - { - for(i = strlen((const char*)s40)-1; i >= 0; i--) - { - for(j = 0; j < 40; j++) - { - if(s40[i]==b40[j]) - { - src=src*40+j; - break; - } - } - } - } - //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; - - //TODO: Any extra meta fills (extended callsign, etc?) - - //pack and compute the CRC16 for LSF - uint16_t crc_cmp = 0; - uint8_t lsf_packed[30]; - memset (lsf_packed, 0, sizeof(lsf_packed)); - for (i = 0; i < 28; i++) - lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_lsf[i*8], 8); - crc_cmp = crc16m17(lsf_packed, 28); - - //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; - - //pack the CRC - for (i = 28; i < 30; i++) - lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_lsf[i*8], 8); - - //Craft and Send Initial LSF frame to be decoded - - //LSF w/ convolutional encoding (double check array sizes) - uint8_t m17_lsfc[488]; memset (m17_lsfc, 0, sizeof(m17_lsfc)); - - //LSF w/ P1 Puncturing - uint8_t m17_lsfp[368]; memset (m17_lsfp, 0, sizeof(m17_lsfp)); - - //LSF w/ Interleave - uint8_t m17_lsfi[368]; memset (m17_lsfi, 0, sizeof(m17_lsfi)); - - //LSF w/ Scrambling - uint8_t m17_lsfs[368]; memset (m17_lsfs, 0, sizeof(m17_lsfs)); - - //Use the convolutional encoder to encode the LSF Frame - simple_conv_encoder (m17_lsf, m17_lsfc, 244); - - //P1 puncture - x = 0; - for (i = 0; i < 488; i++) - { - if (p1[i%61] == 1) - m17_lsfp[x++] = m17_lsfc[i]; - } - - //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_lsfi[x] = m17_lsfp[i]; - } - - //scramble/randomize the frame - for (i = 0; i < 368; i++) - m17_lsfs[i] = (m17_lsfi[i] ^ m17_scramble[i]) & 1; - - //a full sized complete packet paylaod to break into smaller frames - uint8_t m17_p1_full[31*200]; memset (m17_p1_full, 0, sizeof(m17_p1_full)); - - //load protocol value into first 8 bits - k = 0; - for (i = 0; i < 8; i++) - m17_p1_full[k++] = (protocol >> (7-i)) & 1; - - //byte representation of a single string char - uint8_t cbyte; - - //counter values - int tlen = strlen((const char*)text); - int block = 0; //number of blocks in total - int ptr = 0; //ptr to current position of the text - int pad = 0; //amount of padding to apply to last frame - int lst = 0; //amount of significant octets in the last block - - //encode elements - uint8_t pbc = 0; //packet/octet counter - uint8_t eot = 0; //end of tx bit - - //sanity check, if tlen%25 is 23 or 24, need to increment to another block value - if ( (tlen%25) > 23) tlen += (tlen%23) + 1; - - //sanity check, maximum strlen should not exceed 771 for a full encode - if (tlen > 771) tlen = 771; - - //insert a zero byte as the terminator - text[tlen++] = 0x00; - - //insert one at the last available byte position - text[772] = 0x00; - - //debug tlen value - // fprintf (stderr, " STRLEN: %d; ", tlen); - - //Convert a string text message into UTF-8 octets and load into full if using SMS (we are) - fprintf (stderr, "\n SMS: "); - for (i = 0; i < tlen; i++) - { - cbyte = (uint8_t)text[ptr]; - fprintf (stderr, "%c", cbyte); - - for (j = 0; j < 8; j++) - m17_p1_full[k++] = (cbyte >> (7-j)) & 1; - - if (cbyte == 0) break; //if terminator reached - - ptr++; //increment pointer - - - //add line break to keep it under 80 columns - if ( (i%71) == 0 && i != 0) - fprintf (stderr, "\n "); - } - fprintf (stderr, "\n"); - - //end UTF-8 Encoding - - - //calculate blocks, pad, and last values for pbc - block = (ptr / 25) + 1; - pad = (block * 25) - ptr - 4; - // if (pad == 0 && block != 31) //fallback if issues arise - if (pad < 1 && block != 31) - { - block++; - pad = (block * 25) - ptr - 4; - } - lst = 23-pad+2; //pbc value for last block out - - //sanity check block value - // if (block > 31) block = 31; - - //debug position values - // fprintf (stderr, "\nBLOCK: %02d; PAD: %02d; LST: %d; K: %04d; PTR: %04d;\n", block, pad, lst, k, ptr); - - //Calculate the CRC and attach it here - x = 0; - uint8_t m17_p1_packed[31*25]; memset (m17_p1_packed, 0, sizeof(m17_p1_packed)); - for (i = 0; i < 25*31; i++) - { - m17_p1_packed[x] = (uint8_t)ConvertBitIntoBytes(&m17_p1_full[i*8], 8); - if (m17_p1_packed[x] == 0) break; //stop at the termination byte - x++; - } - - //NOTE to self: Revert changes in this commit, if issues with CRC on PKT, or - //the CRC really does go on the last 16 bits of the payload - - //debug dump the packed payload up to x, or x+1 - // fprintf (stderr, "\n P1P:"); - // for (i = 0; i < x+1; i++) - // fprintf (stderr, "%02X", m17_p1_packed[i]); - // fprintf (stderr, "\n"); - - crc_cmp = crc16m17(m17_p1_packed, x+1); //either x, or x+1? - - //debug dump CRC (when pad is literally zero) - // fprintf (stderr, "X: %d; LAST: %02X; TERM: %02X; CRC: %04X; \n", x, m17_p1_packed[x-1], m17_p1_packed[x], crc_cmp); - - ptr = (block*25*8) - 16; - - //attach the crc16 bits to the end of the PKT data - // for (i = 0; i < 16; i++) m17_p1_full[ptr+i] = (crc_cmp >> 15-i) & 1; //this one puts it as the last 16-bits of the full payload - - for (i = 0; i < 16; i++) m17_p1_full[k++] = (crc_cmp >> (15-i)) & 1; //this one puts it immediately after the terminating byte - - //debug the full payload - fprintf (stderr, "\n M17 Packet FULL: "); - for (i = 0; i < 25*block; i++) - { - if ( (i%25) == 0 && i != 0 ) fprintf (stderr, "\n "); - fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&m17_p1_full[i*8], 8)); - } - fprintf (stderr, "\n"); - - //just lump all the UDP IP Frame stuff together and one-shot it - int use_ip = 0; //1 to enable IP Frame Broadcast over UDP - uint8_t reflector_module = 0x41; //'A', single letter reflector module A-Z, 0x41 is A - - //Open UDP port to default or user defined values, if enabled - int sock_err; - if (opts->m17_use_ip == 1) - { - // - sock_err = udp_socket_connectM17(opts, state); - if (sock_err < 0) - { - fprintf (stderr, "Error Configuring UDP Socket for M17 IP Frame :( \n"); - use_ip = 0; - opts->m17_use_ip = 0; - } - else use_ip = 1; - } - - //NOTE: IP Framing is not standard on M17 for PKT mode, but - //I don't see any reason why we can't send them anyways, just - //need to use a new magic for it: MPKT. The receiver here is capable - //of decoding them - - //Standard IP Framing - uint8_t mpkt[4] = {0x4D, 0x50, 0x4B, 0x54}; - uint8_t ackn[4] = {0x41, 0x43, 0x4B, 0x4E}; UNUSED(ackn); - uint8_t nack[4] = {0x4E, 0x41, 0x43, 0x4B}; UNUSED(nack); - uint8_t conn[11]; memset (conn, 0, sizeof(conn)); - uint8_t disc[10]; memset (disc, 0, sizeof(disc)); - uint8_t ping[10]; memset (ping, 0, sizeof(ping)); - uint8_t pong[10]; memset (pong, 0, sizeof(pong)); - uint8_t eotx[10]; memset (eotx, 0, sizeof(eotx)); - int udp_return = 0; UNUSED(udp_return); - uint8_t sid[2]; memset (sid, 0, sizeof(sid)); - uint8_t m17_ip_frame[8000]; memset (m17_ip_frame, 0, sizeof(m17_ip_frame)); - uint8_t m17_ip_packed[25*40]; memset (m17_ip_packed, 0, sizeof(m17_ip_packed)); - uint16_t ip_crc = 0; - - //Setup conn, disc, eotx, ping, pong values - conn[0] = 0x43; conn[1] = 0x4F; conn[2] = 0x4E; conn[3] = 0x4E; conn[10] = reflector_module; - disc[0] = 0x44; disc[1] = 0x49; disc[2] = 0x53; disc[3] = 0x43; - ping[0] = 0x50; ping[1] = 0x49; ping[2] = 0x4E; ping[3] = 0x47; - pong[0] = 0x50; pong[1] = 0x4F; pong[2] = 0x4E; pong[3] = 0x47; - eotx[0] = 0x45; eotx[1] = 0x4F; eotx[2] = 0x54; eotx[3] = 0x58; - - //these values were not loaded correctly before, so just manually handle one and copy to others - conn[4] = (src >> 40UL) & 0xFF; conn[5] = (src >> 32UL) & 0xFF; conn[6] = (src >> 24UL) & 0xFF; - conn[7] = (src >> 16UL) & 0xFF; conn[8] = (src >> 8UL) & 0xFF; conn[9] = (src >> 0UL) & 0xFF; - for (i = 0; i < 6; i++) - { - disc[i+4] = conn[i+4]; ping[i+4] = conn[i+4]; - pong[i+4] = conn[i+4]; eotx[i+4] = conn[i+4]; - } - - //SEND CONN to reflector - if (use_ip == 1) - udp_return = m17_socket_blaster (opts, state, 11, conn); - - //add MPKT header - k = 0; - for (j = 0; j < 4; j++) - { - for (i = 0; i < 8; i++) - m17_ip_frame[k++] = (mpkt[j] >> (7-i)) &1; - } - - //randomize ID - srand(time(NULL)); - sid[0] = rand() & 0xFF; - sid[1] = rand() & 0xFF; - - //add StreamID / PKT ID - for (j = 0; j < 2; j++) - { - for (i = 0; i < 8; i++) - m17_ip_frame[k++] = (sid[j] >> (7-i)) &1; - } - - //add the current LSF, sans CRC - for (i = 0; i < 224; i++) //28 bytes - m17_ip_frame[k++] = m17_lsf[i]; - - //pack current bit array to current - for (i = 0; i < 34; i++) - m17_ip_packed[i] = (uint8_t)ConvertBitIntoBytes(&m17_ip_frame[i*8], 8); - - //pack the entire PKT payload (plus terminator, sans CRC) - for (i = 0; i < x+1; i++) - m17_ip_packed[i+34] = (uint8_t)ConvertBitIntoBytes(&m17_p1_full[i*8], 8); - - //Calculate CRC over everthing packed (including the terminator) - ip_crc = crc16m17(m17_ip_packed, 34+1+x); - - //add CRC value to the ip frame - uint8_t crc_bits[16]; memset (crc_bits, 0, sizeof(crc_bits)); - for (i = 0; i < 16; i++) - crc_bits[i] = (ip_crc >> (15-i))&1; - - //pack CRC into the byte array as well - for (i = x+34+1, j = 0; i < (x+34+3); i++, j++) //double check this - m17_ip_packed[i] = (uint8_t)ConvertBitIntoBytes(&crc_bits[j*8], 8); - - - //NOTE: Fixed recvfrom limitation, MSG_WAITALL seems to be 256 - //manually inserted 1000 into recvfrom instead, max MPKT size should be 809. - - //Send MPKT to reflector - if (use_ip == 1) - udp_return = m17_socket_blaster (opts, state, x+34+3, m17_ip_packed); - - //debug - if (use_ip == 1) - fprintf (stderr, " UDP IP Frame CRC: %04X; UDP RETURN: %d: X: %d; SENT: %d;", ip_crc, udp_return, x, x+34+3); - - //SEND EOTX to reflector - if (use_ip == 1) - udp_return = m17_socket_blaster (opts, state, 10, eotx); - - //SEND DISC to reflector - if (use_ip == 1) - udp_return = m17_socket_blaster (opts, state, 10, disc); - - //flag to determine if we send a new LSF frame for new encode - //only send once at the appropriate time when encoder is toggled on - int new_lsf = 1; - - while (!exitflag) - { - //send LSF frame once, if new encode session - if (new_lsf == 1) - { - - fprintf (stderr, "\n M17 LSF (ENCODER): "); - processM17LSF_debug(opts, state, m17_lsfs); - - //convert bit array into symbols and RF/Audio - memset (nil, 0, sizeof(nil)); - encodeM17RF (opts, state, nil, 11); //Preamble - // for (i = 0; i < 2; i++) - encodeM17RF (opts, state, m17_lsfs, 1); //LSF - - //flag off after sending - new_lsf = 0; - - //reset ptr value to use during chunk loading - ptr = 0; - } - - //PKT - 206 bits of Packet Data + 4 trailing bits - uint8_t m17_p1[210]; memset (m17_p1, 0, sizeof(m17_p1)); - - //PKT - 420 bits of Packet Data (after Convolutional Encode) - uint8_t m17_p2c[420]; memset (m17_p2c, 0, sizeof(m17_p2c)); - - //PKT - 368 bits of Packet Data (after P2 Puncturing) - uint8_t m17_p3p[368]; memset (m17_p3p, 0, sizeof(m17_p3p)); - - //PKT - 368 bits of Packet Data (after Interleaving) - uint8_t m17_p4i[368]; memset (m17_p4i, 0, sizeof(m17_p4i)); - - //PKT - 368 bits of Packet Data (after Scrambling) - uint8_t m17_p4s[368]; memset (m17_p4s, 0, sizeof(m17_p4s)); - - //Break the full payload into 25 octet chunks and load into p1 - for (i = 0; i < 200; i++) - m17_p1[i] = m17_p1_full[ptr++]; - - //Trigger EOT when out of data to encode - if (ptr/8 >= block*25) - { - eot = 1; - pbc = lst; - } - m17_p1[200] = eot; - - //set pbc counter to last 5 bits - for (i = 0; i < 5; i++) - m17_p1[201+i] = (pbc >> (4-i)) & 1; - - //Use the convolutional encoder to encode the packet data - simple_conv_encoder (m17_p1, m17_p2c, 210); //206 + 4 trailing bits - - //P3 puncture - x = 0; - for (i = 0; i < 420; i++) - { - if (p3[i%8] == 1) - m17_p3p[x++] = m17_p2c[i]; - } - - //debug X bit positions - // fprintf (stderr, " X: %d", 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_p4i[x] = m17_p3p[i]; - } - - //scramble/randomize the frame - for (i = 0; i < 368; i++) - m17_p4s[i] = (m17_p4i[i] ^ m17_scramble[i]) & 1; - - //----------------------------------------- - - - fprintf (stderr, "\n M17 Packet (ENCODER): "); - - //Dump Output of the current Packet Frame - for (i = 0; i < 26; i++) - fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&m17_p1[i*8], 8)); - - //debug PBC - // fprintf (stderr, " PBC: %d;", pbc); - - //convert bit array into symbols and RF/Audio - encodeM17RF (opts, state, m17_p4s, 4); - - //send the EOT Marker and some dead air - if (eot) - { - memset (nil, 0, sizeof(nil)); - encodeM17RF (opts, state, nil, 55); //EOT Marker - - //send dead air with type 99 - for (i = 0; i < 25; i++) - encodeM17RF (opts, state, nil, 99); - - //shut it down - exitflag = 1; - } - - //increment packet / byte counter - pbc++; - - } -} - -void decodeM17PKT(dsd_opts * opts, dsd_state * state, uint8_t * input, int len) -{ - //Decode the completed packet - UNUSED(opts); UNUSED(state); - int i; - - uint8_t protocol = input[0]; - fprintf (stderr, " Protocol:"); - if (protocol == 0x00) fprintf (stderr, " Raw;"); - else if (protocol == 0x01) fprintf (stderr, " AX.25;"); - else if (protocol == 0x02) fprintf (stderr, " APRS;"); - else if (protocol == 0x03) fprintf (stderr, " 6LoWPAN;"); - else if (protocol == 0x04) fprintf (stderr, " IPv4;"); - else if (protocol == 0x05) fprintf (stderr, " SMS;"); - else if (protocol == 0x06) fprintf (stderr, " Winlink;"); - else if (protocol == 0x80) fprintf (stderr, " Meta Text Data;"); //internal format only from meta - else if (protocol == 0x81) fprintf (stderr, " Meta GNSS Position Data;"); //internal format only from meta - else if (protocol == 0x82) fprintf (stderr, " Meta Extended CSD;"); //internal format only from meta - else if (protocol == 0x89) fprintf (stderr, " 1600 Arbitrary Data;"); //internal format only from 1600 - else fprintf (stderr, " Res/Unk: %02X;", protocol); - - //check for encryption, if encrypted, skip decode and report as encrypted - if (state->m17_enc != 0) - { - fprintf (stderr, " *Encrypted*"); - goto PKT_END; - } - - //simple UTF-8 SMS Decoder - if (protocol == 0x05) - { - fprintf (stderr, "\n SMS: "); - for (i = 1; i < len; i++) - { - fprintf (stderr, "%c", input[i]); - - //add line break to keep it under 80 columns - if ( (i%71) == 0 && i != 0) - fprintf (stderr, "\n "); - } - } - //Extended Call Sign Data - else if (protocol == 0x82) - { - //NOTE: If doing a shift addition like this, make sure ALL values have (unsigned long long int) in front of it, not just the ones that 'needed' it - unsigned long long int src = ((unsigned long long int)input[1] << 40ULL) + ((unsigned long long int)input[2] << 32ULL) + ((unsigned long long int)input[3] << 24ULL) + ((unsigned long long int)input[4] << 16ULL) + ((unsigned long long int)input[5] << 8ULL) + ((unsigned long long int)input[6] << 0ULL); - unsigned long long int dst = ((unsigned long long int)input[7] << 40ULL) + ((unsigned long long int)input[8] << 32ULL) + ((unsigned long long int)input[9] << 24ULL) + ((unsigned long long int)input[10] << 16ULL) + ((unsigned long long int)input[11] << 8ULL) + ((unsigned long long int)input[12] << 0ULL); - fprintf (stderr, " CF1: "); //Originator - for (i = 0; i < 9; i++) - { - char c = b40[src % 40]; - fprintf (stderr, "%c", c); - src = src / 40; - } - if (dst != 0) //if used - { - fprintf (stderr, " REF: "); //Reflector Name - for (i = 0; i < 9; i++) - { - char c = b40[dst % 40]; - fprintf (stderr, "%c", c); - dst = dst / 40; - } - } - } - //GNSS Positioning - else if (protocol == 0x81) - { - //Decode GNSS Elements - uint8_t data_source = input[1]; - uint8_t station_type = input[2]; - uint8_t lat_deg_int = input[3]; - uint32_t lat_deg_dec = (input[4] << 8) + input[5]; - uint8_t lon_deg_int = input[6]; - uint32_t lon_deg_dec = (input[7] << 8) + input[8]; - uint8_t indicators = input[9]; //nsew, validity bits - uint16_t altitude = (input[10] << 8) + input[11]; - uint16_t bearing = (input[12] << 8) + input[13]; - uint8_t speed = input[14]; - - fprintf (stderr, "\n Latitude: %03d.%05d ", lat_deg_int, lat_deg_dec * 65535); - if (indicators & 1) fprintf (stderr, "S;"); - else fprintf (stderr, "N;"); - fprintf (stderr, " Longitude: %03d.%05d ", lon_deg_int, lon_deg_dec * 65535); - if (indicators & 2) fprintf (stderr, "W;"); - else fprintf (stderr, "E;"); - if (indicators & 4) fprintf (stderr, " Altitude: %d;", altitude + 1500); - if (indicators & 8) fprintf (stderr, " Speed: %d MPH;", speed); - if (indicators & 8) fprintf (stderr, " Bearing: %d Degrees;", bearing); - - if (data_source == 0) fprintf (stderr, " M17 Client;"); - else if (data_source == 1) fprintf (stderr, " OpenRTX;"); - else if (data_source == 0x69) fprintf (stderr, " FME Data Source;"); - else if (data_source == 0xFF) fprintf (stderr, " Other Data Source;"); - else fprintf (stderr, " Reserved Data Source: %02X;", data_source); - - if (station_type == 0) fprintf (stderr, " Fixed Station;"); - else if (station_type == 1) fprintf (stderr, " Mobile Station;"); - else if (station_type == 2) fprintf (stderr, " Handheld;"); - else fprintf (stderr, " Reserved Station Type: %02X;", station_type); - - } - //META Text Message, or 1600 Arbitrary Data - //TODO: Seperate these two so we can assemble a completed Meta Text Message properly - else if (protocol == 0x80 || protocol == 0x89) - { - fprintf (stderr, " "); - - if (protocol == 0x80) //Meta - { - //show Control Byte Len and Segment Values on Meta Text - fprintf (stderr, "%d/%d; ", (input[1] >> 4), input[1] & 0xF); - for (i = 2; i < len; i++) - fprintf (stderr, "%c", input[i]); - } - else - { - for (i = 1; i < len; i++) - fprintf (stderr, "%c", input[i]); - } - - } - //Any Other Raw Data as Hex - else - { - fprintf (stderr, " "); - for (i = 1; i < len; i++) - fprintf (stderr, "%02X", input[i]); - } - - PKT_END: ; //do nothing - -} - -//WIP PKT decoder -void processM17PKT(dsd_opts * opts, dsd_state * state) -{ - - int i, x; - uint8_t dbuf[184]; //384-bit (192 symbol) frame - 16-bit (8 symbol) sync pattern (184 dibits) - uint8_t m17_int_bits[368]; //368 bits that are still interleaved - uint8_t m17_rnd_bits[368]; //368 bits that are still scrambled - uint16_t m17_bits[368]; //368 bits that have been de-interleaved and de-scrambled - uint16_t m17_depunc[488]; //488 weighted byte representation of bits after depuncturing - uint8_t pkt_packed[50]; - uint8_t pkt_bytes[48]; - - uint32_t v_err = 0; //errors in viterbi decoder - UNUSED(v_err); - - memset (dbuf, 0, sizeof(dbuf)); - memset (state->m17_lsf, 0, sizeof(state->m17_lsf)); - memset (m17_int_bits, 0, sizeof(m17_int_bits)); - memset (m17_bits, 0, sizeof(m17_bits)); - memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits)); - memset (m17_depunc, 0, sizeof(m17_depunc)); - - memset (pkt_packed, 0, sizeof(pkt_packed)); - memset (pkt_bytes, 0, sizeof(pkt_bytes)); - - - //load dibits into dibit buffer - for (i = 0; i < 184; i++) - dbuf[i] = getDibit(opts, state); - - //convert dbuf into a bit array - for (i = 0; i < 184; i++) - { - m17_rnd_bits[i*2+0] = (dbuf[i] >> 1) & 1; - m17_rnd_bits[i*2+1] = (dbuf[i] >> 0) & 1; - } - - //descramble the frame - for (i = 0; i < 368; i++) - m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1; - - //deinterleave 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_bits[i] = m17_int_bits[x]; - } - - //P3 Depuncture and Add Weights - x = 0; - for (i = 0; i < 420; i++) - { - if (p3[i%8] == 1) - m17_depunc[i] = m17_bits[x++]; - else m17_depunc[i] = 0; - - if (m17_depunc[i]) - m17_depunc[i] = 0xFFFF; - else m17_depunc[i] = 0x7FFF; - } - - - //use the libM17 Viterbi Decoder - uint16_t len = 420; - v_err = viterbi_decode(pkt_bytes, m17_depunc, len); - // v_err -= 3932040; //cost negation (double check this as well as unit, meaning, etc) - - //debug - // fprintf (stderr, "\n pkt_bytes: \n"); - // for (i = 0; i < 27; i++) - // fprintf (stderr, " %02X", pkt_bytes[i]); - - //copy + left shift one octet - memcpy (pkt_packed, pkt_bytes+1, 26); - - uint8_t counter = (pkt_packed[25] >> 2) & 0x1F; - uint8_t eot = (pkt_packed[25] >> 7) & 1; - - //disabled these checks, this fails if 2 blocks are sent, better just to keep track of it by internal counter - // if (!eot) state->m17_pbc_ct = counter; - // else if (eot && state->m17_pbc_ct == 0) {} //pass if single block packet (bugfix super short text messages) - // else if (eot && state->m17_pbc_ct != 0) state->m17_pbc_ct++; //increment if eot and counter not zero - - int ptr = state->m17_pbc_ct*25; - - //sanity check to we don't go out of bounds on memcpy and total (core dump) - if (ptr > 825) ptr = 825; - if (ptr < 0) ptr = 0; - - int total = ptr + counter - 3; //-3 if changes to M17_Implementations are made - - //sanity check on total - if (total < 0 && eot == 1) total = 0; //this is from a bad decode, and caused a core dump on total being a negative value - - int end = ptr + 25; - - //TODO: Fix this - /* - 00:23:28 Sync: +M17 PREAMBLE - 00:23:28 Sync: +M17 PKT - 00:23:28 Sync: +M17 PKT CNT: 00; LST: 01; EOT: 1;Segmentation fault (core dumped) <--negative total value calculated on this - */ - - //debug counter and eot value - if (!eot) fprintf (stderr, " CNT: %02d; PBC: %02d; EOT: %d;", state->m17_pbc_ct, counter, eot); - else fprintf (stderr, " CNT: %02d; LST: %02d; EOT: %d;", state->m17_pbc_ct, counter, eot); - // fprintf (stderr, " PTR: %d; Total: %d; ", ptr, total); - - //put packet into storage - memcpy (state->m17_pkt+ptr, pkt_packed, 25); - - //debug TOTAL and its value - // fprintf (stderr, " T: %d; P: %02X", total, state->m17_pkt[total]); - - //debug - if (opts->payload == 1) - { - fprintf (stderr, "\n pkt: "); - for (i = 0; i < 26; i++) - fprintf (stderr, " %02X", pkt_packed[i]); - } - - if (eot) - { - //do a CRC check - uint16_t crc_cmp = crc16m17(state->m17_pkt, total+1); //total, or total+1? - // uint16_t crc_ext = (state->m17_pkt[end-2] << 8) + state->m17_pkt[end-1]; //extract from last 16-bits of the payload, or - uint16_t crc_ext = (state->m17_pkt[total+1] << 8) + state->m17_pkt[total+2]; //immediately after the terminating byte - - if (crc_cmp == crc_ext) - // decodeM17PKT(opts, state, state->m17_pkt, end-2); - decodeM17PKT(opts, state, state->m17_pkt, total); //end-2 if CRC at the end, total if CRC after term - else if (opts->aggressive_framesync == 0) //CRC Bypass, check anyways (if enabled) - // decodeM17PKT(opts, state, state->m17_pkt, end-2); - decodeM17PKT(opts, state, state->m17_pkt, total); //end-2 if CRC at the end, total if CRC after term - - if (crc_cmp != crc_ext) - fprintf (stderr, " (CRC ERR) "); - - if (opts->payload == 1) - { - fprintf (stderr, "\n PKT:"); - for (i = 0; i < end; i++) - { - if ( (i%25) == 0 && i != 0) - fprintf (stderr, "\n "); - fprintf (stderr, " %02X", state->m17_pkt[i]); - } - fprintf (stderr, "\n CRC - C: %04X; E: %04X", crc_cmp, crc_ext); - } - - //reset after processing - memset (state->m17_pkt, 0, sizeof(state->m17_pkt)); - state->m17_pbc_ct = 0; - } - - //increment pbc counter last - if (!eot) state->m17_pbc_ct++; - - //ending linebreak - fprintf (stderr, "\n"); - -} //end processM17PKT - -//Process Received IP Frames -void processM17IPF(dsd_opts * opts, dsd_state * state) -{ - - //Tweaks and Enable Ncurses Terminal - opts->dmr_stereo = 0; - opts->audio_in_type = 9; //NULL - if (opts->use_ncurses_terminal == 1) - ncursesOpen(opts, state); - - //NOTE: This Internal Handling is non-blocking and keeps the connection alive - //in the event of the other end opening and closing often (exit and restart) - - //encode with: dsd-fme -fZ -M M17:1:N0CALL:ALL:48000:1 -o m17:127.0.0.1:17000 -N 2> m17out.ans - //decode with: dsd-fme -fU -i m17:127.0.0.1:17000 -N 2> m17ip.ans - - //NOTE: Currently, IP Frame decoding cannot be used with -o udp audio output - //its a rare use case, but should be noted, I think udpbind does something to block that functionality - - //Bind UDP Socket - int err = 1; //NOTE: err will tell us how many bytes were received, if successful - opts->udp_sockfd = UDPBind(opts->m17_hostname, opts->m17_portno); - - int i, j, k; - - //Standard IP Framing - uint8_t ip_frame[1000]; memset (ip_frame, 0, sizeof(ip_frame)); - uint8_t magic[4] = {0x4D, 0x31, 0x37, 0x20}; - uint8_t ackn[4] = {0x41, 0x43, 0x4B, 0x4E}; - uint8_t nack[4] = {0x4E, 0x41, 0x43, 0x4B}; - uint8_t conn[4] = {0x43, 0x4F, 0x4E, 0x4E}; - uint8_t disc[4] = {0x44, 0x49, 0x53, 0x43}; - uint8_t ping[4] = {0x50, 0x49, 0x4E, 0x47}; - uint8_t pong[4] = {0x50, 0x4F, 0x4E, 0x47}; - uint8_t eotx[4] = {0x45, 0x4F, 0x54, 0x58}; //EOTX is not Standard, but going to send / receive anyways - uint8_t mpkt[4] = {0x4D, 0x50, 0x4B, 0x54}; //MPKT is not Standard, but I think sending PKT payloads would be viable over UDP (no reason not to) - - unsigned long long int src = 0; //source derived from CONN, DISC, EOTX, and Other Headers - char c; - - while (!exitflag) - { - - //if reading from socket receiver - if (opts->udp_sockfd) - { - //NOTE: blocking issue resolved with setsockopt in UDPBind - - //NOTE: Using recvfrom seems to load MSB of array first, - //compared to having to push samples through it like with STDIN. - - err = m17_socket_receiver(opts, &ip_frame); - - //debug - // fprintf (stderr, "ERR: %X; ", err); - } - else exitflag = 1; - - src = ((unsigned long long int)ip_frame[4] << 40ULL) + ((unsigned long long int)ip_frame[5] << 32ULL) + ((unsigned long long int)ip_frame[6] << 24ULL) + - ((unsigned long long int)ip_frame[7] << 16ULL) + ((unsigned long long int)ip_frame[8] << 8ULL) + ((unsigned long long int)ip_frame[9] << 0ULL); - - //compare header to magic and decode IP voice frame w/ M17 magic header - if (memcmp(ip_frame, magic, 4) == 0) - { - - //Enable Carrier, synctype, etc - state->carrier = 1; - state->synctype = 8; - - //convert bytes to bits - k = 0; - uint8_t ip_bits[462]; memset(ip_bits, 0, sizeof(ip_bits)); - for (i = 0; i < 54; i++) - { - for (j = 0; j < 8; j++) - ip_bits[k++] = (ip_frame[i] >> (7-j)) & 1; - } - - //copy Stream ID - uint16_t sid = (uint16_t)ConvertBitIntoBytes(&ip_bits[32], 16); - - //copy LSF - for (i = 0; i < 224; i++) - state->m17_lsf[i] = ip_bits[i+48]; - - //get FN and EOT bit - uint16_t fn = (uint16_t)ConvertBitIntoBytes(&ip_bits[273], 15); - uint8_t eot = ip_bits[272]; - - //update IV CTR from FN - state->m17_meta[14] = (uint16_t)ConvertBitIntoBytes(&ip_bits[273], 7); - state->m17_meta[15] = (uint16_t)ConvertBitIntoBytes(&ip_bits[280], 8); - - fprintf (stderr, "\n M17 IP Stream: %04X; FN: %05d;", sid, fn); - if (eot) fprintf (stderr, " EOT;"); - - //copy payload - uint8_t payload[128]; memset(payload, 0, sizeof(payload)); - for (i = 0; i < 128; i++) - payload[i] = ip_bits[i+288]; - - //copy received CRC - uint16_t crc_ext = (ip_frame[52] << 8) + ip_frame[53]; - - //calculate CRC on received packet - uint16_t crc_cmp = crc16m17(ip_frame, 52); - - if (crc_ext == crc_cmp) - M17decodeLSF(state); - - if (state->m17_str_dt == 2) - M17processCodec2_3200(opts, state, payload); - - else if (state->m17_str_dt == 3) - M17processCodec2_1600(opts, state, payload); - - if (opts->payload == 1) - { - fprintf (stderr, "\n IP:"); - for (i = 0; i < 54; i++) - { - if ( (i%14) == 0 ) fprintf (stderr, "\n "); - fprintf (stderr, "[%02X]", ip_frame[i]); - } - fprintf (stderr, " (CRC CHK) E: %04X; C: %04X;", crc_ext, crc_cmp); - } - - if (crc_ext != crc_cmp) fprintf (stderr, " IP CRC ERR"); - - //clear frame - memset (ip_frame, 0, sizeof(ip_frame)); - - } - - //other headers from UDP IP - else if (memcmp(ip_frame, ackn, 4) == 0) - { - fprintf (stderr, "\n M17 IP ACNK: "); - - //clear frame - memset (ip_frame, 0, sizeof(ip_frame)); - } - - else if (memcmp(ip_frame, nack, 4) == 0) - { - fprintf (stderr, "\n M17 IP NACK: "); - - //clear frame - memset (ip_frame, 0, sizeof(ip_frame)); - } - - else if (memcmp(ip_frame, conn, 4) == 0) - { - fprintf (stderr, "\n M17 IP CONN: "); - - if (src == 0xFFFFFFFFFFFF) - fprintf (stderr, "UNKNOWN FFFFFFFFFFFF"); - else if (src == 0) - fprintf (stderr, "RESERVED %012llx", src); - else if (src >= 0xEE6B28000000) - fprintf (stderr, "RESERVED %012llx", src); - else - { - for (i = 0; i < 9; i++) - { - c = b40[src % 40]; - fprintf (stderr, "%c", c); - src = src / 40; - } - } - - //reflector module user is connecting to - fprintf (stderr, "Module: %c; ", ip_frame[10]); - - if (opts->payload == 1) - { - for (i = 0; i < 11; i++) - fprintf (stderr, "%02X ", ip_frame[i]); - } - - //clear frame - memset (ip_frame, 0, sizeof(ip_frame)); - } - - else if (memcmp(ip_frame, disc, 4) == 0) - { - fprintf (stderr, "\n M17 IP DISC: "); - - if (src == 0xFFFFFFFFFFFF) - fprintf (stderr, "UNKNOWN FFFFFFFFFFFF"); - else if (src == 0) - fprintf (stderr, "RESERVED %012llx", src); - else if (src >= 0xEE6B28000000) - fprintf (stderr, "RESERVED %012llx", src); - else - { - for (i = 0; i < 9; i++) - { - c = b40[src % 40]; - fprintf (stderr, "%c", c); - src = src / 40; - } - } - - if (opts->payload == 1) - { - for (i = 0; i < 10; i++) - fprintf (stderr, "%02X ", ip_frame[i]); - } - - //clear frame - memset (ip_frame, 0, sizeof(ip_frame)); - - state->carrier = 0; - state->synctype = -1; - } - - else if (memcmp(ip_frame, eotx, 4) == 0) - { - fprintf (stderr, "\n M17 IP EOTX: "); - - if (src == 0xFFFFFFFFFFFF) - fprintf (stderr, "UNKNOWN FFFFFFFFFFFF"); - else if (src == 0) - fprintf (stderr, "RESERVED %012llx", src); - else if (src >= 0xEE6B28000000) - fprintf (stderr, "RESERVED %012llx", src); - else - { - for (i = 0; i < 9; i++) - { - c = b40[src % 40]; - fprintf (stderr, "%c", c); - src = src / 40; - } - } - - if (opts->payload == 1) - { - for (i = 0; i < 10; i++) - fprintf (stderr, "%02X ", ip_frame[i]); - } - - //clear frame - memset (ip_frame, 0, sizeof(ip_frame)); - - //drop carrier and sync - state->carrier = 0; - state->synctype = -1; - } - - else if (memcmp(ip_frame, ping, 4) == 0) - { - fprintf (stderr, "\n M17 IP PING: "); - - if (src == 0xFFFFFFFFFFFF) - fprintf (stderr, "UNKNOWN FFFFFFFFFFFF"); - else if (src == 0) - fprintf (stderr, "RESERVED %012llx", src); - else if (src >= 0xEE6B28000000) - fprintf (stderr, "RESERVED %012llx", src); - else - { - for (i = 0; i < 9; i++) - { - c = b40[src % 40]; - fprintf (stderr, "%c", c); - src = src / 40; - } - } - - if (opts->payload == 1) - { - for (i = 0; i < 10; i++) - fprintf (stderr, "%02X ", ip_frame[i]); - } - - } - - else if (memcmp(ip_frame, pong, 4) == 0) - { - fprintf (stderr, "\n M17 IP PONG: "); - - if (src == 0xFFFFFFFFFFFF) - fprintf (stderr, "UNKNOWN FFFFFFFFFFFF"); - else if (src == 0) - fprintf (stderr, "RESERVED %012llx", src); - else if (src >= 0xEE6B28000000) - fprintf (stderr, "RESERVED %012llx", src); - else - { - for (i = 0; i < 9; i++) - { - c = b40[src % 40]; - fprintf (stderr, "%c", c); - src = src / 40; - } - } - - if (opts->payload == 1) - { - for (i = 0; i < 10; i++) - fprintf (stderr, "%02X ", ip_frame[i]); - } - } - - else if (memcmp(ip_frame, mpkt, 4) == 0) - { - - //convert bytes to bits - k = 0; - uint8_t ip_bits[462]; memset(ip_bits, 0, sizeof(ip_bits)); - for (i = 0; i < 54; i++) - { - for (j = 0; j < 8; j++) - ip_bits[k++] = (ip_frame[i] >> (7-j)) & 1; - } - - //copy Stream ID (PKT ID) - uint16_t sid = (uint16_t)ConvertBitIntoBytes(&ip_bits[32], 16); - - //copy LSF - for (i = 0; i < 224; i++) - state->m17_lsf[i] = ip_bits[i+48]; - //copy received CRC - uint16_t crc_ext = (ip_frame[err-2] << 8) + ip_frame[err-1]; - - //calculate CRC on received packet - uint16_t crc_cmp = crc16m17(ip_frame, err-2); - - fprintf (stderr, "\n M17 IP MPKT: %04X;", sid); - - if (crc_ext == crc_cmp) - M17decodeLSF(state); - - if (opts->payload == 1) - { - for (i = 0; i < err; i++) - { - if ( (i%25)==0) - fprintf (stderr, "\n "); - fprintf (stderr, "%02X ", ip_frame[i]); - } - fprintf (stderr, " (CRC CHK) E: %04X; C: %04X;", crc_ext, crc_cmp); - fprintf (stderr, "\n M17 IP RECD: %d", err); - } - - if (crc_ext == crc_cmp) - decodeM17PKT (opts, state, ip_frame+34, err-34-3); - if (crc_ext != crc_cmp) fprintf (stderr, " IP CRC ERR"); - - //clear frame - memset (ip_frame, 0, sizeof(ip_frame)); - - } - - //debug - // else if (opts->payload == 1) - // { - // fprintf (stderr, "\n UDP:"); - // for (i = 0; i < 54; i++) - // { - // if ( (i%14) == 0 ) fprintf (stderr, "\n "); - // fprintf (stderr, "[%02X]", ip_frame[i]); - // } - // } - - //refresh ncurses printer, if enabled - if (opts->use_ncurses_terminal == 1) - ncursesPrinter(opts, state); - - //slot 1 - watchdog_event_history(opts, state, 0); - watchdog_event_current(opts, state, 0); - - //clear frame - memset (ip_frame, 0, sizeof(ip_frame)); - - } -} \ No newline at end of file diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp index eefcb8b..269bde5 100644 --- a/src/rtl_sdr_fm.cpp +++ b/src/rtl_sdr_fm.cpp @@ -1034,7 +1034,7 @@ void open_rtlsdr_stream(dsd_opts *opts) //init with low pass if decoding P25 or EDACS/Provoice if (opts->frame_p25p1 == 1 || opts->frame_p25p2 == 1 || opts->frame_provoice == 1) demod_init_ro2(&demod); - else if (opts->analog_only == 1 || opts->m17encoder == 1) + else if (opts->analog_only == 1) demod_init_analog(&demod); else demod_init(&demod); output_init(&output);