Changed algorithm to speed up fixSingleBitErrors() and fixTwoBitsErrors().

Old: Modify mesage, recalculate CRC, compare until a valid solution is found.
New: Calculate CRC, identify incorrect bits bits, correct message.
No recalculation if CRC is needed. Allows fixing of two bit errors on "slow" systems like RaspberryPi.
This commit is contained in:
Kalofin 2014-02-20 21:48:34 +01:00
parent fccf6e2e9e
commit 05c068ce9b

View File

@ -657,72 +657,104 @@ int modesMessageLenByType(int type) {
return MODES_SHORT_MSG_BITS;
}
/* Parity table for MODE S Messages. Same as above but with bits set for
* message bits containing the actual CRC.
*
* By xoring all the elements in this table for which the corresponding bit on
* the message is set to 1 the result is zero for messages with a valid crc.
*
*/
static const uint32_t modes_checksum_fix_table[112] = {
0x3935ea, 0x1c9af5, 0xf1b77e, 0x78dbbf, 0xc397db, 0x9e31e9, 0xb0e2f0, 0x587178,
0x2c38bc, 0x161c5e, 0x0b0e2f, 0xfa7d13, 0x82c48d, 0xbe9842, 0x5f4c21, 0xd05c14,
0x682e0a, 0x341705, 0xe5f186, 0x72f8c3, 0xc68665, 0x9cb936, 0x4e5c9b, 0xd8d449,
0x939020, 0x49c810, 0x24e408, 0x127204, 0x093902, 0x049c81, 0xfdb444, 0x7eda22,
0x3f6d11, 0xe04c8c, 0x702646, 0x381323, 0xe3f395, 0x8e03ce, 0x4701e7, 0xdc7af7,
0x91c77f, 0xb719bb, 0xa476d9, 0xadc168, 0x56e0b4, 0x2b705a, 0x15b82d, 0xf52612,
0x7a9309, 0xc2b380, 0x6159c0, 0x30ace0, 0x185670, 0x0c2b38, 0x06159c, 0x030ace,
0x018567, 0xff38b7, 0x80665f, 0xbfc92b, 0xa01e91, 0xaff54c, 0x57faa6, 0x2bfd53,
0xea04ad, 0x8af852, 0x457c29, 0xdd4410, 0x6ea208, 0x375104, 0x1ba882, 0x0dd441,
0xf91024, 0x7c8812, 0x3e4409, 0xe0d800, 0x706c00, 0x383600, 0x1c1b00, 0x0e0d80,
0x0706c0, 0x038360, 0x01c1b0, 0x00e0d8, 0x00706c, 0x003836, 0x001c1b, 0xfff409,
0x800000, 0x400000, 0x200000, 0x100000, 0x080000, 0x040000, 0x020000, 0x010000,
0x008000, 0x004000, 0x002000, 0x001000, 0x000800, 0x000400, 0x000200, 0x000100,
0x000080, 0x000040, 0x000020, 0x000010, 0x000008, 0x000004, 0x000002, 0x000001
};
/* Try to fix single bit errors using the checksum. On success modifies
* the original buffer with the fixed version, and returns the position
* of the error bit. Otherwise if fixing failed -1 is returned. */
int fixSingleBitErrors(unsigned char *msg, int bits) {
uint32_t crc_zero = 0;
int offset = (bits == 112) ? 0 : (112-56);
int j;
unsigned char aux[MODES_LONG_MSG_BITS/8];
for (j = 0; j < bits; j++) {
/* Calculate CRC for given message. Xoring elements of table above if
* corresponding bit of message is set. An error free message will give
* zero in crc_zero after this procedure.
*/
for(j = 0; j < bits; j++) {
int byte = j/8;
int bitmask = 1 << (7-(j%8));
uint32_t crc1, crc2;
int bit = j%8;
int bitmask = 1 << (7-bit);
memcpy(aux,msg,bits/8);
aux[byte] ^= bitmask; /* Flip j-th bit. */
/* If bit is set, xor with corresponding table entry. */
if (msg[byte] & bitmask)
crc_zero ^= modes_checksum_fix_table[j+offset];
}
crc1 = ((uint32_t)aux[(bits/8)-3] << 16) |
((uint32_t)aux[(bits/8)-2] << 8) |
(uint32_t)aux[(bits/8)-1];
crc2 = modesChecksum(aux,bits);
if (crc1 == crc2) {
/* The error is fixed. Overwrite the original buffer with
* the corrected sequence, and returns the error bit
* position. */
memcpy(msg,aux,bits/8);
/* If message contains a single bit error, the position in the table above
* corresponds to the erroneous bit position */
for (j = 0; j < bits; j++) {
if(crc_zero == modes_checksum_fix_table[j+offset]){
int byte = j/8;
int bitmask = 1 << (7-(j%8));
msg[byte] ^= bitmask; /* Flip j-th bit in original buffer. */
/* The error is fixed. Return the error bit position. */
return j;
}
}
return -1;
}
/* Similar to fixSingleBitErrors() but try every possible two bit combination.
* This is very slow and should be tried only against DF17 messages that
* don't pass the checksum, and only in Aggressive Mode. */
/* Similar to fixSingleBitErrors() but try every possible two bit combination.*/
int fixTwoBitsErrors(unsigned char *msg, int bits) {
int j, i;
unsigned char aux[MODES_LONG_MSG_BITS/8];
uint32_t crc_zero = 0;
int offset = (bits == 112) ? 0 : (112-56);
int i, j;
/* Calculate CRC for given message. Xoring elements of table above if
* corresponding bit of message is set. An error free message will give
* zero in crc_zero after this procedure.
*/
for(j = 0; j < bits; j++) {
int byte = j/8;
int bit = j%8;
int bitmask = 1 << (7-bit);
/* If bit is set, xor with corresponding table entry. */
if (msg[byte] & bitmask)
crc_zero ^= modes_checksum_fix_table[j+offset];
}
/* If message contains two and exactly two bit errors, crc_zero is the XOR
* of two elements of the table above which correspond to the erroneous bit
* positions
* Iterate over all two bit combinations. */
for (j = 0; j < bits; j++) {
int byte1 = j/8;
int bitmask1 = 1 << (7-(j%8));
/* Don't check the same pairs multiple times, so i starts from j+1 */
for (i = j+1; i < bits; i++) {
int byte2 = i/8;
int bitmask2 = 1 << (7-(i%8));
uint32_t crc1, crc2;
memcpy(aux,msg,bits/8);
aux[byte1] ^= bitmask1; /* Flip j-th bit. */
aux[byte2] ^= bitmask2; /* Flip i-th bit. */
crc1 = ((uint32_t)aux[(bits/8)-3] << 16) |
((uint32_t)aux[(bits/8)-2] << 8) |
(uint32_t)aux[(bits/8)-1];
crc2 = modesChecksum(aux,bits);
if (crc1 == crc2) {
/* The error is fixed. Overwrite the original buffer with
* the corrected sequence, and returns the error bit
* position. */
memcpy(msg,aux,bits/8);
/* We return the two bits as a 16 bit integer by shifting
* 'i' on the left. This is possible since 'i' will always
* be non-zero because i starts from j+1. */
/* Try to flip bit j and i.
* Again, we do not actually flip these bits in the message buffer
* but we check if crc_zero would be zero if these bits where
* flipped. */
uint32_t crc_fixed = crc_zero ^ modes_checksum_fix_table[j + offset] ^ modes_checksum_fix_table[i + offset];
if(crc_fixed == 0){
/* We found the two bits which need to be flipped in order to
* get an CRC error free message.*/
int byte1 = j/8;
int bitmask1 = 1 << (7-(j%8));
int byte2 = i/8;
int bitmask2 = 1 << (7-(i%8));
msg[byte1] ^= bitmask1; /* Flip j-th bit. */
msg[byte2] ^= bitmask2; /* Flip i-th bit. */
return j | (i<<8);
}
}
@ -953,7 +985,7 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
if ((mm->errorbit = fixSingleBitErrors(msg,mm->msgbits)) != -1) {
mm->crc = modesChecksum(msg,mm->msgbits);
mm->crcok = 1;
} else if (Modes.aggressive && mm->msgtype == 17 &&
} else if (Modes.aggressive &&
(mm->errorbit = fixTwoBitsErrors(msg,mm->msgbits)) != -1)
{
mm->crc = modesChecksum(msg,mm->msgbits);