diff --git a/include/dsd.h b/include/dsd.h index 4aded7e..c30b2ab 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -706,6 +706,20 @@ typedef struct //Upsampled Audio Smoothing uint8_t audio_smoothing; + //YSF Fusion Call Strings and Info + uint8_t ysf_dt; //data type -- VD1, VD2, Full Rate, etc. + uint8_t ysf_fi; //frame information -- HC, CC, TC + uint8_t ysf_cm; //group or private call + char ysf_tgt[11]; + char ysf_src[11]; + char ysf_upl[11]; + char ysf_dnl[11]; + char ysf_rm1[6]; + char ysf_rm2[6]; + char ysf_rm3[6]; + char ysf_rm4[6]; + char ysf_txt[21][21]; //text storage blocks + } dsd_state; /* diff --git a/src/dsd_dibit.c b/src/dsd_dibit.c index 3fbff10..d7a9705 100644 --- a/src/dsd_dibit.c +++ b/src/dsd_dibit.c @@ -264,18 +264,18 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol) } else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) || - (state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13) || + (state->synctype == 31) || (state->synctype == 11) || (state->synctype == 13) || (state->synctype == 17) || (state->synctype == 29) || (state->synctype == 36) ) { // 1 -P25p1 // 3 -X2-TDMA (inverted signal voice frame) // 5 -X2-TDMA (inverted signal data frame) - // 9 -NXDN (inverted voice frame) // 11 -DMR (inverted signal voice frame) // 13 -DMR (inverted signal data frame) // 17 -NXDN (inverted data frame) // 29 -NXDN (inverted FSW) + // 31 -YSF // 36 -P25p2 int valid; @@ -340,6 +340,7 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol) // 12 +DMR (non inverted signal voice frame) // 16 +NXDN (non inverted data frame) // 28 +NXND (FSW) + // 30 +YSF // 35 +p25p2 int valid; diff --git a/src/dsd_frame.c b/src/dsd_frame.c index 0934ca0..324d339 100644 --- a/src/dsd_frame.c +++ b/src/dsd_frame.c @@ -290,13 +290,7 @@ processFrame (dsd_opts * opts, dsd_state * state) //ysf else if ((state->synctype == 30) || (state->synctype == 31)) { - //Do stuff - //fprintf(stderr, "YSF Sync! \n"); - if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) - { - //openMbeOutFile (opts, state); - } - //sprintf(state->fsubtype, " VOICE "); + //relocate MBEout to inside frame handling -- Not Working Currently for YSF processYSF(opts, state); return; } diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c index d99c507..7103e59 100644 --- a/src/dsd_frame_sync.c +++ b/src/dsd_frame_sync.c @@ -228,13 +228,17 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { t_max = 10; } - //else if dPMR + //dPMR else if (opts->frame_dpmr == 1) { t_max = 12; //based on Frame_Sync_2 pattern } - //if Phase 2 (or YSF in future), then only 19 - else if (state->lastsynctype == 35 || state->lastsynctype == 36) //P2 + else if (opts->frame_ysf == 1) + { + t_max = 20; //20 on YSF + } + //if Phase 2, then only 19 + else if (state->lastsynctype == 35 || state->lastsynctype == 36 ) { t_max = 19; //Phase 2 S-ISCH is only 19 } @@ -573,24 +577,20 @@ getFrameSync (dsd_opts * opts, dsd_state * state) } } //YSF sync - strncpy(synctest20, (synctest_p - 19), 20); //double check make sure this is right + strncpy(synctest20, (synctest_p - 19), 20); if(opts->frame_ysf == 1) //(opts->frame_ysf == 1 { if (0 == 0) //opts->inverted_ysf == 0 { if (strcmp(synctest20, FUSION_SYNC) == 0) { + printFrameSync (opts, state, "+YSF ", synctest_pos + 1, modulation); state->carrier = 1; state->offset = synctest_pos; state->max = ((state->max) + lmax) / 2; state->min = ((state->min) + lmin) / 2; - fprintf (stderr, "\nYSF FUSION SYNC \n"); - opts->inverted_ysf = 0; //should we set this here? + opts->inverted_ysf = 0; state->lastsynctype = 30; - if ( opts->monitor_input_audio == 1) - { - pa_simple_flush(opts->pulse_raw_dev_out, NULL); - } return (30); } } @@ -601,17 +601,13 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { if (strcmp(synctest20, INV_FUSION_SYNC) == 0) { + printFrameSync (opts, state, "-YSF ", synctest_pos + 1, modulation); state->carrier = 1; state->offset = synctest_pos; state->max = ((state->max) + lmax) / 2; state->min = ((state->min) + lmin) / 2; - fprintf (stderr, "\nINVERTED YSF FUSION SYNC \n"); - opts->inverted_ysf = 1; //should we set this here? + opts->inverted_ysf = 1; state->lastsynctype = 31; - if ( opts->monitor_input_audio == 1) - { - pa_simple_flush(opts->pulse_raw_dev_out, NULL); - } return (31); } } diff --git a/src/dsd_main.c b/src/dsd_main.c index 20fe634..e26dfde 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -447,6 +447,20 @@ noCarrier (dsd_opts * opts, dsd_state * state) sprintf (state->dpmr_caller_id, "%s", " "); sprintf (state->dpmr_target_id, "%s", " "); + //YSF Fusion Call Strings + sprintf (state->ysf_tgt, "%s", " "); //10 spaces + sprintf (state->ysf_src, "%s", " "); //10 spaces + sprintf (state->ysf_upl, "%s", " "); //10 spaces + sprintf (state->ysf_dnl, "%s", " "); //10 spaces + sprintf (state->ysf_rm1, "%s", " "); //5 spaces + sprintf (state->ysf_rm2, "%s", " "); //5 spaces + sprintf (state->ysf_rm3, "%s", " "); //5 spaces + sprintf (state->ysf_rm4, "%s", " "); //5 spaces + memset (state->ysf_txt, 0, sizeof(state->ysf_txt)); + state->ysf_dt = 9; + state->ysf_fi = 9; + state->ysf_cm = 9; + } //nocarrier void @@ -1013,6 +1027,21 @@ initState (dsd_state * state) sprintf (state->dpmr_caller_id, "%s", " "); sprintf (state->dpmr_target_id, "%s", " "); + //YSF Fusion Call Strings + sprintf (state->ysf_tgt, "%s", " "); //10 spaces + sprintf (state->ysf_src, "%s", " "); //10 spaces + sprintf (state->ysf_upl, "%s", " "); //10 spaces + sprintf (state->ysf_dnl, "%s", " "); //10 spaces + sprintf (state->ysf_rm1, "%s", " "); //5 spaces + sprintf (state->ysf_rm2, "%s", " "); //5 spaces + sprintf (state->ysf_rm3, "%s", " "); //5 spaces + sprintf (state->ysf_rm4, "%s", " "); //5 spaces + memset (state->ysf_txt, 0, sizeof(state->ysf_txt)); + state->ysf_dt = 9; + state->ysf_fi = 9; + state->ysf_cm = 9; + + } //init_state void @@ -1101,6 +1130,7 @@ usage () printf (" -fn Decode only NXDN96* (12.5 kHz)\n"); printf (" -fp Decode only EDACS/ProVoice*\n"); printf (" -fm Decode only dPMR*\n"); + printf (" -fy Decode only YSF*\n"); printf (" -l Disable DMR, dPMR, and NXDN input filtering\n"); printf (" -u Unvoiced speech quality (default=3)\n"); printf (" -xx Expect non-inverted X2-TDMA signal\n"); @@ -1895,8 +1925,6 @@ main (int argc, char **argv) opts.frame_dpmr = 0; opts.frame_provoice = 0; opts.frame_ysf = 1; - state.samplesPerSymbol = 20; //10 - state.symbolCenter = 10; opts.mod_c4fm = 1; opts.mod_qpsk = 0; opts.mod_gfsk = 0; @@ -1907,8 +1935,7 @@ main (int argc, char **argv) state.dmr_stereo = 0; opts.dmr_mono = 0; sprintf (opts.output_name, "YSF"); - fprintf (stderr,"Setting symbol rate to 2400 / second\n"); - fprintf (stderr,"Decoding only YSF frames.\nNot working yet!\n"); + fprintf (stderr,"Decoding only YSF frames. \n"); } else if (optarg[0] == '2') { diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index bd3d287..38e7f82 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -85,7 +85,7 @@ char * SyncTypes[44] = { "NXDN", "NXDN", "YSF", //30 - "YSF", + "YSF", //31 "DMR", "DMR", "DMR", @@ -338,7 +338,8 @@ char *choices[] = { "Decode dPMR", "Decode NXDN48", "Decode NXDN96", - "Decode DMR Stereo", //was X2-TDMA* + "Decode DMR TDMA", + "Decode YSF FUSION", "Toggle Signal Inversion", "Key Entry", "Reset Call History", @@ -557,7 +558,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) } //Input Output Options - if (choice == 17) + if (choice == 18) { //test making a new window while other window is open test_win = newwin(HEIGHT-1, WIDTH+9, starty+5, startx+5); @@ -1086,7 +1087,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) } //Privacy Key Entry - if (choice == 13) + if (choice == 14) { state->payload_keyid = 0; state->payload_keyidR = 0; @@ -1539,6 +1540,32 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) //opts->unmute_encrypted_p25 = 0; } if (choice == 12) + { + //Decode YSF Fusion + // resetState (state); //use sparingly, may cause memory leak + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + sprintf (opts->output_name, "YSF"); + opts->dmr_mono = 0; + opts->dmr_stereo = 0; //this value is the end user option + state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling + opts->pulse_digi_rate_out = 48000; + opts->pulse_digi_out_channels = 1; + opts->frame_dstar = 0; + opts->frame_x2tdma = 0; + opts->frame_p25p1 = 0; + opts->frame_nxdn48 = 0; + opts->frame_nxdn96 = 0; + opts->frame_dmr = 0; + opts->frame_dpmr = 0; + opts->frame_provoice = 0; + opts->frame_ysf = 1; + opts->mod_c4fm = 1; + opts->mod_qpsk = 0; + opts->mod_gfsk = 0; + state->rf_mod = 0; + } + if (choice == 13) { //Set all signal for inversion or uninversion if (opts->inverted_dmr == 0) @@ -1557,7 +1584,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) } } - if (choice == 14) //reset call history (usually if janky output when switching modes) + if (choice == 15) //reset call history (usually if janky output when switching modes) { for (short int k = 0; k <= 9; k++) { @@ -1582,7 +1609,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) state->lasttgR = 0; } - if (choice == 15) //toggle payload printing + if (choice == 16) //toggle payload printing { if (opts->payload == 0) { @@ -1595,7 +1622,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) fprintf(stderr, "Payload Off\n"); } } - if (choice == 16) + if (choice == 17) { //hardset P2 WACN, SYSID, and NAC entry_win = newwin(6, WIDTH+16, starty+10, startx+10); @@ -1648,7 +1675,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) } - if (choice == 18) + if (choice == 19) { short int lrrpchoice = 0; entry_win = newwin(10, WIDTH+16, starty+10, startx+10); @@ -1714,7 +1741,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) opts->lrrp_out_file[0] = 0; } } - if (choice == 19) + if (choice == 20) { ncursesClose(); //cleanup_rtlsdr_stream(); @@ -2409,6 +2436,66 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } } + //YSF + if (lls == 30 || lls == 31) + { + // printw ("\n"); + printw ("| "); + printw ("Yaesu Fusion - "); + //insert data type and frame information + if (state->ysf_dt == 0) printw("Voice/Data T1 "); + if (state->ysf_dt == 1) printw("Data Full Rate"); + if (state->ysf_dt == 2) printw("Voice/Data T2 "); + if (state->ysf_dt == 3) printw("V/W Full Rate"); + printw (" "); + if (state->ysf_cm == 0) printw("Group/CQ "); + if (state->ysf_cm == 3) printw("Private "); + if (state->ysf_cm == 1) printw("Reserved "); + if (state->ysf_cm == 2) printw("Reserved "); + + if (state->ysf_fi == 0) printw("HC "); + if (state->ysf_fi == 1) printw("CC "); + if (state->ysf_fi == 2) printw("TC "); + if (state->ysf_fi == 3) printw("XX "); + + printw ("\n"); + printw ("| "); + printw ("TGT: %s ", state->ysf_tgt); + printw ("SRC: %s ", state->ysf_src); + printw ("\n"); + printw ("| "); + printw ("UPL: %s ", state->ysf_upl); + printw ("DNL: %s ", state->ysf_dnl); + printw ("\n"); + printw ("| "); + printw ("RM1: %s ", state->ysf_rm1); + printw ("RM2: %s ", state->ysf_rm2); + printw ("\n"); + printw ("| "); + printw ("RM3: %s ", state->ysf_rm3); + printw ("RM4: %s ", state->ysf_rm4); + + //these texts can get pretty long and out of sorts, and lots of 0x20 spaces + //just going to leave these to only be in the console output + + // printw ("\n"); + // printw ("| "); + // printw ("TXT: "); + // for (i = 4; i < 8; i++) + // { + // for (int j = 0; j < 20; j++) + // { + // //no spaces and no asterisks + // if (state->ysf_txt[i][j] != 0x2A) + // printw ("%c", state->ysf_txt[i][j]); + // } + // // printw (" "); //just a single space between each 'block' + // } + + printw ("\n"); + + } + //NXDN if (lls == 28 || lls == 29) { diff --git a/src/dsd_symbol.c b/src/dsd_symbol.c index 65d109f..a28472d 100644 --- a/src/dsd_symbol.c +++ b/src/dsd_symbol.c @@ -277,7 +277,8 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) if (opts->use_cosine_filter) { - if ( (state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33 || state->lastsynctype == 34) + if ( (state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33 + || state->lastsynctype == 34 || state->lastsynctype == 30 || state->lastsynctype == 31) { sample = dmr_filter(sample); } diff --git a/src/ysf.c b/src/ysf.c index 8882036..77760aa 100644 --- a/src/ysf.c +++ b/src/ysf.c @@ -1,85 +1,74 @@ /*------------------------------------------------------------------------------- * ysf.c - * Yaesu Fusion Decoder for DSD + * Yaesu Fusion Decoder (WIP) + * + * Bits of code from DSDcc, Osmocom OP25, and gr-ysf sprinkled in + * * * LWVMOBILE - * 2022-04 DSD-FME Florida Man Edition + * 2023-07 DSD-FME Florida Man Edition *-----------------------------------------------------------------------------*/ - /* - * Copyright (C) 2010 DSD Author - * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - - #include "dsd.h" -const int fichInterleave[100] = { - 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, - 1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 56, 61, 66, 71, 76, 81, 86, 91, 96, - 2, 7, 12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, - 3, 8, 13, 18, 23, 28, 33, 38, 43, 48, 53, 58, 63, 68, 73, 78, 83, 88, 93, 98, - 4, 9, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64, 69, 74, 79, 84, 89, 94, 99, +/* thx gr-ysf fr_vch_decoder_bb_impl.cc * Copyright 2015 Mathias Weyland */ +// I hold Sylvain Munaut in high esteem for figuring this out. +uint8_t fr_interleave[144] = { +0, 7, 12, 19, 24, 31, 36, 43, 48, 55, 60, 67, // [ 0 - 11] yellow message +72, 79, 84, 91, 96, 103, 108, 115, 120, 127, 132, // [ 12 - 22] yellow FEC +139, 1, 6, 13, 18, 25, 30, 37, 42, 49, 54, 61, // [ 23 - 34] orange message +66, 73, 78, 85, 90, 97, 102, 109, 114, 121, 126, // [ 35 - 45] orange FEC +133, 138, 2, 9, 14, 21, 26, 33, 38, 45, 50, 57, // [ 46 - 57] red message +62, 69, 74, 81, 86, 93, 98, 105, 110, 117, 122, // [ 58 - 68] red FEC +129, 134, 141, 3, 8, 15, 20, 27, 32, 39, 44, 51, // [ 69 - 80] pink message +56, 63, 68, 75, 80, 87, 92, 99, 104, 111, 116, // [ 81 - 91] pink FEC +123, 128, 135, 140, 4, 11, 16, 23, 28, 35, 40, // [ 92 - 102] dark blue message +47, 52, 59, 64, // [103 - 106] dark blue FEC +71, 76, 83, 88, 95, 100, 107, 112, 119, 124, 131, // [107 - 117] light blue message +136, 143, 5, 10, // [118 - 121] light blue FEC +17, 22, 29, 34, 41, 46, 53, 58, 65, 70, 77, // [122 - 132] green message +82, 89, 94, 101, // [133 - 136] green FEC +106, 113, 118, 125, 130, 137, 142, // [137 - 143] unprotected }; -const int vd2Interleave[104] = { - 0, 26, 52, 78, - 1, 27, 53, 79, - 2, 28, 54, 80, - 3, 29, 55, 81, - 4, 30, 56, 82, - 5, 31, 57, 83, - 6, 32, 58, 84, - 7, 33, 59, 85, - 8, 34, 60, 86, - 9, 35, 61, 87, - 10, 36, 62, 88, - 11, 37, 63, 89, - 12, 38, 64, 90, - 13, 39, 65, 91, - 14, 40, 66, 92, - 15, 41, 67, 93, - 16, 42, 68, 94, - 17, 43, 69, 95, - 18, 44, 70, 96, - 19, 45, 71, 97, - 20, 46, 72, 98, - 21, 47, 73, 99, - 22, 48, 74, 100, - 23, 49, 75, 101, - 24, 50, 76, 102, - 25, 51, 77, 103 +uint8_t pn95[512] = +{ + 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, + 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, + 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, + 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, + 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, + 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, + 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, + 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, + 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, + 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, + 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, + 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, + 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, + 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, + 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1 }; -const int vfrInterleave[144] = { //IMBE 7200x4400 full rate interleave schedule - 0, 24, 48, 72, 96, 120, 25, 1, 73, 49, 121, 97, - 2, 26, 50, 74, 98, 122, 27, 3, 75, 51, 123, 99, - 4, 28, 52, 76, 100, 124, 29, 5, 77, 53, 125, 101, - 6, 30, 54, 78, 102, 126, 31, 7, 79, 55, 127, 103, - 8, 32, 56, 80, 104, 128, 33, 9, 81, 57, 129, 105, - 10, 34, 58, 82, 106, 130, 35, 11, 83, 59, 131, 107, - 12, 36, 60, 84, 108, 132, 37, 13, 85, 61, 133, 109, - 14, 38, 62, 86, 110, 134, 39, 15, 87, 63, 135, 111, - 16, 40, 64, 88, 112, 136, 41, 17, 89, 65, 137, 113, - 18, 42, 66, 90, 114, 138, 43, 19, 91, 67, 139, 115, - 20, 44, 68, 92, 116, 140, 45, 21, 93, 69, 141, 117, - 22, 46, 70, 94, 118, 142, 47, 23, 95, 71, 143, 119 -}; - -//half-rate ambe3600x2450 interleave schedule -const int YSFrW[36] = { - 0, 1, 0, 1, 0, 1, +//half-rate (from NXDN) +const int YnW[36] = +{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, @@ -87,9 +76,8 @@ const int YSFrW[36] = { 0, 2, 0, 2, 0, 2 }; -// bit index -const int YSFrX[36] = { - 23, 10, 22, 9, 21, 8, +const int YnX[36] = +{ 23, 10, 22, 9, 21, 8, 20, 7, 19, 6, 18, 5, 17, 4, 16, 3, 15, 2, 14, 1, 13, 0, 12, 10, @@ -97,10 +85,8 @@ const int YSFrX[36] = { 8, 6, 7, 5, 6, 4 }; -// bit 0 -// frame index -const int YSFrY[36] = { - 0, 2, 0, 2, 0, 2, +const int YnY[36] = +{ 0, 2, 0, 2, 0, 2, 0, 2, 0, 3, 0, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, @@ -108,9 +94,8 @@ const int YSFrY[36] = { 1, 3, 1, 3, 1, 3 }; -// bit index -const int YSFrZ[36] = { - 5, 3, 4, 2, 3, 1, +const int YnZ[36] = +{ 5, 3, 4, 2, 3, 1, 2, 0, 1, 13, 0, 12, 22, 11, 21, 10, 20, 9, 19, 8, 18, 7, 17, 6, @@ -118,170 +103,1094 @@ const int YSFrZ[36] = { 13, 2, 12, 1, 11, 0 }; -void processYSF(dsd_opts * opts, dsd_state * state) //YSF +//M = 26, depth of 4; -- work on replacing this with a simple deinterleave function like FICH and DCH use +const int vd2Interleave[104] = { +0, 26, 52, 78, +1, 27, 53, 79, +2, 28, 54, 80, +3, 29, 55, 81, +4, 30, 56, 82, +5, 31, 57, 83, +6, 32, 58, 84, +7, 33, 59, 85, +8, 34, 60, 86, +9, 35, 61, 87, +10, 36, 62, 88, +11, 37, 63, 89, +12, 38, 64, 90, +13, 39, 65, 91, +14, 40, 66, 92, +15, 41, 67, 93, +16, 42, 68, 94, +17, 43, 69, 95, +18, 44, 70, 96, +19, 45, 71, 97, +20, 46, 72, 98, +21, 47, 73, 99, +22, 48, 74, 100, +23, 49, 75, 101, +24, 50, 76, 102, +25, 51, 77, 103 +}; + +void ysf_dch_decode (dsd_opts * opts, dsd_state * state, uint8_t bn, uint8_t bt, uint8_t fn, uint8_t ft, int err, uint8_t input[]) { - //480 dibits - 20 dibit sync leaves 460 dibits (920 bits) each 'superframe' - fprintf (stderr, "processYSF Function \n"); - uint32_t i, j, k; - unsigned char dibit; + //TODO: Per Call WAV files using these strings + int i, j, k; + char dch_bytes[20]; + memset (dch_bytes, 0, sizeof(dch_bytes)); + char string1[11]; + char string2[11]; + char string3[21]; + char C; + + for (i = 0; i < 20; i++) + dch_bytes[i] = (char)ConvertBitIntoBytes(&input[i*8], 8); + + switch(bn){ //using bn here so we can use the frame number for sorting the text messages found in here + case 0: //CSD1 + + //Destination / Target + memcpy (string1, dch_bytes, 10); + string1[10] = '\0'; + fprintf (stderr, "TGT: "); + fprintf (stderr, "%s ", string1); + + //Source + memcpy (string2, dch_bytes+10, 10); + string2[10] = '\0'; + fprintf (stderr, "SRC: "); + fprintf (stderr, "%s ", string2); + + //Copy both to Ncurses Call String + memcpy (state->ysf_tgt, dch_bytes, 10); + state->ysf_tgt[10] = '\0'; + + memcpy (state->ysf_src, dch_bytes+10, 10); + state->ysf_src[10] = '\0'; + + break; + case 1: //CSD2 + + //Uplink + memcpy (string1, dch_bytes, 10); + string1[10] = '\0'; + fprintf (stderr, "U/L: "); + fprintf (stderr, "%s ", string1); + + //Downlink + memcpy (string2, dch_bytes+10, 10); + string2[10] = '\0'; + fprintf (stderr, "D/L: "); + fprintf (stderr, "%s ", string2); + + //Copy both to Ncurses Call String + memcpy (state->ysf_upl, dch_bytes, 10); + state->ysf_upl[10] = '\0'; + + state->ysf_dnl[10] = '\0'; + memcpy (state->ysf_dnl, dch_bytes+10, 10); + + break; + case 2: + // fprintf (stderr, "TXT: "); + memcpy (string3, dch_bytes, 20); + string3[20] = '\0'; + fprintf (stderr, "%s ", string3); + + // if (fn == 0) memset (state->ysf_txt, 0, sizeof(state->ysf_txt)); + //copy text to txt storage -- works now (had to expand storage space), but is cumbersome in ncurses, especially when garbage strings show up + // if (fn < 20) + // { + // //switch to checking each byte for a 'nice' ASCII character and + // //not a 'naughty' del/rem/break/garbled non ASCII/ALPHANUMERIC type character + // for (i = 0; i < 20; i++) + // { + // C = dch_bytes[i]; //skipping 0x20 space key + // if (C > 0x20 && C < 0x7F) state->ysf_txt[fn][i] = C; + // else state->ysf_txt[fn][i] = 0; //NULL + // } + // } + + break; + + default: + break; + + } + +} + +void ysf_dch_decode2 (dsd_opts * opts, dsd_state * state, uint8_t bn, uint8_t bt, uint8_t fn, uint8_t ft, int err, uint8_t input[]) +{ + //TODO: Per Call WAV files using these strings + int i, j, k; + char dch_bytes[20]; + memset (dch_bytes, 0, sizeof(dch_bytes)); + char string[11]; + char rem1[6]; + char rem2[6]; + + for (i = 0; i < 10; i++) + dch_bytes[i] = (char)ConvertBitIntoBytes(&input[i*8], 8); + + switch(fn){ + case 0: + //Destination / Target + fprintf (stderr, "TGT: "); + memcpy (string, dch_bytes, 10); + string[10] = '\0'; + fprintf (stderr, "%s", string); + + memcpy (state->ysf_tgt, dch_bytes, 10); + state->ysf_tgt[10] = '\0'; + + break; + case 1: + //Source + memcpy (string, dch_bytes, 10); + string[10] = '\0'; + fprintf (stderr, "SRC: "); + fprintf (stderr, "%s", string); + + memcpy (state->ysf_src, dch_bytes, 10); + state->ysf_src[10] = '\0'; + + break; + case 2: + //Uplink + memcpy (string, dch_bytes, 10); + string[10] = '\0'; + fprintf (stderr, "U/L: "); + fprintf (stderr, "%s", string); + + memcpy (state->ysf_upl, dch_bytes, 10); + state->ysf_upl[10] = '\0'; + + break; + case 3: + //Downlink + memcpy (string, dch_bytes, 10); + string[10] = '\0'; + fprintf (stderr, "D/L: "); + fprintf (stderr, "%s", string); + + state->ysf_dnl[10] = '\0'; + memcpy (state->ysf_dnl, dch_bytes, 10); + + break; + case 4: + //Remarks 1 and 2 + memcpy (rem1, dch_bytes, 5); + rem1[5] = '\0'; + fprintf (stderr, "RM1: "); + fprintf (stderr, "%s ", rem1); + + memcpy (rem2, dch_bytes+5, 5); + rem2[5] = '\0'; + fprintf (stderr, "RM2: "); + fprintf (stderr, "%s ", rem2); + + memcpy (state->ysf_rm1, dch_bytes, 5); + state->ysf_rm1[5] = '\0'; + + memcpy (state->ysf_rm2, dch_bytes+5, 5); + state->ysf_rm2[5] = '\0'; + + break; + case 5: + //Remarks 3 and 4 + memcpy (rem1, dch_bytes, 5); + rem1[5] = '\0'; + fprintf (stderr, "RM3: "); + fprintf (stderr, "%s ", rem1); + + memcpy (rem2, dch_bytes+5, 5); + rem2[5] = '\0'; + fprintf (stderr, "RM4: "); + fprintf (stderr, "%s ", rem2); + + memcpy (state->ysf_rm3, dch_bytes, 5); + state->ysf_rm3[5] = '\0'; + + memcpy (state->ysf_rm4, dch_bytes+5, 5); + state->ysf_rm4[5] = '\0'; + break; + + default: + break; + } + +} + +static inline uint16_t crc16ysf(const uint8_t buf[], int len) +{ + uint32_t poly = (1<<12) + (1<<5) + (1<<0); + uint32_t crc = 0; + for(int i=0; i> 1) & 1; + bits[k++] = (buf[i] >> 0) & 1; + } + + //setup for the convolutional decoder + for (i = 0; i < 200; i++) + temp[i] = bits[i] << 1; + + CNXDNConvolution_start(); + for (i = 0; i < 100; i++) + { + s0 = temp[(2*i)+0]; + s1 = temp[(2*i)+1]; + + CNXDNConvolution_decode(s0, s1); + } + + CNXDNConvolution_chainback(m_data, 96); + + //96/8 = 12, last 4 (96-100) are trailing zeroes + for(i = 0; i < 12; 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; + } + + uint16_t crc = crc16ysf(trellis_buf, 96); + if (crc != 0) err = -2; // crc failure + + for (i = 0; i < 80; i++) + trellis_buf[i] = trellis_buf[i] ^ pn95[i]; + + //reload after de-whitening + memset (m_data, 0, sizeof (m_data)); + for (i = 0; i < 12; i++) + m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8); + + //decode the callsign, etc, found in the DCH when no errors + if (err == 0) + ysf_dch_decode2 (opts, state, bn, bt, fn, ft, err, trellis_buf); + + if (opts->payload == 1) + { + fprintf (stderr, "\n "); + fprintf (stderr, "DCH2: "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", m_data[i]); + } + if (crc != 0) + { + fprintf (stderr, "%s", KRED); + fprintf (stderr, " (CRC ERR)"); + fprintf (stderr, "%s", KNRM); + } + fprintf (stderr, " "); + } + + return err; +} + +//modified version of nxdn_deperm_facch1 -- this one for Full Rate, Type 1 CC, Headers and Terminators DCH (180 dibit version) +int ysf_conv_dch (dsd_opts * opts, dsd_state * state, uint8_t bn, uint8_t bt, uint8_t fn, uint8_t ft, uint8_t input[]) +{ + int i, j, k, err; + uint8_t s0, s1; + uint8_t trellis_buf[190]; + uint8_t temp[370]; + uint8_t m_data[100]; + uint8_t bits[370]; + memset (trellis_buf, 0, sizeof(trellis_buf)); + memset (temp, 0, sizeof (temp)); + memset (m_data, 0, sizeof (m_data)); + memset (bits, 0, sizeof(bits)); + err = 0; + + //dibit de-interleave block length M = 9 dibits and depth N = 20 + uint8_t buf[180]; + memset (buf, 0, sizeof(buf)); + for (i=0; i<20; i++) { //20*9 = 180 + for (j=0; j<9; j++) { + buf[j+(i*9)] = input[i+(j*20)]; + } + } + + k = 0; + //convert dibits to bits + for (i = 0; i < 180; i++) + { + bits[k++] = (buf[i] >> 1) & 1; + bits[k++] = (buf[i] >> 0) & 1; + } + + //setup for the convolutional decoder + for (i = 0; i < 360; i++) + temp[i] = bits[i] << 1; + + CNXDNConvolution_start(); + for (i = 0; i < 180; i++) + { + s0 = temp[(2*i)+0]; + s1 = temp[(2*i)+1]; + + CNXDNConvolution_decode(s0, s1); + } + + CNXDNConvolution_chainback(m_data, 176); + + //176/8 = 22, last 4 (176-180) are trailing zeroes + for(i = 0; i < 22; 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; + } + + uint16_t crc = crc16ysf(trellis_buf, 176); + if (crc != 0) err = -2; // crc failure + + for (i = 0; i < 160; i++) + trellis_buf[i] = trellis_buf[i] ^ pn95[i]; + + //reload after de-whitening + memset (m_data, 0, sizeof (m_data)); + for (i = 0; i < 22; i++) + m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8); + + //decode the callsign, etc, found in the DCH when no errors + if (err == 0) + ysf_dch_decode (opts, state, bn, bt, fn, ft, err, trellis_buf); + + if (opts->payload == 1) + { + fprintf (stderr, "\n "); + fprintf (stderr, "DCH1: "); + for (i = 0; i < 22; i++) + { + fprintf (stderr, "[%02X]", m_data[i]); + } + if (crc != 0) + { + fprintf (stderr, "%s", KRED); + fprintf (stderr, " (CRC ERR)"); + fprintf (stderr, "%s", KNRM); + } + fprintf (stderr, " "); + } + + return err; +} + +//modified version of nxdn_deperm_facch1 +int ysf_conv_fich (uint8_t input[], uint8_t dest[32]) +{ + int i, j, k, err; + uint8_t s0, s1; + uint8_t trellis_buf[100]; + uint8_t temp[210]; + uint8_t m_data[100]; + uint8_t bits[210]; + memset (trellis_buf, 0, sizeof(trellis_buf)); + memset (temp, 0, sizeof (temp)); + memset (m_data, 0, sizeof (m_data)); + memset (bits, 0, sizeof(bits)); + err = 0; + + //dibit de-interleave block length M = 5 dibits and depth N = 10 + uint8_t buf[100]; + memset (buf, 0, sizeof(buf)); + for (i=0; i<20; i++) { + for (j=0; j<5; j++) { + buf[j+(i*5)] = input[i+(j*20)]; + } + } + + k = 0; + //convert dibits to bits + for (i = 0; i < 100; i++) + { + bits[k++] = (buf[i] >> 1) & 1; + bits[k++] = (buf[i] >> 0) & 1; + } + + //setup for the convolutional decoder + for (i = 0; i < 200; i++) //192 + temp[i] = bits[i] << 1; + + CNXDNConvolution_start(); + for (i = 0; i < 100; i++) + { + s0 = temp[(2*i)+0]; + s1 = temp[(2*i)+1]; + + CNXDNConvolution_decode(s0, s1); + } + + CNXDNConvolution_chainback(m_data, 96); + + //96/8 = 12, last 4 (96-100) are trailing zeroes + for(i = 0; i < 12; 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; + } + + uint8_t fich_bits[12*4]; + char temp_b[24]; + bool g[4]; + + // run golay 24_12 error correction + for (i = 0; i < 4; i++) + { + memset (temp, 0, sizeof(temp_b)); + g[i] = FALSE; + + for (j = 0; j < 24; j++) + temp_b[j] = (char) trellis_buf[(i*24)+j]; + + g[i] = Golay_24_12_decode(temp_b); + if(g[i] == FALSE) err = -1; + + for (j = 0; j < 24; j++) + trellis_buf[(i*24)+j] = (uint8_t) temp_b[j]; + } + + //load corrected bits + for (i = 0; i < 12; i++) + { + fich_bits[(12*0)+i] = trellis_buf[i+0]; + fich_bits[(12*1)+i] = trellis_buf[i+24]; + fich_bits[(12*2)+i] = trellis_buf[i+48]; + fich_bits[(12*3)+i] = trellis_buf[i+72]; + } + + uint16_t crc = crc16ysf(fich_bits, 48); + if (crc != 0) err = -2; // crc failure + + memset (m_data, 0, sizeof (m_data)); + for (i = 0; i < 12; i++) + m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8); + + //debug output + // if (1 == 1) + // { + // fprintf (stderr, "FICH: "); + // for (i = 0; i < 12; i++) + // { + // fprintf (stderr, "[%02X]", m_data[i]); + // } + // if (crc != 0) + // { + // fprintf (stderr, "%s", KRED); + // fprintf (stderr, " (CRC ERR)"); + // fprintf (stderr, "%s", KNRM); + // } + // fprintf (stderr, " "); + // } + + memcpy(dest, fich_bits, 32); //copy minus the crc16 + return err; +} + +//YSF pn95 scrambler/whitening bit generator with seed 111001001 +void pn95_lfsr() //test to see if this generates the correct bits now +{ + int i; + int lfsr; + int pN[513]; + memset (pN, 0, sizeof(pN)); + int bit = 0; + + lfsr = 0x1c9; //111001001 initial value + fprintf (stderr, "\n pN95 = { \n"); + for (i = 0; i < 512; i++) + { + pN[i] = lfsr & 0x1; + bit = ( (lfsr >> 4) ^ (lfsr >> 0) ) & 1; + lfsr = ( (lfsr >> 1 ) | (bit << 9) ); //9, or 8 + if (i % 8 == 0) fprintf (stderr, "\n"); + fprintf (stderr, " %d,", pN[i]); + } + fprintf (stderr, "};"); + +} + +void fr_demodulation(uint8_t out[], uint8_t in[], uint16_t n, uint32_t seed, uint8_t shift) +{ + uint32_t v = seed << shift; + // fprintf (stderr, "SEED = %X", seed); + for (uint16_t i=0; i> 15); + } +} + +void ysf_ehr (dsd_opts * opts, dsd_state * state, uint8_t dbuf[180], int start, int stop ) +{ + int i, j, k, dibit; + char ambe_fr[4][24]; + memset (ambe_fr, 0, sizeof(ambe_fr)); + + unsigned char *pr; const int *w, *x, *y, *z; - char ambe_fr[8][4][24]; - unsigned char storage[8][4][24]; //may expand later - unsigned char discard[460]; //just set up for now to hold random dibit grabs with nothing to do but skip them - unsigned char vch[4][36]; //correct size array for 4*32 dibit VD2 VCH? - unsigned char fich[200]; //store as bits after deinterleaving - unsigned char fichraw[100]; - unsigned char fichdibits[100]; //deinterleaved fich dibits - unsigned char fichbytes[26]; - unsigned int fi = 0; - unsigned int cs = 0; - unsigned int cm = 0; - unsigned int bn = 0; - unsigned int bt = 0; - unsigned int fn = 0; - unsigned int ft = 0; - unsigned int mr = 0; - unsigned int ip = 0; - unsigned int dt = 0; //DT, 2 bytes (according to manual, but has to be two bits) - unsigned int sq = 0; - unsigned int sc = 0; - int vd1 = 1; - int vd2 = 0; - unsigned int msbI = 0; - unsigned int lsbI = 0; - unsigned char vd2BitsRaw[104]; - opts->inverted_ysf = 0; //here for testing purposes, move to main later - for (i = 0; i < 100; i++) //100 dibits for fich - { - dibit = getDibit (opts, state); - if (opts->inverted_ysf == 1) //opts->inverted_ysf == 1 - { - dibit = (dibit ^ 2); - } - fichraw[i] = dibit; //raw storage for debug - fichdibits[fichInterleave[i]] = dibit; //sort into proper order - //fich[i*2] = (1 & (dibit >> 1)); // bit 1 - //fich[i*2+1] = (1 & dibit); // bit 0 - fich[i*2] = (fichdibits[fichInterleave[i]] >> 1) & 1; - //fprintf (stderr, "%b", fich[i*2]); - fich[i*2+1] = fichdibits[fichInterleave[i]] & 1; - //fprintf (stderr, "%b", fich[i*2+1]); - if (i == 4) - { - //datatype = dibit; - } - } - //fprintf (stderr, "\nFICH BYTES = "); - for (i = 0; i < 25; i++) //bits to bytes + int st = state->synctype; + state->synctype = 28; + + uint8_t b1, b2; + + k = 0; + + for (start; start < stop; start++) { - fichbytes[i] = 0; //initialize to see what isn't beign set - fichbytes[i] = ( (fich[i*8] << 7) | (fich[i*8+1] << 6) | (fich[i*8+2] << 5) | (fich[i*8+3] << 4) | - (fich[i*8+4] << 3) | (fich[i*8+5] << 2) | (fich[i*8+6] << 1) | (fich[i*8+7] << 0) ); - //fprintf (stderr, "[%02X]", fichbytes[i]); - } - //fprintf (stderr, "\n"); - //datatype = (fich[8] << 1) + fich[9]; - dt = fichbytes[2] & 0x03; - for (i = 0; i < 2; i++) - { - //datatype << 1; - //datatype = datatype | fichraw[i+8]; - //fprintf (stderr, "%02b", fichdibits[i+4]); - //fprintf (stderr, "%02b", fichdibits[i+11]); - } - //fprintf (stderr, "Datatype = %02b\n", dt); - //quick dirty VD1 method? - if (0 == 0) //dt == 0 for VD1 - { - fprintf (stderr, "processYSF VD1 \n"); - for (j = 0; j < 5; j++) //5 DCH and VCH - { - w = YSFrW; - x = YSFrX; - y = YSFrY; - z = YSFrZ; + w = YnW; + x = YnX; + y = YnY; + z = YnZ; k = 0; + + //debug + // fprintf (stderr, " DBUF = "); + for (i = 0; i < 36; i++) { - dibit = getDibit (opts, state); - if (opts->inverted_ysf == 1) //opts->inverted_ysf == 1 - { - dibit = (dibit ^ 2); - } + //debug + // fprintf (stderr, "%d", dbuf[(start*36)+i]); - storage[j][*w][*x] = (1 & (dibit >> 1)); // bit 1 - storage[j][*y][*z] = (1 & dibit); // bit 0 + b1 = dbuf[(start*36)+i] >> 1; + b2 = dbuf[(start*36)+i] & 1; - } - - - - //AMBE VCH - for (i = 0; i < 36; i++) - { - dibit = getDibit (opts, state); - - if (opts->inverted_ysf == 1) //opts->inverted_ysf == 1 - { - dibit = (dibit ^ 2); - } - - ambe_fr[j][*w][*x] = (1 & (dibit >> 1)); // bit 1 - ambe_fr[j][*y][*z] = (1 & dibit); // bit 0 + //should all be loaded back to back + ambe_fr[*w][*x] = (char)b1; + ambe_fr[*y][*z] = (char)b2; + w++; x++; y++; z++; + } - //processMbeFrame (opts, state, NULL, ambe_fr[j], NULL); - } //end j < 4 loop - } //end VD1 - //move processMbeFrame to outside of dibit loop to prevent slip - for (j = 0; j < 5; j++) - { - //processMbeFrame (opts, state, NULL, ambe_fr[j], NULL); - } - //VD2 method - if (0 == 3) //dt == 3 - { - fprintf (stderr, "processYSF VD2 \n"); - for (j = 0; j < 4; j++) - { - //VCH[j] and VeCH[j] - for (i = 0; i < 20; i++) //32? - { - dibit = getDibit (opts, state); - if (opts->inverted_ysf == 1) //opts->inverted_ysf == 1 - { - dibit = (dibit ^ 2); - } - //collect dibits into array for processing - vch[j][i] = dibit; - w = YSFrW; - x = YSFrX; - y = YSFrY; - z = YSFrZ; - msbI = vd2Interleave[(j+1)*i]; //don't this this is remotely correct, really could use the manual right about now - lsbI = vd2Interleave[(j+1)*i+1]; - vd2BitsRaw[msbI] = ((vch[j][i] >> 1) & 1); - vd2BitsRaw[lsbI] = (vch[j][i] & 1); - } // VCH[j] - //DCH[j] - for (i = 0; i < 20; i++) //32? - { - dibit = getDibit (opts, state); + processMbeFrame (opts, state, NULL, ambe_fr, NULL); - if (opts->inverted_ysf == 1) //opts->inverted_ysf == 1 - { - dibit = (dibit ^ 2); - } - discard[i] = dibit; - } //end DCH[j] - } //end for j loop + } + + if (opts->payload == 1) + { + fprintf(stderr, "\n"); + } + + state->synctype = st; +} - } //end VD2 +void processYSF(dsd_opts * opts, dsd_state * state) +{ + static uint8_t last_dt, last_fi; //if we can't get a good dt and fi, then just use the last one instead + int i, j, k, l, err, vstart, vstop, dstart, dstop; //start stops are for Full Rate when we might have some portions of Data present in the Comm Channel + int dibit; + const int *w, *x, *y, *z; + uint8_t fichdibits[100]; //fich dibits + uint8_t fichrawdibits[100]; + uint8_t fichrawbits[200]; + uint8_t fich_d_bits[100]; + uint8_t fich_decode[32]; + memset (fichdibits, 0, sizeof(fichdibits)); + memset (fichrawdibits, 0, sizeof(fichrawdibits)); + memset (fichrawbits, 0, sizeof(fichrawbits)); + memset (fich_d_bits, 0, sizeof(fich_d_bits)); + memset (fich_decode, 0, sizeof(fich_decode)); + char ambe_fr[4][24]; + memset (ambe_fr, 0, sizeof(ambe_fr)); + char imbe_fr[8][23]; + memset (imbe_fr, 0, sizeof(imbe_fr)); + uint8_t b1, b2, msb, lsb; + b1 = b2 = msb = lsb = vstart = vstop = dstart = dstop = 0; + + //fich information + uint8_t fi = 9; //Header, Communications, or Terminator + uint8_t cs = 9; //Type of Callsign + uint8_t cm = 9; //Type of Call + uint8_t bn = 9; //block number + uint8_t bt = 9; //block total + uint8_t fn = 9; //frame number + uint8_t ft = 9; //frame total + uint8_t mr = 9; //message path + uint8_t vp = 9; //VoIP path + uint8_t dt = 9; //Data Type -- type 1 (EHR no VeCH); type 2 (EHR w/ VeCH); type 3 (EFR) + uint8_t st = 9; //SQL Type + uint8_t sc = 69; //SQL Code + + // pn95lfsr(); //run to print the bits for the DCH/VeCH whitening array + + //FICH you + for (i = 0; i < 100; i++) + fichrawdibits[i] = getDibit(opts, state); + + //from nxdn_deperm_facch1 w/ nxdn convolutional decoder + err = ysf_conv_fich (fichrawdibits, fich_decode); + + //seems to still work better by just allowing all decoding, even with errs present + if (err == 0) + { + fi = (uint8_t)ConvertBitIntoBytes(&fich_decode[0], 2); + cs = (uint8_t)ConvertBitIntoBytes(&fich_decode[2], 2); + cm = (uint8_t)ConvertBitIntoBytes(&fich_decode[4], 2); + bn = (uint8_t)ConvertBitIntoBytes(&fich_decode[6], 2); + bt = (uint8_t)ConvertBitIntoBytes(&fich_decode[8], 2); + fn = (uint8_t)ConvertBitIntoBytes(&fich_decode[10], 3); + ft = (uint8_t)ConvertBitIntoBytes(&fich_decode[13], 3); + mr = (uint8_t)ConvertBitIntoBytes(&fich_decode[18], 3); + vp = fich_decode[21]; + dt = (uint8_t)ConvertBitIntoBytes(&fich_decode[22], 2); + st = fich_decode[24]; + sc = (uint8_t)ConvertBitIntoBytes(&fich_decode[25], 7); + + state->ysf_dt = dt; + state->ysf_fi = fi; + state->ysf_cm = cm; + + last_dt = dt; + last_fi = fi; + } + // else goto END; + else + { + dt = last_dt; + fi = last_fi; + } + + //print some useful decoded shit + if (fi == 0) fprintf (stderr, "HC "); + if (fi == 1) fprintf (stderr, "CC "); + if (fi == 2) fprintf (stderr, "TC "); + if (fi == 3) fprintf (stderr, "XX "); //Test + + if (dt == 0) fprintf (stderr, "V/D1 "); + if (dt == 1) fprintf (stderr, "DATA "); + if (dt == 2) fprintf (stderr, "V/D2 "); + if (dt == 3) fprintf (stderr, "VCHF "); + + if (cm == 0) fprintf (stderr, "Group/CQ "); + if (cm == 3) fprintf (stderr, "Private "); + if (cm == 1) fprintf (stderr, "Reserved "); + if (cm == 2) fprintf (stderr, "Reserved "); + + if (mr == 0) fprintf (stderr, "Direct Wave "); + if (mr == 1) fprintf (stderr, "Downlink (BUSY) "); + if (mr == 2) fprintf (stderr, "Downlink (FREE) "); + + if (vp == 1) fprintf (stderr, "Local (Simplex) "); + if (vp == 0) fprintf (stderr, "Internet (Rep) "); + + // if (st && sc != 69) fprintf (stderr, "SQL "); + // if (st && sc != 69) fprintf (stderr, "CODE: %X ", sc); + + //print out current block numbering and frame numbering + // fprintf (stderr, "BN: %d BT: %d FN: %d FT: %d ", bn, bt, fn, ft); + + //simplified version + if (ft != 0) //if frame total is greater than 0 + fprintf (stderr, "FN:%d-%d ", fn, ft); + + if (opts->payload == 1) + { + fprintf (stderr, " FICH: "); + for (int i = 0; i < 4; i++) + fprintf (stderr, "[%02X]", (uint8_t)ConvertBitIntoBytes(&fich_decode[i*8], 8)); + } + + if (err != 0) + { + fprintf (stderr, "%s", KRED); + if (err == -1) + fprintf (stderr, "(FEC ERR)"); + if (err == -2) + fprintf (stderr, "(CRC ERR)"); + fprintf (stderr, "%s", KNRM); + } + + // if (fi == 0) fprintf (stderr, "%s", KGRN); //HC Channel + // else if (fi == 2) fprintf (stderr, "%s", KRED); //TC Channel + // else if (dt == 0 || dt == 2) fprintf (stderr, "%s", KGRN); //Voice CC + // else fprintf (stderr, "%s", KCYN); //Data + + //DCH and VCH + uint8_t dbuf[190]; //data dibit buffer + uint8_t vbuf[190]; //voice dibit buffer + uint8_t vech[255]; //VeCH dibit buffer + uint8_t temp[512]; ///temp space for manipulating VeCH into VBUF + + char ambe_d[49]; + + memset (vbuf, 0, sizeof(vbuf)); + memset (dbuf, 0, sizeof(dbuf)); + memset (vech, 0, sizeof(vech)); + memset (temp, 0, sizeof(temp)); + + //bit buffers + // uint8_t dch_bits[6][72]; + uint8_t dch_bits[160]; + uint8_t vch_bits[6][72]; + uint8_t vech_bits[104]; + uint8_t buf[100]; + + memset (dch_bits, 0, sizeof(dch_bits)); + memset (vch_bits, 0, sizeof(vch_bits)); + memset (vech_bits, 0, sizeof(vech_bits)); + + // V/D Mode Type 1 (no VeCH) + if (fi == 1 && dt == 0) + { + //need to double check all this if I can get a sample of it + for (i = 0; i < 5; i++) //5 on EHR Type 1 (no VeCH) + { + + // DCH First + for (j = 0; j < 36; j++) + dbuf[(i*36)+j] = getDibit(opts, state); + + + //VCH Second + for (j = 0; j < 36; j++) + vbuf[(i*36)+j] = getDibit(opts, state); + + } + + // send VCH to ehr voice handler -- buffer run + ysf_ehr (opts, state, vbuf, 0, 4); + + } + + + /* + In the case of V/D mode type 2, error correction for the purpose of improving the connectivity + of a weak electric field is carried out (separately from the error correction function of the voice + encoder). + */ + + // V/D Mode Type 2 (w/ VeCH and bullshit ECC) + if (fi == 1 && dt == 2) + { + int d = 0; + for (i = 0; i < 5; i++) + { + //DCH + for (j = 0; j < 20; j++) + dbuf[d++] = getDibit(opts, state); + + //VeCH + k = 0; l = 0; + memset (vech_bits, 0, sizeof(vech_bits)); + memset (temp, 0, sizeof(temp)); + + state->errs = 0; + state->errs2 = 0; + + for (j = 0; j < 52; j++) + { + dibit = getDibit(opts, state); + + //deinterleave and de-whiten VeCH (from DSDcc) + b1 = (dibit >> 1) & 1; + b2 = (dibit >> 0) & 1; + + msb = vd2Interleave[k]; k++; + lsb = vd2Interleave[k]; k++; + + vech_bits[msb] = b1 ^ pn95[msb]; + vech_bits[lsb] = b2 ^ pn95[lsb]; + + } + + uint8_t majority[8] = {0,0,0,1,0,1,1,1}; + //I have no idea how this is considered to be a form of forward error correction + l = 0; + for (j = 0; j < 81; j++) + { + //OP25 majority method with table + if (j % 3 == 2) + { + //I still have no idea what the method of this is...hamming table? + temp[l] = majority[ (vech_bits[j-2] << 2) | (vech_bits[j-1] << 1) | vech_bits[j] ]; + l++; + } + } + + for (j = 0; j < 22; j++) + temp[j+27] = vech_bits[j+81]; + + for (j = 0; j < 49; j++) + ambe_d[j] = temp[j]; //(char) + + state->errs2 = vech_bits[103]; //should be zero, but if it isn't, then its an error + + mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, + ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + if (opts->payload == 1) + PrintAMBEData (opts, state, ambe_d); + + processAudio(opts, state); + playSynthesizedVoice (opts, state); + + } + + //process completed DCH + ysf_conv_dch2 (opts, state, bn, bt, fn, ft, dbuf); + + } + + //Full-Rate AMBE+2 EFR (Supposed to work with IMBE?) + uint8_t imbe_vch[144]; + memset (imbe_vch, 0, sizeof(imbe_vch)); + uint8_t pNfr[144]; //144 + uint32_t seed; //for fr_scramble from gr-ysf + + uint8_t imbe_raw[144]; + char imbe_d[88]; + + //this is to setup and use the mbe_golay2312 (in, out); function + char in[23]; + char out[23]; + //hamming on u4-7 + char hin[15]; + char hout[15]; + + //Voice FR Mode (Type 3 AMBE+2 Full Rate) + if (fi == 1 && dt == 3) + { + + /* + Under this pattern, when the initial HC and initial CC (Sub header (CSD3)) cannot be received, the Call sign information can not be obtained. + No CSD3 information can be obtained from other frames except the FT=1/FN=0 frame. + + What we need to do is look at the frame, and determine if its a CSD3 by the ft == 1 and fn == 0 and set an appropirate start/stop value here + */ + + if (ft == 1 && fn == 0) + { + dstart = 0; + dstop = 6; //5 DCH and 1 reserved bank + vstart = 0; + vstop = 2; //only 2 VCH in the CSD3 Sub Header + } + else + { + dstart = 0; + dstop = 0; + vstart = 0; + vstop = 5; + } + + for (dstart; dstart < dstop; dstart++) + { + //get dibits for CSD3 Sub Header DCH -- double check this + for (j = 0; j < 36; j++) //dbufFR[2][190] + { + if (dstart != 5) //only want the first 5 + dbuf[(dstart*36)+j] = getDibit(opts, state); + else skipDibit(opts, state, 1); //skip the reserved bank + } + + + } + + for (vstart; vstart < vstop; vstart++) + { + + //init a bunch of stuff + memset (imbe_raw, 0, sizeof(imbe_raw)); + memset (imbe_d, 0, sizeof(imbe_d)); + memset (imbe_fr, 0, sizeof(imbe_fr)); + memset (pNfr, 0, sizeof(pNfr)); + + memset (in, 0, sizeof(in)); + memset (out, 0, sizeof(out)); + memset (hin, 0, sizeof(hin)); + memset (hout, 0, sizeof(hout)); + + for (j = 0; j < 72; j++) + { + dibit = getDibit(opts, state); + + b1 = (dibit >> 1) & 1; + b2 = (dibit >> 0) & 1; + + imbe_raw[(j*2)+0] = b1; + imbe_raw[(j*2)+1] = b2; + + } + + //de-interleave to vch bits + for (j = 0; j < 144; j++) + imbe_vch[j] = imbe_raw[fr_interleave[j]]; + + //load the first 23 bits (u0) into a temp buffer for ecc + for (j = 0; j < 23; j++) + in[j] = imbe_vch[j]; + + //Run Golay 23,12 on u0 so we get a good demodulation pn sequence + state->errs = mbe_golay2312 (in, out); + + //reload u0 back into imbe_vch buffer + for (j = 0; j < 23; j++) + imbe_vch[j] = out[j]; + + //obtain a seed value to feed the lfsr to demodulate the rest of this frame + seed = 45; + for (j = 0; j < 12; j++) + { + seed = seed << 1; + seed = seed | imbe_vch[j]; + } + + //NOTE: Perhaps AMBE+2 FR and IMBE just use a different demod PN sequence? + + //demod/descramble with pn sequence + fr_demodulation (imbe_vch+23, imbe_vch+23, 144-23-7, seed, 4); + + //do manual error correction here on the rest + state->errs2 = 0; + for (k = 1; k < 4; k++) + { + memset (in, 0, sizeof(in)); + memset (out, 0, sizeof(out)); + + //load the next 23 bits (u1, u2, u3) into a temp buffer for ecc + for (j = 0; j < 23; j++) + in[j] = imbe_vch[(k*23)+j]; //I think the FEC on u0 is incorrect in the interleave + + //Run Golay 23,12 on u(k) + state->errs2 += mbe_golay2312 (in, out); + + //reload u(k) back into imbe_vch buffer + for (j = 0; j < 23; j++) + imbe_vch[(k*23)+j] = out[j]; + } + + // for (k = 4; k < 7; k++) + // { + // //TODO: hamming + // } + + memset (imbe_raw, 0, sizeof(imbe_raw)); + + // FIXME: We should apply FEC here -- already working on it, chief + k = 0; + for(j = 0; j < 12; j++) imbe_raw[k++] = imbe_vch[j]; // u0 + for(j = 23; j < 35; j++) imbe_raw[k++] = imbe_vch[j]; // u1 + for(j = 46; j < 58; j++) imbe_raw[k++] = imbe_vch[j]; // u2 + for(j = 69; j < 81; j++) imbe_raw[k++] = imbe_vch[j]; // u3 + for(j = 92; j < 103; j++) imbe_raw[k++] = imbe_vch[j]; // u4 + for(j =107; j < 118; j++) imbe_raw[k++] = imbe_vch[j]; // u5 + for(j =122; j < 133; j++) imbe_raw[k++] = imbe_vch[j]; // u6 + for(j =137; j < 144; j++) imbe_raw[k++] = imbe_vch[j]; // u7 + + mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, + imbe_raw, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + if (opts->payload == 1) + PrintIMBEData (opts, state, imbe_raw); + + processAudio(opts, state); + playSynthesizedVoice (opts, state); + + } + + if (ft == 1 && fn == 0) + { + //process completed DCH -- use 2 for bn to switch CSD 3 info + ysf_conv_dch (opts, state, 2, bt, fn, ft, dbuf); + } + } + + //full rate data + uint8_t dbufFR[2][180]; + memset (dbufFR, 0, sizeof(dbufFR)); + if (dt == 1 || fi == 0 || fi == 2) + { + for (i = 0; i < 10; i++) + { + for (j = 0; j < 36; j++) + dbufFR[i % 2][((i/2)*36)+j] = getDibit(opts, state); + } + + //clear old txt data + // if (fi == 0) memset (state->ysf_txt, 0, sizeof(state->ysf_txt)); + + for (i = 0; i < 2; i++) + { + //process completed DCH -- use i to for bn to switch CSD1 and CSD2 on HC and TC + if (fi == 0 || fi == 2) + ysf_conv_dch (opts, state, i, bt, fn, ft, dbufFR[i]); + //using bn == 2 for full rate data and fn*2+1 for easier frame storage + else ysf_conv_dch (opts, state, 2, bt, fn*2+i, ft, dbufFR[i]); + + } + + } + + END: + // if (err != 0) skipDibit(opts, state, 360); + + //ending line break + fprintf (stderr, "%s", KNRM); + fprintf (stderr, "\n"); } //end processYSF