diff --git a/README.md b/README.md index ae88057..07aa3ea 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,25 @@ resources: * http://www.lll.lu/~edward/edward/adsb/antenna/ADSBantenna.html * http://modesbeast.com/pix/adsb-ant-drawing.gif +Aggressive mode +--- + +With --aggressive it is possible to activate the *aggressive mode* that is a +modified version of the Mode S packet detection and decoding. +THe aggresive mode uses more CPU usually (especially if there are many planes +sending DF17 packets), but can detect a few more messages. + +The algorithm in aggressive mode is modified in the following ways: + +* Preamble detection is weakened to be more liberal in what is consdered valid. +* Up to two demodulation errors are tolerated (adjacent entires in the magnitude + vector with the same eight). Normally only messages without errors are + checked. +* It tries to fix DF17 messages trying every two bits combination. + +The use of aggressive mdoe is only advised in places where there is low traffic +in order to have a chance to capture some more messages. + Debug mode --- diff --git a/dump1090.c b/dump1090.c index 2433b00..9c6c625 100644 --- a/dump1090.c +++ b/dump1090.c @@ -163,6 +163,7 @@ struct { int stats; /* Print stats at exit in --ifile mode. */ int onlyaddr; /* Print only ICAO addresses. */ int metric; /* Use metric units. */ + int aggressive; /* Aggressive detection algorithm. */ /* Interactive mode */ struct aircraft *aircrafts; @@ -174,6 +175,8 @@ struct { long long stat_goodcrc; long long stat_badcrc; long long stat_fixed; + long long stat_single_bit_fix; + long long stat_two_bits_fix; long long stat_http_requests; } Modes; @@ -225,6 +228,8 @@ void interactiveShowData(void); void interactiveReceiveData(struct modesMessage *mm); void modesSendRawOutput(struct modesMessage *mm); void useModesMessage(struct modesMessage *mm); +int fixSingleBitErrors(unsigned char *msg, int bits); +int fixTwoBitsErrors(unsigned char *msg, int bits); /* ============================= Utility functions ========================== */ @@ -259,6 +264,7 @@ void modesInitConfig(void) { Modes.interactive = 0; Modes.interactive_rows = MODES_INTERACTIVE_ROWS; Modes.interactive_ttl = MODES_INTERACTIVE_TTL; + Modes.aggressive = 0; } void modesInit(void) { @@ -300,6 +306,8 @@ void modesInit(void) { Modes.stat_goodcrc = 0; Modes.stat_badcrc = 0; Modes.stat_fixed = 0; + Modes.stat_single_bit_fix = 0; + Modes.stat_two_bits_fix = 0; Modes.stat_http_requests = 0; Modes.exit = 0; } @@ -496,13 +504,22 @@ void dumpRawMessage(char *descr, unsigned char *msg, uint16_t *m, uint32_t offset) { int j; + int msgtype = msg[0]>>3; + int fixable = 0; + + if (msgtype == 11 || msgtype == 17) { + int msgbits = (msgtype == 11) ? MODES_SHORT_MSG_BITS : + MODES_LONG_MSG_BITS; + if (fixSingleBitErrors(msg,msgbits) != -1) fixable = 1; + else if (fixTwoBitsErrors(msg,msgbits) != -1) fixable = 2; + } printf("\n--- %s\n ", descr); for (j = 0; j < MODES_LONG_MSG_BYTES; j++) { printf("%02x",msg[j]); if (j == MODES_SHORT_MSG_BYTES-1) printf(" ... "); } - printf("\n"); + printf(" (DF %d, Fixable: %d)\n", msgtype, fixable); dumpMagnitudeVector(m,offset); printf("---\n\n"); } @@ -603,6 +620,44 @@ int fixSingleBitErrors(unsigned char *msg, int bits) { 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_BITS/8]; + + for (j = 0; j < bits; j++) { + int byte1 = j/8; + int bitmask1 = 1 << (7-(j%8)); + + 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); + return j | (i<<8); + } + } + } + return -1; +} + /* Hash the ICAO address to index our cache of MODES_ICAO_CACHE_LEN * elements, that is assumed to be a power of two. */ uint32_t ICAOCacheHashAddress(uint32_t a) { @@ -823,6 +878,11 @@ 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 && + (mm->errorbit = fixTwoBitsErrors(msg,mm->msgbits)) != -1) + { + mm->crc = modesChecksum(msg,mm->msgbits); + mm->crcok = 1; } } @@ -1133,35 +1193,39 @@ void detectModeS(uint16_t *m, uint32_t mlen) { continue; } - /* The samples between the two spikes must be < than the average - * of the high spikes level. */ - high = (m[j]+m[j+2]+m[j+7]+m[j+9])/4; - if (m[j+3] >= high || - m[j+4] >= high || - m[j+5] >= high || - m[j+6] >= high) - { - if (Modes.debug == MODES_DEBUG_NOPREAMBLE && - m[j] > MODES_DEBUG_NOPREAMBLE_LEVEL) - dumpRawMessage("Too high level in samples between 3 and 6", - msg, m, j); - continue; - } + if (Modes.aggressive) { + /* The samples between the two spikes must be < than the average + * of the high spikes level. */ + high = (m[j]+m[j+2]+m[j+7]+m[j+9])/4; + if (m[j+3] >= high || + m[j+4] >= high || + m[j+5] >= high || + m[j+6] >= high) + { + if (Modes.debug == MODES_DEBUG_NOPREAMBLE && + m[j] > MODES_DEBUG_NOPREAMBLE_LEVEL) + dumpRawMessage( + "Too high level in samples between 3 and 6", + msg, m, j); + continue; + } - /* Similarly samples in the range 10-15 must be low, as it is the - * space between the preamble and real data. */ - if (m[j+10] >= high || - m[j+11] >= high || - m[j+12] >= high || - m[j+13] >= high || - m[j+14] >= high || - m[j+15] >= high) - { - if (Modes.debug == MODES_DEBUG_NOPREAMBLE && - m[j] > MODES_DEBUG_NOPREAMBLE_LEVEL) - dumpRawMessage("Too high level in samples between 10 and 15", - msg, m, j); - continue; + /* Similarly samples in the range 10-15 must be low, as it is the + * space between the preamble and real data. */ + if (m[j+10] >= high || + m[j+11] >= high || + m[j+12] >= high || + m[j+13] >= high || + m[j+14] >= high || + m[j+15] >= high) + { + if (Modes.debug == MODES_DEBUG_NOPREAMBLE && + m[j] > MODES_DEBUG_NOPREAMBLE_LEVEL) + dumpRawMessage( + "Too high level in samples between 10 and 15", + msg, m, j); + continue; + } } Modes.stat_valid_preamble++; @@ -1218,12 +1282,12 @@ void detectModeS(uint16_t *m, uint32_t mlen) { /* If we reached this point, and error is zero, we are very likely * with a Mode S message in our hands, but it may still be broken * and CRC may not be correct. This is handled by the next layer. */ - if (errors == 0) { + if (errors == 0 || (Modes.aggressive && errors < 3)) { struct modesMessage mm; /* Decode the received message and update statistics */ decodeModesMessage(&mm,msg); - Modes.stat_demodulated++; + if (errors == 0) Modes.stat_demodulated++; if (mm.errorbit == -1) { if (mm.crcok) Modes.stat_goodcrc++; @@ -1232,12 +1296,17 @@ void detectModeS(uint16_t *m, uint32_t mlen) { } else { Modes.stat_badcrc++; Modes.stat_fixed++; + if (mm.errorbit < MODES_LONG_MSG_BITS) + Modes.stat_single_bit_fix++; + else + Modes.stat_two_bits_fix++; } /* Output debug mode info if needed. */ if (Modes.debug == MODES_DEBUG_DEMOD) dumpRawMessage("Demodulated with 0 errors", msg, m, j); - else if (Modes.debug == MODES_DEBUG_BADCRC && !mm.crcok) + else if (Modes.debug == MODES_DEBUG_BADCRC && + (!mm.crcok || mm.errorbit != -1)) dumpRawMessage("Decoded with bad CRC", msg, m, j); else if (Modes.debug == MODES_DEBUG_GOODCRC && mm.crcok && mm.errorbit == -1) @@ -2002,6 +2071,7 @@ void showHelp(void) { "--net-http-port HTTP server port (default: 8080).\n" "--no-fix Disable single-bits error correction using CRC.\n" "--no-crc-check Disable messages with broken CRC (discouraged).\n" +"--aggressive More CPU for more messages (two bits fixes, ...).\n" "--stats With --ifile print stats at exit. No other output.\n" "--onlyaddr Show only ICAO addresses (testing purposes).\n" "--metric Use metric units (meters, km/h, ...).\n" @@ -2072,6 +2142,8 @@ int main(int argc, char **argv) { Modes.onlyaddr = 1; } else if (!strcmp(argv[j],"--metric")) { Modes.metric = 1; + } else if (!strcmp(argv[j],"--aggressive")) { + Modes.aggressive++; } else if (!strcmp(argv[j],"--interactive")) { Modes.interactive = 1; } else if (!strcmp(argv[j],"--interactive-rows")) { @@ -2153,7 +2225,11 @@ int main(int argc, char **argv) { printf("%lld demodulated with zero errors\n", Modes.stat_demodulated); printf("%lld with good crc\n", Modes.stat_goodcrc); printf("%lld with bad crc\n", Modes.stat_badcrc); - printf("%lld single bit errors corrected\n", Modes.stat_fixed); + printf("%lld errors corrected\n", Modes.stat_fixed); + printf("%lld single bit errors\n", Modes.stat_single_bit_fix); + printf("%lld two bits errors\n", Modes.stat_two_bits_fix); + printf("%lld total usable messages\n", + Modes.stat_goodcrc + Modes.stat_fixed); } rtlsdr_close(Modes.dev);