diff --git a/CMakeLists.txt b/CMakeLists.txt index 2eb5ead..e85f58f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,9 @@ git_describe(GIT_TAG) find_package(LibSndFile REQUIRED) find_package(LibMbe REQUIRED) +find_package(ITPP REQUIRED) -FILE(GLOB SRCS *.c) +FILE(GLOB SRCS *.c *.cpp) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/git_ver.c.in" "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c" @ONLY) list(APPEND SRCS "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c" git_ver.h) @@ -18,9 +19,10 @@ INCLUDE_DIRECTORIES( "${PROJECT_SOURCE_DIR}" "${LIBSNDFILE_INCLUDE_DIR}" "${LIBMBE_INCLUDE_DIR}" + "${ITPP_INCLUDE_DIR}" ) -SET(LIBS ${LIBS} ${LIBMBE_LIBRARY} ${LIBSNDFILE_LIBRARY}) +SET(LIBS ${LIBS} ${LIBMBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY}) ADD_EXECUTABLE(dsd ${SRCS}) TARGET_LINK_LIBRARIES(dsd ${LIBS}) diff --git a/cmake/FindITPP.cmake b/cmake/FindITPP.cmake new file mode 100644 index 0000000..e252911 --- /dev/null +++ b/cmake/FindITPP.cmake @@ -0,0 +1,20 @@ +# Find ITPP + +FIND_PATH(ITPP_INCLUDE_DIR itpp/itcomm.h) + +SET(ITPP_NAMES ${ITPP_NAMES} itpp libitpp libitpp.dll) +FIND_LIBRARY(ITPP_LIBRARY NAMES ${ITPP_NAMES} PATH) + +IF (ITPP_INCLUDE_DIR AND ITPP_LIBRARY) + SET(ITPP_FOUND TRUE) +ENDIF (ITPP_INCLUDE_DIR AND ITPP_LIBRARY) + +IF (ITPP_FOUND) + IF (NOT ITPP_FIND_QUIETLY) + MESSAGE (STATUS "Found ITPP: ${ITPP_LIBRARY}") + ENDIF (NOT ITPP_FIND_QUIETLY) +ELSE (ITPP_FOUND_FOUND) + IF (ITPP_FIND_REQUIRED) + MESSAGE (FATAL_ERROR "Could not find ITPP") + ENDIF (ITPP_FIND_REQUIRED) +ENDIF (ITPP_FOUND) diff --git a/dsd.h b/dsd.h index ba4eb0a..ad6ffdc 100644 --- a/dsd.h +++ b/dsd.h @@ -168,6 +168,11 @@ typedef struct mbe_parms *prev_mp; mbe_parms *prev_mp_enhanced; int p25kid; + + unsigned int debug_audio_errors; + unsigned int debug_header_errors; + unsigned int debug_header_critical_errors; + } dsd_state; /* diff --git a/dsd_frame.c b/dsd_frame.c index 8a7aef1..893c367 100644 --- a/dsd_frame.c +++ b/dsd_frame.c @@ -20,6 +20,8 @@ #define NULL 0 #endif +#include "p25p1_check_nid.h" + void printFrameInfo (dsd_opts * opts, dsd_state * state) { @@ -52,6 +54,16 @@ processFrame (dsd_opts * opts, dsd_state * state) char nac[13]; int level; + char status_0, status_1; + char bch_code[63]; + int index_bch_code; + unsigned char parity; + char v; + int new_nac; + char new_duid[3]; + int check_result; + + nac[12] = 0; duid[2] = 0; j = 0; @@ -234,26 +246,92 @@ processFrame (dsd_opts * opts, dsd_state * state) } else { + // Read the NAC, 12 bits j = 0; + index_bch_code = 0; for (i = 0; i < 6; i++) { dibit = getDibit (opts, state); - nac[j] = (1 & (dibit >> 1)) + 48; // bit 1 + + v = 1 & (dibit >> 1); // bit 1 + nac[j] = v + 48; j++; - nac[j] = (1 & dibit) + 48; // bit 0 + bch_code[index_bch_code] = v; + index_bch_code++; + + v = 1 & dibit; // bit 0 + nac[j] = v + 48; j++; + bch_code[index_bch_code] = v; + index_bch_code++; } - nac[12] = 0; state->nac = strtol (nac, NULL, 2); + // Read the DUID, 4 bits for (i = 0; i < 2; i++) { - duid[i] = getDibit (opts, state) + 48; + dibit = getDibit (opts, state); + duid[i] = dibit + 48; + + bch_code[index_bch_code] = 1 & (dibit >> 1); // bit 1 + index_bch_code++; + bch_code[index_bch_code] = 1 & dibit; // bit 0 + index_bch_code++; } + + // Read the BCH data for error correction of NAC and DUID + for (i = 0; i < 3; i++) + { + dibit = getDibit (opts, state); + + bch_code[index_bch_code] = 1 & (dibit >> 1); // bit 1 + index_bch_code++; + bch_code[index_bch_code] = 1 & dibit; // bit 0 + index_bch_code++; + } + status_0 = getDibit (opts, state) + 48; + for (i = 0; i < 20; i++) + { + dibit = getDibit (opts, state); + + bch_code[index_bch_code] = 1 & (dibit >> 1); // bit 1 + index_bch_code++; + bch_code[index_bch_code] = 1 & dibit; // bit 0 + index_bch_code++; + } + + // Read the parity bit + dibit = getDibit (opts, state); + bch_code[index_bch_code] = 1 & (dibit >> 1); // bit 1 + parity = (1 & dibit); // bit 0 + + // Check if the NID is correct + check_result = check_NID (bch_code, &new_nac, new_duid, parity); + if (check_result) { + if (new_nac != state->nac) { + // NAC fixed by error correction + state->nac = new_nac; + state->debug_header_errors++; + } + if (strcmp(new_duid, duid) != 0) { + // DUID fixed by error correction + //printf("Fixing DUID %s -> %s\n", duid, new_duid); + duid[0] = new_duid[0]; + duid[1] = new_duid[1]; + state->debug_header_errors++; + } + } else { + // Check of NID failed and unable to recover its value + //printf("NID error\n"); + duid[0] = 'E'; + duid[1] = 'E'; + state->debug_header_critical_errors ++; + } } if (strcmp (duid, "00") == 0) { + // Header Data Unit if (opts->errorbars == 1) { printFrameInfo (opts, state); @@ -271,6 +349,7 @@ processFrame (dsd_opts * opts, dsd_state * state) } else if (strcmp (duid, "11") == 0) { + // Logical Link Data Unit 1 if (opts->errorbars == 1) { printFrameInfo (opts, state); @@ -290,6 +369,7 @@ processFrame (dsd_opts * opts, dsd_state * state) } else if (strcmp (duid, "22") == 0) { + // Logical Link Data Unit 2 if (state->lastp25type != 1) { if (opts->errorbars == 1) @@ -322,6 +402,7 @@ processFrame (dsd_opts * opts, dsd_state * state) } else if (strcmp (duid, "33") == 0) { + // Terminator with subsequent Link Control if (opts->errorbars == 1) { printFrameInfo (opts, state); @@ -347,6 +428,7 @@ processFrame (dsd_opts * opts, dsd_state * state) } else if (strcmp (duid, "03") == 0) { + // Terminator without subsequent Link Control if (opts->errorbars == 1) { printFrameInfo (opts, state); @@ -362,7 +444,11 @@ processFrame (dsd_opts * opts, dsd_state * state) state->lastp25type = 0; state->err_str[0] = 0; sprintf (state->fsubtype, " TDU "); - skipDibit (opts, state, 40); + + // Now processing NID + + skipDibit (opts, state, 14); // 28 null bits + status_1 = getDibit (opts, state) + 48; } else if (strcmp (duid, "13") == 0) { @@ -379,7 +465,10 @@ processFrame (dsd_opts * opts, dsd_state * state) state->lastsrc = 0; state->lastp25type = 3; sprintf (state->fsubtype, " TSDU "); - skipDibit (opts, state, 328); + + // Now processing NID + + skipDibit (opts, state, 328-25); } else if (strcmp (duid, "30") == 0) { @@ -417,7 +506,9 @@ processFrame (dsd_opts * opts, dsd_state * state) openMbeOutFile (opts, state); } } - state->lastp25type = 0; + //state->lastp25type = 0; + // Guess that the state is LDU2 + state->lastp25type = 2; sprintf (state->fsubtype, "(LDU2) "); state->numtdulc = 0; processLDU2 (opts, state); @@ -436,7 +527,9 @@ processFrame (dsd_opts * opts, dsd_state * state) openMbeOutFile (opts, state); } } - state->lastp25type = 0; + //state->lastp25type = 0; + // Guess that the state is LDU1 + state->lastp25type = 1; sprintf (state->fsubtype, "(LDU1) "); state->numtdulc = 0; processLDU1 (opts, state); @@ -448,9 +541,14 @@ processFrame (dsd_opts * opts, dsd_state * state) printFrameInfo (opts, state); printf (" (TSDU)\n"); } - state->lastp25type = 0; + //state->lastp25type = 0; + // Guess that the state is TSDU + state->lastp25type = 3; sprintf (state->fsubtype, "(TSDU) "); - skipDibit (opts, state, 328); + + // Now processing NID + + skipDibit (opts, state, 328-25); } else if (state->lastp25type == 4) { diff --git a/dsd_frame_sync.c b/dsd_frame_sync.c index 91ed884..bf44760 100644 --- a/dsd_frame_sync.c +++ b/dsd_frame_sync.c @@ -53,7 +53,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) * 7 = -D-STAR * 8 = +NXDN (non inverted voice frame) * 9 = -NXDN (inverted voice frame) - * 10 = +DMR (non inverted singlan data frame) + * 10 = +DMR (non inverted signal data frame) * 11 = -DMR (inverted signal voice frame) * 12 = +DMR (non inverted signal voice frame) * 13 = -DMR (inverted signal data frame) @@ -65,6 +65,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) * 19 = -D-STAR_HD */ + int i, j, t, o, dibit, sync, symbol, synctest_pos, lastt; char synctest[25]; char synctest18[19]; @@ -104,6 +105,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { t++; symbol = getSymbol (opts, state, 0); + lbuf[lidx] = symbol; state->sbuf[state->sidx] = symbol; if (lidx == 23) @@ -164,13 +166,13 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { *state->dibit_buf_p = 1; state->dibit_buf_p++; - dibit = 49; + dibit = 49; // '1' } else { *state->dibit_buf_p = 3; state->dibit_buf_p++; - dibit = 51; + dibit = 51; // '3' } *synctest_p = dibit; @@ -673,33 +675,33 @@ getFrameSync (dsd_opts * opts, dsd_state * state) return (7); } if (strcmp (synctest, DSTAR_HD) == 0) - { - state->carrier = 1; - state->offset = synctest_pos; - state->max = ((state->max) + lmax) / 2; - state->min = ((state->min) + lmin) / 2; - sprintf (state->ftype, " D-STAR_HD "); - if (opts->errorbars == 1) - { - printFrameSync (opts, state, " +D-STAR_HD ", synctest_pos + 1, modulation); - } - state->lastsynctype = 18; - return (18); - } + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " D-STAR_HD "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " +D-STAR_HD ", synctest_pos + 1, modulation); + } + state->lastsynctype = 18; + return (18); + } if (strcmp (synctest, INV_DSTAR_HD) == 0) - { - state->carrier = 1; - state->offset = synctest_pos; - state->max = ((state->max) + lmax) / 2; - state->min = ((state->min) + lmin) / 2; - sprintf (state->ftype, " D-STAR_HD "); - if (opts->errorbars == 1) - { - printFrameSync (opts, state, " -D-STAR_HD ", synctest_pos + 1, modulation); - } - state->lastsynctype = 19; - return (19); - } + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, " D-STAR_HD "); + if (opts->errorbars == 1) + { + printFrameSync (opts, state, " -D-STAR_HD ", synctest_pos + 1, modulation); + } + state->lastsynctype = 19; + return (19); + } } diff --git a/dsd_main.c b/dsd_main.c index 8ce83d8..d59704c 100644 --- a/dsd_main.c +++ b/dsd_main.c @@ -220,6 +220,10 @@ initState (dsd_state * state) state->prev_mp_enhanced = malloc (sizeof (mbe_parms)); mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); state->p25kid = 0; + + state->debug_audio_errors = 0; + state->debug_header_errors = 0; + state->debug_header_critical_errors = 0; } void @@ -318,6 +322,12 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state) { closeWavOutFile (opts, state); } + + printf("\n"); + printf("Total audio errors: %i\n", state->debug_audio_errors); + printf("Total header errors: %i\n", state->debug_header_errors); + printf("Total irrecoverable header errors: %i\n", state->debug_header_critical_errors); + printf ("Exiting.\n"); exit (0); } @@ -325,8 +335,8 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state) void sigfun (int sig) { - exitflag = 1; - signal (SIGINT, SIG_DFL); + exitflag = 1; + signal (SIGINT, SIG_DFL); } int @@ -381,7 +391,7 @@ main (int argc, char **argv) } else if (optarg[0] == 'u') { - opts.unmute_encrypted_p25 = 1; + opts.unmute_encrypted_p25 = 1; } break; case 'q': @@ -688,24 +698,28 @@ main (int argc, char **argv) opts.split = 1; opts.playoffset = 0; opts.delay = 0; - if(strlen(opts.wav_out_file) > 0) { - openWavOutFile (&opts, &state); - } - else { - openAudioOutDevice (&opts, 8000); - } + if (strlen(opts.wav_out_file) > 0) + { + openWavOutFile (&opts, &state); + } + else + { + openAudioOutDevice (&opts, 8000); + } } else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0) { opts.split = 1; opts.playoffset = 0; opts.delay = 0; - if(strlen(opts.wav_out_file) > 0) { - openWavOutFile (&opts, &state); - } - else { - openAudioOutDevice (&opts, 8000); - } + if (strlen(opts.wav_out_file) > 0) + { + openWavOutFile (&opts, &state); + } + else + { + openAudioOutDevice (&opts, 8000); + } openAudioInDevice (&opts); } else @@ -723,7 +737,7 @@ main (int argc, char **argv) } else { - liveScanner (&opts, &state); + liveScanner (&opts, &state); } cleanupAndExit (&opts, &state); return (0); diff --git a/dsd_mbe.c b/dsd_mbe.c index a7984c1..e0b7997 100644 --- a/dsd_mbe.c +++ b/dsd_mbe.c @@ -43,7 +43,7 @@ playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv) writeSynthesizedVoice (opts, state); } - if (opts->audio_out != 1) + if (opts->audio_out == 1) { playSynthesizedVoice (opts, state); } @@ -103,13 +103,13 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } } else if ((state->synctype == 6) || (state->synctype == 7)) - { - mbe_processAmbe3600x2400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); - if (opts->mbe_out_f != NULL) - { - saveAmbe2450Data (opts, state, ambe_d); - } - } + { + mbe_processAmbe3600x2400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + if (opts->mbe_out_f != NULL) + { + saveAmbe2450Data (opts, state, ambe_d); + } + } else { mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); @@ -134,6 +134,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a printf ("%s", state->err_str); } + state->debug_audio_errors += state->errs2; + processAudio (opts, state); if (opts->wav_out_f != NULL) { diff --git a/p25p1_check_nid.cpp b/p25p1_check_nid.cpp new file mode 100644 index 0000000..9a4e305 --- /dev/null +++ b/p25p1_check_nid.cpp @@ -0,0 +1,92 @@ +#include + +#include "p25p1_check_nid.h" + + + +using namespace itpp; + +// Ideas taken from http://op25.osmocom.org/trac/wiki.png/browser/op25/gr-op25/lib/decoder_ff_impl.cc +// See also p25_training_guide.pdf page 48. +// See also tia-102-baaa-a-project_25-fdma-common_air_interface.pdf page 40. +// BCH encoder/decoder implementation from IT++. GNU GPL 3 license. + +itpp::BCH bch(63, 16, 11, "6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true); + +/** Convenience class to calculate the parity of the DUID values. Keeps a table with the expected outcomes + * for fast lookup. + */ +class ParityTable +{ +private: + unsigned char table[16]; + + unsigned char get_index(unsigned char x, unsigned char y) + { + return (x<<2) + y; + } + +public: + ParityTable() + { + for (unsigned int i=0; i> 1)) + 48; // bit 1 diff --git a/p25p1_ldu1.c b/p25p1_ldu1.c index fd6abe8..859c037 100644 --- a/p25p1_ldu1.c +++ b/p25p1_ldu1.c @@ -21,8 +21,8 @@ void processLDU1 (dsd_opts * opts, dsd_state * state) { - // extracts IMBE frames rom LDU frame - int i, j, k, dibit, stats, count, scount; + // extracts IMBE frames from LDU frame + int i, j, k, dibit, stats, scount; char imbe_fr[8][23]; char lcformat[9], mfid[9], lcinfo[57], lsd1[9], lsd2[9], status[25]; const int *w, *x, *y, *z; @@ -34,10 +34,8 @@ processLDU1 (dsd_opts * opts, dsd_state * state) lsd2[8] = 0; status[24] = 0; - skipDibit (opts, state, 3); - status[0] = getDibit (opts, state) + 48; - skipDibit (opts, state, 21); - count = 57; + // Now processing NID + status[0] = 0; scount = 1; if (opts->errorbars == 1) @@ -62,14 +60,12 @@ processLDU1 (dsd_opts * opts, dsd_state * state) status[scount] = getDibit (opts, state) + 48; scount++; stats = 1; - count++; } else { stats++; } dibit = getDibit (opts, state); - count++; imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 imbe_fr[*y][*z] = (1 & dibit); // bit 0 w++; @@ -102,7 +98,6 @@ processLDU1 (dsd_opts * opts, dsd_state * state) { status[scount] = getDibit (opts, state) + 48; scount++; - count++; stats = 1; } else @@ -110,7 +105,6 @@ processLDU1 (dsd_opts * opts, dsd_state * state) stats++; } skipDibit (opts, state, 1); - count++; } if (i == 1) diff --git a/p25p1_ldu2.c b/p25p1_ldu2.c index a0f8fbb..b1641fe 100644 --- a/p25p1_ldu2.c +++ b/p25p1_ldu2.c @@ -21,8 +21,8 @@ void processLDU2 (dsd_opts * opts, dsd_state * state) { - // extracts IMBE frames rom LDU frame - int i, j, k, dibit, stats, count, scount; + // extracts IMBE frames from LDU frame + int i, j, k, dibit, stats, scount; char imbe_fr[8][23]; char mi[73], algid[9], kid[17], lsd3[9], lsd4[9], status[25]; const int *w, *x, *y, *z; @@ -35,13 +35,10 @@ processLDU2 (dsd_opts * opts, dsd_state * state) lsd3[8] = 0; lsd4[8] = 0; - skipDibit (opts, state, 3); - status[0] = getDibit (opts, state) + 48; - skipDibit (opts, state, 21); + // Now processing NID + status[0] = 0; scount = 1; - count = 57; - if (opts->errorbars == 1) { printf ("e:"); @@ -65,14 +62,12 @@ processLDU2 (dsd_opts * opts, dsd_state * state) status[scount] = getDibit (opts, state) + 48; scount++; stats = 1; - count++; } else { stats++; } dibit = getDibit (opts, state); - count++; imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 imbe_fr[*y][*z] = (1 & dibit); // bit 0 w++; @@ -106,7 +101,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state) { status[scount] = getDibit (opts, state) + 48; scount++; - count++; stats = 1; } else @@ -114,7 +108,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state) stats++; } skipDibit (opts, state, 1); - count++; } if (i == 1) diff --git a/p25p1_tdulc.c b/p25p1_tdulc.c index 77fe6c6..097970d 100644 --- a/p25p1_tdulc.c +++ b/p25p1_tdulc.c @@ -22,14 +22,13 @@ processTDULC (dsd_opts * opts, dsd_state * state) { char lcinfo[57], lcformat[9], mfid[9]; - int dibit, count; + int dibit; lcformat[8] = 0; mfid[8] = 0; lcinfo[56] = 0; - skipDibit (opts, state, 25); - count = 57; + // Now processing NID dibit = getDibit (opts, state); lcformat[0] = (1 & (dibit >> 1)) + 48; // bit 1