mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-14 09:47:30 -05:00
Some much needed organization
This commit is contained in:
412
include/Golay24.hpp
Normal file
412
include/Golay24.hpp
Normal file
@@ -0,0 +1,412 @@
|
||||
|
||||
#ifndef GOLAY24_HPP_7a68240afda9406facf81fcad3851111
|
||||
#define GOLAY24_HPP_7a68240afda9406facf81fcad3851111
|
||||
|
||||
/**
|
||||
* Based on the work of Mr Hank Wallace.
|
||||
*
|
||||
* Code adapted from http://www.aqdi.com/golay.htm
|
||||
*
|
||||
* Tried before with the implementation from ITPP library but couldn't make it produce the same outputs
|
||||
* expected from the P25 transmissions that I have tested. This implementation does work.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define POLY 0xAE3
|
||||
|
||||
class Golay24
|
||||
{
|
||||
private:
|
||||
unsigned int golay(unsigned int cw)
|
||||
/* This function calculates [23,12] Golay codewords.
|
||||
The format of the returned int is
|
||||
[checkbits(11),data(12)]. */
|
||||
{
|
||||
int i;
|
||||
unsigned int c;
|
||||
cw&=0xfffl;
|
||||
c=cw; /* save original codeword */
|
||||
for (i=1; i<=12; i++) /* examine each data bit */
|
||||
{
|
||||
if (cw & 1) /* test data bit */
|
||||
cw^=POLY; /* XOR polynomial */
|
||||
cw>>=1; /* shift intermediate result */
|
||||
}
|
||||
return((cw<<12)|c); /* assemble codeword */
|
||||
}
|
||||
|
||||
int parity(unsigned int cw)
|
||||
/* This function checks the overall parity of codeword cw.
|
||||
If parity is even, 0 is returned, else 1. */
|
||||
{
|
||||
unsigned char p;
|
||||
|
||||
/* XOR the bytes of the codeword */
|
||||
p=*(unsigned char*)&cw;
|
||||
p^=*((unsigned char*)&cw+1);
|
||||
p^=*((unsigned char*)&cw+2);
|
||||
|
||||
/* XOR the halves of the intermediate result */
|
||||
p=p ^ (p>>4);
|
||||
p=p ^ (p>>2);
|
||||
p=p ^ (p>>1);
|
||||
|
||||
/* return the parity result */
|
||||
return(p & 1);
|
||||
}
|
||||
|
||||
unsigned int syndrome(unsigned int cw)
|
||||
/* This function calculates and returns the syndrome
|
||||
of a [23,12] Golay codeword. */
|
||||
{
|
||||
int i;
|
||||
cw&=0x7fffffl;
|
||||
for (i=1; i<=12; i++) /* examine each data bit */
|
||||
{
|
||||
if (cw & 1) /* test data bit */
|
||||
cw^=POLY; /* XOR polynomial */
|
||||
cw>>=1; /* shift intermediate result */
|
||||
}
|
||||
return(cw<<12); /* value pairs with upper bits of cw */
|
||||
}
|
||||
|
||||
int weight(unsigned int cw)
|
||||
/* This function calculates the weight of
|
||||
23 bit codeword cw. */
|
||||
{
|
||||
int bits,k;
|
||||
|
||||
/* nibble weight table */
|
||||
const char wgt[16] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
|
||||
|
||||
bits=0; /* bit counter */
|
||||
k=0;
|
||||
/* do all bits, six nibbles max */
|
||||
while ((k<6) && (cw))
|
||||
{
|
||||
bits=bits+wgt[cw & 0xf];
|
||||
cw>>=4;
|
||||
k++;
|
||||
}
|
||||
|
||||
return(bits);
|
||||
}
|
||||
|
||||
unsigned int rotate_left(unsigned int cw, int n)
|
||||
/* This function rotates 23 bit codeword cw left by n bits. */
|
||||
{
|
||||
int i;
|
||||
|
||||
if (n != 0)
|
||||
{
|
||||
for (i=1; i<=n; i++)
|
||||
{
|
||||
if ((cw & 0x400000l) != 0)
|
||||
cw=(cw << 1) | 1;
|
||||
else
|
||||
cw<<=1;
|
||||
}
|
||||
}
|
||||
|
||||
return(cw & 0x7fffffl);
|
||||
}
|
||||
|
||||
unsigned int rotate_right(unsigned int cw, int n)
|
||||
/* This function rotates 23 bit codeword cw right by n bits. */
|
||||
{
|
||||
int i;
|
||||
|
||||
if (n != 0)
|
||||
{
|
||||
for (i=1; i<=n; i++)
|
||||
{
|
||||
if ((cw & 1) != 0)
|
||||
cw=(cw >> 1) | 0x400000l;
|
||||
else
|
||||
cw>>=1;
|
||||
}
|
||||
}
|
||||
|
||||
return(cw & 0x7fffffl);
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned int correct(unsigned int cw, int *errs, unsigned int *errors_detected)
|
||||
/* This function corrects Golay [23,12] codeword cw, returning the
|
||||
corrected codeword. This function will produce the corrected codeword
|
||||
for three or fewer errors. It will produce some other valid Golay
|
||||
codeword for four or more errors, possibly not the intended
|
||||
one. *errs is set to the number of bit errors corrected. */
|
||||
{
|
||||
unsigned char
|
||||
w; /* current syndrome limit weight, 2 or 3 */
|
||||
unsigned int
|
||||
mask; /* mask for bit flipping */
|
||||
int
|
||||
i,j; /* index */
|
||||
unsigned int
|
||||
s, /* calculated syndrome */
|
||||
cwsaver; /* saves initial value of cw */
|
||||
|
||||
cwsaver=cw; /* save */
|
||||
*errs=0;
|
||||
*errors_detected = 0;
|
||||
|
||||
w=3; /* initial syndrome weight threshold */
|
||||
j=-1; /* -1 = no trial bit flipping on first pass */
|
||||
mask=1;
|
||||
while (j<23) /* flip each trial bit */
|
||||
{
|
||||
if (j != -1) /* toggle a trial bit */
|
||||
{
|
||||
if (j>0) /* restore last trial bit */
|
||||
{
|
||||
cw=cwsaver ^ mask;
|
||||
mask+=mask; /* point to next bit */
|
||||
}
|
||||
cw=cwsaver ^ mask; /* flip next trial bit */
|
||||
w=2; /* lower the threshold while bit diddling */
|
||||
}
|
||||
|
||||
s=syndrome(cw); /* look for errors */
|
||||
if (s) /* errors exist */
|
||||
{
|
||||
(*errors_detected)++;
|
||||
for (i=0; i<23; i++) /* check syndrome of each cyclic shift */
|
||||
{
|
||||
if ((*errs=weight(s)) <= w) /* syndrome matches error pattern */
|
||||
{
|
||||
cw=cw ^ s; /* remove errors */
|
||||
cw=rotate_right(cw,i); /* unrotate data */
|
||||
return(s=cw);
|
||||
}
|
||||
else
|
||||
{
|
||||
cw=rotate_left(cw,1); /* rotate to next pattern */
|
||||
s=syndrome(cw); /* calc new syndrome */
|
||||
}
|
||||
}
|
||||
j++; /* toggle next trial bit */
|
||||
}
|
||||
else
|
||||
{
|
||||
return(cw); /* return corrected codeword */
|
||||
}
|
||||
}
|
||||
|
||||
return(cwsaver); /* return original if no corrections */
|
||||
} /* correct */
|
||||
|
||||
unsigned int encode(unsigned int data)
|
||||
{
|
||||
unsigned int codeword =golay(data); /* make a test codeword */
|
||||
if (parity(codeword)) {
|
||||
codeword^=0x800000l;
|
||||
}
|
||||
|
||||
return codeword;
|
||||
}
|
||||
|
||||
unsigned int encode23(unsigned int data)
|
||||
{
|
||||
return golay(data); /* make a test codeword */
|
||||
}
|
||||
|
||||
int decode(int *errs, unsigned int *cw)
|
||||
/* This function decodes codeword *cw. Here error correction is attempted,
|
||||
with *errs set to the number of
|
||||
bits corrected, and returning 0 if no errors exist, or 1 if parity errors
|
||||
exist. */
|
||||
{
|
||||
unsigned int parity_bit;
|
||||
unsigned int detected_errors;
|
||||
parity_bit=*cw & 0x800000l; /* save parity bit */
|
||||
*cw&=~0x800000l; /* remove parity bit for correction */
|
||||
|
||||
*cw=correct(*cw, errs, &detected_errors); /* correct up to three bits */
|
||||
*cw|=parity_bit; /* restore parity bit */
|
||||
|
||||
/* check for 4 bit errors */
|
||||
if (parity(*cw)) /* odd parity is an error */
|
||||
return(1);
|
||||
|
||||
return(0); /* no errors */
|
||||
} /* decode */
|
||||
|
||||
int detect(int *errs, unsigned int cw)
|
||||
/* This function decodes codeword cw. Here error detection is performed on cw,
|
||||
returning 0 if no errors exist, 1 if an overall parity error exists, and
|
||||
2 if a codeword error exists. */
|
||||
{
|
||||
*errs=0;
|
||||
if (parity(cw)) /* odd parity is an error */
|
||||
{
|
||||
*errs=1;
|
||||
return(1);
|
||||
}
|
||||
if (syndrome(cw))
|
||||
{
|
||||
*errs=1;
|
||||
return(2);
|
||||
}
|
||||
else
|
||||
return(0); /* no errors */
|
||||
|
||||
} /* decode */
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience class that adapts Mr Wallace's implementation to the input/output format of DSD.
|
||||
* DSD works with data stored in char arrays where each element represents a bit (0 and 1 values).
|
||||
* The original implementation works with codewords that pack the 24 bits of information (12 data and
|
||||
* another 12 of parity) in an integer.
|
||||
*/
|
||||
class DSDGolay24 : public Golay24
|
||||
{
|
||||
public:
|
||||
unsigned int adapt_to_codeword(const char* word, unsigned int length, const char* parity)
|
||||
{
|
||||
unsigned int codeword = 0;
|
||||
|
||||
// Data needs to be packed with the 12 bits of parity as the most significant
|
||||
// bits and 12 bits of data as the less significant. All these discovered by trial and error.
|
||||
for (unsigned int i=0; i<12; i++) {
|
||||
assert(parity[11-i] == 0 || parity[11-i] == 1);
|
||||
codeword <<= 1;
|
||||
codeword |= parity[11-i];
|
||||
}
|
||||
for (unsigned int i=0; i<length; i++) {
|
||||
char bit = word[length-1-i];
|
||||
assert(bit == 0 || bit == 1);
|
||||
codeword <<= 1;
|
||||
codeword |= bit;
|
||||
}
|
||||
// We only have length bits of data. We fill up the less significant bits of codeword with zeros.
|
||||
if (length < 12) {
|
||||
codeword <<= (12 - length);
|
||||
}
|
||||
|
||||
return codeword;
|
||||
}
|
||||
|
||||
void adapt_to_word(unsigned int codeword, char* word, unsigned int length)
|
||||
{
|
||||
// put back in word the bits from codeword
|
||||
for (unsigned int i=0, mask = 1<<(12-length); i<length; i++, mask<<=1) {
|
||||
word[i] = (codeword & mask) != 0? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int adapt_from_word(char* word, unsigned int length)
|
||||
{
|
||||
unsigned int codeword = 0;
|
||||
|
||||
// encode the hex bits into a codeword
|
||||
for (unsigned int i=0; i<length; i++) {
|
||||
int bit = word[length-1-i];
|
||||
assert(bit == 0 || bit == 1);
|
||||
codeword <<= 1;
|
||||
codeword |= bit;
|
||||
}
|
||||
|
||||
// We only have length bits of data. We fill up the less significant bits of codeword with zeros.
|
||||
if (length < 12) {
|
||||
codeword <<= (12-length);
|
||||
}
|
||||
|
||||
return codeword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Important method that takes an hex word, a 12 bit parity word and uses the Golay24 implementation
|
||||
* to error correct it.
|
||||
* \param hex The data to error correct, packed in an array of 6 chars, representing a bit each.
|
||||
* \param parity The 12 bits of parity packed in an array of chars.
|
||||
* \param fixed_errors Output argument, returns the number of errors detected and fixed.
|
||||
* \return 1 if we were unable to correct the hex word. Too many errors detected.
|
||||
* in this case the original data remains unchanged.
|
||||
* 0 if the data was successfully error corrected.
|
||||
*/
|
||||
int decode_6(char* hex, const char* parity, int* fixed_errors)
|
||||
{
|
||||
unsigned int codeword = adapt_to_codeword(hex, 6, parity);
|
||||
// codeword now contains:
|
||||
// bits 0- 5: zeros
|
||||
// bits 6-11: hex bits
|
||||
// bits 12-23: golay (24,12) parity bits
|
||||
|
||||
// bits are ordered from left to right, so bit 0 is the most significant and bit 23 is the less.
|
||||
|
||||
int uncorrectable_errors = Golay24::decode(fixed_errors, &codeword);
|
||||
|
||||
// codeword is now hopefully fixed
|
||||
|
||||
// If there are uncorrectable errors and the fixed proposal includes ones
|
||||
// in bits 0-5 then probably the fix is not good and we discard it.
|
||||
// Bits 0-5 should always be zero, if there is a problem it's on the other bits
|
||||
// from 6 to 24.
|
||||
if (uncorrectable_errors == 1 && (codeword & 0x3f) != 0) {
|
||||
// discard, don't touch hex
|
||||
} else {
|
||||
// put it back into our hex format
|
||||
adapt_to_word(codeword, hex, 6);
|
||||
uncorrectable_errors = 0;
|
||||
}
|
||||
|
||||
return uncorrectable_errors;
|
||||
}
|
||||
|
||||
int decode_12(char* dodeca, const char* parity, int* fixed_errors)
|
||||
{
|
||||
unsigned int codeword = adapt_to_codeword(dodeca, 12, parity);
|
||||
// codeword contains:
|
||||
// bits 0-11: dodeca bits
|
||||
// bits 12-23: golay (24,12) parity bits
|
||||
|
||||
// bits are ordered from left to right, so bit 0 is the most significant and bit 23 is the less.
|
||||
|
||||
int uncorrectable_errors = Golay24::decode(fixed_errors, &codeword);
|
||||
|
||||
// codeword is now hopefully fixed
|
||||
|
||||
// If there are uncorrectable errors and the fixed proposal includes ones
|
||||
// in bits 0-5 then probably the fix is not good and we discard it.
|
||||
// Bits 0-5 should always be zero, if there is a problem it's on the other bits
|
||||
// from 6 to 24.
|
||||
if (uncorrectable_errors == 1 && (codeword & 0x3f) != 0) {
|
||||
// discard, don't touch hex
|
||||
} else {
|
||||
// put it back into our hex format
|
||||
adapt_to_word(codeword, dodeca, 12);
|
||||
uncorrectable_errors = 0;
|
||||
}
|
||||
|
||||
return uncorrectable_errors;
|
||||
}
|
||||
|
||||
void encode_6(char* hex, char* out_parity)
|
||||
{
|
||||
unsigned int data = adapt_from_word(hex, 6);
|
||||
unsigned int codeword = Golay24::encode(data);
|
||||
|
||||
// Fill up the parity
|
||||
for (unsigned int i=0, mask = 1<<12; i<12; i++, mask<<=1) {
|
||||
out_parity[i] = (codeword & mask) != 0? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void encode_12(char* dodeca, char* out_parity)
|
||||
{
|
||||
unsigned int data = adapt_from_word(dodeca, 12);
|
||||
unsigned int codeword = Golay24::encode(data);
|
||||
|
||||
// Fill up the parity
|
||||
for (unsigned int i=0, mask = 1<<12; i<12; i++, mask<<=1) {
|
||||
out_parity[i] = (codeword & mask) != 0? 1 : 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // GOLAY24_HPP_7a68240afda9406facf81fcad3851111
|
||||
413
include/Hamming.hpp
Normal file
413
include/Hamming.hpp
Normal file
@@ -0,0 +1,413 @@
|
||||
|
||||
#ifndef HAMMING_HPP_e7123c3795b94d14b5774d5d8f016a04
|
||||
#define HAMMING_HPP_e7123c3795b94d14b5774d5d8f016a04
|
||||
|
||||
#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<6> gt0;
|
||||
std::bitset<6> gt1;
|
||||
std::bitset<6> gt2;
|
||||
std::bitset<6> gt3;
|
||||
|
||||
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"));
|
||||
|
||||
gt0 = std::bitset<6>(std::string("111001"));
|
||||
gt1 = std::bitset<6>(std::string("110101"));
|
||||
gt2 = std::bitset<6>(std::string("101110"));
|
||||
gt3 = std::bitset<6>(std::string("011110"));
|
||||
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
|
||||
class Hamming_15_11_3_data
|
||||
{
|
||||
public:
|
||||
std::bitset<15> g0;
|
||||
std::bitset<15> g1;
|
||||
std::bitset<15> g2;
|
||||
std::bitset<15> g3;
|
||||
std::bitset<15> g4;
|
||||
std::bitset<15> g5;
|
||||
std::bitset<15> g6;
|
||||
std::bitset<15> g7;
|
||||
std::bitset<15> g8;
|
||||
std::bitset<15> g9;
|
||||
std::bitset<15> g10;
|
||||
|
||||
|
||||
std::bitset<11> gt0;
|
||||
std::bitset<11> gt1;
|
||||
std::bitset<11> gt2;
|
||||
std::bitset<11> gt3;
|
||||
|
||||
std::bitset<15> h0;
|
||||
std::bitset<15> h1;
|
||||
std::bitset<15> h2;
|
||||
std::bitset<15> h3;
|
||||
|
||||
int bad_bit_table[16];
|
||||
|
||||
Hamming_15_11_3_data()
|
||||
{
|
||||
// G matrix come from the APCO 25 reference documentation:
|
||||
g0 = std::bitset<15>(std::string("100000000001111"));
|
||||
g1 = std::bitset<15>(std::string("010000000001110"));
|
||||
g2 = std::bitset<15>(std::string("001000000001101"));
|
||||
g3 = std::bitset<15>(std::string("000100000001100"));
|
||||
g4 = std::bitset<15>(std::string("000010000001011"));
|
||||
g5 = std::bitset<15>(std::string("000001000001010"));
|
||||
g6 = std::bitset<15>(std::string("000000100001001"));
|
||||
g7 = std::bitset<15>(std::string("000000010000111"));
|
||||
g8 = std::bitset<15>(std::string("000000001000110"));
|
||||
g9 = std::bitset<15>(std::string("000000000100101"));
|
||||
g10 = std::bitset<15>(std::string("000000000010011"));
|
||||
|
||||
gt0 = std::bitset<11>(std::string("11111110000"));
|
||||
gt1 = std::bitset<11>(std::string("11110001110"));
|
||||
gt2 = std::bitset<11>(std::string("11001101101"));
|
||||
gt3 = std::bitset<11>(std::string("10101011011"));
|
||||
|
||||
// H matrix, calculated transposing G. See wikipedia.
|
||||
h0 = std::bitset<15>(std::string("111111100001000"));
|
||||
h1 = std::bitset<15>(std::string("111100011100100"));
|
||||
h2 = std::bitset<15>(std::string("110011011010010"));
|
||||
h3 = std::bitset<15>(std::string("101010110110001"));
|
||||
|
||||
// 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;
|
||||
|
||||
virtual int encode(int input) = 0;
|
||||
|
||||
virtual void encode(char* hex, char* out_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] == 1)? true : false;
|
||||
}
|
||||
for (unsigned int i=0; i<4; i++) {
|
||||
value[3-i] = (parity[i] == 1)? true : false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int encode(std::bitset<6>& input);
|
||||
|
||||
int encode(int input)
|
||||
{
|
||||
assert (input < 64 && input >= 0);
|
||||
|
||||
std::bitset<6> bitset_input(input);
|
||||
|
||||
return encode(bitset_input);
|
||||
}
|
||||
|
||||
void encode(char* hex, char* out_parity)
|
||||
{
|
||||
// Make a bitset from hex
|
||||
std::bitset<6> value;
|
||||
// in the bitset 5 is the left-most and 0 is the right-most
|
||||
for (unsigned int i=0; i<6; i++) {
|
||||
value[5-i] = (hex[i] == 1)? true : false;
|
||||
}
|
||||
|
||||
int parity = encode(value);
|
||||
|
||||
// Put the calculated parity in the form of a char array
|
||||
for (int i=3; i>=0; i--) {
|
||||
out_parity[i] = parity & 1;
|
||||
parity >>= 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \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];
|
||||
int encode_parities[64];
|
||||
|
||||
/**
|
||||
* \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;
|
||||
}
|
||||
|
||||
for (int i=0; i<64; i++) {
|
||||
int parity = hamming.encode(i);
|
||||
encode_parities[i] = parity;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \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++) {
|
||||
assert(hex[i] == 0 || hex[i] == 1);
|
||||
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++) {
|
||||
assert(hex[i] == 0 || hex[i] == 1);
|
||||
value <<= 1;
|
||||
value |= hex[i];
|
||||
}
|
||||
for (unsigned int i=0; i<4; i++) {
|
||||
assert(parity[i] == 0 || parity[i] == 1);
|
||||
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;
|
||||
}
|
||||
|
||||
int encode(int input);
|
||||
|
||||
void encode(char* hex, char* out_parity)
|
||||
{
|
||||
int value = convert_hex_to_int(hex);
|
||||
int parity = encode(value);
|
||||
|
||||
// Put the calculated parity in the form of a char array
|
||||
for (int i=3; i>=0; i--) {
|
||||
out_parity[i] = parity & 1;
|
||||
parity >>= 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // HAMMING_HPP_e7123c3795b94d14b5774d5d8f016a04
|
||||
670
include/ReedSolomon.hpp
Normal file
670
include/ReedSolomon.hpp
Normal file
@@ -0,0 +1,670 @@
|
||||
|
||||
#ifndef REEDSOLOMON_HPP_b1405fdab6374ba2a4e65e8d45ec3d80
|
||||
#define REEDSOLOMON_HPP_b1405fdab6374ba2a4e65e8d45ec3d80
|
||||
|
||||
/**
|
||||
* Code taken and adapted from www.eccpage.com/rs.c
|
||||
* Credit goes to Mr Simon Rockliff.
|
||||
*
|
||||
* Tried before with the implementation from ITPP library but couldn't make it produce the same outputs
|
||||
* expected from the P25 transmissions that I have tested. This implementation does work.
|
||||
*/
|
||||
|
||||
/* This program is an encoder/decoder for Reed-Solomon codes. Encoding is in
|
||||
systematic form, decoding via the Berlekamp iterative algorithm.
|
||||
In the present form , the constants mm, nn, tt, and kk=nn-2tt must be
|
||||
specified (the double letters are used simply to avoid clashes with
|
||||
other n,k,t used in other programs into which this was incorporated!)
|
||||
Also, the irreducible polynomial used to generate GF(2**mm) must also be
|
||||
entered -- these can be found in Lin and Costello, and also Clark and Cain.
|
||||
|
||||
The representation of the elements of GF(2**m) is either in index form,
|
||||
where the number is the power of the primitive element alpha, which is
|
||||
convenient for multiplication (add the powers modulo 2**m-1) or in
|
||||
polynomial form, where the bits represent the coefficients of the
|
||||
polynomial representation of the number, which is the most convenient form
|
||||
for addition. The two forms are swapped between via lookup tables.
|
||||
This leads to fairly messy looking expressions, but unfortunately, there
|
||||
is no easy alternative when working with Galois arithmetic.
|
||||
|
||||
The code is not written in the most elegant way, but to the best
|
||||
of my knowledge, (no absolute guarantees!), it works.
|
||||
However, when including it into a simulation program, you may want to do
|
||||
some conversion of global variables (used here because I am lazy!) to
|
||||
local variables where appropriate, and passing parameters (eg array
|
||||
addresses) to the functions may be a sensible move to reduce the number
|
||||
of global variables and thus decrease the chance of a bug being introduced.
|
||||
|
||||
This program does not handle erasures at present, but should not be hard
|
||||
to adapt to do this, as it is just an adjustment to the Berlekamp-Massey
|
||||
algorithm. It also does not attempt to decode past the BCH bound -- see
|
||||
Blahut "Theory and practice of error control codes" for how to do this.
|
||||
|
||||
Simon Rockliff, University of Adelaide 21/9/89
|
||||
|
||||
26/6/91 Slight modifications to remove a compiler dependent bug which hadn't
|
||||
previously surfaced. A few extra comments added for clarity.
|
||||
Appears to all work fine, ready for posting to net!
|
||||
|
||||
Notice
|
||||
--------
|
||||
This program may be freely modified and/or given to whoever wants it.
|
||||
A condition of such distribution is that the author's contribution be
|
||||
acknowledged by his name being left in the comments heading the program,
|
||||
however no responsibility is accepted for any financial or other loss which
|
||||
may result from some unforseen errors or malfunctioning of the program
|
||||
during use.
|
||||
Simon Rockliff, 26th June 1991
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
template <int TT>
|
||||
class ReedSolomon_63
|
||||
{
|
||||
private:
|
||||
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 */
|
||||
static const int 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]
|
||||
lookup tables: index->polynomial form alpha_to[] contains j=alpha**i;
|
||||
polynomial form -> index form index_of[j=alpha**i] = i
|
||||
alpha=2 is the primitive element of GF(2**mm)
|
||||
*/
|
||||
{
|
||||
register int i, mask;
|
||||
|
||||
mask = 1;
|
||||
alpha_to[MM] = 0;
|
||||
for (i = 0; i < MM; i++) {
|
||||
alpha_to[i] = mask;
|
||||
index_of[alpha_to[i]] = i;
|
||||
if (generator_polinomial[i] != 0)
|
||||
alpha_to[MM] ^= mask;
|
||||
mask <<= 1;
|
||||
}
|
||||
index_of[alpha_to[MM]] = MM;
|
||||
mask >>= 1;
|
||||
for (i = MM + 1; i < NN; i++) {
|
||||
if (alpha_to[i - 1] >= mask)
|
||||
alpha_to[i] = alpha_to[MM] ^ ((alpha_to[i - 1] ^ mask) << 1);
|
||||
else
|
||||
alpha_to[i] = alpha_to[i - 1] << 1;
|
||||
index_of[alpha_to[i]] = i;
|
||||
}
|
||||
index_of[0] = -1;
|
||||
}
|
||||
|
||||
void gen_poly()
|
||||
/* Obtain the generator polynomial of the tt-error correcting, length
|
||||
nn=(2**mm -1) Reed Solomon code from the product of (X+alpha**i), i=1..2*tt
|
||||
*/
|
||||
{
|
||||
register int i, j;
|
||||
|
||||
gg[0] = 2; /* primitive element alpha = 2 for GF(2**mm) */
|
||||
gg[1] = 1; /* g(x) = (X+alpha) initially */
|
||||
for (i = 2; i <= NN - KK; i++) {
|
||||
gg[i] = 1;
|
||||
for (j = i - 1; j > 0; j--)
|
||||
if (gg[j] != 0)
|
||||
gg[j] = gg[j - 1] ^ alpha_to[(index_of[gg[j]] + i) % NN];
|
||||
else
|
||||
gg[j] = gg[j - 1];
|
||||
gg[0] = alpha_to[(index_of[gg[0]] + i) % NN]; /* gg[0] can never be zero */
|
||||
}
|
||||
/* convert gg[] to index form for quicker encoding */
|
||||
for (i = 0; i <= NN - KK; i++)
|
||||
gg[i] = index_of[gg[i]];
|
||||
}
|
||||
|
||||
public:
|
||||
ReedSolomon_63()
|
||||
{
|
||||
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[] = { 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(const 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]
|
||||
data[] is input and bb[] is output in polynomial form.
|
||||
Encoding is done by using a feedback shift register with appropriate
|
||||
connections specified by the elements of gg[], which was generated above.
|
||||
Codeword is c(X) = data(X)*X**(nn-kk)+ b(X) */
|
||||
{
|
||||
register int i, j;
|
||||
int feedback;
|
||||
|
||||
for (i = 0; i < NN - KK; i++)
|
||||
bb[i] = 0;
|
||||
for (i = KK - 1; i >= 0; i--) {
|
||||
feedback = index_of[data[i] ^ bb[NN - KK - 1]];
|
||||
if (feedback != -1) {
|
||||
for (j = NN - KK - 1; j > 0; j--)
|
||||
if (gg[j] != -1)
|
||||
bb[j] = bb[j - 1] ^ alpha_to[(gg[j] + feedback) % NN];
|
||||
else
|
||||
bb[j] = bb[j - 1];
|
||||
bb[0] = alpha_to[(gg[0] + feedback) % NN];
|
||||
} else {
|
||||
for (j = NN - KK - 1; j > 0; j--)
|
||||
bb[j] = bb[j - 1];
|
||||
bb[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
evaluating, storing the syndromes in s[i], i=1..2tt (leave s[0] zero) .
|
||||
Then we use the Berlekamp iteration to find the error location polynomial
|
||||
elp[i]. If the degree of the elp is >tt, we cannot correct all the errors
|
||||
and hence just put out the information symbols uncorrected. If the degree of
|
||||
elp is <=tt, we substitute alpha**i , i=1..n into the elp to get the roots,
|
||||
hence the inverse roots, the error location numbers. If the number of errors
|
||||
located does not equal the degree of the elp, we have more than tt errors
|
||||
and cannot correct them. Otherwise, we then solve for the error value at
|
||||
the error location and correct the error. The procedure is that found in
|
||||
Lin and Costello. For the cases where the number of errors is known to be too
|
||||
large to correct, the information symbols as received are output (the
|
||||
advantage of systematic encoding is that hopefully some of the information
|
||||
symbols will be okay and that if we are in luck, the errors are in the
|
||||
parity part of the transmitted codeword). Of course, these insoluble cases
|
||||
can be returned as error flags to the calling routine if desired. */
|
||||
{
|
||||
register int i, j, u, q;
|
||||
int elp[NN - KK + 2][NN - KK], d[NN - KK + 2], l[NN - KK + 2], u_lu[NN - KK
|
||||
+ 2], s[NN - KK + 1];
|
||||
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) */
|
||||
|
||||
/* first form the syndromes */
|
||||
for (i = 1; i <= NN - KK; i++) {
|
||||
s[i] = 0;
|
||||
for (j = 0; j < NN; j++)
|
||||
if (recd[j] != -1)
|
||||
s[i] ^= alpha_to[(recd[j] + i * j) % NN]; /* recd[j] in index form */
|
||||
/* convert syndrome from polynomial form to index form */
|
||||
if (s[i] != 0)
|
||||
syn_error = 1; /* set flag if non-zero syndrome => error */
|
||||
s[i] = index_of[s[i]];
|
||||
}
|
||||
|
||||
if (syn_error) /* if errors, try and correct */
|
||||
{
|
||||
/* compute the error location polynomial via the Berlekamp iterative algorithm,
|
||||
following the terminology of Lin and Costello : d[u] is the 'mu'th
|
||||
discrepancy, where u='mu'+1 and 'mu' (the Greek letter!) is the step number
|
||||
ranging from -1 to 2*tt (see L&C), l[u] is the
|
||||
degree of the elp at that step, and u_l[u] is the difference between the
|
||||
step number and the degree of the elp.
|
||||
*/
|
||||
/* initialise table entries */
|
||||
d[0] = 0; /* index form */
|
||||
d[1] = s[1]; /* index form */
|
||||
elp[0][0] = 0; /* index form */
|
||||
elp[1][0] = 1; /* polynomial form */
|
||||
for (i = 1; i < NN - KK; i++) {
|
||||
elp[0][i] = -1; /* index form */
|
||||
elp[1][i] = 0; /* polynomial form */
|
||||
}
|
||||
l[0] = 0;
|
||||
l[1] = 0;
|
||||
u_lu[0] = -1;
|
||||
u_lu[1] = 0;
|
||||
u = 0;
|
||||
|
||||
do {
|
||||
u++;
|
||||
if (d[u] == -1) {
|
||||
l[u + 1] = l[u];
|
||||
for (i = 0; i <= l[u]; i++) {
|
||||
elp[u + 1][i] = elp[u][i];
|
||||
elp[u][i] = index_of[elp[u][i]];
|
||||
}
|
||||
} else
|
||||
/* search for words with greatest u_lu[q] for which d[q]!=0 */
|
||||
{
|
||||
q = u - 1;
|
||||
while ((d[q] == -1) && (q > 0))
|
||||
q--;
|
||||
/* have found first non-zero d[q] */
|
||||
if (q > 0) {
|
||||
j = q;
|
||||
do {
|
||||
j--;
|
||||
if ((d[j] != -1) && (u_lu[q] < u_lu[j]))
|
||||
q = j;
|
||||
} while (j > 0);
|
||||
};
|
||||
|
||||
/* have now found q such that d[u]!=0 and u_lu[q] is maximum */
|
||||
/* store degree of new elp polynomial */
|
||||
if (l[u] > l[q] + u - q)
|
||||
l[u + 1] = l[u];
|
||||
else
|
||||
l[u + 1] = l[q] + u - q;
|
||||
|
||||
/* form new elp(x) */
|
||||
for (i = 0; i < NN - KK; i++)
|
||||
elp[u + 1][i] = 0;
|
||||
for (i = 0; i <= l[q]; i++)
|
||||
if (elp[q][i] != -1)
|
||||
elp[u + 1][i + u - q] = alpha_to[(d[u] + NN - d[q]
|
||||
+ elp[q][i]) % NN];
|
||||
for (i = 0; i <= l[u]; i++) {
|
||||
elp[u + 1][i] ^= elp[u][i];
|
||||
elp[u][i] = index_of[elp[u][i]]; /*convert old elp value to index*/
|
||||
}
|
||||
}
|
||||
u_lu[u + 1] = u - l[u + 1];
|
||||
|
||||
/* form (u+1)th discrepancy */
|
||||
if (u < NN - KK) /* no discrepancy computed on last iteration */
|
||||
{
|
||||
if (s[u + 1] != -1)
|
||||
d[u + 1] = alpha_to[s[u + 1]];
|
||||
else
|
||||
d[u + 1] = 0;
|
||||
for (i = 1; i <= l[u + 1]; i++)
|
||||
if ((s[u + 1 - i] != -1) && (elp[u + 1][i] != 0))
|
||||
d[u + 1] ^= alpha_to[(s[u + 1 - i]
|
||||
+ index_of[elp[u + 1][i]]) % NN];
|
||||
d[u + 1] = index_of[d[u + 1]]; /* put d[u+1] into index form */
|
||||
}
|
||||
} while ((u < NN - KK) && (l[u + 1] <= TT));
|
||||
|
||||
u++;
|
||||
if (l[u] <= TT) /* can correct error */
|
||||
{
|
||||
/* put elp into index form */
|
||||
for (i = 0; i <= l[u]; i++)
|
||||
elp[u][i] = index_of[elp[u][i]];
|
||||
|
||||
/* find roots of the error location polynomial */
|
||||
for (i = 1; i <= l[u]; i++)
|
||||
reg[i] = elp[u][i];
|
||||
count = 0;
|
||||
for (i = 1; i <= NN; i++) {
|
||||
q = 1;
|
||||
for (j = 1; j <= l[u]; j++)
|
||||
if (reg[j] != -1) {
|
||||
reg[j] = (reg[j] + j) % NN;
|
||||
q ^= alpha_to[reg[j]];
|
||||
};
|
||||
if (!q) /* store root and error location number indices */
|
||||
{
|
||||
root[count] = i;
|
||||
loc[count] = NN - i;
|
||||
count++;
|
||||
};
|
||||
};
|
||||
|
||||
if (count == l[u]) /* no. roots = degree of elp hence <= tt errors */
|
||||
{
|
||||
/* form polynomial z(x) */
|
||||
for (i = 1; i <= l[u]; i++) /* Z[0] = 1 always - do not need */
|
||||
{
|
||||
if ((s[i] != -1) && (elp[u][i] != -1))
|
||||
z[i] = alpha_to[s[i]] ^ alpha_to[elp[u][i]];
|
||||
else if ((s[i] != -1) && (elp[u][i] == -1))
|
||||
z[i] = alpha_to[s[i]];
|
||||
else if ((s[i] == -1) && (elp[u][i] != -1))
|
||||
z[i] = alpha_to[elp[u][i]];
|
||||
else
|
||||
z[i] = 0;
|
||||
for (j = 1; j < i; j++)
|
||||
if ((s[j] != -1) && (elp[u][i - j] != -1))
|
||||
z[i] ^= alpha_to[(elp[u][i - j] + s[j]) % NN];
|
||||
z[i] = index_of[z[i]]; /* put into index form */
|
||||
};
|
||||
|
||||
/* evaluate errors at locations given by error location numbers loc[i] */
|
||||
for (i = 0; i < NN; i++) {
|
||||
err[i] = 0;
|
||||
if (recd[i] != -1) /* convert recd[] to polynomial form */
|
||||
recd[i] = alpha_to[recd[i]];
|
||||
else
|
||||
recd[i] = 0;
|
||||
}
|
||||
for (i = 0; i < l[u]; i++) /* compute numerator of error term first */
|
||||
{
|
||||
err[loc[i]] = 1; /* accounts for z[0] */
|
||||
for (j = 1; j <= l[u]; j++)
|
||||
if (z[j] != -1)
|
||||
err[loc[i]] ^= alpha_to[(z[j] + j * root[i]) % NN];
|
||||
if (err[loc[i]] != 0) {
|
||||
err[loc[i]] = index_of[err[loc[i]]];
|
||||
q = 0; /* form denominator of error term */
|
||||
for (j = 0; j < l[u]; j++)
|
||||
if (j != i)
|
||||
q += index_of[1
|
||||
^ alpha_to[(loc[j] + root[i]) % NN]];
|
||||
q = q % NN;
|
||||
err[loc[i]] = alpha_to[(err[loc[i]] - q + NN) % NN];
|
||||
recd[loc[i]] ^= err[loc[i]]; /*recd[i] must be in polynomial form */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* no. roots != degree of elp => >tt errors and cannot solve */
|
||||
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;
|
||||
}
|
||||
|
||||
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(const char* input)
|
||||
{
|
||||
int output = ((input[0] != 0)? 32 : 0) |
|
||||
((input[1] != 0)? 16 : 0) |
|
||||
((input[2] != 0)? 8 : 0) |
|
||||
((input[3] != 0)? 4 : 0) |
|
||||
((input[4] != 0)? 2 : 0) |
|
||||
((input[5] != 0)? 1 : 0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void hex_to_bin(int input, char* output)
|
||||
{
|
||||
output[0] = ((input & 32) != 0)? 1 : 0;
|
||||
output[1] = ((input & 16) != 0)? 1 : 0;
|
||||
output[2] = ((input & 8) != 0)? 1 : 0;
|
||||
output[3] = ((input & 4) != 0)? 1 : 0;
|
||||
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<8>
|
||||
{
|
||||
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. Bits are corrected in place.
|
||||
* \param hex_parity Parity packed bits, originally a char[16][6], 16 hex words.
|
||||
* \return 1 if irrecoverable errors have been detected, 0 otherwise.
|
||||
*/
|
||||
int decode(char* hex_data, const char* hex_parity)
|
||||
{
|
||||
int input[63];
|
||||
int output[63];
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Then the 20 hex words of data
|
||||
for(unsigned int i=16; i<16+20; i++) {
|
||||
input[i] = bin_to_hex(hex_data + (i-16)*6);
|
||||
}
|
||||
|
||||
// Fill up with zeros to complete the 47 expected hex words of data
|
||||
for(unsigned int i=16+20; i<63; i++) {
|
||||
input[i] = 0;
|
||||
}
|
||||
|
||||
// Now we can call decode on the base class
|
||||
int irrecoverable_errors = ReedSolomon_63<8>::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;
|
||||
}
|
||||
|
||||
void encode(const char* hex_data, char* out_hex_parity)
|
||||
{
|
||||
int input[47];
|
||||
int output[63];
|
||||
|
||||
// Put the 20 hex words of data
|
||||
for(unsigned int i=0; i<20; i++) {
|
||||
input[i] = bin_to_hex(hex_data + i*6);
|
||||
}
|
||||
|
||||
// Fill up with zeros to complete the 47 expected hex words of data
|
||||
for(unsigned int i=20; i<47; i++) {
|
||||
input[i] = 0;
|
||||
}
|
||||
|
||||
// Now we can call encode on the base class
|
||||
ReedSolomon_63<8>::encode(input, output);
|
||||
|
||||
// Convert it back to binary form and put it into the parity
|
||||
for(unsigned int i=0; i<16; i++) {
|
||||
hex_to_bin(output[i], out_hex_parity + i*6);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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<6>
|
||||
{
|
||||
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. Bits are corrected in place.
|
||||
* \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, const 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<6>::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;
|
||||
}
|
||||
|
||||
void encode(const char* hex_data, char* out_hex_parity)
|
||||
{
|
||||
int input[51];
|
||||
int output[63];
|
||||
|
||||
// Put the 12 hex words of data
|
||||
for(unsigned int i=0; i<12; i++) {
|
||||
input[i] = bin_to_hex(hex_data + i*6);
|
||||
}
|
||||
|
||||
// Fill up with zeros to complete the 51 expected hex words of data
|
||||
for(unsigned int i=12; i<51; i++) {
|
||||
input[i] = 0;
|
||||
}
|
||||
|
||||
// Now we can call encode on the base class
|
||||
ReedSolomon_63<6>::encode(input, output);
|
||||
|
||||
// Convert it back to binary form and put it into the parity
|
||||
for(unsigned int i=0; i<12; i++) {
|
||||
hex_to_bin(output[i], out_hex_parity + i*6);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 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<4>
|
||||
{
|
||||
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. Bits are corrected in place.
|
||||
* \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, const 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+16; 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+16; i<63; i++) {
|
||||
input[i] = 0;
|
||||
}
|
||||
|
||||
// Now we can call decode on the base class
|
||||
int irrecoverable_errors = ReedSolomon_63<4>::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+16; i++) {
|
||||
hex_to_bin(output[i], hex_data + (i-8)*6);
|
||||
}
|
||||
|
||||
return irrecoverable_errors;
|
||||
}
|
||||
|
||||
void encode(const char* hex_data, char* out_hex_parity)
|
||||
{
|
||||
int input[55];
|
||||
int output[63];
|
||||
|
||||
// Put the 16 hex words of data
|
||||
for(unsigned int i=0; i<16; i++) {
|
||||
input[i] = bin_to_hex(hex_data + i*6);
|
||||
}
|
||||
|
||||
// Fill up with zeros to complete the 55 expected hex words of data
|
||||
for(unsigned int i=16; i<55; i++) {
|
||||
input[i] = 0;
|
||||
}
|
||||
|
||||
// Now we can call encode on the base class
|
||||
ReedSolomon_63<4>::encode(input, output);
|
||||
|
||||
// Convert it back to binary form and put it into the parity
|
||||
for(unsigned int i=0; i<8; i++) {
|
||||
hex_to_bin(output[i], out_hex_parity + i*6);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // REEDSOLOMON_HPP_b1405fdab6374ba2a4e65e8d45ec3d80
|
||||
32
include/config.h
Normal file
32
include/config.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* System target
|
||||
*/
|
||||
#define BSD // bsd/linux audio interface
|
||||
//#define SOLARIS // solaris audio interface, untested
|
||||
|
||||
/*
|
||||
* noisy debug/development options
|
||||
*/
|
||||
//#define X2TDMA_DUMP // cach and sync bits dump
|
||||
//#define DMR_DUMP
|
||||
//#define DSTAR_DUMP // dstar frame dump
|
||||
//#define NXDN_DUMP
|
||||
//#define UPSAMPLE_DEBUG
|
||||
//#define PROVOICE_DUMP
|
||||
298
include/descramble.h
Normal file
298
include/descramble.h
Normal file
@@ -0,0 +1,298 @@
|
||||
/* descramble.h */
|
||||
|
||||
// Functions for processing the radio-header:
|
||||
// descramble
|
||||
// deinterleave
|
||||
// FECdecoder
|
||||
|
||||
// (C) 2011 Jonathan Naylor G4KLX
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
// This code was originally written by JOnathan Naylor, G4KLX, as part
|
||||
// of the "pcrepeatercontroller" project
|
||||
// More info:
|
||||
// http://groups.yahoo.com/group/pcrepeatercontroller
|
||||
|
||||
|
||||
|
||||
// Changes:
|
||||
// Convert C++ to C
|
||||
|
||||
// Version 20111106: initial release
|
||||
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// function traceBack
|
||||
int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_pathMemory2, int * m_pathMemory3) {
|
||||
enum FEC_STATE { S0, S1, S2, S3 } state;
|
||||
int loop;
|
||||
int length=0;
|
||||
|
||||
state=S0;
|
||||
|
||||
for (loop=329; loop >= 0; loop--, length++) {
|
||||
|
||||
switch (state) {
|
||||
case S0: // if state S0
|
||||
if (m_pathMemory0[loop]) {
|
||||
state = S2; // lower path
|
||||
} else {
|
||||
state = S0; // upper path
|
||||
}; // end else - if
|
||||
out[loop]=0;
|
||||
break;
|
||||
|
||||
case S1: // if state S1
|
||||
if (m_pathMemory1[loop]) {
|
||||
state = S2; // lower path
|
||||
} else {
|
||||
state = S0; // upper path
|
||||
}; // end else - if
|
||||
out[loop]=1;
|
||||
break;
|
||||
|
||||
case S2: // if state S2
|
||||
if (m_pathMemory2[loop]) {
|
||||
state = S3; // lower path
|
||||
} else {
|
||||
state = S1; // upper path
|
||||
}; // end else - if
|
||||
out[loop]=0;
|
||||
break;
|
||||
|
||||
case S3: // if state S3
|
||||
if (m_pathMemory3[loop]) {
|
||||
state = S3; // lower path
|
||||
} else {
|
||||
state = S1; // upper path
|
||||
}; // end else - if
|
||||
out[loop]=1;
|
||||
break;
|
||||
|
||||
}; // end switch
|
||||
}; // end for
|
||||
|
||||
return(length);
|
||||
}; // end function
|
||||
|
||||
|
||||
|
||||
// function viterbiDecode
|
||||
|
||||
void viterbiDecode (int n, int *data, int *m_pathMemory0, int *m_pathMemory1, int *m_pathMemory2, int *m_pathMemory3, int *m_pathMetric) {
|
||||
int tempMetric[4];
|
||||
int metric[8];
|
||||
int loop;
|
||||
|
||||
int m1;
|
||||
int m2;
|
||||
|
||||
metric[0]=(data[1]^0)+(data[0]^0);
|
||||
metric[1]=(data[1]^1)+(data[0]^1);
|
||||
metric[2]=(data[1]^1)+(data[0]^0);
|
||||
metric[3]=(data[1]^0)+(data[0]^1);
|
||||
metric[4]=(data[1]^1)+(data[0]^1);
|
||||
metric[5]=(data[1]^0)+(data[0]^0);
|
||||
metric[6]=(data[1]^0)+(data[0]^1);
|
||||
metric[7]=(data[1]^1)+(data[0]^0);
|
||||
|
||||
// Pres. state = S0, Prev. state = S0 & S2
|
||||
m1=metric[0]+m_pathMetric[0];
|
||||
m2=metric[4]+m_pathMetric[2];
|
||||
if (m1<m2) {
|
||||
m_pathMemory0[n]=0;
|
||||
tempMetric[0]=m1;
|
||||
} else {
|
||||
m_pathMemory0[n]=1;
|
||||
tempMetric[0]=m2;
|
||||
}; // end else - if
|
||||
|
||||
// Pres. state = S1, Prev. state = S0 & S2
|
||||
m1=metric[1]+m_pathMetric[0];
|
||||
m2=metric[5]+m_pathMetric[2];
|
||||
if (m1<m2) {
|
||||
m_pathMemory1[n]=0;
|
||||
tempMetric[1]=m1;
|
||||
} else {
|
||||
m_pathMemory1[n]=1;
|
||||
tempMetric[1]=m2;
|
||||
}; // end else - if
|
||||
|
||||
// Pres. state = S2, Prev. state = S2 & S3
|
||||
m1=metric[2]+m_pathMetric[1];
|
||||
m2=metric[6]+m_pathMetric[3];
|
||||
if (m1<m2) {
|
||||
m_pathMemory2[n]=0;
|
||||
tempMetric[2]=m1;
|
||||
} else {
|
||||
m_pathMemory2[n]=1;
|
||||
tempMetric[2]=m2;
|
||||
}
|
||||
|
||||
// Pres. state = S3, Prev. state = S1 & S3
|
||||
m1=metric[3]+m_pathMetric[1];
|
||||
m2=metric[7]+m_pathMetric[3];
|
||||
if (m1 < m2) {
|
||||
m_pathMemory3[n]=0;
|
||||
tempMetric[3]=m1;
|
||||
} else {
|
||||
m_pathMemory3[n]=1;
|
||||
tempMetric[3]=m2;
|
||||
}; // end else - if
|
||||
|
||||
for (loop=0;loop<4;loop++) {
|
||||
m_pathMetric[loop]=tempMetric[loop];
|
||||
}; // end for
|
||||
|
||||
}; // end function ViterbiDecode
|
||||
|
||||
|
||||
// function FECdecoder
|
||||
// returns outlen
|
||||
int FECdecoder (int * in, int * out) {
|
||||
int outLen;
|
||||
|
||||
int m_pathMemory0[330];
|
||||
int m_pathMemory1[330];
|
||||
int m_pathMemory2[330];
|
||||
int m_pathMemory3[330];
|
||||
int m_pathMetric[4];
|
||||
|
||||
int loop,loop2;
|
||||
|
||||
int n=0;
|
||||
|
||||
memset(m_pathMemory0,0,330*sizeof(int));
|
||||
memset(m_pathMemory1,0,330*sizeof(int));
|
||||
memset(m_pathMemory2,0,330*sizeof(int));
|
||||
memset(m_pathMemory3,0,330*sizeof(int));
|
||||
|
||||
for (loop=0;loop<4;loop++) {
|
||||
m_pathMetric[loop]=0;
|
||||
}; // end for
|
||||
|
||||
|
||||
for (loop2=0;loop2<660;loop2+=2, n++) {
|
||||
int data[2];
|
||||
|
||||
if (in[loop2]) {
|
||||
data[1]=1;
|
||||
} else {
|
||||
data[1]=0;
|
||||
}; // end else - if
|
||||
|
||||
if (in[loop2+1]) {
|
||||
data[0]=1;
|
||||
} else {
|
||||
data[0]=0;
|
||||
}; // end else - if
|
||||
|
||||
viterbiDecode(n, data, m_pathMemory0, m_pathMemory1, m_pathMemory2, m_pathMemory3, m_pathMetric);
|
||||
}; // end for
|
||||
|
||||
outLen=traceBack(out, m_pathMemory0, m_pathMemory1, m_pathMemory2, m_pathMemory3);
|
||||
|
||||
// Swap endian-ness
|
||||
// code removed (done converting bits into octets), done in main program
|
||||
|
||||
//for (loop=0;loop<330;loop+=8) {
|
||||
// int temp;
|
||||
// temp=out[loop];out[loop]=out[loop+7];out[loop+7]=temp;
|
||||
// temp=out[loop+1];out[loop+1]=out[loop+6];out[loop+6]=temp;
|
||||
// temp=out[loop+2];out[loop+2]=out[loop+5];out[loop+5]=temp;
|
||||
// temp=out[loop+3];out[loop+3]=out[loop+4];out[loop+4]=temp;
|
||||
//}
|
||||
|
||||
return(outLen);
|
||||
|
||||
}; // end function FECdecoder
|
||||
|
||||
|
||||
// function deinterleave
|
||||
void deinterleave (int * in, int * out) {
|
||||
|
||||
int k=0;
|
||||
int loop=0;
|
||||
// function starts here
|
||||
|
||||
// init vars
|
||||
k=0;
|
||||
|
||||
for (loop=0;loop<660;loop++) {
|
||||
out[k]=in[loop];
|
||||
|
||||
k += 24;
|
||||
|
||||
if (k >= 672) {
|
||||
k -= 671;
|
||||
} else if (k >= 660) {
|
||||
k -= 647;
|
||||
}; // end elsif - if
|
||||
}; // end for
|
||||
|
||||
}; // end function deinterleave
|
||||
|
||||
|
||||
|
||||
/// function scramble
|
||||
|
||||
void scramble (int * in,int * out) {
|
||||
|
||||
static const int SCRAMBLER_TABLE_BITS[] = {
|
||||
0,0,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,
|
||||
0,0,1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,
|
||||
1,1,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,
|
||||
1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,
|
||||
0,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,
|
||||
0,1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,
|
||||
1,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,
|
||||
1,1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,
|
||||
0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,
|
||||
1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,
|
||||
0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,
|
||||
1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,
|
||||
0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,
|
||||
0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,
|
||||
1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1,
|
||||
1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,
|
||||
1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,
|
||||
0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,1,
|
||||
0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1,1,
|
||||
1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,
|
||||
1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,
|
||||
1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,1,0,
|
||||
1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0};
|
||||
|
||||
const int SCRAMBLER_TABLE_BITS_LENGTH=720;
|
||||
|
||||
int loop=0;
|
||||
int m_count=0;
|
||||
|
||||
|
||||
for (loop=0; loop < 660; loop++) {
|
||||
out[loop] = in[loop] ^ SCRAMBLER_TABLE_BITS[m_count++];
|
||||
|
||||
if (m_count >= SCRAMBLER_TABLE_BITS_LENGTH) {
|
||||
m_count = 0U;
|
||||
}; // end if
|
||||
}; // end for
|
||||
|
||||
}; // end function scramble
|
||||
|
||||
|
||||
|
||||
|
||||
64
include/dmr_const.h
Normal file
64
include/dmr_const.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _MAIN
|
||||
extern const int rW[36];
|
||||
extern const int rX[36];
|
||||
extern const int rY[36];
|
||||
extern const int rZ[36];
|
||||
|
||||
#else
|
||||
/*
|
||||
* DMR AMBE interleave schedule
|
||||
*/
|
||||
const int rW[36] = {
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 2,
|
||||
0, 2, 0, 2, 0, 2,
|
||||
0, 2, 0, 2, 0, 2
|
||||
};
|
||||
|
||||
const int rX[36] = {
|
||||
23, 10, 22, 9, 21, 8,
|
||||
20, 7, 19, 6, 18, 5,
|
||||
17, 4, 16, 3, 15, 2,
|
||||
14, 1, 13, 0, 12, 10,
|
||||
11, 9, 10, 8, 9, 7,
|
||||
8, 6, 7, 5, 6, 4
|
||||
};
|
||||
|
||||
const int rY[36] = {
|
||||
0, 2, 0, 2, 0, 2,
|
||||
0, 2, 0, 3, 0, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3
|
||||
};
|
||||
|
||||
const int rZ[36] = {
|
||||
5, 3, 4, 2, 3, 1,
|
||||
2, 0, 1, 13, 0, 12,
|
||||
22, 11, 21, 10, 20, 9,
|
||||
19, 8, 18, 7, 17, 6,
|
||||
16, 5, 15, 4, 14, 3,
|
||||
13, 2, 12, 1, 11, 0
|
||||
};
|
||||
|
||||
#endif
|
||||
320
include/dsd.h
Normal file
320
include/dsd.h
Normal file
@@ -0,0 +1,320 @@
|
||||
#ifndef DSD_H
|
||||
#define DSD_H
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#define __USE_XOPEN
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#ifdef SOLARIS
|
||||
#include <sys/audioio.h>
|
||||
#endif
|
||||
#if defined(BSD) && !defined(__APPLE__)
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include <mbelib.h>
|
||||
#include <sndfile.h>
|
||||
|
||||
#include "p25p1_heuristics.h"
|
||||
|
||||
|
||||
#define SAMPLE_RATE_IN 48000
|
||||
#define SAMPLE_RATE_OUT 8000
|
||||
|
||||
#ifdef USE_PORTAUDIO
|
||||
#include "portaudio.h"
|
||||
#define PA_FRAMES_PER_BUFFER 64
|
||||
//Buffer needs to be large enough to prevent input buffer overruns while DSD is doing other struff (like outputting voice)
|
||||
//else you get skipped samples which result in incomplete/erronous decodes and a mountain of error messages.
|
||||
#define PA_LATENCY_IN 0.500
|
||||
//Buffer needs to be large enough to prevent output buffer underruns while DSD is doing other stuff (like decoding input)
|
||||
//else you get choppy audio and in 'extreme' cases errors.
|
||||
//Buffer also needs to be as small as possible so we don't have a lot of audio delay.
|
||||
#define PA_LATENCY_OUT 0.100
|
||||
#endif
|
||||
|
||||
/*
|
||||
* global variables
|
||||
*/
|
||||
int exitflag;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int onesymbol;
|
||||
char mbe_in_file[1024];
|
||||
FILE *mbe_in_f;
|
||||
int errorbars;
|
||||
int datascope;
|
||||
int symboltiming;
|
||||
int verbose;
|
||||
int p25enc;
|
||||
int p25lc;
|
||||
int p25status;
|
||||
int p25tg;
|
||||
int scoperate;
|
||||
char audio_in_dev[1024];
|
||||
int audio_in_fd;
|
||||
SNDFILE *audio_in_file;
|
||||
SF_INFO *audio_in_file_info;
|
||||
#ifdef USE_PORTAUDIO
|
||||
PaStream* audio_in_pa_stream;
|
||||
#endif
|
||||
int audio_in_type; // 0 for device, 1 for file, 2 for portaudio
|
||||
char audio_out_dev[1024];
|
||||
int audio_out_fd;
|
||||
SNDFILE *audio_out_file;
|
||||
SF_INFO *audio_out_file_info;
|
||||
#ifdef USE_PORTAUDIO
|
||||
PaStream* audio_out_pa_stream;
|
||||
#endif
|
||||
int audio_out_type; // 0 for device, 1 for file, 2 for portaudio
|
||||
int split;
|
||||
int playoffset;
|
||||
char mbe_out_dir[1024];
|
||||
char mbe_out_file[1024];
|
||||
char mbe_out_path[1024];
|
||||
FILE *mbe_out_f;
|
||||
float audio_gain;
|
||||
int audio_out;
|
||||
char wav_out_file[1024];
|
||||
SNDFILE *wav_out_f;
|
||||
//int wav_out_fd;
|
||||
int serial_baud;
|
||||
char serial_dev[1024];
|
||||
int serial_fd;
|
||||
int resume;
|
||||
int frame_dstar;
|
||||
int frame_x2tdma;
|
||||
int frame_p25p1;
|
||||
int frame_nxdn48;
|
||||
int frame_nxdn96;
|
||||
int frame_dmr;
|
||||
int frame_provoice;
|
||||
int mod_c4fm;
|
||||
int mod_qpsk;
|
||||
int mod_gfsk;
|
||||
int uvquality;
|
||||
int inverted_x2tdma;
|
||||
int inverted_dmr;
|
||||
int mod_threshold;
|
||||
int ssize;
|
||||
int msize;
|
||||
int playfiles;
|
||||
int delay;
|
||||
int use_cosine_filter;
|
||||
int unmute_encrypted_p25;
|
||||
} dsd_opts;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int *dibit_buf;
|
||||
int *dibit_buf_p;
|
||||
int repeat;
|
||||
short *audio_out_buf;
|
||||
short *audio_out_buf_p;
|
||||
float *audio_out_float_buf;
|
||||
float *audio_out_float_buf_p;
|
||||
float audio_out_temp_buf[160];
|
||||
float *audio_out_temp_buf_p;
|
||||
int audio_out_idx;
|
||||
int audio_out_idx2;
|
||||
//int wav_out_bytes;
|
||||
int center;
|
||||
int jitter;
|
||||
int synctype;
|
||||
int min;
|
||||
int max;
|
||||
int lmid;
|
||||
int umid;
|
||||
int minref;
|
||||
int maxref;
|
||||
int lastsample;
|
||||
int sbuf[128];
|
||||
int sidx;
|
||||
int maxbuf[1024];
|
||||
int minbuf[1024];
|
||||
int midx;
|
||||
char err_str[64];
|
||||
char fsubtype[16];
|
||||
char ftype[16];
|
||||
int symbolcnt;
|
||||
int rf_mod;
|
||||
int numflips;
|
||||
int lastsynctype;
|
||||
int lastp25type;
|
||||
int offset;
|
||||
int carrier;
|
||||
char tg[25][16];
|
||||
int tgcount;
|
||||
int lasttg;
|
||||
int lastsrc;
|
||||
int nac;
|
||||
int errs;
|
||||
int errs2;
|
||||
int mbe_file_type;
|
||||
int optind;
|
||||
int numtdulc;
|
||||
int firstframe;
|
||||
char slot0light[8];
|
||||
char slot1light[8];
|
||||
float aout_gain;
|
||||
float aout_max_buf[200];
|
||||
float *aout_max_buf_p;
|
||||
int aout_max_buf_idx;
|
||||
int samplesPerSymbol;
|
||||
int symbolCenter;
|
||||
char algid[9];
|
||||
char keyid[17];
|
||||
int currentslot;
|
||||
mbe_parms *cur_mp;
|
||||
mbe_parms *prev_mp;
|
||||
mbe_parms *prev_mp_enhanced;
|
||||
int p25kid;
|
||||
|
||||
unsigned int debug_audio_errors;
|
||||
unsigned int debug_header_errors;
|
||||
unsigned int debug_header_critical_errors;
|
||||
|
||||
// Last dibit read
|
||||
int last_dibit;
|
||||
|
||||
// Heuristics state data for +P5 signals
|
||||
P25Heuristics p25_heuristics;
|
||||
|
||||
// Heuristics state data for -P5 signals
|
||||
P25Heuristics inv_p25_heuristics;
|
||||
|
||||
#ifdef TRACE_DSD
|
||||
char debug_prefix;
|
||||
char debug_prefix_2;
|
||||
unsigned int debug_sample_index;
|
||||
unsigned int debug_sample_left_edge;
|
||||
unsigned int debug_sample_right_edge;
|
||||
FILE* debug_label_file;
|
||||
FILE* debug_label_dibit_file;
|
||||
FILE* debug_label_imbe_file;
|
||||
#endif
|
||||
|
||||
} dsd_state;
|
||||
|
||||
/*
|
||||
* Frame sync patterns
|
||||
*/
|
||||
#define INV_P25P1_SYNC "333331331133111131311111"
|
||||
#define P25P1_SYNC "111113113311333313133333"
|
||||
|
||||
#define X2TDMA_BS_VOICE_SYNC "113131333331313331113311"
|
||||
#define X2TDMA_BS_DATA_SYNC "331313111113131113331133"
|
||||
#define X2TDMA_MS_DATA_SYNC "313113333111111133333313"
|
||||
#define X2TDMA_MS_VOICE_SYNC "131331111333333311111131"
|
||||
|
||||
#define DSTAR_HD "131313131333133113131111"
|
||||
#define INV_DSTAR_HD "313131313111311331313333"
|
||||
#define DSTAR_SYNC "313131313133131113313111"
|
||||
#define INV_DSTAR_SYNC "131313131311313331131333"
|
||||
|
||||
#define NXDN_MS_DATA_SYNC "313133113131111333"
|
||||
#define INV_NXDN_MS_DATA_SYNC "131311331313333111"
|
||||
#define NXDN_MS_VOICE_SYNC "313133113131113133"
|
||||
#define INV_NXDN_MS_VOICE_SYNC "131311331313331311"
|
||||
#define INV_NXDN_BS_DATA_SYNC "131311331313333131"
|
||||
#define NXDN_BS_DATA_SYNC "313133113131111313"
|
||||
#define INV_NXDN_BS_VOICE_SYNC "131311331313331331"
|
||||
#define NXDN_BS_VOICE_SYNC "313133113131113113"
|
||||
|
||||
#define DMR_BS_DATA_SYNC "313333111331131131331131"
|
||||
#define DMR_BS_VOICE_SYNC "131111333113313313113313"
|
||||
#define DMR_MS_DATA_SYNC "311131133313133331131113"
|
||||
#define DMR_MS_VOICE_SYNC "133313311131311113313331"
|
||||
|
||||
#define INV_PROVOICE_SYNC "31313111333133133311331133113311"
|
||||
#define PROVOICE_SYNC "13131333111311311133113311331133"
|
||||
#define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311"
|
||||
#define PROVOICE_EA_SYNC "31131311331331111133131311311133"
|
||||
|
||||
/*
|
||||
* function prototypes
|
||||
*/
|
||||
void processDMRdata (dsd_opts * opts, dsd_state * state);
|
||||
void processDMRvoice (dsd_opts * opts, dsd_state * state);
|
||||
void processAudio (dsd_opts * opts, dsd_state * state);
|
||||
void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state);
|
||||
void playSynthesizedVoice (dsd_opts * opts, dsd_state * state);
|
||||
void openAudioOutDevice (dsd_opts * opts, int speed);
|
||||
void openAudioInDevice (dsd_opts * opts);
|
||||
|
||||
int getDibit (dsd_opts * opts, dsd_state * state);
|
||||
int get_dibit_and_analog_signal (dsd_opts * opts, dsd_state * state, int * out_analog_signal);
|
||||
|
||||
void skipDibit (dsd_opts * opts, dsd_state * state, int count);
|
||||
void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
||||
void saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d);
|
||||
int readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
||||
int readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d);
|
||||
void openMbeInFile (dsd_opts * opts, dsd_state * state);
|
||||
void closeMbeOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void openMbeOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void openWavOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void closeWavOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void printFrameInfo (dsd_opts * opts, dsd_state * state);
|
||||
void processFrame (dsd_opts * opts, dsd_state * state);
|
||||
void printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation);
|
||||
int getFrameSync (dsd_opts * opts, dsd_state * state);
|
||||
int comp (const void *a, const void *b);
|
||||
void noCarrier (dsd_opts * opts, dsd_state * state);
|
||||
void initOpts (dsd_opts * opts);
|
||||
void initState (dsd_state * state);
|
||||
void usage ();
|
||||
void liveScanner (dsd_opts * opts, dsd_state * state);
|
||||
void cleanupAndExit (dsd_opts * opts, dsd_state * state);
|
||||
void sigfun (int sig);
|
||||
int main (int argc, char **argv);
|
||||
void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv);
|
||||
void processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24]);
|
||||
void openSerial (dsd_opts * opts, dsd_state * state);
|
||||
void resumeScan (dsd_opts * opts, dsd_state * state);
|
||||
int getSymbol (dsd_opts * opts, dsd_state * state, int have_sync);
|
||||
void upsample (dsd_state * state, float invalue);
|
||||
void processDSTAR (dsd_opts * opts, dsd_state * state);
|
||||
void processNXDNVoice (dsd_opts * opts, dsd_state * state);
|
||||
void processNXDNData (dsd_opts * opts, dsd_state * state);
|
||||
void processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo);
|
||||
void processHDU (dsd_opts * opts, dsd_state * state);
|
||||
void processLDU1 (dsd_opts * opts, dsd_state * state);
|
||||
void processLDU2 (dsd_opts * opts, dsd_state * state);
|
||||
void processTDU (dsd_opts * opts, dsd_state * state);
|
||||
void processTDULC (dsd_opts * opts, dsd_state * state);
|
||||
void processProVoice (dsd_opts * opts, dsd_state * state);
|
||||
void processX2TDMAdata (dsd_opts * opts, dsd_state * state);
|
||||
void processX2TDMAvoice (dsd_opts * opts, dsd_state * state);
|
||||
void processDSTAR_HD (dsd_opts * opts, dsd_state * state);
|
||||
short dmr_filter(short sample);
|
||||
short nxdn_filter(short sample);
|
||||
|
||||
#endif // DSD_H
|
||||
129
include/dstar_const.h
Normal file
129
include/dstar_const.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* dstar interleave experiments
|
||||
*/
|
||||
|
||||
#ifndef _MAIN
|
||||
|
||||
extern const int dW[72];
|
||||
extern const int dX[72];
|
||||
|
||||
#else
|
||||
const int dW[72] = {
|
||||
|
||||
// 0-11
|
||||
0, 0,
|
||||
3, 2,
|
||||
1, 1,
|
||||
0, 0,
|
||||
1, 1,
|
||||
0, 0,
|
||||
|
||||
// 12-23
|
||||
3, 2,
|
||||
1, 1,
|
||||
3, 2,
|
||||
1, 1,
|
||||
0, 0,
|
||||
3, 2,
|
||||
|
||||
// 24-35
|
||||
0, 0,
|
||||
3, 2,
|
||||
1, 1,
|
||||
0, 0,
|
||||
1, 1,
|
||||
0, 0,
|
||||
|
||||
// 36-47
|
||||
3, 2,
|
||||
1, 1,
|
||||
3, 2,
|
||||
1, 1,
|
||||
0, 0,
|
||||
3, 2,
|
||||
|
||||
// 48-59
|
||||
0, 0,
|
||||
3, 2,
|
||||
1, 1,
|
||||
0, 0,
|
||||
1, 1,
|
||||
0, 0,
|
||||
|
||||
// 60-71
|
||||
3, 2,
|
||||
1, 1,
|
||||
3, 3,
|
||||
2, 1,
|
||||
0, 0,
|
||||
3, 3,
|
||||
};
|
||||
const int dX[72] = {
|
||||
|
||||
// 0-11
|
||||
10, 22,
|
||||
11, 9,
|
||||
10, 22,
|
||||
11, 23,
|
||||
8, 20,
|
||||
9, 21,
|
||||
|
||||
// 12-23
|
||||
10, 8,
|
||||
9, 21,
|
||||
8, 6,
|
||||
7, 19,
|
||||
8, 20,
|
||||
9, 7,
|
||||
|
||||
// 24-35
|
||||
6, 18,
|
||||
7, 5,
|
||||
6, 18,
|
||||
7, 19,
|
||||
4, 16,
|
||||
5, 17,
|
||||
|
||||
// 36-47
|
||||
6, 4,
|
||||
5, 17,
|
||||
4, 2,
|
||||
3, 15,
|
||||
4, 16,
|
||||
5, 3,
|
||||
|
||||
// 48-59
|
||||
2, 14,
|
||||
3, 1,
|
||||
2, 14,
|
||||
3, 15,
|
||||
0, 12,
|
||||
1, 13,
|
||||
|
||||
// 60-71
|
||||
2, 0,
|
||||
1, 13,
|
||||
0, 12,
|
||||
10, 11,
|
||||
0, 12,
|
||||
1, 13,
|
||||
};
|
||||
|
||||
#endif
|
||||
6
include/dstar_header.h
Normal file
6
include/dstar_header.h
Normal file
@@ -0,0 +1,6 @@
|
||||
/* This is the header file for dstar_header.c, which is under the GPL. */
|
||||
|
||||
#ifndef _DSTAR_HEADER_H
|
||||
#define _DSTAR_HEADER_H
|
||||
void dstar_header_decode(int radioheaderbuffer[660]);
|
||||
#endif /* _DSTAR_HEADER_H */
|
||||
89
include/fcs.h
Normal file
89
include/fcs.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/* fcs.h */
|
||||
|
||||
// Viterbi decoder using Traceback method.
|
||||
|
||||
// Original Source was written by Sho Tamaoki and Tom Wada
|
||||
// See http://www.lsi.ie.u-ryukyu.ac.jp/~sho/midterm/
|
||||
// Modified by Satoshi Yasuda 7m3tjz/ad6gz
|
||||
// Modified by Jonathan Nayor, G4KLX (C) 2009
|
||||
|
||||
// Converted from C++ to C by Kristoff Bonne, ON1ARF
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010 by Kristoff Bonne, ON1ARF
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static const unsigned short ccittTab[] = {
|
||||
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
|
||||
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
|
||||
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
|
||||
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
|
||||
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
|
||||
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
|
||||
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
|
||||
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
|
||||
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
|
||||
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
|
||||
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
|
||||
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
|
||||
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
|
||||
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
|
||||
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
|
||||
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
|
||||
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
|
||||
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
|
||||
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
|
||||
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
|
||||
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
|
||||
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
|
||||
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
|
||||
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
|
||||
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
|
||||
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
|
||||
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
|
||||
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
|
||||
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
|
||||
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
|
||||
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
|
||||
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78};
|
||||
|
||||
|
||||
uint16_t calc_fcs (unsigned char * dvstartframe, int size) {
|
||||
// this function calculated the CRC-values of a DSTAR digital
|
||||
// voice frame. It calculates this value on octets 0 up to 38 of the D-STAR
|
||||
// radio header (fields flag1, flag2, flag3, destination, departure, companion,
|
||||
// own1 and own2)
|
||||
uint16_t m_crc;
|
||||
int loop;
|
||||
unsigned short tmp;
|
||||
|
||||
m_crc=0xFFFF;
|
||||
|
||||
for (loop=0; loop < size; loop++) {
|
||||
tmp = (m_crc & 0x00ff) ^ dvstartframe[loop];
|
||||
|
||||
m_crc = (m_crc >> 8) ^ ccittTab[tmp];
|
||||
|
||||
}; // end for
|
||||
|
||||
// calculate and save crc-value in fields 54 and 55 of dvframe
|
||||
m_crc = ~m_crc;
|
||||
|
||||
tmp = m_crc;
|
||||
m_crc = (m_crc << 8) | (tmp >> 8 & 0xFF);
|
||||
|
||||
|
||||
// done
|
||||
return(m_crc);
|
||||
}; // end function
|
||||
1
include/git_ver.h
Normal file
1
include/git_ver.h
Normal file
@@ -0,0 +1 @@
|
||||
extern const char GIT_TAG[];
|
||||
62
include/nxdn96_const.h
Normal file
62
include/nxdn96_const.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NXDN AMBE interleave schedule
|
||||
*/
|
||||
|
||||
#ifndef _MAIN
|
||||
extern const int nW[36];
|
||||
extern const int nX[36];
|
||||
extern const int nY[36];
|
||||
extern const int nZ[36];
|
||||
|
||||
#else
|
||||
|
||||
const int nW[36] = { 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 2,
|
||||
0, 2, 0, 2, 0, 2,
|
||||
0, 2, 0, 2, 0, 2
|
||||
};
|
||||
|
||||
const int nX[36] = { 23, 10, 22, 9, 21, 8,
|
||||
20, 7, 19, 6, 18, 5,
|
||||
17, 4, 16, 3, 15, 2,
|
||||
14, 1, 13, 0, 12, 10,
|
||||
11, 9, 10, 8, 9, 7,
|
||||
8, 6, 7, 5, 6, 4
|
||||
};
|
||||
|
||||
const int nY[36] = { 0, 2, 0, 2, 0, 2,
|
||||
0, 2, 0, 3, 0, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3
|
||||
};
|
||||
|
||||
const int nZ[36] = { 5, 3, 4, 2, 3, 1,
|
||||
2, 0, 1, 13, 0, 12,
|
||||
22, 11, 21, 10, 20, 9,
|
||||
19, 8, 18, 7, 17, 6,
|
||||
16, 5, 15, 4, 14, 3,
|
||||
13, 2, 12, 1, 11, 0
|
||||
};
|
||||
|
||||
#endif
|
||||
66
include/nxdn_const.h
Normal file
66
include/nxdn_const.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _MAIN
|
||||
extern const int nW[36];
|
||||
extern const int nX[36];
|
||||
extern const int nY[36];
|
||||
extern const int nZ[36];
|
||||
extern const char nxdnpr[145];
|
||||
|
||||
#else
|
||||
/*
|
||||
* pseudorandom bit sequence
|
||||
*/
|
||||
const char nxdnpr[145] = { 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1 };
|
||||
|
||||
/*
|
||||
* NXDN AMBE interleave schedule
|
||||
*/
|
||||
const int nW[36] = { 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 2,
|
||||
0, 2, 0, 2, 0, 2,
|
||||
0, 2, 0, 2, 0, 2
|
||||
};
|
||||
|
||||
const int nX[36] = { 23, 10, 22, 9, 21, 8,
|
||||
20, 7, 19, 6, 18, 5,
|
||||
17, 4, 16, 3, 15, 2,
|
||||
14, 1, 13, 0, 12, 10,
|
||||
11, 9, 10, 8, 9, 7,
|
||||
8, 6, 7, 5, 6, 4
|
||||
};
|
||||
|
||||
const int nY[36] = { 0, 2, 0, 2, 0, 2,
|
||||
0, 2, 0, 3, 0, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3
|
||||
};
|
||||
|
||||
const int nZ[36] = { 5, 3, 4, 2, 3, 1,
|
||||
2, 0, 1, 13, 0, 12,
|
||||
22, 11, 21, 10, 20, 9,
|
||||
19, 8, 18, 7, 17, 6,
|
||||
16, 5, 15, 4, 14, 3,
|
||||
13, 2, 12, 1, 11, 0
|
||||
};
|
||||
|
||||
#endif
|
||||
60
include/p25p1_check_hdu.h
Normal file
60
include/p25p1_check_hdu.h
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
#ifndef P25P1_CHECK_HDU_H_f5f079faf2d64cf5831e1da1ab83b9ba
|
||||
#define P25P1_CHECK_HDU_H_f5f079faf2d64cf5831e1da1ab83b9ba
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Attempts to correct an hex (6-bit) word using the Golay(24,12,8) FEC.
|
||||
* \param hex The 6-bit word to error correct, given as a char array of 6 elements, one bit each.
|
||||
* \param parity A 12-bit word with the Golay parity data, given as a char array of 12 elements.
|
||||
* \param fixed_error Output. Filled with the number of errors fixed in the input.
|
||||
* \return 1 if there were uncorrectable errors in the input, 0 otherwise.
|
||||
*/
|
||||
int check_and_fix_golay_24_6(char* hex, char* parity, int* fixed_errors);
|
||||
|
||||
/**
|
||||
* Attempts to correct a 12-bit word using the Golay(24,12,8) FEC.
|
||||
* \param dodeca The 12-bit word to error correct, given as a char array of 12 elements, one bit each.
|
||||
* \param parity A 12-bit word with the Golay parity data, given as a char array of 12 elements.
|
||||
* \param fixed_error Output. Filled with the number of errors fixed in the input.
|
||||
* \return 1 if there were uncorrectable errors in the input, 0 otherwise.
|
||||
*/
|
||||
int check_and_fix_golay_24_12(char* dodeca, char* parity, int* fixed_errors);
|
||||
|
||||
/**
|
||||
* Encodes an hex word using the Golay(24,12,8) FEC.
|
||||
* \param hex A 6-bit word to encode.
|
||||
* \param out_parity The address to be filled with the calculated Golay parity.
|
||||
*/
|
||||
void encode_golay_24_6(char* hex, char* out_parity);
|
||||
|
||||
/**
|
||||
* Encodes an 12-bitword using the Golay(24,12,8) FEC.
|
||||
* \param dodeca A 12-bit word to encode.
|
||||
* \param out_parity The address to be filled with the calculated Golay parity.
|
||||
*/
|
||||
void encode_golay_24_12(char* dodeca, char* out_parity);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
int check_and_fix_redsolomon_36_20_17(char* data, char* parity);
|
||||
|
||||
/**
|
||||
* Calculates the Reed-Solomon parity of 20 words of 6 bits each.
|
||||
* \param hex_data The address with the words whose parity we want to calculate.
|
||||
* \param fixed_parity The address to be filled with the calculated parity. 16 words of 6 bits are produced.
|
||||
*/
|
||||
void encode_reedsolomon_36_20_17(char* hex_data, char* fixed_parity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // P25P1_CHECK_HDU_H_f5f079faf2d64cf5831e1da1ab83b9ba
|
||||
58
include/p25p1_check_ldu.h
Normal file
58
include/p25p1_check_ldu.h
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
#ifndef P25P1_CHECK_LDU_H_c1734445a67e47caa25673d7a4ce7520
|
||||
#define P25P1_CHECK_LDU_H_c1734445a67e47caa25673d7a4ce7520
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Attempts to error correct a hex (6-bit) word using the Hamming(10,6,3) FEC.
|
||||
* \param hex The 6-bit word to error correct.
|
||||
* \param parity The parity to use in the error correction. 4 bits.
|
||||
* \return The estimated error count. It might be erroneous.
|
||||
*/
|
||||
int check_and_fix_hamming_10_6_3(char* hex, char* parity);
|
||||
|
||||
/**
|
||||
* Encodes an hex word with the Hamming(10,6,3) FEC.
|
||||
* \param hex The 6-bit word to error correct.
|
||||
* \param out_parity The address where to store the calculated parity. 4 bytes are used, one for each bit.
|
||||
*/
|
||||
void encode_hamming_10_6_3(char* hex, char* out_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_reedsolomon_24_12_13(char* data, char* parity);
|
||||
|
||||
/**
|
||||
* Encodes 12 hex words with the Reed-Solomon(24,12,13) FEC.
|
||||
* \param hex_data The packed 12 hex words to encode.
|
||||
* \fixed_parity The address were to store the 12 hex words with the Reed-Solomon parity.
|
||||
*/
|
||||
void encode_reedsolomon_24_12_13(char* hex_data, char* fixed_parity);
|
||||
|
||||
/**
|
||||
* Attempts to correct 16 hex words using the Reed-Solomon(24,16,9) FEC.
|
||||
* \param data The packed 16 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_reedsolomon_24_16_9(char* data, char* parity);
|
||||
|
||||
/**
|
||||
* Encodes 12 hex words with the Reed-Solomon(24,16,9) FEC.
|
||||
* \param hex_data The packed 16 hex words to encode.
|
||||
* \fixed_parity The address were to store the 8 hex words with the Reed-Solomon parity.
|
||||
*/
|
||||
void encode_reedsolomon_24_16_9(char* hex_data, char* fixed_parity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // P25P1_CHECK_LDU_H_c1734445a67e47caa25673d7a4ce7520
|
||||
26
include/p25p1_check_nid.h
Normal file
26
include/p25p1_check_nid.h
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
#ifndef P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
||||
#define P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Checks a NID value, returns the fixed NAC, DUID and also an indication if it failed to decode the NID.
|
||||
* \param bch_code Input. An array to the 63 bytes, each containing one bit of the NID. This includes the
|
||||
* NAC (12 bits), DUID (4 bits) and 47 bits of BCH parity.
|
||||
* \param new_nac Output. An address where to store the calculated NAC value after error correction. Should
|
||||
* be large enough to accommodate for an integer.
|
||||
* \param new_duid Output. An address where to store the calculated DUID value after error correction. Should
|
||||
* be able to accommodate 3 chars.
|
||||
* \param parity Input. The parity value read.
|
||||
* \return 0 if there were errors processing the NID.
|
||||
*/
|
||||
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
||||
89
include/p25p1_const.h
Normal file
89
include/p25p1_const.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _MAIN
|
||||
|
||||
extern const int iW[72];
|
||||
extern const int iX[72];
|
||||
extern const int iY[72];
|
||||
extern const int iZ[72];
|
||||
|
||||
#else
|
||||
/*
|
||||
* P25 Phase1 IMBE interleave schedule
|
||||
*/
|
||||
|
||||
const int iW[72] = {
|
||||
0, 2, 4, 1, 3, 5,
|
||||
0, 2, 4, 1, 3, 6,
|
||||
0, 2, 4, 1, 3, 6,
|
||||
0, 2, 4, 1, 3, 6,
|
||||
0, 2, 4, 1, 3, 6,
|
||||
0, 2, 4, 1, 3, 6,
|
||||
0, 2, 5, 1, 3, 6,
|
||||
0, 2, 5, 1, 3, 6,
|
||||
0, 2, 5, 1, 3, 7,
|
||||
0, 2, 5, 1, 3, 7,
|
||||
0, 2, 5, 1, 4, 7,
|
||||
0, 3, 5, 2, 4, 7
|
||||
};
|
||||
|
||||
const int iX[72] = {
|
||||
22, 20, 10, 20, 18, 0,
|
||||
20, 18, 8, 18, 16, 13,
|
||||
18, 16, 6, 16, 14, 11,
|
||||
16, 14, 4, 14, 12, 9,
|
||||
14, 12, 2, 12, 10, 7,
|
||||
12, 10, 0, 10, 8, 5,
|
||||
10, 8, 13, 8, 6, 3,
|
||||
8, 6, 11, 6, 4, 1,
|
||||
6, 4, 9, 4, 2, 6,
|
||||
4, 2, 7, 2, 0, 4,
|
||||
2, 0, 5, 0, 13, 2,
|
||||
0, 21, 3, 21, 11, 0
|
||||
};
|
||||
|
||||
const int iY[72] = {
|
||||
1, 3, 5, 0, 2, 4,
|
||||
1, 3, 6, 0, 2, 4,
|
||||
1, 3, 6, 0, 2, 4,
|
||||
1, 3, 6, 0, 2, 4,
|
||||
1, 3, 6, 0, 2, 4,
|
||||
1, 3, 6, 0, 2, 5,
|
||||
1, 3, 6, 0, 2, 5,
|
||||
1, 3, 6, 0, 2, 5,
|
||||
1, 3, 6, 0, 2, 5,
|
||||
1, 3, 7, 0, 2, 5,
|
||||
1, 4, 7, 0, 3, 5,
|
||||
2, 4, 7, 1, 3, 5
|
||||
};
|
||||
|
||||
const int iZ[72] = {
|
||||
21, 19, 1, 21, 19, 9,
|
||||
19, 17, 14, 19, 17, 7,
|
||||
17, 15, 12, 17, 15, 5,
|
||||
15, 13, 10, 15, 13, 3,
|
||||
13, 11, 8, 13, 11, 1,
|
||||
11, 9, 6, 11, 9, 14,
|
||||
9, 7, 4, 9, 7, 12,
|
||||
7, 5, 2, 7, 5, 10,
|
||||
5, 3, 0, 5, 3, 8,
|
||||
3, 1, 5, 3, 1, 6,
|
||||
1, 14, 3, 1, 22, 4,
|
||||
22, 12, 1, 22, 20, 2
|
||||
};
|
||||
#endif
|
||||
73
include/p25p1_hdu.h
Normal file
73
include/p25p1_hdu.h
Normal file
@@ -0,0 +1,73 @@
|
||||
|
||||
#ifndef P25P1_HDU_H_9f95c3a5072842e8aaf94444e1452d20
|
||||
#define P25P1_HDU_H_9f95c3a5072842e8aaf94444e1452d20
|
||||
|
||||
|
||||
#include "p25p1_heuristics.h"
|
||||
|
||||
/**
|
||||
* Reads a dibit (two bits) from the stream of data. Takes into account the periodic occurrence of status
|
||||
* bits that show up every 36 dibits. Status bits are discarded.
|
||||
* \param opts A pointer the the DSD options.
|
||||
* \param state A pointer the the DSD state structure.
|
||||
* \param output A pointer to be filled with the dibit read. Two bytes used for each dibit.
|
||||
* \param status_count Variable used to keep track of the status symbols in the dibit stream. There is one
|
||||
* status every 36 dibits. With this counter we can skip the status.
|
||||
* \param analog_signal A pointer with the actual analog value read from the input signal and that has been
|
||||
* interpreted as the dibit we are returning in output.
|
||||
* \param did_read_status Address were a boolean is returned. This is set to true when one status symbol was
|
||||
* read (and skipped). This indicates that the sequence on dibits has been broken and is used by the P25
|
||||
* heuristics.
|
||||
*/
|
||||
int read_dibit (dsd_opts* opts, dsd_state* state, char* output, int* status_count, int* analog_signal,
|
||||
int* did_read_status);
|
||||
|
||||
/**
|
||||
* Reads a number of dibits and stores its value together with the actual analog value that has been
|
||||
* intrepreted as the dibit into an AnalogSignal structure. This is used later in the P25 heuristics module
|
||||
* to improve the accuracy of the digitizer.
|
||||
* \param opts A pointer the the DSD options.
|
||||
* \param state A pointer the the DSD state structure.
|
||||
* \param output A pointer to be filled with the dibits read.
|
||||
* \param count The number of bits to read (remember: 1 dibit = 2 bits).
|
||||
* \param status_count Variable used to keep track of the status symbols in the dibit stream. There is one
|
||||
* status every 36 dibits. With this counter we can skip the status.
|
||||
* \param analog_signal_array The pointer to the start of a sequence of AnalogSignal structures. The
|
||||
* information is updated for each dibit read.
|
||||
* \param analog_signal_index The actual index into the AnalogSignal array. This is increased here wich each
|
||||
* dibit read.
|
||||
*/
|
||||
void read_dibit_update_analog_data (dsd_opts* opts, dsd_state* state, char* buffer, unsigned int count,
|
||||
int* status_count, AnalogSignal* analog_signal_array, int* analog_signal_index);
|
||||
|
||||
/**
|
||||
* Reads a word, made up of length bits or length/2 dibits. Also keeps track of the status dibits.
|
||||
*/
|
||||
void read_word (dsd_opts* opts, dsd_state* state, char* word, unsigned int length, int* status_count,
|
||||
AnalogSignal* analog_signal_array, int* analog_signal_index);
|
||||
|
||||
/**
|
||||
* Reads 4 bits from the stream of data. Those are the parity bits that follow each hex word.
|
||||
*/
|
||||
void read_hamm_parity (dsd_opts* opts, dsd_state* state, char* parity, int* status_count,
|
||||
AnalogSignal* analog_signal_array, int* analog_signal_index);
|
||||
|
||||
/**
|
||||
* Reads 12 bits from the stream of data. Those are the extended Golay parity bits that follow a word of data.
|
||||
*/
|
||||
void read_golay24_parity (dsd_opts* opts, dsd_state* state, char* parity, int* status_count, AnalogSignal* analog_signal_array, int* analog_signal_index);
|
||||
|
||||
/**
|
||||
* Reads bits from the data stream that should all be zeros. This is valuable information for the
|
||||
* heuristics module and we update it.
|
||||
* \param opts A pointer the the DSD options.
|
||||
* \param state A pointer the the DSD state structure.
|
||||
* \param analog_signal_array The pointer to the start of a sequence of AnalogSignal structures.
|
||||
* \param length Number of bits to read.
|
||||
* \param status_count Variable used to keep track of the status symbols in the dibit stream.
|
||||
* \param new_sequence Bool used to update the sequence_broken value of the first AnalogSignal element.
|
||||
*/
|
||||
void read_zeros(dsd_opts* opts, dsd_state* state, AnalogSignal* analog_signal_array, unsigned int length,
|
||||
int* status_count, int new_sequence);
|
||||
|
||||
#endif // P25P1_HDU_H_9f95c3a5072842e8aaf94444e1452d20
|
||||
91
include/p25p1_heuristics.h
Normal file
91
include/p25p1_heuristics.h
Normal file
@@ -0,0 +1,91 @@
|
||||
|
||||
#ifndef P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6
|
||||
#define P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6
|
||||
|
||||
#define HEURISTICS_SIZE 200
|
||||
typedef struct
|
||||
{
|
||||
int values[HEURISTICS_SIZE];
|
||||
float means[HEURISTICS_SIZE];
|
||||
int index;
|
||||
int count;
|
||||
float sum;
|
||||
float var_sum;
|
||||
} SymbolHeuristics;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int bit_count;
|
||||
unsigned int bit_error_count;
|
||||
SymbolHeuristics symbols[4][4];
|
||||
} P25Heuristics;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int value;
|
||||
int dibit;
|
||||
int corrected_dibit;
|
||||
int sequence_broken;
|
||||
} AnalogSignal;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initializes the heuristics state.
|
||||
* \param heuristics The P25Heuristics structure to initialize.
|
||||
*/
|
||||
void initialize_p25_heuristics(P25Heuristics* heuristics);
|
||||
|
||||
/**
|
||||
* Important method that estimates the most likely symbol for a given analog signal value and previous dibit.
|
||||
* This is called by the digitizer.
|
||||
* \param rf_mod Indicates the modulation used. The previous dibit is only used on C4FM.
|
||||
* \param heuristics Pointer to the P25Heuristics module with all the needed state information.
|
||||
* \param previous_dibit The previous dibit.
|
||||
* \param analog_value The signal's analog value we want to interpret as a dibit.
|
||||
* \param dibit Address were to store the estimated dibit.
|
||||
* \return A boolean set to true if we are able to estimate a dibit. The reason why we might not be able
|
||||
* to estimate it is because we don't have enough information to model the Gaussians (not enough data
|
||||
* has been passed to contribute_to_heuristics).
|
||||
*/
|
||||
int estimate_symbol(int rf_mod, P25Heuristics* heuristics, int previous_dibit, int analog_value, int* dibit);
|
||||
|
||||
/**
|
||||
* Log some useful information on the heuristics state.
|
||||
*/
|
||||
void debug_print_heuristics(P25Heuristics* heuristics);
|
||||
|
||||
/**
|
||||
* This method contributes valuable information from dibits whose value we are confident is correct. We take
|
||||
* the dibits and corresponding analog signal values to model the Gaussians for each dibit (and previous
|
||||
* dibit if enabled).
|
||||
* \param rf_mod Indicates the modulation used. The previous dibit is only used on C4FM.
|
||||
* \param heuristics Pointer to the P25Heuristics module with all the needed state information.
|
||||
* \param analog_signal_array Sequence of AnalogSignal which contain the cleared dibits and analog values.
|
||||
* \param count number of cleared dibits passed (= number of elements to use from analog_signal_array).
|
||||
*/
|
||||
void contribute_to_heuristics(int rf_mod, P25Heuristics* heuristics, AnalogSignal* analog_signal_array, int count);
|
||||
|
||||
/**
|
||||
* Updates the estimate for the BER (bit error rate). Mind this is method is not called for every single
|
||||
* bit in the data stream but only for those bits over which we have an estimate of its error rate,
|
||||
* specifically the bits that are protected by Reed-Solomon codes.
|
||||
* \param heuristics The heuristics state.
|
||||
* \param bits The number of bits we have read.
|
||||
* \param errors The number of errors we estimate in those bits.
|
||||
*/
|
||||
void update_error_stats(P25Heuristics* heuristics, int bits, int errors);
|
||||
|
||||
/**
|
||||
* Returns the estimate for the BER (bit error rate).
|
||||
* \return The estimated BER. This is just the percentage of errors over the processed bits.
|
||||
*/
|
||||
float get_P25_BER_estimate(P25Heuristics* heuristics);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6
|
||||
49
include/p25p1_ldu.h
Normal file
49
include/p25p1_ldu.h
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
#ifndef P25P1_LDU_H_a3c417fcb7804991b0e6d828066bd133
|
||||
#define P25P1_LDU_H_a3c417fcb7804991b0e6d828066bd133
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
#include "p25p1_hdu.h"
|
||||
#include "p25p1_const.h"
|
||||
#include "p25p1_heuristics.h"
|
||||
|
||||
/**
|
||||
* Separate imbe frames and deinterleave.
|
||||
* This important methods read the IMBE data from the stream and passes it to the vocoder to produce audio.
|
||||
* \param opts The DSD options.
|
||||
* \param state The DSD state.
|
||||
* \status_count An index that allows us to skip the status words interleaved every 36 dibit in the data
|
||||
* stream.
|
||||
*/
|
||||
void process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count);
|
||||
|
||||
/**
|
||||
* Reads an hex word, its parity bits and attempts to error correct it using the Hamming FEC.
|
||||
* \param opts The DSD options.
|
||||
* \param state The DSD state.
|
||||
* \param hex Pointer where to store the read hex word. Six bytes, one per bit.
|
||||
* \param status_count An index that allows us to skip the status words interleaved every 36 dibit in the data
|
||||
* stream.
|
||||
* \param analog_singal_array Pointer to a sequence of AnalogSignal elements.
|
||||
* \param analog_signal_index The current index in the analog_singal_array. This value is increased on each
|
||||
* dibit read.
|
||||
*/
|
||||
void read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count,
|
||||
AnalogSignal* analog_signal_array, int* analog_signal_index);
|
||||
|
||||
/**
|
||||
* Correct the information in analog_signal_array according with the content of data, which has been
|
||||
* error corrected and should be valid.
|
||||
* \param Dibits that have already been error corrected and we trust are correct.
|
||||
* \count Number of dibits.
|
||||
* \param analog_signal_array Pointer to a sequence of AnalogSignal elements, as many as the value of count.
|
||||
*/
|
||||
void correct_hamming_dibits(char* hex_data, int hex_count, AnalogSignal* analog_signal_array);
|
||||
|
||||
/**
|
||||
* Logs some debug info.
|
||||
*/
|
||||
void debug_ldu_header(dsd_state* state);
|
||||
|
||||
#endif // P25P1_LDU_H_a3c417fcb7804991b0e6d828066bd133
|
||||
6
include/pa_devs.h
Normal file
6
include/pa_devs.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef PA_DEVS_H
|
||||
#define PA_DEVS_H
|
||||
|
||||
void printPortAudioDevices();
|
||||
|
||||
#endif
|
||||
81
include/provoice_const.h
Normal file
81
include/provoice_const.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _MAIN
|
||||
|
||||
extern const int pW[142];
|
||||
extern const int pX[142];
|
||||
|
||||
#else
|
||||
/*
|
||||
* ProVoice IMBE interleave schedule
|
||||
*/
|
||||
|
||||
const int pW[142] = {
|
||||
0, 1, 2, 3, 4, 6,
|
||||
0, 1, 2, 3, 4, 6,
|
||||
0, 1, 2, 3, 4, 6,
|
||||
0, 1, 2, 3, 5, 6,
|
||||
0, 1, 2, 3, 5, 6,
|
||||
0, 1, 2, 3, 5, 6,
|
||||
0, 1, 3, 4, 5, 6,
|
||||
1, 2, 3, 4, 5, 6,
|
||||
0, 1, 2, 3, 4, 6,
|
||||
0, 1, 2, 3, 4, 6,
|
||||
0, 1, 2, 3, 4, 6,
|
||||
0, 1, 2, 3, 5, 6,
|
||||
0, 1, 2, 3, 5, 6,
|
||||
0, 1, 2, 3, 5, 6,
|
||||
1, 2, 3, 4, 5, 6,
|
||||
1, 2, 3, 4, 5,
|
||||
0, 1, 2, 3, 4, 6,
|
||||
0, 1, 2, 3, 4, 6,
|
||||
0, 1, 2, 3, 5, 6,
|
||||
0, 1, 2, 3, 5, 6,
|
||||
0, 1, 2, 3, 5, 6,
|
||||
0, 1, 2, 4, 5, 6,
|
||||
1, 2, 3, 4, 5, 6,
|
||||
1, 2, 3, 4, 6
|
||||
};
|
||||
|
||||
const int pX[142] = {
|
||||
18, 18, 17, 16, 7, 21,
|
||||
15, 15, 14, 13, 4, 18,
|
||||
12, 12, 11, 10, 1, 15,
|
||||
9, 9, 8, 7, 13, 12,
|
||||
6, 6, 5, 4, 10, 9,
|
||||
3, 3, 2, 1, 7, 6,
|
||||
0, 0, 22, 13, 4, 3,
|
||||
21, 20, 19, 10, 1, 0,
|
||||
17, 17, 16, 15, 6, 20,
|
||||
14, 14, 13, 12, 3, 17,
|
||||
11, 11, 10, 9, 0, 14,
|
||||
8, 8, 7, 6, 12, 11,
|
||||
5, 5, 4, 3, 9, 8,
|
||||
2, 2, 1, 0, 6, 5,
|
||||
23, 22, 21, 12, 3, 2,
|
||||
20, 19, 18, 9, 0,
|
||||
16, 16, 15, 14, 5, 19,
|
||||
13, 13, 12, 11, 2, 16,
|
||||
10, 10, 9, 8, 14, 13,
|
||||
7, 7, 6, 5, 11, 10,
|
||||
4, 4, 3, 2, 8, 7,
|
||||
1, 1, 0, 14, 5, 4,
|
||||
22, 21, 20, 11, 2, 1,
|
||||
19, 18, 17, 8, 22
|
||||
};
|
||||
#endif
|
||||
62
include/x2tdma_const.h
Normal file
62
include/x2tdma_const.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* X2TDMA AMBE interleave schedule
|
||||
*/
|
||||
|
||||
#ifndef _MAIN
|
||||
extern const int aW[36];
|
||||
extern const int aX[36];
|
||||
extern const int aY[36];
|
||||
extern const int aZ[36];
|
||||
|
||||
#else
|
||||
|
||||
const int aW[36] = { 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 2,
|
||||
0, 2, 0, 2, 0, 2,
|
||||
0, 2, 0, 2, 0, 2
|
||||
};
|
||||
|
||||
const int aX[36] = { 23, 10, 22, 9, 21, 8,
|
||||
20, 7, 19, 6, 18, 5,
|
||||
17, 4, 16, 3, 15, 2,
|
||||
14, 1, 13, 0, 12, 10,
|
||||
11, 9, 10, 8, 9, 7,
|
||||
8, 6, 7, 5, 6, 4
|
||||
};
|
||||
|
||||
const int aY[36] = { 0, 2, 0, 2, 0, 2,
|
||||
0, 2, 0, 3, 0, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3
|
||||
};
|
||||
|
||||
const int aZ[36] = { 5, 3, 4, 2, 3, 1,
|
||||
2, 0, 1, 13, 0, 12,
|
||||
22, 11, 21, 10, 20, 9,
|
||||
19, 8, 18, 7, 17, 6,
|
||||
16, 5, 15, 4, 14, 3,
|
||||
13, 2, 12, 1, 11, 0
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user