Merge pull request #23 from EdFuentetaja/master

Error correction on the metadata fields of P25 LDU1 and LDU2
This commit is contained in:
Jared Szechy
2014-04-22 19:23:07 -04:00
18 changed files with 1609 additions and 620 deletions

62
Hamming.cpp Normal file
View File

@@ -0,0 +1,62 @@
#include <Hamming.hpp>
// 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];
}

264
Hamming.hpp Normal file
View File

@@ -0,0 +1,264 @@
#ifndef __HAMMING_HPP__
#define __HAMMING_HPP__
#include <bitset>
#include <string>
#include <assert.h>
#include <iostream>
/**
* \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__

View File

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

View File

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

View File

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

View File

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

110
p25p1_check_ldu.cpp Normal file
View File

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

30
p25p1_check_ldu.h Normal file
View File

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

View File

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

15
p25p1_hdu.h Normal file
View File

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

107
p25p1_ldu.c Normal file
View File

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

18
p25p1_ldu.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

251
test/hamming-test.cpp Normal file
View File

@@ -0,0 +1,251 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include <iostream>
#include <bitset>
#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
}

View File

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