mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-12 16:57:23 -05:00
Merge pull request #23 from EdFuentetaja/master
Error correction on the metadata fields of P25 LDU1 and LDU2
This commit is contained in:
62
Hamming.cpp
Normal file
62
Hamming.cpp
Normal 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
264
Hamming.hpp
Normal 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__
|
||||
221
ReedSolomon.hpp
221
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
14
dsd_frame.c
14
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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
110
p25p1_check_ldu.cpp
Normal 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
30
p25p1_check_ldu.h
Normal 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__
|
||||
30
p25p1_hdu.c
30
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
|
||||
{
|
||||
|
||||
15
p25p1_hdu.h
Normal file
15
p25p1_hdu.h
Normal 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
107
p25p1_ldu.c
Normal 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
18
p25p1_ldu.h
Normal 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__
|
||||
457
p25p1_ldu1.c
457
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);
|
||||
}
|
||||
|
||||
534
p25p1_ldu2.c
534
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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
251
test/hamming-test.cpp
Normal 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
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user