From 9b9cb78ddf542a0946658f211850d77ec450b007 Mon Sep 17 00:00:00 2001 From: EdFuentetaja Date: Sun, 2 Feb 2014 14:45:19 +0800 Subject: [PATCH] Added decoding and error correction on the NID fields: NAC and DUID. Making use of the IT++ library for BCH encoding/decoding. --- CMakeLists.txt | 6 ++- check_nid.cpp | 109 +++++++++++++++++++++++++++++++++++++++++++ check_nid.h | 14 ++++++ cmake/FindITPP.cmake | 20 ++++++++ dsd.h | 4 ++ dsd_frame.c | 105 ++++++++++++++++++++++++++++++++++++++--- dsd_frame_sync.c | 60 ++++++++++++------------ dsd_main.c | 44 ++++++++++------- dsd_mbe.c | 18 +++---- p25p1_hdu.c | 5 +- p25p1_ldu1.c | 14 ++---- p25p1_ldu2.c | 15 ++---- p25p1_tdulc.c | 5 +- 13 files changed, 330 insertions(+), 89 deletions(-) create mode 100644 check_nid.cpp create mode 100644 check_nid.h create mode 100644 cmake/FindITPP.cmake 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/check_nid.cpp b/check_nid.cpp new file mode 100644 index 0000000..299563b --- /dev/null +++ b/check_nid.cpp @@ -0,0 +1,109 @@ +#include + +#include "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 + + 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); + // 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++; } + + // Now processing NID + index_bch_code = 0; + 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++; + } + + // last bit is 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 + 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 + duid[0] = 'E'; + duid[1] = 'E'; + state->debug_header_errors += 10; + } } if (strcmp (duid, "00") == 0) { + // Header Data Unit if (opts->errorbars == 1) { printFrameInfo (opts, state); @@ -271,6 +348,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 +368,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 +401,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 +427,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 +443,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 +464,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) { @@ -450,7 +538,10 @@ processFrame (dsd_opts * opts, dsd_state * state) } state->lastp25type = 0; 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..c1d141b 100644 --- a/dsd_main.c +++ b/dsd_main.c @@ -220,6 +220,9 @@ 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; } void @@ -318,6 +321,11 @@ 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 ("Exiting.\n"); exit (0); } @@ -325,8 +333,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 +389,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 +696,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 +735,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_hdu.c b/p25p1_hdu.c index 2f0f3f9..0842331 100644 --- a/p25p1_hdu.c +++ b/p25p1_hdu.c @@ -22,7 +22,7 @@ processHDU (dsd_opts * opts, dsd_state * state) { char mi[73], mfid[9], algid[9], kid[17], tgid[17], tmpstr[255]; - int dibit, count, i, j; + int dibit, i, j; long talkgroup; int algidhex, kidhex; @@ -32,8 +32,7 @@ processHDU (dsd_opts * opts, dsd_state * state) kid[16] = 0; tgid[16] = 0; - skipDibit (opts, state, 25); - count = 57; + // Now processing NID dibit = getDibit (opts, state); mi[0] = (1 & (dibit >> 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