diff --git a/Hamming.cpp b/Hamming.cpp new file mode 100644 index 0000000..97a0d43 --- /dev/null +++ b/Hamming.cpp @@ -0,0 +1,62 @@ + +#include + +// definition outside class declaration +Hamming_10_6_3_data Hamming_10_6_3::data; + +// definition outside class declaration +// Should go *after* Hamming_10_6_3_data since Hamming_10_6_3_TableImpl_data constructor uses +// Hamming_10_6_3 which in its turn depends on Hamming_10_6_3_data +Hamming_10_6_3_TableImpl_data Hamming_10_6_3_TableImpl::data; + + +int Hamming_10_6_3::decode(std::bitset<10>& input) +{ + int error_count; + + // Compute syndromes + int s0 = ((data.h0 & input).count() & 1) << 3; + int s1 = ((data.h1 & input).count() & 1) << 2; + int s2 = ((data.h2 & input).count() & 1) << 1; + int s3 = ((data.h3 & input).count() & 1); + int parity = s0 | s1 | s2 | s3; + + if (parity == 0) { + //std::cout << input << " is OK" << std::endl; + error_count = 0; + } else { + // Error detected, attempt to fix it + int bad_bit_index = data.bad_bit_table[parity]; + + if (bad_bit_index < 0) { + //std::cout << "Irrecoverable error: " << std::bitset<6>(input.to_string()) << std::endl; + error_count = 2; + } else { + // Error in a data bit, or more than one error + // If there is one erroneous bit, the bad one is the one indicated by parity + if (bad_bit_index < 4) { + // Error detected in a parity bit + //std::cout << "Error on parity bit " << bad_bit_index << std::endl; + error_count = 1; + } else { + input.flip(bad_bit_index); + //std::cout << "Error on data bit " << bad_bit_index << ", hopefully fixed: " << std::bitset<6>(input.to_string()) << std::endl; + error_count = 1; + } + } + } + //std::cout << std::endl; + + return error_count; +} + +int Hamming_10_6_3_TableImpl::decode(int input, int* output) +{ + assert (input < 1024 && input >= 0); + + // Making use of a table... + + *output = data.fixed_values[input]; + + return data.error_counts[input]; +} diff --git a/Hamming.hpp b/Hamming.hpp new file mode 100644 index 0000000..e64ec6d --- /dev/null +++ b/Hamming.hpp @@ -0,0 +1,264 @@ + +#ifndef __HAMMING_HPP__ +#define __HAMMING_HPP__ + +#include +#include +#include + + +#include + +/** + * \brief Holds data for the Hamming_10_6_3 class. See next. + */ +class Hamming_10_6_3_data +{ +public: + std::bitset<10> g0; + std::bitset<10> g1; + std::bitset<10> g2; + std::bitset<10> g3; + std::bitset<10> g4; + std::bitset<10> g5; + + std::bitset<10> h0; + std::bitset<10> h1; + std::bitset<10> h2; + std::bitset<10> h3; + + int bad_bit_table[16]; + + Hamming_10_6_3_data() + { + // G matrix come from the APCO 25 reference documentation: + g0 = std::bitset<10>(std::string("1000001110")); + g1 = std::bitset<10>(std::string("0100001101")); + g2 = std::bitset<10>(std::string("0010001011")); + g3 = std::bitset<10>(std::string("0001000111")); + g4 = std::bitset<10>(std::string("0000100011")); + g5 = std::bitset<10>(std::string("0000011100")); + + // H matrix, calculated transposing G. See wikipedia. + h0 = std::bitset<10>(std::string("1110011000")); + h1 = std::bitset<10>(std::string("1101010100")); + h2 = std::bitset<10>(std::string("1011100010")); + h3 = std::bitset<10>(std::string("0111100001")); + + // bad_bit_table indicates which is the bit to correct from the calculated syndromes. + // It's calculated from the previous matrices: See the left-most column of the matrix whose rows are + // h0,h1,h2 and h3. It's [1 1 1 0]. It means: when the syndrome value is the binary number 1110, the + // bit that is wrong is the bit 9 (the left-most column is for the bit 9). Another example with + // the right-most column: it's column is [0 0 0 1], so when the syndrome is 0001, the bit to fix is + // bit 0 (one of the parity bits). + bad_bit_table[ 1] = 0; + bad_bit_table[ 2] = 1; + bad_bit_table[ 4] = 2; + bad_bit_table[ 8] = 3; + bad_bit_table[12] = 4; + bad_bit_table[ 3] = 5; + bad_bit_table[ 7] = 6; + bad_bit_table[11] = 7; + bad_bit_table[13] = 8; + bad_bit_table[14] = 9; + + // If the syndrome is zero, then the data is correct, no errors detected. + bad_bit_table[ 0] = -2; + + // Incorrect values, if the syndrome gets one of this values, then we fail to correct the data. + bad_bit_table[ 5] = -1; + bad_bit_table[ 6] = -1; + bad_bit_table[ 9] = -1; + bad_bit_table[10] = -1; + bad_bit_table[15] = -1; + } +}; + +/** + * An interface used by the two implementations defined here. + */ +class Hamming_Inteface +{ +public: + virtual ~Hamming_Inteface() + { + // Does nothing + } + + /** + * \brief Decodes using the Hamming (10,6,3) algorithm a sequence of 10 bits expressed as an integer. + * \arg input The number to decode. + * \arg output A pointer to int where the decoded result is stored. + * \return Count of detected errors. + */ + virtual int decode(int input, int* output) = 0; + + /** + * \brief Decodes using the Hamming (10,6,3) algorithm a sequence of 10 bits expressed as a pointer + * to six chars (data) and a pointer to four chars (parity). Altogether ten chars, each holding one bit. + * \arg hex A pointer to six chars. If error are detected the values are modified acordingly. + * \arg parity A pointer to four chars. Represent the parity of the data. + * \return Count of detected errors. + */ + virtual int decode(char* hex, char* parity) = 0; +}; + +/** + * \brief Hamming (10,6,3) error correction implementation. + */ +class Hamming_10_6_3 : public Hamming_Inteface +{ +private: + static Hamming_10_6_3_data data; + +public: + /** + * \brief Decodes using the Hamming (10,6,3) algorithm a sequence of 10 bits expressed as a std::bitset. + * \arg input The sequence to decode. + * \return Count of detected errors. + */ + int decode(std::bitset<10>& input); + + int decode(int input, int* output) + { + assert (input < 1024 && input >= 0); + + std::bitset<10> bitset_input(input); + int error_count = decode(bitset_input); + if (error_count == 1) { + // t has possibly been modified + input = (int)bitset_input.to_ulong(); + } else { + // both in case that there were no errors or there were irrecoverable errors we leave the data as + // it is + } + + // discard the four parity bits at the end + *output = input >> 4; + + return error_count; + } + + int decode(char* hex, char* parity) + { + // Make a bitset from hex and parity + std::bitset<10> value; + // in the bitset 9 is the left-most and 0 is the right-most + for (unsigned int i=0; i<6; i++) { + value[9-i] = hex[i]; + } + for (unsigned int i=0; i<4; i++) { + value[3-i] = parity[i]; + } + + int error_count = decode(value); + + // Modify hex if needed + if (error_count == 1) { + for (unsigned int i=0; i<6; i++) { + hex[i] = value[9-i]; + } + } else { + // No errors or irrecoverable errors, in both cases don't touch the input + } + + return error_count; + } +}; + +/** + * \brief Stores data for the Hamming_10_6_3_TableImpl that comes next. + */ +class Hamming_10_6_3_TableImpl_data +{ +public: + int fixed_values[1024]; + int error_counts[1024]; + + /** + * \brief On initialization it builds a table to calculate every possible outcome (there are 1024) before + * hand. Uses Hamming_10_6_3 to build the table. + */ + Hamming_10_6_3_TableImpl_data() + { + Hamming_10_6_3 hamming; + + // Build the tables + for (int i=0; i<1024; i++) { + int fixed; + int error_count = hamming.decode(i, &fixed); + fixed_values[i] = fixed; + error_counts[i] = error_count; + } + } +}; + +/** + * \brief Hamming (10,6,3) error correction implementation. + */ +class Hamming_10_6_3_TableImpl : public Hamming_Inteface +{ +private: + static Hamming_10_6_3_TableImpl_data data; + +public: + int decode(int input, int* output); + + static int convert_hex_to_int(char* hex) + { + // Make an int from hex + int value = 0; + // in the bitset 9 is the left-most and 0 is the right-most + for (unsigned int i=0; i<6; i++) { + value <<= 1; + value |= hex[i]; + } + + return value; + } + + static int convert_hex_parity_to_int(char* hex, char* parity) + { + // Make an int from hex and parity + int value = 0; + // in the bitset 9 is the left-most and 0 is the right-most + for (unsigned int i=0; i<6; i++) { + value <<= 1; + value |= hex[i]; + } + for (unsigned int i=0; i<4; i++) { + value <<= 1; + value |= parity[i]; + } + + return value; + } + + static void convert_int_to_hex(int value, char* hex) + { + unsigned int v = value; + for (unsigned int i=0; i<6; i++) { + hex[5-i] = v & 1; + v >>= 1; + } + } + + int decode(char* hex, char* parity) + { + int value = convert_hex_parity_to_int(hex, parity); + int fixed; + int error_count = decode(value, &fixed); + + // Modify hex if needed + if (error_count == 1) { + convert_int_to_hex(fixed, hex); + } else { + // No errors or irrecoverable errors, in both cases don't touch the input + } + + return error_count; + } +}; + + +#endif // __HAMMING_HPP__ diff --git a/ReedSolomon.hpp b/ReedSolomon.hpp index 40c7895..021e34f 100644 --- a/ReedSolomon.hpp +++ b/ReedSolomon.hpp @@ -61,16 +61,18 @@ // Constants to adapt the code to DSD/P25 needs -#define mm 6 /* RS code over GF(2**4) - change to suit */ -#define nn 63 /* nn=2**mm -1 length of codeword */ -#define tt 8 /* number of errors that can be corrected */ -#define kk 47 /* kk = nn-2*tt */ -// distance = nn-kk+1 = 63-47+1 = 17 - -class ReedSolomon_63_47_17 +class ReedSolomon_63 { private: - int alpha_to[nn + 1], index_of[nn + 1], gg[nn - kk + 1]; + static const int mm = 6; /* RS code over GF(2**mm) */ + static const int nn = 63; /* nn=2**mm -1 length of codeword */ + int tt; /* number of errors that can be corrected */ + int kk; /* kk = nn-2*tt */ + // distance = nn-kk+1 = 2*tt+1 + + int* alpha_to; + int* index_of; + int* gg; void generate_gf(int* generator_polinomial) /* generate GF(2**mm) from the irreducible polynomial p(X) in pp[0]..pp[mm] @@ -126,15 +128,30 @@ private: } public: - ReedSolomon_63_47_17() + ReedSolomon_63(int a_tt) { + tt = a_tt; /* number of errors that can be corrected */ + kk = nn-2*tt; + + alpha_to = new int[nn + 1]; + index_of = new int[nn + 1]; + gg = new int[nn - kk + 1]; + // Polynom used in P25 is alpha**6+alpha+1 - int generator_polinomial[mm + 1] = { 1, 1, 0, 0, 0, 0, 1 }; /* specify irreducible polynomial coeffts */ + int generator_polinomial[] = { 1, 1, 0, 0, 0, 0, 1 }; /* specify irreducible polynomial coeffts */ + generate_gf(generator_polinomial); gen_poly(); } + virtual ~ReedSolomon_63() + { + delete[] gg; + delete[] index_of; + delete[] alpha_to; + } + void encode(int* data, int* bb) /* take the string of symbols in data[i], i=0..(k-1) and encode systematically to produce 2*tt parity symbols in bb[0]..bb[2*tt-1] @@ -165,7 +182,7 @@ public: } } - void decode(const int* input, int* recd) + int decode(const int* input, int* recd) /* assume we have received bits grouped into mm-bit symbols in recd[i], i=0..(nn-1), and recd[i] is polynomial form. We first compute the 2*tt syndromes by substituting alpha**i into rec(X) and @@ -191,6 +208,8 @@ public: int count = 0, syn_error = 0, root[tt], loc[tt], z[tt + 1], err[nn], reg[tt + 1]; + int irrecoverable_error = 0; + for (int i = 0; i < nn; i++) recd[i] = index_of[input[i]]; /* put recd[i] into index form (ie as powers of alpha) */ @@ -315,6 +334,7 @@ public: count++; }; }; + if (count == l[u]) /* no. roots = degree of elp hence <= tt errors */ { /* form polynomial z(x) */ @@ -360,37 +380,37 @@ public: recd[loc[i]] ^= err[loc[i]]; /*recd[i] must be in polynomial form */ } } - } else + } else { /* no. roots != degree of elp => >tt errors and cannot solve */ - for (i = 0; i < nn; i++) /* could return error flag if desired */ - if (recd[i] != -1) /* convert recd[] to polynomial form */ - recd[i] = alpha_to[recd[i]]; - else - recd[i] = 0; /* just output received codeword as is */ - } else - /* elp has degree has degree >tt hence cannot solve */ - for (i = 0; i < nn; i++) /* could return error flag if desired */ - if (recd[i] != -1) /* convert recd[] to polynomial form */ - recd[i] = alpha_to[recd[i]]; - else - recd[i] = 0; /* just output received codeword as is */ - } else + irrecoverable_error = 1; + } + + } else { + /* elp has degree >tt hence cannot solve */ + irrecoverable_error = 1; + } + + } else { /* no non-zero syndromes => no errors: output received codeword */ for (i = 0; i < nn; i++) if (recd[i] != -1) /* convert recd[] to polynomial form */ recd[i] = alpha_to[recd[i]]; else recd[i] = 0; - } -}; + } -/** - * Convenience class that does a Reed-Solomon (63,20,17) error correction adapting input and output to - * the DSD data format: hex words packed as char arrays. - */ -class DSDReedSolomon_63_20_17 : public ReedSolomon_63_47_17 -{ -private: + if (irrecoverable_error) { + for (i = 0; i < nn; i++) /* could return error flag if desired */ + if (recd[i] != -1) /* convert recd[] to polynomial form */ + recd[i] = alpha_to[recd[i]]; + else + recd[i] = 0; /* just output received codeword as is */ + } + + return irrecoverable_error; + } + +protected: int bin_to_hex(char* input) { int output = ((input[0] != 0)? 32 : 0) | @@ -412,20 +432,35 @@ private: output[4] = ((input & 2) != 0)? 1 : 0; output[5] = ((input & 1) != 0)? 1 : 0; } +}; +/** + * Convenience class that does a Reed-Solomon (36,20,17) error correction adapting input and output to + * the DSD data format: hex words packed as char arrays. + */ +class DSDReedSolomon_36_20_17 : public ReedSolomon_63 +{ public: + // tt = (dd-1)/2 + // dd = 17 --> tt = 8 + DSDReedSolomon_36_20_17() : ReedSolomon_63(8) + { + // Does nothing + } + /** * Does a Reed-Solomon decode adapting the input and output to the expected DSD data format. * \param hex_data Data packed bits, originally a char[20][6], so containing 20 hex works, each char * is a bit. * \param hex_parity Parity packed bits, originally a char[16][6], 16 hex words. + * \return 1 if irrecoverable errors have been detected, 0 otherwise. */ - void decode(char* hex_data, char* hex_parity) + int decode(char* hex_data, char* hex_parity) { int input[63]; int output[63]; - // First put the parity data, 16 + // First put the parity data, 16 hex words for(unsigned int i=0; i<16; i++) { input[i] = bin_to_hex(hex_parity + i*6); } @@ -436,18 +471,128 @@ public: } // Fill up with zeros to complete the 47 expected hex words of data - for(unsigned int i=36; i<63; i++) { + for(unsigned int i=16+20; i<63; i++) { input[i] = 0; } // Now we can call decode on the base class - ReedSolomon_63_47_17::decode(input, output); + int irrecoverable_errors = ReedSolomon_63::decode(input, output); // Convert it back to binary and put it into hex_data. If decode failed we should have // the input unchanged. for(unsigned int i=16; i<16+20; i++) { hex_to_bin(output[i], hex_data + (i-16)*6); } + + return irrecoverable_errors; + } +}; + +/** + * Convenience class that does a Reed-Solomon (24,12,13) error correction adapting input and output to + * the DSD data format: hex words packed as char arrays. + */ +class DSDReedSolomon_24_12_13 : public ReedSolomon_63 +{ +public: + // tt = (dd-1)/2 + // dd = 13 --> tt = 6 + DSDReedSolomon_24_12_13() : ReedSolomon_63(6) + { + // Does nothing + } + + /** + * Does a Reed-Solomon decode adapting the input and output to the expected DSD data format. + * \param hex_data Data packed bits, originally a char[12][6], so containing 12 hex works, each char + * is a bit. + * \param hex_parity Parity packed bits, originally a char[12][6], 12 hex words. + * \return 1 if irrecoverable errors have been detected, 0 otherwise. + */ + int decode(char* hex_data, char* hex_parity) + { + int input[63]; + int output[63]; + + // First put the parity data, 12 hex words + for(unsigned int i=0; i<12; i++) { + input[i] = bin_to_hex(hex_parity + i*6); + } + + // Then the 12 hex words of data + for(unsigned int i=12; i<12+12; i++) { + input[i] = bin_to_hex(hex_data + (i-12)*6); + } + + // Fill up with zeros to complete the 51 expected hex words of data + for(unsigned int i=12+12; i<63; i++) { + input[i] = 0; + } + + // Now we can call decode on the base class + int irrecoverable_errors = ReedSolomon_63::decode(input, output); + + // Convert it back to binary and put it into hex_data. If decode failed we should have + // the input unchanged. + for(unsigned int i=12; i<12+12; i++) { + hex_to_bin(output[i], hex_data + (i-12)*6); + } + + return irrecoverable_errors; + } +}; + +/** + * Convenience class that does a Reed-Solomon (24,16,9) error correction adapting input and output to + * the DSD data format: hex words packed as char arrays. + */ +class DSDReedSolomon_24_16_9 : public ReedSolomon_63 +{ +public: + // tt = (dd-1)/2 + // dd = 9 --> tt = 4 + DSDReedSolomon_24_16_9() : ReedSolomon_63(4) + { + // Does nothing + } + + /** + * Does a Reed-Solomon decode adapting the input and output to the expected DSD data format. + * \param hex_data Data packed bits, originally a char[16][6], so containing 16 hex works, each char + * is a bit. + * \param hex_parity Parity packed bits, originally a char[8][6], 8 hex words. + * \return 1 if irrecoverable errors have been detected, 0 otherwise. + */ + int decode(char* hex_data, char* hex_parity) + { + int input[63]; + int output[63]; + + // First put the parity data, 8 hex words + for(unsigned int i=0; i<8; i++) { + input[i] = bin_to_hex(hex_parity + i*6); + } + + // Then the 16 hex words of data + for(unsigned int i=8; i<8+12; i++) { + input[i] = bin_to_hex(hex_data + (i-8)*6); + } + + // Fill up with zeros to complete the 55 expected hex words of data + for(unsigned int i=8+12; i<63; i++) { + input[i] = 0; + } + + // Now we can call decode on the base class + int irrecoverable_errors = ReedSolomon_63::decode(input, output); + + // Convert it back to binary and put it into hex_data. If decode failed we should have + // the input unchanged. + for(unsigned int i=8; i<8+12; i++) { + hex_to_bin(output[i], hex_data + (i-8)*6); + } + + return irrecoverable_errors; } }; diff --git a/dsd_frame.c b/dsd_frame.c index 893c367..21cd744 100644 --- a/dsd_frame.c +++ b/dsd_frame.c @@ -254,13 +254,13 @@ processFrame (dsd_opts * opts, dsd_state * state) dibit = getDibit (opts, state); v = 1 & (dibit >> 1); // bit 1 - nac[j] = v + 48; + nac[j] = v + '0'; j++; bch_code[index_bch_code] = v; index_bch_code++; v = 1 & dibit; // bit 0 - nac[j] = v + 48; + nac[j] = v + '0'; j++; bch_code[index_bch_code] = v; index_bch_code++; @@ -271,7 +271,7 @@ processFrame (dsd_opts * opts, dsd_state * state) for (i = 0; i < 2; i++) { dibit = getDibit (opts, state); - duid[i] = dibit + 48; + duid[i] = dibit + '0'; bch_code[index_bch_code] = 1 & (dibit >> 1); // bit 1 index_bch_code++; @@ -289,7 +289,9 @@ processFrame (dsd_opts * opts, dsd_state * state) bch_code[index_bch_code] = 1 & dibit; // bit 0 index_bch_code++; } - status_0 = getDibit (opts, state) + 48; + // Intermission: read the status dibit + status_0 = getDibit (opts, state) + '0'; + // ... continue reading the BCH error correction data for (i = 0; i < 20; i++) { dibit = getDibit (opts, state); @@ -325,7 +327,7 @@ processFrame (dsd_opts * opts, dsd_state * state) //printf("NID error\n"); duid[0] = 'E'; duid[1] = 'E'; - state->debug_header_critical_errors ++; + state->debug_header_critical_errors++; } } @@ -448,7 +450,7 @@ processFrame (dsd_opts * opts, dsd_state * state) // Now processing NID skipDibit (opts, state, 14); // 28 null bits - status_1 = getDibit (opts, state) + 48; + status_1 = getDibit (opts, state) + '0'; } else if (strcmp (duid, "13") == 0) { diff --git a/p25p1_check_hdu.cpp b/p25p1_check_hdu.cpp index e4fc452..0a58cf5 100644 --- a/p25p1_check_hdu.cpp +++ b/p25p1_check_hdu.cpp @@ -21,7 +21,7 @@ int check_and_fix_golay24(char* hex, char* parity, int* fixed_errors) printf("]"); #endif - int uncorrectable_errors = golay24.decode(hex, parity, fixed_errors); + int irrecoverable_errors = golay24.decode(hex, parity, fixed_errors); #ifdef __CHECK_HDU_DEBUG__ printf(" -> ["); @@ -29,20 +29,20 @@ int check_and_fix_golay24(char* hex, char* parity, int* fixed_errors) printf("%c", (hex[i] != 0)? 'X': ' '); } printf("]"); - if (uncorrectable_errors) { - printf(" Errors: +4"); + if (irrecoverable_errors) { + printf(" Errors: >4"); } else { printf(" Errors: %i", *fixed_errors); } printf("\n"); #endif - return uncorrectable_errors; + return irrecoverable_errors; } -void check_and_fix_redsolomon63(char* data, char* parity) +int check_and_fix_redsolomon_36_20_17(char* data, char* parity) { - static DSDReedSolomon_63_20_17 reed_solomon63; + static DSDReedSolomon_36_20_17 reed_solomon_36_20_17; #ifdef __CHECK_HDU_DEBUG__ char original[20][6]; @@ -53,22 +53,36 @@ void check_and_fix_redsolomon63(char* data, char* parity) } #endif - reed_solomon63.decode(data, parity); + int irrecoverable_errors = reed_solomon_36_20_17.decode(data, parity); #ifdef __CHECK_HDU_DEBUG__ - printf("Results for Reed-Solomon code (n=%3d, k=%3d, t= %3d)\n\n", nn, kk, tt); - printf(" i original fixed\n"); - for (int i = 0; i < 20; i++) { - printf("%3d [", i); - for (int j = 0; j < 6; j++) { - printf("%c", (original[i][j] == 1)? 'X' : ' '); + printf("Results for Reed-Solomon code (36,20,17)\n\n"); + if (irrecoverable_errors == 0) { + printf(" i original fixed\n"); + for (int i = 0; i < 20; i++) { + printf("%3d [", i); + for (int j = 0; j < 6; j++) { + printf("%c", (original[i][j] == 1)? 'X' : ' '); + } + printf("] ["); + for (int j = 0; j < 6; j++) { + printf("%c", (data[i*6+j] == 1)? 'X' : ' '); + } + printf("]\n"); } - printf("] ["); - for (int j = 0; j < 6; j++) { - printf("%c", (data[i*6+j] == 1)? 'X' : ' '); + } else { + printf("Irrecoverable errors found\n"); + printf(" i original fixed\n"); + for (int i = 0; i < 20; i++) { + printf("%3d [", i); + for (int j = 0; j < 6; j++) { + printf("%c", (original[i][j] == 1)? 'X' : ' '); + } + printf("]\n"); } - printf("]\n"); } printf("\n"); #endif + + return irrecoverable_errors; } diff --git a/p25p1_check_hdu.h b/p25p1_check_hdu.h index d15e0e1..ef74a6e 100644 --- a/p25p1_check_hdu.h +++ b/p25p1_check_hdu.h @@ -15,11 +15,12 @@ extern "C" { int check_and_fix_golay24(char* hex, char* parity, int* fixed_errors); /** - * Attempts to correct 20 hex words using the Reed-Solomon(63,20,17) FEC. + * Attempts to correct 20 hex words using the Reed-Solomon(36,20,17) FEC. * \param data The packed hex words, each of 6 chars, one after the other. * \param parity The corresponding 16 hex words with the parity information. + * \return 1 if irrecoverable errors have been detected, 0 otherwise. */ -void check_and_fix_redsolomon63(char* data, char* parity); +int check_and_fix_redsolomon_36_20_17(char* data, char* parity); #ifdef __cplusplus } diff --git a/p25p1_check_ldu.cpp b/p25p1_check_ldu.cpp new file mode 100644 index 0000000..82ec0ee --- /dev/null +++ b/p25p1_check_ldu.cpp @@ -0,0 +1,110 @@ + +#include "p25p1_check_ldu.h" + +#include "Hamming.hpp" +#include "ReedSolomon.hpp" + + +//#define __CHECK_HDU_DEBUG__ + + +int check_and_fix_hamming_10_12_13(char* hex, char* parity) +{ + static Hamming_10_6_3_TableImpl hamming; + + return hamming.decode(hex, parity); +} + +int check_and_fix_redsolomon_24_12_13(char* data, char* parity) +{ + static DSDReedSolomon_24_12_13 reed_solomon_24_12_13; + +#ifdef __CHECK_HDU_DEBUG__ + char original[12][6]; + for (int i = 0; i < 12; i++) { + for (int j = 0; j < 6; j++) { + original[i][j] = data[i*6+j]; + } + } +#endif + + int irrecoverable_error = reed_solomon_24_12_13.decode(data, parity); + +#ifdef __CHECK_HDU_DEBUG__ + printf("Results for Reed-Solomon code (24,12,13)\n\n"); + if (irrecoverable_error == 0) { + printf(" i original fixed\n"); + for (int i = 0; i < 12; i++) { + printf("%3d [", i); + for (int j = 0; j < 6; j++) { + printf("%c", (original[i][j] == 1)? 'X' : ' '); + } + printf("] ["); + for (int j = 0; j < 6; j++) { + printf("%c", (data[i*6+j] == 1)? 'X' : ' '); + } + printf("]\n"); + } + } else { + printf("Irrecoverable errors found\n"); + printf(" i original fixed\n"); + for (int i = 0; i < 12; i++) { + printf("%3d [", i); + for (int j = 0; j < 6; j++) { + printf("%c", (original[i][j] == 1)? 'X' : ' '); + } + printf("]\n"); + } + } + printf("\n"); +#endif + + return irrecoverable_error; +} + +int check_and_fix_redsolomon_24_16_9(char* data, char* parity) +{ + static DSDReedSolomon_24_16_9 reed_solomon_24_16_9; + +#ifdef __CHECK_HDU_DEBUG__ + char original[16][6]; + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 6; j++) { + original[i][j] = data[i*6+j]; + } + } +#endif + + int irrecoverable_error = reed_solomon_24_16_9.decode(data, parity); + +#ifdef __CHECK_HDU_DEBUG__ + printf("Results for Reed-Solomon code (24,16,9)\n\n"); + if (irrecoverable_error == 0) { + printf(" i original fixed\n"); + for (int i = 0; i < 16; i++) { + printf("%3d [", i); + for (int j = 0; j < 6; j++) { + printf("%c", (original[i][j] == 1)? 'X' : ' '); + } + printf("] ["); + for (int j = 0; j < 6; j++) { + printf("%c", (data[i*6+j] == 1)? 'X' : ' '); + } + printf("]\n"); + } + } else { + printf("Irrecoverable errors found\n"); + printf(" i original fixed\n"); + for (int i = 0; i < 16; i++) { + printf("%3d [", i); + for (int j = 0; j < 6; j++) { + printf("%c", (original[i][j] == 1)? 'X' : ' '); + } + printf("]\n"); + } + } + printf("\n"); +#endif + + return irrecoverable_error; +} diff --git a/p25p1_check_ldu.h b/p25p1_check_ldu.h new file mode 100644 index 0000000..7cc22bf --- /dev/null +++ b/p25p1_check_ldu.h @@ -0,0 +1,30 @@ +#ifndef __P25P1_CHECK_LDU_H__ +#define __P25P1_CHECK_LDU_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +int check_and_fix_hamming_10_12_13(char* hex, char* parity); + +/** + * Attempts to correct 12 hex words using the Reed-Solomon(24,12,13) FEC. + * \param data The packed hex words, each of 6 chars, one after the other. + * \param parity The corresponding 12 hex words with the parity information. + * \return 1 if irrecoverable errors have been detected, 0 otherwise. + */ +int check_and_fix_redsolomon_24_12_13(char* data, char* parity); + +/** + * Attempts to correct 16 hex words using the Reed-Solomon(24,16,9) FEC. + * \param data The packed hex words, each of 6 chars, one after the other. + * \param parity The corresponding 8 hex words with the parity information. + * \return 1 if irrecoverable errors have been detected, 0 otherwise. + */ +int check_and_fix_redsolomon_24_16_9(char* data, char* parity); + +#ifdef __cplusplus +} +#endif + +#endif // __P25P1_CHECK_LDU_H__ diff --git a/p25p1_hdu.c b/p25p1_hdu.c index c8f7433..a9039c0 100644 --- a/p25p1_hdu.c +++ b/p25p1_hdu.c @@ -24,7 +24,7 @@ * Read two bits from the stream of data. Takes into account the periodic occurrence of status bits. * Those are discarded. */ -static void +void read_dibit (dsd_opts* opts, dsd_state* state, char* output, int* status_count) { int dibit; @@ -47,7 +47,7 @@ read_dibit (dsd_opts* opts, dsd_state* state, char* output, int* status_count) /** * Read an hex word from the stream of data. */ -static void +void read_hex (dsd_opts* opts, dsd_state* state, char* hex, int* status_count) { unsigned int i; @@ -80,12 +80,12 @@ static void correct_hex_word (dsd_state* state, char* hex, char* parity) { int fixed_errors; - int unrecoverable_errors; + int irrecoverable_errors; - unrecoverable_errors = check_and_fix_golay24(hex, parity, &fixed_errors); + irrecoverable_errors = check_and_fix_golay24(hex, parity, &fixed_errors); state->debug_header_errors += fixed_errors; - if (unrecoverable_errors != 0) + if (irrecoverable_errors != 0) { state->debug_header_critical_errors++; } @@ -98,7 +98,6 @@ static void read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count) { char parity[12]; - unsigned int i; // Read the hex word read_hex (opts, state, hex, status_count); @@ -111,19 +110,20 @@ read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* sta void processHDU (dsd_opts * opts, dsd_state * state) { - char mi[73], mfid[9], algid[9], kid[17], tgid[17], tmpstr[255]; int dibit, i, j; long talkgroup; int algidhex, kidhex; char hex[6]; - char parity[12]; + int status_count; int status; char hex_data[20][6]; // Data in hex-words (6 bit words). A total of 20 hex words. char hex_parity[16][6]; // Parity of the data, again in hex-word format. A total of 16 parity hex words. + int irrecoverable_errors; + status_count = 35 - 14; // Read 20 hex words, correct them using their Golay24 parity data. @@ -150,7 +150,11 @@ processHDU (dsd_opts * opts, dsd_state * state) } // Use the Reed-Solomon algorithm to correct the data. hex_data is modified in place - check_and_fix_redsolomon63((char*)hex_data, (char*)hex_parity); + irrecoverable_errors = check_and_fix_redsolomon_36_20_17((char*)hex_data, (char*)hex_parity); + if (irrecoverable_errors != 0) + { + state->debug_header_critical_errors++; + } mi[72] = 0; mfid[8] = 0; @@ -333,10 +337,10 @@ processHDU (dsd_opts * opts, dsd_state * state) tmpstr[j] = tgid[i]; j++; } - tmpstr[12] = 48; - tmpstr[13] = 48; - tmpstr[14] = 48; - tmpstr[15] = 48; + tmpstr[12] = '0'; + tmpstr[13] = '0'; + tmpstr[14] = '0'; + tmpstr[15] = '0'; } else { diff --git a/p25p1_hdu.h b/p25p1_hdu.h new file mode 100644 index 0000000..b5ee4d3 --- /dev/null +++ b/p25p1_hdu.h @@ -0,0 +1,15 @@ + +#ifndef __P25P1_HDU_H__ +#define __P25P1_HDU_H__ + +/** + * Reads a dibit keeping track of the status dibits that shows up every 70 bits + */ +void read_dibit (dsd_opts* opts, dsd_state* state, char* output, int* status_count); + +/** + * Read an "hex" word. An hex word is made up of 3 dibits. Also keeps track of the status dibits. + */ +void read_hex (dsd_opts* opts, dsd_state* state, char* hex, int* status_count); + +#endif // __P25P1_HDU_H__ diff --git a/p25p1_ldu.c b/p25p1_ldu.c new file mode 100644 index 0000000..990e229 --- /dev/null +++ b/p25p1_ldu.c @@ -0,0 +1,107 @@ + +#include "dsd.h" +#include "p25p1_const.h" +#include "p25p1_hdu.h" + +// separate imbe frames and deinterleave +void +process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count) +{ + int j, dibit, status; + char imbe_fr[8][23]; + const int *w, *x, *y, *z; + + w = iW; + x = iX; + y = iY; + z = iZ; + + for (j = 0; j < 72; j++) + { + if (*status_count == 35) + { + status = getDibit (opts, state); + // TODO: do something useful with the status bits... + *status_count = 1; + } + else + { + (*status_count)++; + } + dibit = getDibit (opts, state); + imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 + imbe_fr[*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + + if (state->p25kid == 0 || opts->unmute_encrypted_p25 == 1) + { + processMbeFrame (opts, state, imbe_fr, NULL, NULL); + } +} + +/** + * Read 4 bits from the stream of data. Those are the parity bits that follow each hex word. + */ +static void +read_hamm_parity (dsd_opts* opts, dsd_state* state, char* parity, int* status_count) +{ + // Read 2 dibits = read 4 bits. + read_dibit(opts, state, parity, status_count); + read_dibit(opts, state, parity + 2, status_count); +} + +//#define __LDU_DEBUG__ + +/** + * Read an hex word, its parity bits and attempts to error correct it using the Hamming algorithm. + */ +void +read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count) +{ + char parity[4]; + int i; + + // Read the hex word + read_hex (opts, state, hex, status_count); + // Read the parity + read_hamm_parity (opts, state, parity, status_count); + +#ifdef __LDU_DEBUG__ + printf("["); + for (i = 0; i < 6; i++) { + printf("%c", (hex[i] == 1)? 'X' : ' '); + } + printf("-"); + for (i = 0; i < 4; i++) { + printf("%c", (parity[i] == 1)? 'X' : ' '); + } + printf("]"); +#endif + + // Use Hamming to error correct the hex word + int error_count = check_and_fix_hamming_10_12_13(hex, parity); + + if (error_count == 1) { + state->debug_header_errors++; + } else if (error_count ==2) { + state->debug_header_critical_errors++; + } + +#ifdef __LDU_DEBUG__ + printf(" -> ["); + for (i = 0; i < 6; i++) { + printf("%c", (hex[i] == 1)? 'X' : ' '); + } + printf("]"); + if (error_count == 1) { + printf(" fixed!"); + } else if (error_count ==2) { + printf(" IRRECOVERABLE"); + } + printf("\n"); +#endif +} diff --git a/p25p1_ldu.h b/p25p1_ldu.h new file mode 100644 index 0000000..fa73a19 --- /dev/null +++ b/p25p1_ldu.h @@ -0,0 +1,18 @@ + +#ifndef __P25P1_LDU_H__ +#define __P25P1_LDU_H__ + +#include "dsd.h" +#include "p25p1_const.h" + +// separate imbe frames and deinterleave +void +process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count); + +/** + * Read an hex word, its parity bits and attempts to error correct it using the Hamming algorithm. + */ +void +read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count); + +#endif // __P25P1_LDU_H__ diff --git a/p25p1_ldu1.c b/p25p1_ldu1.c index 859c037..99060d7 100644 --- a/p25p1_ldu1.c +++ b/p25p1_ldu1.c @@ -18,265 +18,139 @@ #include "dsd.h" #include "p25p1_const.h" +#include "p25p1_ldu.h" +#include "p25p1_check_ldu.h" + + + void -processLDU1 (dsd_opts * opts, dsd_state * state) +processLDU1 (dsd_opts* opts, dsd_state* state) { // 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; + int i, j, k, dibit; + char lcformat[9], mfid[9], lcinfo[57]; + char lsd1[9], lsd2[9]; + + int status_count; + + char hex_data[12][6]; // Data in hex-words (6 bit words). A total of 12 hex words. + char hex_parity[12][6]; // Parity of the data, again in hex-word format. A total of 12 parity hex words. + + int irrecoverable_errors; lcformat[8] = 0; mfid[8] = 0; lcinfo[56] = 0; lsd1[8] = 0; lsd2[8] = 0; - status[24] = 0; - // Now processing NID - status[0] = 0; - scount = 1; + // we skip the status dibits that occur every 36 symbols + // the first IMBE frame starts 14 symbols before next status + // so we start counter at 22 + status_count = 21; if (opts->errorbars == 1) { printf ("e:"); } - // separate imbe frames and deinterleave - stats = 21; // we skip the status dibits that occur every 36 symbols - // the first IMBE frame starts 14 symbols before next status - // so we start counter at 22 - for (i = 0; i < 9; i++) - { // 9 IMBE frames per LDU - w = iW; - x = iX; - y = iY; - z = iZ; - for (j = 0; j < 72; j++) - { - if (stats == 35) - { - status[scount] = getDibit (opts, state) + 48; - scount++; - stats = 1; - } - else - { - stats++; - } - dibit = getDibit (opts, state); - imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 - imbe_fr[*y][*z] = (1 & dibit); // bit 0 - w++; - x++; - y++; - z++; - } - if (state->p25kid == 0 || opts->unmute_encrypted_p25 == 1) - { - processMbeFrame (opts, state, imbe_fr, NULL, NULL); - } + // IMBE 1 + process_IMBE (opts, state, &status_count); - // skip over non imbe data sometimes between frames - if ((i < 4) || (i == 8)) - { - k = 0; - } - else if (i == 7) - { - //k=16; - k = 0; - } - else - { - k = 20; - } - for (j = 0; j < k; j++) - { - if (stats == 35) - { - status[scount] = getDibit (opts, state) + 48; - scount++; - stats = 1; - } - else - { - stats++; - } - skipDibit (opts, state, 1); - } + // IMBE 2 + process_IMBE (opts, state, &status_count); - if (i == 1) - { - dibit = getDibit (opts, state); - lcformat[0] = (1 & (dibit >> 1)) + 48; // bit 1 - lcformat[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcformat[2] = (1 & (dibit >> 1)) + 48; // bit 1 - lcformat[3] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcformat[4] = (1 & (dibit >> 1)) + 48; // bit 1 - lcformat[5] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - lcformat[6] = (1 & (dibit >> 1)) + 48; // bit 1 - lcformat[7] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mfid[0] = (1 & (dibit >> 1)) + 48; // bit 1 - mfid[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mfid[2] = (1 & (dibit >> 1)) + 48; // bit 1 - mfid[3] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - status[scount] = getDibit (opts, state) + 48; - scount++; - dibit = getDibit (opts, state); - mfid[4] = (1 & (dibit >> 1)) + 48; // bit 1 - mfid[5] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mfid[6] = (1 & (dibit >> 1)) + 48; // bit 1 - mfid[7] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[0] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[1] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - lcinfo[2] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[3] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[4] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[5] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[6] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[7] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - stats = 10; - } - else if (i == 2) - { - dibit = getDibit (opts, state); - lcinfo[8] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[9] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[10] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[11] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[12] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[13] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - lcinfo[14] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[15] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[16] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[17] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[18] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[19] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - lcinfo[20] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[21] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[22] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[23] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[24] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[25] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - lcinfo[26] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[27] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[28] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[29] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[30] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[31] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - stats = 32; - } - else if (i == 3) - { - dibit = getDibit (opts, state); - lcinfo[32] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[33] = (1 & dibit) + 48; // bit 0 - status[scount] = getDibit (opts, state) + 48; - scount++; - dibit = getDibit (opts, state); - lcinfo[34] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[35] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[36] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[37] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - lcinfo[38] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[39] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[40] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[41] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[42] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[43] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - lcinfo[44] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[45] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[46] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[47] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[48] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[49] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - lcinfo[50] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[51] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[52] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[53] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lcinfo[54] = (1 & (dibit >> 1)) + 48; // bit 1 - lcinfo[55] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - stats = 19; - } - else if (i == 7) - { - dibit = getDibit (opts, state); - lsd1[0] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd1[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd1[2] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd1[3] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd1[4] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd1[5] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd1[6] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd1[7] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 4); - dibit = getDibit (opts, state); - lsd2[0] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd2[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd2[2] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd2[3] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd2[4] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd2[5] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd2[6] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd2[7] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 4); - stats = 33; - } - } - // trailing status symbol - status[scount] = getDibit (opts, state) + 48; - scount++; + // Read data after IMBE 2 + read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 9][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 8][0]), &status_count); + + // IMBE 3 + process_IMBE (opts, state, &status_count); + + // Read data after IMBE 3 + read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 5][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 4][0]), &status_count); + + // IMBE 4 + process_IMBE (opts, state, &status_count); + + // Read data after IMBE 4 + read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 1][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 0][0]), &status_count); + + // IMBE 5 + process_IMBE (opts, state, &status_count); + + // Read data after IMBE 5 + read_and_correct_hex_word (opts, state, &(hex_parity[11][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[10][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 9][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 8][0]), &status_count); + + // IMBE 6 + process_IMBE (opts, state, &status_count); + + // Read data after IMBE 6 + read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 5][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 4][0]), &status_count); + + // IMBE 7 + process_IMBE (opts, state, &status_count); + + // Read data after IMBE 7 + read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 1][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 0][0]), &status_count); + + // IMBE 8 + process_IMBE (opts, state, &status_count); + + // Read data after IMBE 8: LSD (low speed data) + { + char lsd[8]; + char cyclic_parity[8]; + + for (i=0; i<=6; i+=2) + { + read_dibit(opts, state, lsd+i, &status_count); + } + for (i=0; i<=6; i+=2) + { + read_dibit(opts, state, cyclic_parity+i, &status_count); + } + for (i=0; i<8; i++) + { + lsd1[i] = lsd[i] + '0'; + } + + for (i=0; i<=6; i+=2) + { + read_dibit(opts, state, lsd+i, &status_count); + } + for (i=0; i<=6; i+=2) + { + read_dibit(opts, state, cyclic_parity+i, &status_count); + } + for (i=0; i<8; i++) + { + lsd2[i] = lsd[i] + '0'; + } + + // TODO: error correction of the LSD bytes... + // TODO: do something useful with the LSD bytes... + } + + // IMBE 9 + process_IMBE (opts, state, &status_count); if (opts->errorbars == 1) { @@ -285,8 +159,107 @@ processLDU1 (dsd_opts * opts, dsd_state * state) if (opts->p25status == 1) { - printf ("status: %s lsd1: %s lsd2: %s\n", status, lsd1, lsd2); + printf ("lsd1: %s lsd2: %s\n", lsd1, lsd2); } + // trailing status symbol + { + int status; + status = getDibit (opts, state) + 48; + // TODO: do something useful with the status bits... + } + + // Error correct the hex_data using Reed-Solomon hex_parity + irrecoverable_errors = check_and_fix_redsolomon_24_12_13((char*)hex_data, (char*)hex_parity); + if (irrecoverable_errors == 1) { + state->debug_header_critical_errors++; + } + + + // Put the corrected data into the DSD structures + lcformat[0] = hex_data[11][0] + '0'; + lcformat[1] = hex_data[11][1] + '0'; + lcformat[2] = hex_data[11][2] + '0'; + lcformat[3] = hex_data[11][3] + '0'; + lcformat[4] = hex_data[11][4] + '0'; + lcformat[5] = hex_data[11][5] + '0'; + + lcformat[6] = hex_data[10][0] + '0'; + lcformat[7] = hex_data[10][1] + '0'; + mfid[0] = hex_data[10][2] + '0'; + mfid[1] = hex_data[10][3] + '0'; + mfid[2] = hex_data[10][4] + '0'; + mfid[3] = hex_data[10][5] + '0'; + + mfid[4] = hex_data[ 9][0] + '0'; + mfid[5] = hex_data[ 9][1] + '0'; + mfid[6] = hex_data[ 9][2] + '0'; + mfid[7] = hex_data[ 9][3] + '0'; + lcinfo[0] = hex_data[ 9][4] + '0'; + lcinfo[1] = hex_data[ 9][5] + '0'; + + lcinfo[2] = hex_data[ 8][0] + '0'; + lcinfo[3] = hex_data[ 8][1] + '0'; + lcinfo[4] = hex_data[ 8][2] + '0'; + lcinfo[5] = hex_data[ 8][3] + '0'; + lcinfo[6] = hex_data[ 8][4] + '0'; + lcinfo[7] = hex_data[ 8][5] + '0'; + + lcinfo[8] = hex_data[ 7][0] + '0'; + lcinfo[9] = hex_data[ 7][1] + '0'; + lcinfo[10] = hex_data[ 7][2] + '0'; + lcinfo[11] = hex_data[ 7][3] + '0'; + lcinfo[12] = hex_data[ 7][4] + '0'; + lcinfo[13] = hex_data[ 7][5] + '0'; + + lcinfo[14] = hex_data[ 6][0] + '0'; + lcinfo[15] = hex_data[ 6][1] + '0'; + lcinfo[16] = hex_data[ 6][2] + '0'; + lcinfo[17] = hex_data[ 6][3] + '0'; + lcinfo[18] = hex_data[ 6][4] + '0'; + lcinfo[19] = hex_data[ 6][5] + '0'; + + lcinfo[20] = hex_data[ 5][0] + '0'; + lcinfo[21] = hex_data[ 5][1] + '0'; + lcinfo[22] = hex_data[ 5][2] + '0'; + lcinfo[23] = hex_data[ 5][3] + '0'; + lcinfo[24] = hex_data[ 5][4] + '0'; + lcinfo[25] = hex_data[ 5][5] + '0'; + + lcinfo[26] = hex_data[ 4][0] + '0'; + lcinfo[27] = hex_data[ 4][1] + '0'; + lcinfo[28] = hex_data[ 4][2] + '0'; + lcinfo[29] = hex_data[ 4][3] + '0'; + lcinfo[30] = hex_data[ 4][4] + '0'; + lcinfo[31] = hex_data[ 4][5] + '0'; + + lcinfo[32] = hex_data[ 3][0] + '0'; + lcinfo[33] = hex_data[ 3][1] + '0'; + lcinfo[34] = hex_data[ 3][2] + '0'; + lcinfo[35] = hex_data[ 3][3] + '0'; + lcinfo[36] = hex_data[ 3][4] + '0'; + lcinfo[37] = hex_data[ 3][5] + '0'; + + lcinfo[38] = hex_data[ 2][0] + '0'; + lcinfo[39] = hex_data[ 2][1] + '0'; + lcinfo[40] = hex_data[ 2][2] + '0'; + lcinfo[41] = hex_data[ 2][3] + '0'; + lcinfo[42] = hex_data[ 2][4] + '0'; + lcinfo[43] = hex_data[ 2][5] + '0'; + + lcinfo[44] = hex_data[ 1][0] + '0'; + lcinfo[45] = hex_data[ 1][1] + '0'; + lcinfo[46] = hex_data[ 1][2] + '0'; + lcinfo[47] = hex_data[ 1][3] + '0'; + lcinfo[48] = hex_data[ 1][4] + '0'; + lcinfo[49] = hex_data[ 1][5] + '0'; + + lcinfo[50] = hex_data[ 0][0] + '0'; + lcinfo[51] = hex_data[ 0][1] + '0'; + lcinfo[52] = hex_data[ 0][2] + '0'; + lcinfo[53] = hex_data[ 0][3] + '0'; + lcinfo[54] = hex_data[ 0][4] + '0'; + lcinfo[55] = hex_data[ 0][5] + '0'; + processP25lcw (opts, state, lcformat, mfid, lcinfo); } diff --git a/p25p1_ldu2.c b/p25p1_ldu2.c index b1641fe..5b7fe15 100644 --- a/p25p1_ldu2.c +++ b/p25p1_ldu2.c @@ -18,317 +18,140 @@ #include "dsd.h" #include "p25p1_const.h" +#include "p25p1_ldu.h" +#include "p25p1_check_ldu.h" + + + void processLDU2 (dsd_opts * opts, dsd_state * state) { // 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; + int i, j, k, dibit; + char mi[73], algid[9], kid[17]; + char lsd1[9], lsd2[9]; int algidhex, kidhex; - status[24] = 0; + int status_count; + + char hex_data[16][6]; // Data in hex-words (6 bit words). A total of 12 hex words. + char hex_parity[8][6]; // Parity of the data, again in hex-word format. A total of 12 parity hex words. + + int irrecoverable_errors; + mi[72] = 0; algid[8] = 0; kid[16] = 0; - lsd3[8] = 0; - lsd4[8] = 0; + lsd1[8] = 0; + lsd2[8] = 0; - // Now processing NID - status[0] = 0; - scount = 1; + // we skip the status dibits that occur every 36 symbols + // the first IMBE frame starts 14 symbols before next status + // so we start counter at 22 + status_count = 21; if (opts->errorbars == 1) { printf ("e:"); } - // separate imbe frames and deinterleave - stats = 21; - // we skip the status dibits that occur every 36 symbols - // the first IMBE frame starts 14 symbols before next status - // so we start counter at 22 - for (i = 0; i < 9; i++) - { // 9 IMBE frames per LDU - w = iW; - x = iX; - y = iY; - z = iZ; - for (j = 0; j < 72; j++) - { - if (stats == 35) - { - status[scount] = getDibit (opts, state) + 48; - scount++; - stats = 1; - } - else - { - stats++; - } - dibit = getDibit (opts, state); - imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 - imbe_fr[*y][*z] = (1 & dibit); // bit 0 - w++; - x++; - y++; - z++; - } - if (state->p25kid == 0 || opts->unmute_encrypted_p25 == 1) - { - processMbeFrame (opts, state, imbe_fr, NULL, NULL); - } + // IMBE 1 + process_IMBE (opts, state, &status_count); - // skip over non imbe data sometimes between frames - if ((i < 5) || (i == 8)) - { - k = 0; - } - else if (i == 7) - { - //k=16; - k = 0; - } - else - { - k = 20; - } + // IMBE 2 + process_IMBE (opts, state, &status_count); - for (j = 0; j < k; j++) - { - if (stats == 35) - { - status[scount] = getDibit (opts, state) + 48; - scount++; - stats = 1; - } - else - { - stats++; - } - skipDibit (opts, state, 1); - } + // Read data after IMBE 2 + read_and_correct_hex_word (opts, state, &(hex_data[15][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[14][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[13][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[12][0]), &status_count); - if (i == 1) - { - dibit = getDibit (opts, state); - mi[0] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[2] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[3] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[4] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[5] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - mi[6] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[7] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[8] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[9] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[10] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[11] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - status[scount] = getDibit (opts, state) + 48; - scount++; - dibit = getDibit (opts, state); - mi[12] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[13] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[14] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[15] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[16] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[17] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - mi[18] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[19] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[20] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[21] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[22] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[23] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - stats = 10; - } - else if (i == 2) - { - dibit = getDibit (opts, state); - mi[24] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[25] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[26] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[27] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[28] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[29] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - mi[30] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[31] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[32] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[33] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[34] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[35] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - mi[36] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[37] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[38] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[39] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[40] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[41] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - mi[42] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[43] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[44] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[45] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[46] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[47] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - stats = 32; - } - else if (i == 3) - { - dibit = getDibit (opts, state); - mi[48] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[49] = (1 & dibit) + 48; // bit 0 - status[scount] = getDibit (opts, state) + 48; - scount++; - dibit = getDibit (opts, state); - mi[50] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[51] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[52] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[53] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - mi[54] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[55] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[56] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[57] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[58] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[59] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - mi[60] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[61] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[62] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[63] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[64] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[65] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - mi[66] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[67] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[68] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[69] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - mi[70] = (1 & (dibit >> 1)) + 48; // bit 1 - mi[71] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - stats = 19; - } - else if (i == 4) - { - dibit = getDibit (opts, state); - algid[0] = (1 & (dibit >> 1)) + 48; // bit 1 - algid[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - algid[2] = (1 & (dibit >> 1)) + 48; // bit 1 - algid[3] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - algid[4] = (1 & (dibit >> 1)) + 48; // bit 1 - algid[5] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - algid[6] = (1 & (dibit >> 1)) + 48; // bit 1 - algid[7] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - kid[0] = (1 & (dibit >> 1)) + 48; // bit 1 - kid[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - kid[2] = (1 & (dibit >> 1)) + 48; // bit 1 - kid[3] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - dibit = getDibit (opts, state); - kid[4] = (1 & (dibit >> 1)) + 48; // bit 1 - kid[5] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - kid[6] = (1 & (dibit >> 1)) + 48; // bit 1 - kid[7] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - kid[8] = (1 & (dibit >> 1)) + 48; // bit 1 - kid[9] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 1); - status[scount] = getDibit (opts, state) + 48; - scount++; - skipDibit (opts, state, 1); - dibit = getDibit (opts, state); - kid[10] = (1 & (dibit >> 1)) + 48; // bit 1 - kid[11] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - kid[12] = (1 & (dibit >> 1)) + 48; // bit 1 - kid[13] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - kid[14] = (1 & (dibit >> 1)) + 48; // bit 1 - kid[15] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 2); - stats = 6; - } - else if (i == 7) - { - dibit = getDibit (opts, state); - lsd3[0] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd3[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd3[2] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd3[3] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd3[4] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd3[5] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd3[6] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd3[7] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 4); - dibit = getDibit (opts, state); - lsd4[0] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd4[1] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd4[2] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd4[3] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd4[4] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd4[5] = (1 & dibit) + 48; // bit 0 - dibit = getDibit (opts, state); - lsd4[6] = (1 & (dibit >> 1)) + 48; // bit 1 - lsd4[7] = (1 & dibit) + 48; // bit 0 - skipDibit (opts, state, 4); - stats = 33; - } + // IMBE 3 + process_IMBE (opts, state, &status_count); - } + // Read data after IMBE 3 + read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 9][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 8][0]), &status_count); - //trailing status symbol - status[scount] = getDibit (opts, state) + 48; - scount++; + // IMBE 4 + process_IMBE (opts, state, &status_count); + + // Read data after IMBE 4 + read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 5][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 4][0]), &status_count); + + // IMBE 5 + process_IMBE (opts, state, &status_count); + + // Read data after IMBE 5 + read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 1][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_data[ 0][0]), &status_count); + + // IMBE 6 + process_IMBE (opts, state, &status_count); + + // Read data after IMBE 6 + read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 5][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 4][0]), &status_count); + + // IMBE 7 + process_IMBE (opts, state, &status_count); + + // Read data after IMBE 7 + read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 1][0]), &status_count); + read_and_correct_hex_word (opts, state, &(hex_parity[ 0][0]), &status_count); + + // IMBE 8 + process_IMBE (opts, state, &status_count); + + // Read data after IMBE 8: LSD (low speed data) + { + char lsd[8]; + char cyclic_parity[8]; + + for (i=0; i<=6; i+=2) + { + read_dibit(opts, state, lsd+i, &status_count); + } + for (i=0; i<=6; i+=2) + { + read_dibit(opts, state, cyclic_parity+i, &status_count); + } + for (i=0; i<8; i++) + { + lsd1[i] = lsd[i] + '0'; + } + + for (i=0; i<=6; i+=2) + { + read_dibit(opts, state, lsd+i, &status_count); + } + for (i=0; i<=6; i+=2) + { + read_dibit(opts, state, cyclic_parity+i, &status_count); + } + for (i=0; i<8; i++) + { + lsd2[i] = lsd[i] + '0'; + } + + // TODO: error correction of the LSD bytes... + // TODO: do something useful with the LSD bytes... + } + + // IMBE 9 + process_IMBE (opts, state, &status_count); if (opts->errorbars == 1) { @@ -337,8 +160,137 @@ processLDU2 (dsd_opts * opts, dsd_state * state) if (opts->p25status == 1) { - printf ("status: %s lsd3: %s lsd4: %s\n", status, lsd3, lsd4); + printf ("lsd1: %s lsd2: %s\n", lsd1, lsd2); } + + // trailing status symbol + { + int status; + status = getDibit (opts, state) + 48; + // TODO: do something useful with the status bits... + } + + // Error correct the hex_data using Reed-Solomon hex_parity + irrecoverable_errors = check_and_fix_redsolomon_24_16_9((char*)hex_data, (char*)hex_parity); + if (irrecoverable_errors == 1) { + state->debug_header_critical_errors++; + } + + + // Put the corrected data into the DSD structures + mi[ 0] = hex_data[15][0] + '0'; + mi[ 1] = hex_data[15][1] + '0'; + mi[ 2] = hex_data[15][2] + '0'; + mi[ 3] = hex_data[15][3] + '0'; + mi[ 4] = hex_data[15][4] + '0'; + mi[ 5] = hex_data[15][5] + '0'; + + mi[ 6] = hex_data[14][0] + '0'; + mi[ 7] = hex_data[14][1] + '0'; + mi[ 8] = hex_data[14][2] + '0'; + mi[ 9] = hex_data[14][3] + '0'; + mi[10] = hex_data[14][4] + '0'; + mi[11] = hex_data[14][5] + '0'; + + mi[12] = hex_data[13][0] + '0'; + mi[13] = hex_data[13][1] + '0'; + mi[14] = hex_data[13][2] + '0'; + mi[15] = hex_data[13][3] + '0'; + mi[16] = hex_data[13][4] + '0'; + mi[17] = hex_data[13][5] + '0'; + + mi[18] = hex_data[12][0] + '0'; + mi[19] = hex_data[12][1] + '0'; + mi[20] = hex_data[12][2] + '0'; + mi[21] = hex_data[12][3] + '0'; + mi[22] = hex_data[12][4] + '0'; + mi[23] = hex_data[12][5] + '0'; + + mi[24] = hex_data[11][0] + '0'; + mi[25] = hex_data[11][1] + '0'; + mi[26] = hex_data[11][2] + '0'; + mi[27] = hex_data[11][3] + '0'; + mi[28] = hex_data[11][4] + '0'; + mi[29] = hex_data[11][5] + '0'; + + mi[30] = hex_data[10][0] + '0'; + mi[31] = hex_data[10][1] + '0'; + mi[32] = hex_data[10][2] + '0'; + mi[33] = hex_data[10][3] + '0'; + mi[34] = hex_data[10][4] + '0'; + mi[35] = hex_data[10][5] + '0'; + + mi[36] = hex_data[ 9][0] + '0'; + mi[37] = hex_data[ 9][1] + '0'; + mi[38] = hex_data[ 9][2] + '0'; + mi[39] = hex_data[ 9][3] + '0'; + mi[40] = hex_data[ 9][4] + '0'; + mi[41] = hex_data[ 9][5] + '0'; + + mi[42] = hex_data[ 8][0] + '0'; + mi[43] = hex_data[ 8][1] + '0'; + mi[44] = hex_data[ 8][2] + '0'; + mi[45] = hex_data[ 8][3] + '0'; + mi[46] = hex_data[ 8][4] + '0'; + mi[47] = hex_data[ 8][5] + '0'; + + mi[48] = hex_data[ 7][0] + '0'; + mi[49] = hex_data[ 7][1] + '0'; + mi[50] = hex_data[ 7][2] + '0'; + mi[51] = hex_data[ 7][3] + '0'; + mi[52] = hex_data[ 7][4] + '0'; + mi[53] = hex_data[ 7][5] + '0'; + + mi[54] = hex_data[ 6][0] + '0'; + mi[55] = hex_data[ 6][1] + '0'; + mi[56] = hex_data[ 6][2] + '0'; + mi[57] = hex_data[ 6][3] + '0'; + mi[58] = hex_data[ 6][4] + '0'; + mi[59] = hex_data[ 6][5] + '0'; + + mi[60] = hex_data[ 5][0] + '0'; + mi[61] = hex_data[ 5][1] + '0'; + mi[62] = hex_data[ 5][2] + '0'; + mi[63] = hex_data[ 5][3] + '0'; + mi[64] = hex_data[ 5][4] + '0'; + mi[65] = hex_data[ 5][5] + '0'; + + mi[66] = hex_data[ 4][0] + '0'; + mi[67] = hex_data[ 4][1] + '0'; + mi[68] = hex_data[ 4][2] + '0'; + mi[69] = hex_data[ 4][3] + '0'; + mi[70] = hex_data[ 4][4] + '0'; + mi[71] = hex_data[ 4][5] + '0'; + + algid[0] = hex_data[ 3][0] + '0'; + algid[1] = hex_data[ 3][1] + '0'; + algid[2] = hex_data[ 3][2] + '0'; + algid[3] = hex_data[ 3][3] + '0'; + algid[4] = hex_data[ 3][4] + '0'; + algid[5] = hex_data[ 3][5] + '0'; + + algid[6] = hex_data[ 2][0] + '0'; + algid[7] = hex_data[ 2][1] + '0'; + kid[0] = hex_data[ 2][2] + '0'; + kid[1] = hex_data[ 2][3] + '0'; + kid[2] = hex_data[ 2][4] + '0'; + kid[3] = hex_data[ 2][5] + '0'; + + kid[4] = hex_data[ 1][0] + '0'; + kid[5] = hex_data[ 1][1] + '0'; + kid[6] = hex_data[ 1][2] + '0'; + kid[7] = hex_data[ 1][3] + '0'; + kid[8] = hex_data[ 1][4] + '0'; + kid[9] = hex_data[ 1][5] + '0'; + + kid[10] = hex_data[ 0][0] + '0'; + kid[11] = hex_data[ 0][1] + '0'; + kid[12] = hex_data[ 0][2] + '0'; + kid[13] = hex_data[ 0][3] + '0'; + kid[14] = hex_data[ 0][4] + '0'; + kid[15] = hex_data[ 0][5] + '0'; + + if (opts->p25enc == 1) { algidhex = strtol (algid, NULL, 2); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5073575..8889006 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,12 +3,13 @@ project(dsdtest) add_subdirectory(gtest) add_subdirectory(gmock) -FILE(GLOB SRCS *.cpp) +FILE(GLOB SRCS *.cpp ${dsdtest_SOURCE_DIR}/../Hamming.cpp) include_directories( ${PROJECT_SOURCE_DIR}/gtest/include ${PROJECT_SOURCE_DIR}/gmock/include - ${dsd_SOURCE_DIR} + ${dsdtest_SOURCE_DIR} + ${dsdtest_SOURCE_DIR}/.. ) add_custom_target(test diff --git a/test/golay24-test.cpp b/test/golay24-test.cpp index d49c3b1..14950de 100644 --- a/test/golay24-test.cpp +++ b/test/golay24-test.cpp @@ -1,5 +1,10 @@ +/** + * Unit tests for the Golay24 implementation. + */ + #include "gtest/gtest.h" #include "gmock/gmock.h" + #include "Golay24.hpp" class Golay24Test : public testing::Test diff --git a/test/hamming-test.cpp b/test/hamming-test.cpp new file mode 100644 index 0000000..c842c76 --- /dev/null +++ b/test/hamming-test.cpp @@ -0,0 +1,251 @@ + +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include +#include + +#include "Hamming.hpp" + +class HammingTest : public testing::Test +{ +protected: + + static void print_debug(int value, int fixed, int error_count) + { + std::cout << std::bitset<10>(value) << ": "; + switch (error_count) { + case 0: + std::cout << "OK"; + break; + case 1: + std::cout << "one error detected, hopefully fixed: " << std::bitset<6>(fixed); + break; + case 2: + std::cout << "irrecoverable :("; + break; + default: + break; + } + std::cout << std::endl; + } + + static void check_hamming(int v, int expected_v, int expected_errors) + { + Hamming_10_6_3 hamming; + Hamming_10_6_3_TableImpl hamming_table; + + int output_1; + int output_2; + int error_count_1 = hamming.decode(v, &output_1); + int error_count_2 = hamming_table.decode(v, &output_2); + + //print_debug(v, output_1, error_count_1); + + if (expected_errors != -1) { + EXPECT_THAT(expected_errors, error_count_1); + } + EXPECT_THAT(error_count_1, error_count_2); + + if (expected_v != -1) { + EXPECT_THAT(expected_v, output_1); + } + EXPECT_THAT(output_1, output_2); + } + + static void check_hamming(Hamming_Inteface* hamming, char* hex, char* parity, int expected_errors, char* expected) + { + int value = Hamming_10_6_3_TableImpl::convert_hex_parity_to_int(hex, parity); + int error_count = hamming->decode(hex, parity); + int fixed = Hamming_10_6_3_TableImpl::convert_hex_to_int(hex); + + //print_debug(value, fixed, error_count); + + EXPECT_THAT(expected_errors, error_count); + for (unsigned int i=0; i<6; i++) { + EXPECT_THAT(expected[i], hex[i]); + } + } + +}; + +TEST_F(HammingTest, Test1) +{ + // OK + std::bitset<10> value(std::string("1010100110")); + std::bitset< 6> expected(std::string("101010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 0); +} + +TEST_F(HammingTest, Test2) +{ + // Error on parity bit 0 (9 is the left-most and 0 is the right-most) + std::bitset<10> value(std::string("1010100111")); + std::bitset< 6> expected(std::string("101010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); +} + +TEST_F(HammingTest, Test3) +{ + // Error on parity bit 1 (9 is the left-most and 0 is the right-most) + std::bitset<10> value(std::string("1010100100")); + std::bitset< 6> expected(std::string("101010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); +} + +TEST_F(HammingTest, Test4) +{ + // Error on parity bit 2 (9 is the left-most and 0 is the right-most) + std::bitset<10> value(std::string("1010100010")); + std::bitset< 6> expected(std::string("101010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); +} + +TEST_F(HammingTest, Test5) +{ + // Error on parity bit 3 (9 is the left-most and 0 is the right-most) + std::bitset<10> value(std::string("1010101110")); + std::bitset< 6> expected(std::string("101010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); +} + +TEST_F(HammingTest, Test6) +{ + // Error on bit 4 (9 is the left-most and 0 is the right-most) + std::bitset<10> value(std::string("1010110110")); + std::bitset< 6> expected(std::string("101010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); +} + +TEST_F(HammingTest, Test7) +{ + // Error on bit 5 (9 is the left-most and 0 is the right-most) + std::bitset<10> value(std::string("1010000110")); + std::bitset< 6> expected(std::string("101010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); +} + +TEST_F(HammingTest, Test8) +{ + // Error on bit 6 (9 is the left-most and 0 is the right-most) + std::bitset<10> value(std::string("1011100110")); + std::bitset< 6> expected(std::string("101010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); +} + +TEST_F(HammingTest, Test9) +{ + // Error on bit 7 (9 is the left-most and 0 is the right-most) + std::bitset<10> value(std::string("1000100110")); + std::bitset< 6> expected(std::string("101010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); +} + +TEST_F(HammingTest, Test10) +{ + // Error on bit 8 (9 is the left-most and 0 is the right-most) + std::bitset<10> value(std::string("1110100110")); + std::bitset< 6> expected(std::string("101010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); +} + +TEST_F(HammingTest, Test11) +{ + // Error on bit 9 (9 is the left-most and 0 is the right-most) + std::bitset<10> value(std::string("0010100110")); + std::bitset< 6> expected(std::string("101010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); +} + +TEST_F(HammingTest, Test12) +{ + // Two errors + std::bitset<10> value(std::string("0010100111")); + std::bitset< 6> expected(std::string("001010")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 2); +} + +TEST_F(HammingTest, Test13) +{ + // Two errors, in this case they go undetected, thinks it's a parity error + std::bitset<10> value(std::string("1011000110")); + std::bitset< 6> expected(std::string("101100")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1); +} + +TEST_F(HammingTest, Test14) +{ + // OK + std::bitset<10> value(std::string("0001000111")); + std::bitset< 6> expected(std::string("000100")); + check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 0); +} + +TEST_F(HammingTest, TestEveryValue) +{ + // Test every posible value + for (int v=0; v<1023; v++) { + check_hamming(v, -1, -1); + } +} + +TEST_F(HammingTest, Test_hex_parity_interface_no_errors) +{ + char hex [6] = {1,1,1,0,1,0}; + char fixed [6] = {1,1,1,0,1,0}; + char parity[4] = {1,0,1,1}; + + Hamming_10_6_3 hamming; + check_hamming(&hamming, hex, parity, 0, fixed); + + Hamming_10_6_3_TableImpl hamming_table; + check_hamming(&hamming_table, hex, parity, 0, fixed); +} + +TEST_F(HammingTest, Test_hex_parity_interface_one_error_1) +{ + char hex_1 [6] = {1,1,1,1,1,0}; + char hex_2 [6] = {1,1,1,1,1,0}; + char fixed [6] = {1,1,1,0,1,0}; + char parity[4] = {1,0,1,1}; + + Hamming_10_6_3 hamming; + check_hamming(&hamming, hex_1, parity, 1, fixed); + // hex is modified in place + + Hamming_10_6_3_TableImpl hamming_table; + check_hamming(&hamming_table, hex_2, parity, 1, fixed); + // hex is modified in place +} + +TEST_F(HammingTest, Test_hex_parity_interface_one_error_2) +{ + char hex_1 [6] = {1,1,1,1,1,0}; + char hex_2 [6] = {1,1,1,1,1,0}; + char fixed [6] = {1,1,1,1,1,1}; + char parity[4] = {0,0,0,0}; + + Hamming_10_6_3 hamming; + check_hamming(&hamming, hex_1, parity, 1, fixed); + // hex is modified in place + + Hamming_10_6_3_TableImpl hamming_table; + check_hamming(&hamming_table, hex_2, parity, 1, fixed); + // hex is modified in place +} + +TEST_F(HammingTest, Test_hex_parity_interface_one_error_3) +{ + char hex_1 [6] = {1,0,0,0,0,0}; + char hex_2 [6] = {1,0,0,0,0,0}; + char fixed [6] = {0,0,0,0,0,0}; + char parity[4] = {0,0,0,0}; + + Hamming_10_6_3 hamming; + check_hamming(&hamming, hex_1, parity, 1, fixed); + // hex is modified in place + + Hamming_10_6_3_TableImpl hamming_table; + check_hamming(&hamming_table, hex_2, parity, 1, fixed); + // hex is modified in place +} diff --git a/test/reedsolomon-test.cpp b/test/reedsolomon-test.cpp index 343044a..3bf6786 100644 --- a/test/reedsolomon-test.cpp +++ b/test/reedsolomon-test.cpp @@ -1,7 +1,22 @@ +/** + * Unit tests for the Reed-Solomon implementation. + */ + #include "gtest/gtest.h" #include "gmock/gmock.h" + #include "ReedSolomon.hpp" +static void byte_to_binary(char* b, int x) +{ + int z, i; + + for (z = 32, i=0; z > 0; z >>= 1, i++) { + b[i] = ((x & z) != 0) ? 'X' : ' '; + } + b[6] = 0; +} + TEST(ReedSolomonTest, Test1) { ReedSolomon_63_47_17 rs; @@ -10,25 +25,29 @@ TEST(ReedSolomonTest, Test1) int output[63]; // send this message - recd[16+0] = 1; - recd[16+6] = 8; - recd[ 0] = 8+4; recd[ 1] = 3; recd[ 2] = 8+2; recd[ 3] = 16+1; recd[ 4] = 16+2; - recd[ 5] = 32+8+3; + recd[ 5] = 32+8+3; // error recd[ 6] = 4; recd[ 7] = 32+2; - recd[ 8] = 32+2; + recd[ 8] = 32+2; // error recd[ 9] = 32+16+8+1; recd[10] = 32+16+1; recd[11] = 32+16+3; - recd[12] = 16+8; - recd[13] = 32+2; + recd[12] = 16+8; // error + recd[13] = 32+2; // error recd[14] = 16+4; recd[15] = 16+4+3; + recd[16+0] = 1; + recd[16+1] = 0; + recd[16+2] = 0; + recd[16+3] = 0; + recd[16+4] = 0; + recd[16+5] = 0; + recd[16+6] = 8; // expect this message expected[ 0] = 8+4; @@ -47,11 +66,27 @@ TEST(ReedSolomonTest, Test1) expected[13] = 32+8+2; expected[14] = 16+4; expected[15] = 16+4+3; - expected[16] = 1; - expected[22] = 8; + expected[16+0] = 1; + expected[16+1] = 0; + expected[16+2] = 0; + expected[16+3] = 0; + expected[16+4] = 0; + expected[16+5] = 0; + expected[16+6] = 8; rs.decode(recd, output); /* recd[] is returned in polynomial form */ + /* + printf("Results for Reed-Solomon code (n=%3d, k=%3d, t= %3d)\n\n", nn, kk, tt); + printf(" i recd[i](decoded)\n"); + for (int i = 0; i < nn; i++) { + char b[9]; + byte_to_binary(b, output[i]); + printf("%3d [%s]\n", i, b); + } + printf("\n"); + */ + EXPECT_THAT(expected, testing::ElementsAreArray(output, 63)); }