diff --git a/dump1090.c b/dump1090.c index d986e32..2ed60ba 100644 --- a/dump1090.c +++ b/dump1090.c @@ -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);