UKUEHN : Various Improvements

Sorry Ulrich - I can't get Github to resolve the merge errors and
preserve your commit notes, so I'll add them here.
Improvements on bit error correction, doc update, preparation for
program installation/package build

Hi,
I committed some further improvements on the bit error correction code,
updated the readme, and implemented a way to install the program in the
linux file system hierarchy (allows for package building).

Regards,
Ulrich
This commit is contained in:
Malcolm Robb 2013-05-24 21:24:16 +01:00
parent ee742cf8db
commit 9edba9332a
3 changed files with 107 additions and 58 deletions

View file

@ -1,12 +1,24 @@
#
# When building a package or installing otherwise in the system, make
# sure that the variable PREFIX is defined, e.g. make PREFIX=/usr/local
#
PROGNAME=dump1090
ifdef PREFIX
BINDIR=$(PREFIX)/bin
SHAREDIR=$(PREFIX)/share/$(PROGNAME)
EXTRACFLAGS=-DHTMLPATH=\"$(SHAREDIR)\"
endif
CFLAGS=-O2 -g -Wall -W `pkg-config --cflags librtlsdr` CFLAGS=-O2 -g -Wall -W `pkg-config --cflags librtlsdr`
LIBS=`pkg-config --libs librtlsdr` -lpthread -lm LIBS=`pkg-config --libs librtlsdr` -lpthread -lm
CC=gcc CC=gcc
PROGNAME=dump1090
all: dump1090 all: dump1090
%.o: %.c %.o: %.c
$(CC) $(CFLAGS) -c $< $(CC) $(CFLAGS) $(EXTRACFLAGS) -c $<
dump1090: dump1090.o anet.o dump1090: dump1090.o anet.o
$(CC) -g -o dump1090 dump1090.o anet.o $(LIBS) $(CC) -g -o dump1090 dump1090.o anet.o $(LIBS)

View file

@ -86,9 +86,13 @@ it without arguments at all is the best thing to do.
Reliability Reliability
--- ---
By default Dump1090 tries to fix single bit errors using the checksum. By default Dump1090 checks for decoding errors using the 24-bit CRC checksum,
Basically the program will try to flip every bit of the message and check if where available. Messages with errors are discarded.
the checksum of the resulting message matches.
The --fix command line switch enables fixing single bit error correction
based on the CRC checksum. Technically, it uses a table of precomputed
checksum differences resulting from single bit errors to look up the
wrong bit position.
This is indeed able to fix errors and works reliably in my experience, This is indeed able to fix errors and works reliably in my experience,
however if you are interested in very reliable data I suggest to use however if you are interested in very reliable data I suggest to use
@ -190,18 +194,19 @@ Aggressive mode
With --aggressive it is possible to activate the *aggressive mode* that is a With --aggressive it is possible to activate the *aggressive mode* that is a
modified version of the Mode S packet detection and decoding. modified version of the Mode S packet detection and decoding.
THe aggresive mode uses more CPU usually (especially if there are many planes The aggresive mode uses more CPU usually (especially if there are many planes
sending DF17 packets), but can detect a few more messages. sending DF17 packets), but can detect a few more messages.
The algorithm in aggressive mode is modified in the following ways: The algorithm in aggressive mode is modified in the following ways:
* Up to two demodulation errors are tolerated (adjacent entires in the magnitude * Up to two demodulation errors are tolerated (adjacent entires in the
vector with the same eight). Normally only messages without errors are magnitude vector with the same eight). Normally only messages without
checked. errors are checked.
* It tries to fix DF17 messages trying every two bits combination. * It tries to fix DF17 messages with CRC errors resulting from any two bit
errors.
The use of aggressive mdoe is only advised in places where there is low traffic The use of aggressive mdoe is only advised in places where there is
in order to have a chance to capture some more messages. low traffic in order to have a chance to capture some more messages.
Debug mode Debug mode
--- ---

View file

