Added code for table based correction of bit errors. Code is not called yet except initialisation.

This commit is contained in:
Ulrich Kuehn 2013-05-12 17:33:44 +02:00
parent f56679a61d
commit 0a4fc6e98f

View file

@ -329,6 +329,7 @@ void modesSendSBSOutput(struct modesMessage *mm);
void useModesMessage(struct modesMessage *mm); void useModesMessage(struct modesMessage *mm);
int fixSingleBitErrors(unsigned char *msg, int bits); int fixSingleBitErrors(unsigned char *msg, int bits);
int fixTwoBitsErrors(unsigned char *msg, int bits); int fixTwoBitsErrors(unsigned char *msg, int bits);
void modesInitErrorInfo();
int modesMessageLenByType(int type); int modesMessageLenByType(int type);
/* ============================= Utility functions ========================== */ /* ============================= Utility functions ========================== */
@ -461,6 +462,9 @@ void modesInit(void) {
Modes.maglut[(i*256)+q] = (uint16_t) ((mag < 65535) ? mag : 65535); Modes.maglut[(i*256)+q] = (uint16_t) ((mag < 65535) ? mag : 65535);
} }
} }
/* Prepare error correction tables */
modesInitErrorInfo();
} }
/* =============================== RTLSDR handling ========================== */ /* =============================== RTLSDR handling ========================== */
@ -1207,6 +1211,185 @@ int fixTwoBitsErrors(unsigned char *msg, int bits) {
return (-1); return (-1);
} }
/* Code for introducing a less CPU-intensive method of correcting
* single bit errors.
*
* Makes use of the fact that the crc checksum is linear with respect to
* the bitwise xor operation, i.e.
* crc(m^e) = (crc(m)^crc(e)
* where m and e are the message resp. error bit vectors.
*
* Call crc(e) the syndrome.
*
* The code below works by precomputing a table of (crc(e), e) for all
* possible error vectors e (here only single bit and double bit errors),
* search for the syndrome in the table, and correct the then known error.
* The error vector e is represented by one or two bit positions that are
* changed. If a second bit position is not used, it is -1.
*
* Run-time is binary search in a sorted table, plus some constant overhead,
* instead of running through all possible bit positions (resp. pairs of
* bit positions).
*
*
*
*/
struct errorinfo {
uint32_t syndrome; /* CRC syndrome */
int pos0; /* bit position of first error */
int pos1; /* bit position of second error, or -1 */
};
#define NERRORINFO \
(MODES_LONG_MSG_BITS+MODES_LONG_MSG_BITS*(MODES_LONG_MSG_BITS-1)/2)
struct errorinfo bitErrorTable[NERRORINFO];
/* Compare function as needed for stdlib's qsort and bsearch functions */
int cmpErrorInfo(const void *p0, const void *p1) {
struct errorinfo *e0 = (struct errorinfo*)p0;
struct errorinfo *e1 = (struct errorinfo*)p1;
if (e0->syndrome == e1->syndrome) {
return 0;
} else if (e0->syndrome < e1->syndrome) {
return -1;
} else {
return 1;
}
}
/* Compute the table of all syndromes for 1-bit and 2-bit error vectors */
void modesInitErrorInfo() {
unsigned char msg[MODES_LONG_MSG_BYTES];
int i, j, n;
uint32_t crc;
n = 0;
memset(bitErrorTable, 0, sizeof(bitErrorTable));
/* First, insert infos about all possible single bit errors */
for (i = 0; i < MODES_LONG_MSG_BITS; i++) {
int bytepos = (i >> 3);
int mask = 1 << (7 - (i & 7));
memset(msg, 0, MODES_LONG_MSG_BYTES);
msg[bytepos] ^= mask;
crc = modesChecksum(msg, MODES_LONG_MSG_BITS);
bitErrorTable[n].syndrome = crc;
bitErrorTable[n].pos0 = i;
bitErrorTable[n].pos1 = -1;
n += 1;
}
/* Add also all double bit errors */
for (i = 0; i < MODES_LONG_MSG_BITS; i++) {
int bytepos0 = (i >> 3);
int mask0 = 1 << (7 - (i & 7));
memset(msg, 0, MODES_LONG_MSG_BYTES);
msg[bytepos0] ^= mask0;
for (j = i+1; j < MODES_LONG_MSG_BITS; j++) {
int bytepos1 = (j >> 3);
int mask1 = 1 << (7 - (j & 7));
msg[bytepos1] ^= mask1;
crc = modesChecksum(msg, MODES_LONG_MSG_BITS);
if (n >= NERRORINFO) {
/*
fprintf(stderr,
"Internal error, too many "
"entries, fix NERRORINFO\n");
*/
break;
}
bitErrorTable[n].syndrome = crc;
bitErrorTable[n].pos0 = i;
bitErrorTable[n].pos1 = j;
n += 1;
}
}
qsort(bitErrorTable, NERRORINFO,
sizeof(struct errorinfo), cmpErrorInfo);
/* Test code: report if any syndrome appears at least twice. In this
* case the correction cannot be done without ambiguity.
* Tried it, does not happen for 1- and 2-bit errors.
*/
/*
for (i = 1; i < NERRORINFO; i++) {
if (bitErrorTable[i-1].syndrome
== bitErrorTable[i].syndrome) {
fprintf(stderr, "modesInitErrorInfo: "
"Collision for syndrome %06x\n",
(int)bitErrorTable[i].syndrome);
}
}
*/
/*
for (i = 0; i < NERRORINFO; i++) {
printf("syndrome %06x bit0 %3d bit1 %3d\n",
bitErrorTable[i].syndrome,
bitErrorTable[i].pos0, bitErrorTable[i].pos1);
}
*/
}
/* Flip a bit, but make sure that the DF field (first 5 bits)
* is never changed
*/
int flipBit(unsigned char *msg, int nbits, int bit) {
int bytepos, mask;
if ((bit < 0) || (bit >= nbits)) {
return 0;
}
if (bit < 5) {
return 0;
}
bytepos = (bit >> 3);
mask = 1 << (7 - (bit & 7));
msg[bytepos] ^= mask;
return 1;
}
/* Search syndrome in table and, if an entry is found, flip the necessary
* bits. Make sure the indices fit into the array, and for 2-bit errors,
* are different.
* Return number of fixed bits.
*/
int fixBitErrors(unsigned char *msg, int bits) {
struct errorinfo *pei;
struct errorinfo ei;
int bitpos0, bitpos1, offset, res;
ei.syndrome = modesChecksum(msg, bits);
ei.pos0 = -1;
ei.pos1 = -1;
pei = bsearch(&ei, bitErrorTable, NERRORINFO,
sizeof(struct errorinfo), cmpErrorInfo);
if (pei == NULL) {
/* Nothing found */
return 0;
}
offset = MODES_LONG_MSG_BITS-bits;
bitpos0 = pei->pos0;
bitpos1 = pei->pos1;
res = 0;
if (bitpos1 >= 0) { /* two-bit error pattern */
bitpos0 -= offset;
bitpos1 -= offset;
if ((bitpos0 < 0) || (bitpos0 >= bits) ||
(bitpos1 < 0) || (bitpos1 >= bits)) {
return res;
}
res +=flipBit(msg, bits, bitpos0);
if (bitpos0 != bitpos1) {
res += flipBit(msg, bits, bitpos1);
return res;
}
return res;
} else {
bitpos0 -= offset;
if ((bitpos0 < 0) || (bitpos0 >= bits)) {
return res;
}
res += flipBit(msg, bits, bitpos0);
return res;
}
}
/* Hash the ICAO address to index our cache of MODES_ICAO_CACHE_LEN /* Hash the ICAO address to index our cache of MODES_ICAO_CACHE_LEN
* elements, that is assumed to be a power of two. */ * elements, that is assumed to be a power of two. */
uint32_t ICAOCacheHashAddress(uint32_t a) { uint32_t ICAOCacheHashAddress(uint32_t a) {