Added decoding and error correction on the NID fields: NAC and DUID. Making use of the IT++ library for BCH encoding/decoding.

This commit is contained in:
EdFuentetaja 2014-02-02 14:45:19 +08:00
parent e40e89ae81
commit 9b9cb78ddf
13 changed files with 330 additions and 89 deletions

View File

@ -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})

109
check_nid.cpp Normal file
View File

@ -0,0 +1,109 @@
#include <itpp/itcomm.h>
#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<sizeof(table); i++) {
table[i] = 0;
}
table[get_index(1,1)] = 1;
table[get_index(2,2)] = 1;
}
unsigned char get_value(unsigned char x, unsigned char y)
{
return table[get_index(x,y)];
}
} parity_table;
/** Checks a NID value, returns the fixed NAC, DUID and also an indication if it failed to decode the NID.
*
* \param bch_code Input. An array to the 63 bytes, each containing one bit of the NID.
* \param new_nac Output. An address where to store the calculated NAC value after error correction. Should
* be large enough to accommodate for an integer.
* \param new_duid Output. An address where to store the calculated DUID value after error correction. Should
* be able to accommodate 3 chars.
* \param parity Input. The parity value read.
* \return 0 if there were errors processing the NID.
*/
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity)
{
int result;
// Fill up with the input given
bvec input(63);
for(unsigned int i=0; i<63; i++) {
input[i] = bch_code[i];
}
// Decode it
bvec decoded = bch.decode(input);
// Check if the decoded output is zero
bool zero = true;
for (int i=0; i<decoded.length(); i++) {
if (decoded[i] != 0) {
zero = false;
break;
}
}
if (zero) {
// Decode failed
result = 0;
} else {
// Encode it again
bvec encoded = bch.encode(decoded);
// Take the fixed NAC from the encoded output. It's a 12 bit number starting from position 47.
// Just convert the output from a binary sequence to an integer.
int nac = 0;
for (int i=47; i<47+12; i++) {
nac <<= 1;
nac |= (int)encoded[i];
}
*new_nac = nac;
// Take the fixed DUID from the encoded output. 4 bit value starting at position 59.
unsigned char x = (((int)encoded[59])<<1) + ((int)encoded[60]);
unsigned char y = (((int)encoded[61])<<1) + ((int)encoded[62]);
new_duid[0] = x + '0';
new_duid[1] = y + '0';
new_duid[2] = 0;
// Check the parity
unsigned char expected_parity = parity_table.get_value(x,y);
// Returns false (0) if they don't match
result = (expected_parity == parity);
}
return result;
}

14
check_nid.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef __CHECK_NID_H__
#define __CHECK_NID_H__
#ifdef __cplusplus
extern "C" {
#endif
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity);
#ifdef __cplusplus
}
#endif
#endif // __CHECK_NID_H__

20
cmake/FindITPP.cmake Normal file
View File

@ -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)

4
dsd.h
View File

@ -168,6 +168,10 @@ typedef struct
mbe_parms *prev_mp;
mbe_parms *prev_mp_enhanced;
int p25kid;
unsigned int debug_audio_errors;
unsigned int debug_header_errors;
} dsd_state;
/*

View File

@ -20,6 +20,8 @@
#define NULL 0
#endif
#include "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,91 @@ processFrame (dsd_opts * opts, dsd_state * state)
}
else
{
// NAC, 12 bits
j = 0;
index_bch_code = 47;
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);
// 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)
{

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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)
{

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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