@ -72,6 +72,9 @@
#define MODES_MSG_SQUELCH_LEVEL 0x02FF /* Average signal strength limit */ #define MODES_MSG_SQUELCH_LEVEL 0x02FF /* Average signal strength limit */
#define MODES_MSG_ENCODER_ERRS 3 /* Maximum number of encoding errors */ #define MODES_MSG_ENCODER_ERRS 3 /* Maximum number of encoding errors */
/* When changing, change also fixBitErrors() and modesInitErrorTable() !! */
#define MODES_MAX_BITERRORS 2 /* Global max for fixable bit erros */
#define MODEAC_MSG_SAMPLES (25 * 2) /* include up to the SPI bit */ #define MODEAC_MSG_SAMPLES (25 * 2) /* include up to the SPI bit */
#define MODEAC_MSG_BYTES 2 #define MODEAC_MSG_BYTES 2
#define MODEAC_MSG_SQUELCH_LEVEL 0x07FF /* Average signal strength limit */ #define MODEAC_MSG_SQUELCH_LEVEL 0x07FF /* Average signal strength limit */
@ -150,6 +153,10 @@
#define MODES_CLIENT_BUF_SIZE 1024 #define MODES_CLIENT_BUF_SIZE 1024
#define MODES_NET_SNDBUF_SIZE (1024*64) #define MODES_NET_SNDBUF_SIZE (1024*64)
#ifndef HTMLPATH
#define HTMLPATH "./public_html" /* default path for gmap.html etc. */
#endif
#define MODES_NOTUSED(V) ((void) V) #define MODES_NOTUSED(V) ((void) V)
/* Structure used to describe a networking client. */ /* Structure used to describe a networking client. */
@ -229,7 +236,7 @@ struct {
/* Configuration */ /* Configuration */
char *filename; /* Input form file, --ifile option. */ char *filename; /* Input form file, --ifile option. */
int phase_enhance; /* Enable phase enhancement if true */ int phase_enhance; /* Enable phase enhancement if true */
int fix_errors; /* Single bit error correction if true. */ int fix_errors; /* If > 0 no of bit errors to fix */
int check_crc; /* Only display messages with good CRC. */ int check_crc; /* Only display messages with good CRC. */
int raw; /* Raw output format. */ int raw; /* Raw output format. */
int beast; /* Beast binary format output. */ int beast; /* Beast binary format output. */
@ -273,8 +280,12 @@ struct {
unsigned int stat_goodcrc; unsigned int stat_goodcrc;
unsigned int stat_badcrc; unsigned int stat_badcrc;
unsigned int stat_fixed; unsigned int stat_fixed;
unsigned int stat_single_bit_fix;
unsigned int stat_two_bits_fix; /* Histogram of fixed bit errors: index 0 for single bit erros,
* index 1 for double bit errors etc.
*/
unsigned int stat_bit_fix[MODES_MAX_BITERRORS];
unsigned int stat_http_requests; unsigned int stat_http_requests;
unsigned int stat_sbs_connections; unsigned int stat_sbs_connections;
unsigned int stat_out_of_phase; unsigned int stat_out_of_phase;
@ -300,7 +311,8 @@ struct modesMessage {
int msgtype; // Downlink format # int msgtype; // Downlink format #
int crcok; // True if CRC was valid int crcok; // True if CRC was valid
uint32_t crc; // Message CRC uint32_t crc; // Message CRC
int correctedbits; // No. of bits corrected int correctedbits; // No. of bits corrected
int corrected[MODES_MAX_BITERRORS]; // corrected bit positions
uint32_t addr; // ICAO Address from bytes 1 2 and 3 uint32_t addr; // ICAO Address from bytes 1 2 and 3
int phase_corrected; // True if phase correction was applied int phase_corrected; // True if phase correction was applied
uint64_t timestampMsg; // Timestamp of the message uint64_t timestampMsg; // Timestamp of the message
@ -341,7 +353,7 @@ void modesSendRawOutput(struct modesMessage *mm);
void modesSendBeastOutput(struct modesMessage *mm); void modesSendBeastOutput(struct modesMessage *mm);
void modesSendSBSOutput(struct modesMessage *mm); void modesSendSBSOutput(struct modesMessage *mm);
void useModesMessage(struct modesMessage *mm); void useModesMessage(struct modesMessage *mm);
int fixBitErrors(unsigned char *msg, int bits); int fixBitErrors(unsigned char *msg, int bits, int maxfixable, int *bitpos);
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(); void modesInitErrorInfo();
@ -672,7 +684,7 @@ void dumpMagnitudeVector(uint16_t *m, uint32_t offset) {
/* Produce a raw representation of the message as a Javascript file /* Produce a raw representation of the message as a Javascript file
* loadable by debug.html. */ * loadable by debug.html. */
void dumpRawMessageJS(char *descr, unsigned char *msg, void dumpRawMessageJS(char *descr, unsigned char *msg,
uint16_t *m, uint32_t offset, int fixable) uint16_t *m, uint32_t offset, int fixable, int *bitpos)
{ {
int padding = 5; /* Show a few samples before the actual start. */ int padding = 5; /* Show a few samples before the actual start. */
int start = offset - padding; int start = offset - padding;
@ -680,6 +692,7 @@ void dumpRawMessageJS(char *descr, unsigned char *msg,
FILE *fp; FILE *fp;
int j; int j;
MODES_NOTUSED(fixable);
if ((fp = fopen("frames.js","a")) == NULL) { if ((fp = fopen("frames.js","a")) == NULL) {
fprintf(stderr, "Error opening frames.js: %s\n", strerror(errno)); fprintf(stderr, "Error opening frames.js: %s\n", strerror(errno));
exit(1); exit(1);
@ -690,8 +703,8 @@ void dumpRawMessageJS(char *descr, unsigned char *msg,
fprintf(fp,"%d", j < 0 ? 0 : m[j]); fprintf(fp,"%d", j < 0 ? 0 : m[j]);
if (j != end) fprintf(fp,","); if (j != end) fprintf(fp,",");
} }
fprintf(fp,"], \"fixed\": %d, \"bits\": %d, \"hex\": \"", fprintf(fp,"], \"fix1\": %d, \"fix2\": %d, \"bits\": %d, \"hex\": \"",
fixable, modesMessageLenByType(msg[0]>>3)); bitpos[0], bitpos[1] , modesMessageLenByType(msg[0]>>3));
for (j = 0; j < MODES_LONG_MSG_BYTES; j++) for (j = 0; j < MODES_LONG_MSG_BYTES; j++)
fprintf(fp,"\\x%02x",msg[j]); fprintf(fp,"\\x%02x",msg[j]);
fprintf(fp,"\"});\n"); fprintf(fp,"\"});\n");
@ -716,13 +729,18 @@ void dumpRawMessage(char *descr, unsigned char *msg,
int j; int j;
int msgtype = msg[0] >> 3; int msgtype = msg[0] >> 3;
int fixable = 0; int fixable = 0;
int bitpos[MODES_MAX_BITERRORS];
for (j = 0; j < MODES_MAX_BITERRORS; j++) {
bitpos[j] = -1;
}
if (msgtype == 17) { if (msgtype == 17) {
fixable = fixBitErrors(msg, MODES_LONG_MSG_BITS); fixable = fixBitErrors(msg, MODES_LONG_MSG_BITS,
MODES_MAX_BITERRORS, bitpos);
} }
if (Modes.debug & MODES_DEBUG_JS) { if (Modes.debug & MODES_DEBUG_JS) {
dumpRawMessageJS(descr, msg, m, offset, fixable); dumpRawMessageJS(descr, msg, m, offset, fixable, bitpos);
return; return;
} }
@ -1253,8 +1271,8 @@ int fixTwoBitsErrors(unsigned char *msg, int bits) {
*/ */
struct errorinfo { struct errorinfo {
uint32_t syndrome; /* CRC syndrome */ uint32_t syndrome; /* CRC syndrome */
int pos0; /* bit position of first error */ int bits; /* No of bit positions to fix */
int pos1; /* bit position of second error, or -1 */ int pos[MODES_MAX_BITERRORS]; /* bit positions */
}; };
#define NERRORINFO \ #define NERRORINFO \
@ -1290,8 +1308,9 @@ void modesInitErrorInfo() {
msg[bytepos0] ^= mask0; // create error0 msg[bytepos0] ^= mask0; // create error0
crc = modesChecksum(msg, MODES_LONG_MSG_BITS); crc = modesChecksum(msg, MODES_LONG_MSG_BITS);
bitErrorTable[n].syndrome = crc; // single bit error case bitErrorTable[n].syndrome = crc; // single bit error case
bitErrorTable[n].pos0 = i; bitErrorTable[n].bits = 1;
bitErrorTable[n].pos1 = -1; bitErrorTable[n].pos[0] = i;
bitErrorTable[n].pos[1] = -1;
n += 1; n += 1;
if (Modes.aggressive) { if (Modes.aggressive) {
@ -1308,9 +1327,10 @@ void modesInitErrorInfo() {
*/ */
break; break;
} }
bitErrorTable[n].syndrome = crc; // two bit error case bitErrorTable[n].syndrome = crc; // two bit error case
bitErrorTable[n].pos0 = i; bitErrorTable[n].bits = 2;
bitErrorTable[n].pos1 = j; bitErrorTable[n].pos[0] = i;
bitErrorTable[n].pos[1] = j;
n += 1; n += 1;
msg[bytepos1] ^= mask1; // revert error1 msg[bytepos1] ^= mask1; // revert error1
} }
@ -1362,35 +1382,43 @@ int flipBit(unsigned char *msg, int nbits, int bit) {
// Search syndrome in table and, if an entry is found, flip the necessary // 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, // bits. Make sure the indices fit into the array, and for 2-bit errors,
// are different. // are different.
// 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. // Return number of fixed bits.
// //
int fixBitErrors(unsigned char *msg, int bits) { int fixBitErrors(unsigned char *msg, int bits,
int maxfixable, int *fixedbitpos) {
struct errorinfo *pei; struct errorinfo *pei;
struct errorinfo ei; struct errorinfo ei;
int bitpos0, bitpos1, offset, res; int bitpos, offset, res, i;
memset(&ei, 0, sizeof(struct errorinfo));
ei.syndrome = modesChecksum(msg, bits); ei.syndrome = modesChecksum(msg, bits);
ei.pos0 = -1;
ei.pos1 = -1;
pei = bsearch(&ei, bitErrorTable, NERRORINFO, pei = bsearch(&ei, bitErrorTable, NERRORINFO,
sizeof(struct errorinfo), cmpErrorInfo); sizeof(struct errorinfo), cmpErrorInfo);
if (pei == NULL) { if (pei == NULL) {
return 0; // No syndrome found return 0; // No syndrome found
} }
if (maxfixable < pei->bits) {
return 0;
}
res = 0; res = 0;
offset = MODES_LONG_MSG_BITS-bits; offset = MODES_LONG_MSG_BITS-bits;
bitpos0 = pei->pos0 - offset; /* Check that all bit positions are inside message boundaries */
if ((bitpos0 < 0) || (bitpos0 >= bits)) { for (i = 0; i < pei->bits; i++) {
return 0; bitpos = pei->pos[i] - offset;
if ((bitpos < 0) || (bitpos >= bits)) {
return 0;
}
} }
msg[(bitpos0 >> 3)] ^= (1 << (7 - (bitpos0 & 7))); /* Fix the bits */
res++; for (i = 0; i < pei->bits; i++) {
if (pei->pos1 >= 0) { /* two-bit error pattern */ bitpos = pei->pos[i] - offset;
bitpos1 = pei->pos1 - offset; msg[(bitpos >> 3)] ^= (1 << (7 - (bitpos & 7)));
if ((bitpos1 < 0) || (bitpos1 >= bits)) { if (fixedbitpos != NULL) {
return 0; fixedbitpos[res] = bitpos;
} }
msg[(bitpos1 >> 3)] ^= (1 << (7 - (bitpos1 & 7))); res++;
res++;
} }
return res; return res;
} }
@ -1492,7 +1520,8 @@ void testAndTimeBitCorrection() {
inittmsg1(); inittmsg1();
gettimeofday(&starttv, NULL); gettimeofday(&starttv, NULL);
for (i = 0; i < MODES_LONG_MSG_BITS; i++) { for (i = 0; i < MODES_LONG_MSG_BITS; i++) {
fixBitErrors(&tmsg1[i][0], MODES_LONG_MSG_BITS); fixBitErrors(&tmsg1[i][0], MODES_LONG_MSG_BITS,
MODES_MAX_BITERRORS, NULL);
} }
gettimeofday(&endtv, NULL); gettimeofday(&endtv, NULL);
printf(" New code: 1-bit errors on %d msgs: %ld usecs\n", printf(" New code: 1-bit errors on %d msgs: %ld usecs\n",
@ -1511,7 +1540,8 @@ void testAndTimeBitCorrection() {
inittmsg2(); inittmsg2();
gettimeofday(&starttv, NULL); gettimeofday(&starttv, NULL);
for (i = 0; i < NTWOBITS; i++) { for (i = 0; i < NTWOBITS; i++) {
fixBitErrors(&tmsg2[i][0], MODES_LONG_MSG_BITS); fixBitErrors(&tmsg2[i][0], MODES_LONG_MSG_BITS,
MODES_MAX_BITERRORS, NULL);
} }
gettimeofday(&endtv, NULL); gettimeofday(&endtv, NULL);
printf(" New code: 2-bit errors on %d msgs: %ld usecs\n", printf(" New code: 2-bit errors on %d msgs: %ld usecs\n",
@ -1745,7 +1775,8 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) {
// using the results. Perhaps check the ICAO against known aircraft, and check // using the results. Perhaps check the ICAO against known aircraft, and check
// IID against known good IID's. That's a TODO. // IID against known good IID's. That's a TODO.
// //
mm->correctedbits = fixBitErrors(msg, mm->msgbits); mm->correctedbits = fixBitErrors(msg, mm->msgbits,
Modes.fix_errors, mm->corrected);
// If we correct, validate ICAO addr to help filter birthday paradox solutions. // If we correct, validate ICAO addr to help filter birthday paradox solutions.
if (mm->correctedbits) { if (mm->correctedbits) {
uint32_t addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); uint32_t addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]);
@ -2601,11 +2632,10 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
} else { } else {
Modes.stat_badcrc++; Modes.stat_badcrc++;
Modes.stat_fixed++; Modes.stat_fixed += 1;
if (mm.correctedbits == 1) { if ((mm.correctedbits > 0) &&
Modes.stat_single_bit_fix++; (mm.correctedbits <= MODES_MAX_BITERRORS)) {
} else if (mm.correctedbits == 2) { Modes.stat_bit_fix[mm.correctedbits-1] += 1;
Modes.stat_two_bits_fix++;
} }
} }
} }
@ -3858,9 +3888,10 @@ int handleHTTPRequest(struct client *c) {
} }
if (strlen(url) < 2) { if (strlen(url) < 2) {
snprintf(getFile, sizeof getFile, "./public_html/gmap.html"); // Default file snprintf(getFile, sizeof getFile, "%s/%s",
HTMLPATH, "gmap.html"); // Default file
} else { } else {
snprintf(getFile, sizeof getFile, "./public_html%s", url); snprintf(getFile, sizeof getFile, "%s/%s", HTMLPATH, url);
} }
/* Select the content to send, we have just two so far: /* Select the content to send, we have just two so far:
@ -4155,7 +4186,7 @@ int main(int argc, char **argv) {
Modes.metric = 1; Modes.metric = 1;
} else if (!strcmp(argv[j],"--aggressive")) { } else if (!strcmp(argv[j],"--aggressive")) {
Modes.aggressive = 1; Modes.aggressive = 1;
Modes.fix_errors = 1; Modes.fix_errors = MODES_MAX_BITERRORS;
} else if (!strcmp(argv[j],"--interactive")) { } else if (!strcmp(argv[j],"--interactive")) {
Modes.interactive = 1; Modes.interactive = 1;
} else if (!strcmp(argv[j],"--interactive-rows") && more) { } else if (!strcmp(argv[j],"--interactive-rows") && more) {
@ -4280,8 +4311,9 @@ int main(int argc, char **argv) {
printf("%d with good crc\n", Modes.stat_goodcrc); printf("%d with good crc\n", Modes.stat_goodcrc);
printf("%d with bad crc\n", Modes.stat_badcrc); printf("%d with bad crc\n", Modes.stat_badcrc);
printf("%d errors corrected\n", Modes.stat_fixed); printf("%d errors corrected\n", Modes.stat_fixed);
printf("%d single bit errors\n", Modes.stat_single_bit_fix); for (j = 0; j < MODES_MAX_BITERRORS; j++) {
printf("%d two bits errors\n", Modes.stat_two_bits_fix); printf(" %d with %d bit %s\n", Modes.stat_bit_fix[j], j+1, (j==0)?"error":"errors");
}
printf("%d phase enhancement attempts\n", Modes.stat_out_of_phase); printf("%d phase enhancement attempts\n", Modes.stat_out_of_phase);
printf("%d phase enhanced demodulated with 0 errors\n", Modes.stat_ph_demodulated0); printf("%d phase enhanced demodulated with 0 errors\n", Modes.stat_ph_demodulated0);
printf("%d phase enhanced demodulated with 1 error\n", Modes.stat_ph_demodulated1); printf("%d phase enhanced demodulated with 1 error\n", Modes.stat_ph_demodulated1);