Move CRC code to a separate file.
This commit is contained in:
parent
721412dc9b
commit
07df054590
8
Makefile
8
Makefile
|
@ -21,11 +21,11 @@ all: dump1090 view1090
|
||||||
%.o: %.c dump1090.h
|
%.o: %.c dump1090.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c $<
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c $<
|
||||||
|
|
||||||
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o
|
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o
|
||||||
$(CC) -g -o dump1090 dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o $(LIBS) $(LIBS_RTL) $(LDFLAGS)
|
$(CC) -g -o dump1090 $^ $(LIBS) $(LIBS_RTL) $(LDFLAGS)
|
||||||
|
|
||||||
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o
|
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o
|
||||||
$(CC) -g -o view1090 view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o $(LIBS) $(LDFLAGS)
|
$(CC) -g -o view1090 $^ $(LIBS) $(LDFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o dump1090 view1090
|
rm -f *.o dump1090 view1090
|
||||||
|
|
245
crc.c
Normal file
245
crc.c
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
// dump1090, a Mode S messages decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "dump1090.h"
|
||||||
|
|
||||||
|
// Parity table for MODE S Messages.
|
||||||
|
// The table contains 112 elements, every element corresponds to a bit set
|
||||||
|
// in the message, starting from the first bit of actual data after the
|
||||||
|
// preamble.
|
||||||
|
//
|
||||||
|
// For messages of 112 bit, the whole table is used.
|
||||||
|
// For messages of 56 bits only the last 56 elements are used.
|
||||||
|
//
|
||||||
|
// The algorithm is as simple as xoring all the elements in this table
|
||||||
|
// for which the corresponding bit on the message is set to 1.
|
||||||
|
//
|
||||||
|
// The latest 24 elements in this table are set to 0 as the checksum at the
|
||||||
|
// end of the message should not affect the computation.
|
||||||
|
//
|
||||||
|
// Note: this function can be used with DF11 and DF17, other modes have
|
||||||
|
// the CRC xored with the sender address as they are reply to interrogations,
|
||||||
|
// but a casual listener can't split the address from the checksum.
|
||||||
|
//
|
||||||
|
uint32_t modes_checksum_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,
|
||||||
|
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
|
||||||
|
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
|
||||||
|
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t modesChecksum(unsigned char *msg, int bits) {
|
||||||
|
uint32_t crc = 0;
|
||||||
|
uint32_t rem = 0;
|
||||||
|
int offset = (bits == 112) ? 0 : (112-56);
|
||||||
|
uint8_t theByte = *msg;
|
||||||
|
uint32_t * pCRCTable = &modes_checksum_table[offset];
|
||||||
|
int j;
|
||||||
|
|
||||||
|
// We don't really need to include the checksum itself
|
||||||
|
bits -= 24;
|
||||||
|
for(j = 0; j < bits; j++) {
|
||||||
|
if ((j & 7) == 0)
|
||||||
|
theByte = *msg++;
|
||||||
|
|
||||||
|
// If bit is set, xor with corresponding table entry.
|
||||||
|
if (theByte & 0x80) {crc ^= *pCRCTable;}
|
||||||
|
pCRCTable++;
|
||||||
|
theByte = theByte << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rem = (msg[0] << 16) | (msg[1] << 8) | msg[2]; // message checksum
|
||||||
|
return ((crc ^ rem) & 0x00FFFFFF); // 24 bit checksum syndrome.
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
//
|
||||||
|
// 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 bits; // Number of bit positions to fix
|
||||||
|
int pos[MODES_MAX_BITERRORS]; // Bit positions corrected by this syndrome
|
||||||
|
};
|
||||||
|
|
||||||
|
#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
|
||||||
|
static 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));
|
||||||
|
memset(msg, 0, MODES_LONG_MSG_BYTES);
|
||||||
|
// Add all possible single and double bit errors
|
||||||
|
// don't include errors in first 5 bits (DF type)
|
||||||
|
for (i = 5; i < MODES_LONG_MSG_BITS; i++) {
|
||||||
|
int bytepos0 = (i >> 3);
|
||||||
|
int mask0 = 1 << (7 - (i & 7));
|
||||||
|
msg[bytepos0] ^= mask0; // create error0
|
||||||
|
crc = modesChecksum(msg, MODES_LONG_MSG_BITS);
|
||||||
|
bitErrorTable[n].syndrome = crc; // single bit error case
|
||||||
|
bitErrorTable[n].bits = 1;
|
||||||
|
bitErrorTable[n].pos[0] = i;
|
||||||
|
bitErrorTable[n].pos[1] = -1;
|
||||||
|
n += 1;
|
||||||
|
|
||||||
|
if (Modes.nfix_crc > 1) {
|
||||||
|
for (j = i+1; j < MODES_LONG_MSG_BITS; j++) {
|
||||||
|
int bytepos1 = (j >> 3);
|
||||||
|
int mask1 = 1 << (7 - (j & 7));
|
||||||
|
msg[bytepos1] ^= mask1; // create error1
|
||||||
|
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; // two bit error case
|
||||||
|
bitErrorTable[n].bits = 2;
|
||||||
|
bitErrorTable[n].pos[0] = i;
|
||||||
|
bitErrorTable[n].pos[1] = j;
|
||||||
|
n += 1;
|
||||||
|
msg[bytepos1] ^= mask1; // revert error1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg[bytepos0] ^= mask0; // revert error0
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//=========================================================================
|
||||||
|
//
|
||||||
|
// Search for syndrome in table and if an entry is found, flip the necessary
|
||||||
|
// bits. Make sure the indices fit into the array
|
||||||
|
// Additional parameter: fix only less than maxcorrected bits, and record
|
||||||
|
// fixed bit positions in corrected[]. This array can be NULL, otherwise
|
||||||
|
// must be of length at least maxcorrected.
|
||||||
|
// Return number of fixed bits.
|
||||||
|
//
|
||||||
|
int fixBitErrors(unsigned char *msg, int bits, int maxfix, char *fixedbits) {
|
||||||
|
struct errorinfo *pei;
|
||||||
|
struct errorinfo ei;
|
||||||
|
int bitpos, offset, res, i;
|
||||||
|
memset(&ei, 0, sizeof(struct errorinfo));
|
||||||
|
ei.syndrome = modesChecksum(msg, bits);
|
||||||
|
pei = bsearch(&ei, bitErrorTable, NERRORINFO,
|
||||||
|
sizeof(struct errorinfo), cmpErrorInfo);
|
||||||
|
if (pei == NULL) {
|
||||||
|
return 0; // No syndrome found
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the syndrome fixes more bits than we allow
|
||||||
|
if (maxfix < pei->bits) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that all bit positions lie inside the message length
|
||||||
|
offset = MODES_LONG_MSG_BITS-bits;
|
||||||
|
for (i = 0; i < pei->bits; i++) {
|
||||||
|
bitpos = pei->pos[i] - offset;
|
||||||
|
if ((bitpos < 0) || (bitpos >= bits)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix the bits
|
||||||
|
for (i = res = 0; i < pei->bits; i++) {
|
||||||
|
bitpos = pei->pos[i] - offset;
|
||||||
|
msg[bitpos >> 3] ^= (1 << (7 - (bitpos & 7)));
|
||||||
|
if (fixedbits) {
|
||||||
|
fixedbits[res++] = bitpos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
40
crc.h
Normal file
40
crc.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// dump1090, a Mode S messages decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DUMP1090_CRC_H
|
||||||
|
#define DUMP1090_CRC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void modesInitErrorInfo();
|
||||||
|
uint32_t modesChecksum(unsigned char *msg, int bits);
|
||||||
|
int fixBitErrors(unsigned char *msg, int bits, int maxfix, char *fixedbits);
|
||||||
|
|
||||||
|
#endif
|
|
@ -65,13 +65,13 @@
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "rtl-sdr.h"
|
|
||||||
#include "anet.h"
|
|
||||||
#else
|
#else
|
||||||
#include "winstubs.h" //Put everything Windows specific in here
|
#include "winstubs.h" //Put everything Windows specific in here
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "rtl-sdr.h"
|
#include "rtl-sdr.h"
|
||||||
#include "anet.h"
|
#include "anet.h"
|
||||||
#endif
|
#include "crc.h"
|
||||||
|
|
||||||
// ============================= #defines ===============================
|
// ============================= #defines ===============================
|
||||||
//
|
//
|
||||||
|
|
290
mode_s.c
290
mode_s.c
|
@ -32,65 +32,9 @@
|
||||||
//
|
//
|
||||||
// ===================== Mode S detection and decoding ===================
|
// ===================== Mode S detection and decoding ===================
|
||||||
//
|
//
|
||||||
// Parity table for MODE S Messages.
|
|
||||||
// The table contains 112 elements, every element corresponds to a bit set
|
|
||||||
// in the message, starting from the first bit of actual data after the
|
|
||||||
// preamble.
|
|
||||||
//
|
//
|
||||||
// For messages of 112 bit, the whole table is used.
|
|
||||||
// For messages of 56 bits only the last 56 elements are used.
|
|
||||||
//
|
//
|
||||||
// The algorithm is as simple as xoring all the elements in this table
|
|
||||||
// for which the corresponding bit on the message is set to 1.
|
|
||||||
//
|
|
||||||
// The latest 24 elements in this table are set to 0 as the checksum at the
|
|
||||||
// end of the message should not affect the computation.
|
|
||||||
//
|
|
||||||
// Note: this function can be used with DF11 and DF17, other modes have
|
|
||||||
// the CRC xored with the sender address as they are reply to interrogations,
|
|
||||||
// but a casual listener can't split the address from the checksum.
|
|
||||||
//
|
|
||||||
uint32_t modes_checksum_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,
|
|
||||||
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
|
|
||||||
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
|
|
||||||
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t modesChecksum(unsigned char *msg, int bits) {
|
|
||||||
uint32_t crc = 0;
|
|
||||||
uint32_t rem = 0;
|
|
||||||
int offset = (bits == 112) ? 0 : (112-56);
|
|
||||||
uint8_t theByte = *msg;
|
|
||||||
uint32_t * pCRCTable = &modes_checksum_table[offset];
|
|
||||||
int j;
|
|
||||||
|
|
||||||
// We don't really need to include the checksum itself
|
|
||||||
bits -= 24;
|
|
||||||
for(j = 0; j < bits; j++) {
|
|
||||||
if ((j & 7) == 0)
|
|
||||||
theByte = *msg++;
|
|
||||||
|
|
||||||
// If bit is set, xor with corresponding table entry.
|
|
||||||
if (theByte & 0x80) {crc ^= *pCRCTable;}
|
|
||||||
pCRCTable++;
|
|
||||||
theByte = theByte << 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rem = (msg[0] << 16) | (msg[1] << 8) | msg[2]; // message checksum
|
|
||||||
return ((crc ^ rem) & 0x00FFFFFF); // 24 bit checksum syndrome.
|
|
||||||
}
|
|
||||||
//
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
//
|
//
|
||||||
// Given the Downlink Format (DF) of the message, return the message length in bits.
|
// Given the Downlink Format (DF) of the message, return the message length in bits.
|
||||||
|
@ -102,241 +46,7 @@ uint32_t modesChecksum(unsigned char *msg, int bits) {
|
||||||
int modesMessageLenByType(int type) {
|
int modesMessageLenByType(int type) {
|
||||||
return (type & 0x10) ? MODES_LONG_MSG_BITS : MODES_SHORT_MSG_BITS ;
|
return (type & 0x10) ? MODES_LONG_MSG_BITS : MODES_SHORT_MSG_BITS ;
|
||||||
}
|
}
|
||||||
//
|
|
||||||
//=========================================================================
|
|
||||||
//
|
|
||||||
// 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) {
|
|
||||||
int j;
|
|
||||||
unsigned char aux[MODES_LONG_MSG_BYTES];
|
|
||||||
|
|
||||||
memcpy(aux, msg, bits/8);
|
|
||||||
|
|
||||||
// Do not attempt to error correct Bits 0-4. These contain the DF, and must
|
|
||||||
// be correct because we can only error correct DF17
|
|
||||||
for (j = 5; j < bits; j++) {
|
|
||||||
int byte = j/8;
|
|
||||||
int bitmask = 1 << (7 - (j & 7));
|
|
||||||
|
|
||||||
aux[byte] ^= bitmask; // Flip j-th bit
|
|
||||||
|
|
||||||
if (0 == modesChecksum(aux, bits)) {
|
|
||||||
// The error is fixed. Overwrite the original buffer with the
|
|
||||||
// corrected sequence, and returns the error bit position
|
|
||||||
msg[byte] = aux[byte];
|
|
||||||
return (j);
|
|
||||||
}
|
|
||||||
|
|
||||||
aux[byte] ^= bitmask; // Flip j-th bit back again
|
|
||||||
}
|
|
||||||
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.
|
|
||||||
/*
|
|
||||||
int fixTwoBitsErrors(unsigned char *msg, int bits) {
|
|
||||||
int j, i;
|
|
||||||
unsigned char aux[MODES_LONG_MSG_BYTES];
|
|
||||||
|
|
||||||
memcpy(aux, msg, bits/8);
|
|
||||||
|
|
||||||
// Do not attempt to error correct Bits 0-4. These contain the DF, and must
|
|
||||||
// be correct because we can only error correct DF17
|
|
||||||
for (j = 5; j < bits; j++) {
|
|
||||||
int byte1 = j/8;
|
|
||||||
int bitmask1 = 1 << (7 - (j & 7));
|
|
||||||
aux[byte1] ^= bitmask1; // Flip j-th bit
|
|
||||||
|
|
||||||
// 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 & 7));
|
|
||||||
|
|
||||||
aux[byte2] ^= bitmask2; // Flip i-th bit
|
|
||||||
|
|
||||||
if (0 == modesChecksum(aux, bits)) {
|
|
||||||
// The error is fixed. Overwrite the original buffer with
|
|
||||||
// the corrected sequence, and returns the error bit position
|
|
||||||
msg[byte1] = aux[byte1];
|
|
||||||
msg[byte2] = aux[byte2];
|
|
||||||
|
|
||||||
// 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
|
|
||||||
return (j | (i << 8));
|
|
||||||
|
|
||||||
aux[byte2] ^= bitmask2; // Flip i-th bit back
|
|
||||||
}
|
|
||||||
|
|
||||||
aux[byte1] ^= bitmask1; // Flip j-th bit back
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 bits; // Number of bit positions to fix
|
|
||||||
int pos[MODES_MAX_BITERRORS]; // Bit positions corrected by this syndrome
|
|
||||||
};
|
|
||||||
|
|
||||||
#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));
|
|
||||||
memset(msg, 0, MODES_LONG_MSG_BYTES);
|
|
||||||
// Add all possible single and double bit errors
|
|
||||||
// don't include errors in first 5 bits (DF type)
|
|
||||||
for (i = 5; i < MODES_LONG_MSG_BITS; i++) {
|
|
||||||
int bytepos0 = (i >> 3);
|
|
||||||
int mask0 = 1 << (7 - (i & 7));
|
|
||||||
msg[bytepos0] ^= mask0; // create error0
|
|
||||||
crc = modesChecksum(msg, MODES_LONG_MSG_BITS);
|
|
||||||
bitErrorTable[n].syndrome = crc; // single bit error case
|
|
||||||
bitErrorTable[n].bits = 1;
|
|
||||||
bitErrorTable[n].pos[0] = i;
|
|
||||||
bitErrorTable[n].pos[1] = -1;
|
|
||||||
n += 1;
|
|
||||||
|
|
||||||
if (Modes.nfix_crc > 1) {
|
|
||||||
for (j = i+1; j < MODES_LONG_MSG_BITS; j++) {
|
|
||||||
int bytepos1 = (j >> 3);
|
|
||||||
int mask1 = 1 << (7 - (j & 7));
|
|
||||||
msg[bytepos1] ^= mask1; // create error1
|
|
||||||
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; // two bit error case
|
|
||||||
bitErrorTable[n].bits = 2;
|
|
||||||
bitErrorTable[n].pos[0] = i;
|
|
||||||
bitErrorTable[n].pos[1] = j;
|
|
||||||
n += 1;
|
|
||||||
msg[bytepos1] ^= mask1; // revert error1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
msg[bytepos0] ^= mask0; // revert error0
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
//
|
|
||||||
//=========================================================================
|
|
||||||
//
|
|
||||||
// Search for syndrome in table and if an entry is found, flip the necessary
|
|
||||||
// bits. Make sure the indices fit into the array
|
|
||||||
// Additional parameter: fix only less than maxcorrected bits, and record
|
|
||||||
// fixed bit positions in corrected[]. This array can be NULL, otherwise
|
|
||||||
// must be of length at least maxcorrected.
|
|
||||||
// Return number of fixed bits.
|
|
||||||
//
|
|
||||||
int fixBitErrors(unsigned char *msg, int bits, int maxfix, char *fixedbits) {
|
|
||||||
struct errorinfo *pei;
|
|
||||||
struct errorinfo ei;
|
|
||||||
int bitpos, offset, res, i;
|
|
||||||
memset(&ei, 0, sizeof(struct errorinfo));
|
|
||||||
ei.syndrome = modesChecksum(msg, bits);
|
|
||||||
pei = bsearch(&ei, bitErrorTable, NERRORINFO,
|
|
||||||
sizeof(struct errorinfo), cmpErrorInfo);
|
|
||||||
if (pei == NULL) {
|
|
||||||
return 0; // No syndrome found
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the syndrome fixes more bits than we allow
|
|
||||||
if (maxfix < pei->bits) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that all bit positions lie inside the message length
|
|
||||||
offset = MODES_LONG_MSG_BITS-bits;
|
|
||||||
for (i = 0; i < pei->bits; i++) {
|
|
||||||
bitpos = pei->pos[i] - offset;
|
|
||||||
if ((bitpos < 0) || (bitpos >= bits)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix the bits
|
|
||||||
for (i = res = 0; i < pei->bits; i++) {
|
|
||||||
bitpos = pei->pos[i] - offset;
|
|
||||||
msg[bitpos >> 3] ^= (1 << (7 - (bitpos & 7)));
|
|
||||||
if (fixedbits) {
|
|
||||||
fixedbits[res++] = bitpos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// ============================== Debugging =================================
|
// ============================== Debugging =================================
|
||||||
//
|
//
|
||||||
// Helper function for dumpMagnitudeVector().
|
// Helper function for dumpMagnitudeVector().
|
||||||
|
|
Loading…
Reference in a new issue