From 92fd06bcd6af8d8458abf5aac6b34bc61e7bdd2c Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Tue, 21 May 2013 11:28:56 +0100 Subject: [PATCH 1/9] VK1ET : Bugfix in Error correction table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vk1etI believe there is an error in the way the CRC error syndromes are being created in the two bit case. The inner loop was introducing an extra error bit each time through rather than moving it. Below is the modified code fragment for syndrome creation collapsedSun 07:26 19 May 2013 07:26vk1et [notifications@github.com]Actions To:Mantirez/dump1090 ‎[dump1090@noreply.github.com]‎Cc:MMalcolmRobb ‎[Support@ATTAvionics.com]‎ To help protect your privacy, some content in this message has been blocked. If you're sure this message is from a trusted sender and you want to re-enable the blocked features, click here. Bugfix first noted by VK1ET, and posted here : https://github.com/antirez/dump1090/pull/23#issuecomment-18113094 I believe there is an error in the way the CRC error syndromes are being created in the two bit case. The inner loop was introducing an extra error bit each time through rather than moving it. --- dump1090.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/dump1090.c b/dump1090.c index 59a02e8..d2ef607 100644 --- a/dump1090.c +++ b/dump1090.c @@ -56,7 +56,7 @@ // MinorVer changes when additional features are added, but not for bug fixes (range 00-99) // DayDate & Year changes for all changes, including for bug fixes. It represent the release date of the update // -#define MODES_DUMP1090_VERSION "1.06.1405.13" +#define MODES_DUMP1090_VERSION "1.06.2105.13" #define MODES_USER_LATITUDE_DFLT (0.0) #define MODES_USER_LONGITUDE_DFLT (0.0) @@ -1258,28 +1258,22 @@ void modesInitErrorInfo() { uint32_t crc; n = 0; memset(bitErrorTable, 0, sizeof(bitErrorTable)); - /* First, insert infos about all possible single bit errors */ - for (i = 0; i < MODES_LONG_MSG_BITS; i++) { - int bytepos = (i >> 3); - int mask = 1 << (7 - (i & 7)); - memset(msg, 0, MODES_LONG_MSG_BYTES); - msg[bytepos] ^= mask; - crc = modesChecksum(msg, MODES_LONG_MSG_BITS); - bitErrorTable[n].syndrome = crc; - bitErrorTable[n].pos0 = i; - bitErrorTable[n].pos1 = -1; - n += 1; - } - /* Add also all double bit errors */ + memset(msg, 0, MODES_LONG_MSG_BYTES); + + /* Add all possible single and double bit errors */ for (i = 0; i < MODES_LONG_MSG_BITS; i++) { int bytepos0 = (i >> 3); int mask0 = 1 << (7 - (i & 7)); - memset(msg, 0, MODES_LONG_MSG_BYTES); - msg[bytepos0] ^= mask0; + msg[bytepos0] ^= mask0; // create error0 + crc = modesChecksum(msg, MODES_LONG_MSG_BITS); + bitErrorTable[n].syndrome = crc; // single bit error case + bitErrorTable[n].pos0 = i; + bitErrorTable[n].pos1 = -1; + n += 1; for (j = i+1; j < MODES_LONG_MSG_BITS; j++) { int bytepos1 = (j >> 3); int mask1 = 1 << (7 - (j & 7)); - msg[bytepos1] ^= mask1; + msg[bytepos1] ^= mask1; // create error1 crc = modesChecksum(msg, MODES_LONG_MSG_BITS); if (n >= NERRORINFO) { /* @@ -1289,11 +1283,13 @@ void modesInitErrorInfo() { */ break; } - bitErrorTable[n].syndrome = crc; + bitErrorTable[n].syndrome = crc; // two bit error case bitErrorTable[n].pos0 = i; bitErrorTable[n].pos1 = j; n += 1; + msg[bytepos1] ^= mask1; // revert error1 } + msg[bytepos0] ^= mask0; // revert error0 } qsort(bitErrorTable, NERRORINFO, sizeof(struct errorinfo), cmpErrorInfo); From f33a7090b04c4e9c298b05471bcfdefdd3549e55 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Tue, 21 May 2013 12:08:35 +0100 Subject: [PATCH 2/9] VK1ET : Better pthread termination Close threads, mutex and conditions using pthread functions Also, correct/update a few comments. --- dump1090.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/dump1090.c b/dump1090.c index d2ef607..9098987 100644 --- a/dump1090.c +++ b/dump1090.c @@ -347,7 +347,8 @@ static uint64_t mstime(void) { void sigintHandler(int dummy) { MODES_NOTUSED(dummy); - Modes.exit = 1; // Signal to threads that we are done + signal(SIGINT, SIG_DFL); // reset signal handler - bit extra safety + Modes.exit = 1; // Signal to threads that we are done } /* =============================== Initialization =========================== */ @@ -549,6 +550,7 @@ void readDataFromFile(void) { ssize_t nread, toread; unsigned char *p; + if (Modes.exit == 1) break; if (Modes.data_ready) { pthread_cond_wait(&Modes.data_cond,&Modes.data_mutex); continue; @@ -596,7 +598,11 @@ void *readerThreadEntryPoint(void *arg) { } else { readDataFromFile(); } - return NULL; + /* Signal to the other thread that new data is ready - dummy really so threads don't mutually lock */ + Modes.data_ready = 1; + pthread_cond_signal(&Modes.data_cond); + pthread_mutex_unlock(&Modes.data_mutex); + pthread_exit(NULL); } /* ============================== Debugging ================================= */ @@ -3188,14 +3194,14 @@ void snipMode(int level) { } /* ============================= Networking ================================= - * Note: here we risregard any kind of good coding practice in favor of + * Note: here we disregard any kind of good coding practice in favor of * extreme simplicity, that is: * * 1) We only rely on the kernel buffers for our I/O without any kind of * user space buffering. * 2) We don't register any kind of event handler, from time to time a * function gets called and we accept new connections. All the rest is - * handled via non-blocking I/O and manually pullign clients to see if + * handled via non-blocking I/O and manually polling clients to see if * they have something new to share with us when reading is needed. */ @@ -3357,7 +3363,7 @@ void modesSendRawOutput(struct modesMessage *mm) { sprintf(p, "%02X", pTimeStamp[j]); p += 2; } - Modes.rawOutUsed += 12; // additional 12 characters for timestamp + Modes.rawOutUsed += 12; // additional 12 characters for timestamp } else *p++ = '*'; @@ -4136,7 +4142,12 @@ int main(int argc, char **argv) { printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_fixed); } - rtlsdr_cancel_async(Modes.dev); // Cancel rtlsdr_read_async will cause data input thread to terminate cleanly - rtlsdr_close(Modes.dev); - exit (0); + if (Modes.filename == NULL) { + rtlsdr_cancel_async(Modes.dev); // Cancel rtlsdr_read_async will cause data input thread to terminate cleanly + rtlsdr_close(Modes.dev); + } + pthread_cond_destroy(&Modes.data_cond); // Thread cleanup + pthread_mutex_destroy(&Modes.data_mutex); + pthread_join(Modes.reader_thread,NULL); // Wait on reader thread exit + pthread_exit(0); } From 640d63a0d1472a3965f6f11dba70423dc5fb1f2b Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Tue, 21 May 2013 12:54:34 +0100 Subject: [PATCH 3/9] VK1ET: Shorten CRC calculation We don't need to include the CRC itself one bit at a time. This shortens the loop count by 24 iterations, so should be much faster --- dump1090.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dump1090.c b/dump1090.c index 9098987..55c5baf 100644 --- a/dump1090.c +++ b/dump1090.c @@ -1115,16 +1115,19 @@ uint32_t modesChecksum(unsigned char *msg, int bits) { 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++; rem = (rem << 8) | theByte;} + theByte = *msg++; // If bit is set, xor with corresponding table entry. if (theByte & 0x80) {crc ^= *pCRCTable;} pCRCTable++; theByte = theByte << 1; } - return ((crc ^ rem) & 0x00FFFFFF); // 24 bit checksum. + 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. From 0a0ba165dbc126041a53fa637644b351b5ccea23 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Tue, 21 May 2013 13:25:33 +0100 Subject: [PATCH 4/9] VK1ET : Changes to modesInitError() Restrict Syndromes to exclude DF bits. Do NOT introduce syndromes for errors in the first 5 bits (DF field) Use the --aggressive flag to see if we populate the two-bit error syndromes. If --aggressive is not specified, then we don't attempt to fix two bit errors. --- dump1090.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dump1090.c b/dump1090.c index 55c5baf..55dd8b3 100644 --- a/dump1090.c +++ b/dump1090.c @@ -1126,6 +1126,7 @@ uint32_t modesChecksum(unsigned char *msg, int bits) { pCRCTable++; theByte = theByte << 1; } + rem = (msg[0] << 16) | (msg[1] << 8) | msg[2]; // message checksum return ((crc ^ rem) & 0x00FFFFFF); // 24 bit checksum syndrome. } @@ -1268,9 +1269,9 @@ void modesInitErrorInfo() { n = 0; memset(bitErrorTable, 0, sizeof(bitErrorTable)); memset(msg, 0, MODES_LONG_MSG_BYTES); - - /* Add all possible single and double bit errors */ - for (i = 0; i < MODES_LONG_MSG_BITS; i++) { + // 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 @@ -1279,7 +1280,9 @@ void modesInitErrorInfo() { bitErrorTable[n].pos0 = i; bitErrorTable[n].pos1 = -1; n += 1; - for (j = i+1; j < MODES_LONG_MSG_BITS; j++) { + + if (Modes.aggressive) { + 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 @@ -1297,6 +1300,7 @@ void modesInitErrorInfo() { bitErrorTable[n].pos1 = j; n += 1; msg[bytepos1] ^= mask1; // revert error1 + } } msg[bytepos0] ^= mask0; // revert error0 } From 542b94dedbc64a15154199d4dee58c2b4c5f595a Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Tue, 21 May 2013 13:40:07 +0100 Subject: [PATCH 5/9] VK1ET : Changes to fixBitErrors() 1) Reduce complexity of fixBitErrors() 2) Inline flipBits() 3) Remove validation checks that can never occur. --- dump1090.c | 83 ++++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 46 deletions(-) diff --git a/dump1090.c b/dump1090.c index 55dd8b3..887b15b 100644 --- a/dump1090.c +++ b/dump1090.c @@ -1328,10 +1328,10 @@ void modesInitErrorInfo() { } */ } - -/* Flip a bit, but make sure that the DF field (first 5 bits) - * is never changed - */ +// +// Flip a bit, but make sure that the DF field (first 5 bits) +// is never changed +/* int flipBit(unsigned char *msg, int nbits, int bit) { int bytepos, mask; if ((bit < 0) || (bit >= nbits)) { @@ -1345,50 +1345,41 @@ int flipBit(unsigned char *msg, int nbits, int bit) { msg[bytepos] ^= mask; return 1; } - -/* 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, - * are different. - * Return number of fixed bits. - */ +*/ +// 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, +// are different. +// Return number of fixed bits. +// int fixBitErrors(unsigned char *msg, int bits) { - struct errorinfo *pei; - struct errorinfo ei; - int bitpos0, bitpos1, offset, res; - ei.syndrome = modesChecksum(msg, bits); - ei.pos0 = -1; - ei.pos1 = -1; - pei = bsearch(&ei, bitErrorTable, NERRORINFO, - sizeof(struct errorinfo), cmpErrorInfo); - if (pei == NULL) { - /* Nothing found */ - return 0; - } - offset = MODES_LONG_MSG_BITS-bits; - bitpos0 = pei->pos0; - bitpos1 = pei->pos1; - res = 0; - if (bitpos1 >= 0) { /* two-bit error pattern */ - bitpos0 -= offset; - bitpos1 -= offset; - if ((bitpos0 < 0) || (bitpos0 >= bits) || - (bitpos1 < 0) || (bitpos1 >= bits)) { - return res; - } - res +=flipBit(msg, bits, bitpos0); - if (bitpos0 != bitpos1) { - res += flipBit(msg, bits, bitpos1); - return res; - } - return res; - } else { - bitpos0 -= offset; - if ((bitpos0 < 0) || (bitpos0 >= bits)) { - return res; - } - res += flipBit(msg, bits, bitpos0); - return res; + struct errorinfo *pei; + struct errorinfo ei; + int bitpos0, bitpos1, offset, res; + ei.syndrome = modesChecksum(msg, bits); + ei.pos0 = -1; + ei.pos1 = -1; + pei = bsearch(&ei, bitErrorTable, NERRORINFO, + sizeof(struct errorinfo), cmpErrorInfo); + if (pei == NULL) { + return 0; // No syndrome found + } + res = 0; + offset = MODES_LONG_MSG_BITS-bits; + bitpos0 = pei->pos0 - offset; + if ((bitpos0 < 0) || (bitpos0 >= bits)) { + return 0; + } + msg[(bitpos0 >> 3)] ^= (1 << (7 - (bitpos0 & 7))); + res++; + if (pei->pos1 >= 0) { /* two-bit error pattern */ + bitpos1 = pei->pos1 - offset; + if ((bitpos1 < 0) || (bitpos1 >= bits)) { + return 0; } + msg[(bitpos1 >> 3)] ^= (1 << (7 - (bitpos1 & 7))); + res++; + } + return res; } /* Code for testing the timing: run all possible 1- and 2-bit error From e33591d65d03fd29b14685b255e4366acc765626 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Tue, 21 May 2013 16:01:54 +0100 Subject: [PATCH 6/9] VK1ET : Check Bit Correction against ICAO cache If we error correct a DF17 frame, check that the ICAOaddr exists in our recently seen ICAO cache. This reduces the likelyhood of birthday paradox solutions producing false ICAO addresses --- dump1090.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dump1090.c b/dump1090.c index 887b15b..f7fb858 100644 --- a/dump1090.c +++ b/dump1090.c @@ -1707,7 +1707,7 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { mm->msgtype = msg[0] >> 3; // Downlink Format mm->msgbits = modesMessageLenByType(mm->msgtype); mm->correctedbits = 0; // No errors fixed - mm->phase_corrected = 0; + mm->phase_corrected = 0; mm->crc = modesChecksum(msg, mm->msgbits); if ((mm->crc) && (Modes.fix_errors) && (mm->msgtype == 17)) { @@ -1723,9 +1723,12 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { // IID against known good IID's. That's a TODO. // mm->correctedbits = fixBitErrors(msg, mm->msgbits); - //if ((mm->errorbit == -1) && (Modes.aggressive)) { - // mm->errorbit = fixTwoBitsErrors(msg, mm->msgbits); - //} + // If we correct, validate ICAO addr to help filter birthday paradox solutions. + if (mm->correctedbits) { + uint32_t addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); + if (!ICAOAddressWasRecentlySeen(addr)) + mm->correctedbits = 0; + } } // // Note that most of the other computation happens *after* we fix the From be6cb6eaf001f6570f37e03395591e4a496063a0 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Tue, 21 May 2013 16:43:07 +0100 Subject: [PATCH 7/9] VK1ET : Use error corrected DF17 Actually use the (DF17) messages where we do bit correction. Other changes to AVR message I/O. 1) treat mlat timestamp of zero as invalid (easier to work with than (-1) and equally unlikely). 2) If we don't have a valid timestamp send a without timestamp '*.......' message rather than '@.......' with invalid time. 3) Drop interpretation of obsolete AVR ' #' & '$' formats - they wouldn't have worked anyway (wrong length). --- dump1090.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dump1090.c b/dump1090.c index f7fb858..49cf851 100644 --- a/dump1090.c +++ b/dump1090.c @@ -1974,7 +1974,7 @@ void displayModesMessage(struct modesMessage *mm) { } // Show the raw message. - if (Modes.mlat) { + if (Modes.mlat && mm->timestampMsg) { printf("@"); pTimeStamp = (unsigned char *) &mm->timestampMsg; for (j=5; j>=0;j--) { @@ -2465,7 +2465,7 @@ void detectModeS(uint16_t *m, uint32_t mlen) { // Update statistics if (Modes.stats) { - if (mm.crcok || use_correction) { + if (mm.crcok || use_correction || !mm.crc) { if (errors == 0) Modes.stat_demodulated++; if (mm.correctedbits == 0) { if (mm.crcok) {Modes.stat_goodcrc++;} @@ -2542,7 +2542,7 @@ void detectModeS(uint16_t *m, uint32_t mlen) { // processing and visualization // void useModesMessage(struct modesMessage *mm) { - if ((Modes.check_crc == 0) || (mm->crcok)) { + if ((Modes.check_crc == 0) || (mm->crcok) || (mm->crc == 0)) { // not checking, ok or fixed // Track aircrafts if... if ( (Modes.interactive) // in interactive mode @@ -2916,7 +2916,9 @@ int decodeCPRrelative(struct aircraft *a, int fflag, int surface) { struct aircraft *interactiveReceiveData(struct modesMessage *mm) { struct aircraft *a, *aux; - if (Modes.check_crc && mm->crcok == 0) return NULL; + // Return if (checking crc) AND (not crcok) AND (not fixed) + if (Modes.check_crc && (mm->crcok == 0) && mm->crc) + return NULL; // Loookup our aircraft or create a new one a = interactiveFindAircraft(mm->addr); @@ -3357,7 +3359,7 @@ void modesSendRawOutput(struct modesMessage *mm) { int j; unsigned char * pTimeStamp; - if (Modes.mlat) { + if (Modes.mlat && mm->timestampMsg) { *p++ = '@'; pTimeStamp = (unsigned char *) &mm->timestampMsg; for (j = 5; j >= 0; j--) { @@ -3429,7 +3431,7 @@ void modesSendSBSOutput(struct modesMessage *mm) { p += sprintf(p, "MSG,%d,111,11111,%06X,111111,", msgType, mm->addr); // Fields 7 & 8 are the current time and date - if (mm->timestampMsg != (uint64_t)(-1)) { // Make sure the records' timestamp is valid before outputing it + if (mm->timestampMsg) { // Make sure the records' timestamp is valid before outputing it epocTime = Modes.stSystemTimeBlk; // This is the time of the start of the Block we're processing offset = (int) (mm->timestampMsg - Modes.timestampBlk); // This is the time (in 12Mhz ticks) into the Block offset = offset / 12000; // convert to milliseconds @@ -3559,7 +3561,7 @@ int decodeHexMessage(struct client *c) { // Mixing of data from two or more different receivers and publishing // as coming from one would lead to corrupt mlat data // Non timemarked internet data has indeterminate delay - mm.timestampMsg = -1; + mm.timestampMsg = 0; mm.signalLevel = -1; // Remove spaces on the left and on the right @@ -3572,7 +3574,7 @@ int decodeHexMessage(struct client *c) { // Turn the message into binary. // Accept *-AVR raw @-AVR/BEAST timeS+raw %-AVR timeS+raw (CRC good) <-BEAST timeS+sigL+raw - // and some AVR recorer that we can understand + // and some AVR records that we can understand if (hex[l-1] != ';') {return (0);} // not complete - abort switch(hex[0]) { @@ -3581,11 +3583,9 @@ int decodeHexMessage(struct client *c) { hex += 15; l -= 16; // Skip <, timestamp and siglevel, and ; break;} - case '@': - case '%': - case '#': - case '$': { - hex += 13; l -= 14; // Skip @,%,#,$, and timestamp, and ; + case '@': // No CRC check + case '%': { // CRC is OK + hex += 13; l -= 14; // Skip @,%, and timestamp, and ; break;} case '*': From 08ffc3f54182a2e0cff4b75d1a4a09002132d1b8 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Tue, 21 May 2013 23:16:49 +0100 Subject: [PATCH 8/9] Change mm.crc checks to mm.correctedbits Instead of force clearing mm.crc to zero if we successfully correct bit errors, just use the mm.correctedbits variable. This allows us to print out the crc value containing the errors during list output modes. --- dump1090.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/dump1090.c b/dump1090.c index 49cf851..5b98438 100644 --- a/dump1090.c +++ b/dump1090.c @@ -1748,14 +1748,8 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { mm->crcok = (mm->crc == 0); mm->addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); - if (0 != mm->correctedbits) { - // DF 17 : if (error corrected) force crc = 0 but do not try to add this address - // to the whitelist of recently seen ICAO addresses. - mm->crc = 0; - - } else if (0 == mm->crc) { - // DF 17 : if uncorrected and crc == 0 add this address to the whitelist of - // recently seen ICAO addresses. + if (0 == mm->crc) { + // DF 17 : if crc == 0 try to populate our ICAO addresses whitelist. addRecentlySeenICAOAddr(mm->addr); } @@ -2465,7 +2459,7 @@ void detectModeS(uint16_t *m, uint32_t mlen) { // Update statistics if (Modes.stats) { - if (mm.crcok || use_correction || !mm.crc) { + if (mm.crcok || use_correction || mm.correctedbits) { if (errors == 0) Modes.stat_demodulated++; if (mm.correctedbits == 0) { if (mm.crcok) {Modes.stat_goodcrc++;} @@ -2542,7 +2536,7 @@ void detectModeS(uint16_t *m, uint32_t mlen) { // processing and visualization // void useModesMessage(struct modesMessage *mm) { - if ((Modes.check_crc == 0) || (mm->crcok) || (mm->crc == 0)) { // not checking, ok or fixed + if ((Modes.check_crc == 0) || (mm->crcok) || (mm->correctedbits)) { // not checking, ok or fixed // Track aircrafts if... if ( (Modes.interactive) // in interactive mode @@ -2917,7 +2911,7 @@ struct aircraft *interactiveReceiveData(struct modesMessage *mm) { struct aircraft *a, *aux; // Return if (checking crc) AND (not crcok) AND (not fixed) - if (Modes.check_crc && (mm->crcok == 0) && mm->crc) + if (Modes.check_crc && (mm->crcok == 0) && (mm->correctedbits == 0)) return NULL; // Loookup our aircraft or create a new one From 4a3113f65aa3baa0e5315443138f69f23d75c116 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Wed, 22 May 2013 00:05:03 +0100 Subject: [PATCH 9/9] Decode DF-18 --- dump1090.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/dump1090.c b/dump1090.c index 5b98438..fec1f37 100644 --- a/dump1090.c +++ b/dump1090.c @@ -296,7 +296,7 @@ struct modesMessage { int ca; // Responder capabilities int iid; - // DF 17 + // DF 17, DF 18 int metype; // Extended squitter message type. int mesub; // Extended squitter message subtype. int heading; // Reported by aircraft, or computed from from EW and NS velocity @@ -1653,6 +1653,18 @@ char *ca_str[8] = { /* 7 */ "Level 7 ???" }; +// DF 18 Control field table. +char *cf_str[8] = { + /* 0 */ "ADS-B ES/NT device with ICAO 24-bit address", + /* 1 */ "ADS-B ES/NT device with other address", + /* 2 */ "Fine format TIS-B", + /* 3 */ "Coarse format TIS-B", + /* 4 */ "TIS-B managment message", + /* 5 */ "TIS-B relay of ADS-B message with other address", + /* 6 */ "ADS-B rebroadcast using DF-17 message format", + /* 7 */ "Reserved" +}; + /* Flight status table. */ char *fs_str[8] = { /* 0 */ "Normal, Airborne", @@ -1710,7 +1722,7 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { mm->phase_corrected = 0; mm->crc = modesChecksum(msg, mm->msgbits); - if ((mm->crc) && (Modes.fix_errors) && (mm->msgtype == 17)) { + if ((mm->crc) && (Modes.fix_errors) && ((mm->msgtype == 17) || (mm->msgtype == 18))) { // if ((mm->crc) && (Modes.fix_errors) && ((mm->msgtype == 11) || (mm->msgtype == 17))) { // // Fixing single bit errors in DF-11 is a bit dodgy because we have no way to @@ -1738,6 +1750,7 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { mm->crcok = (mm->crc < 80); mm->iid = mm->crc; mm->addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); + mm->ca = (msg[0] & 0x07); // Responder capabilities if (0 == mm->crc) { // DF 11 : if crc == 0 try to populate our ICAO addresses whitelist. @@ -1747,12 +1760,23 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { } else if (mm->msgtype == 17) { // DF 17 mm->crcok = (mm->crc == 0); mm->addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); + mm->ca = (msg[0] & 0x07); // Responder capabilities if (0 == mm->crc) { // DF 17 : if crc == 0 try to populate our ICAO addresses whitelist. addRecentlySeenICAOAddr(mm->addr); } + } else if (mm->msgtype == 18) { // DF 18 + mm->crcok = (mm->crc == 0); + mm->addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); + mm->ca = (msg[0] & 0x07); // Control Field + + if (0 == mm->crc) { + // DF 18 : if crc == 0 try to populate our ICAO addresses whitelist. + addRecentlySeenICAOAddr(mm->addr); + } + } else { // All other DF's // Compare the checksum with the whitelist of recently seen ICAO // addresses. If it matches one, then declare the message as valid @@ -1770,8 +1794,7 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { } // Fields for DF11, DF17 - if (mm->msgtype == 11 || mm->msgtype == 17) { - mm->ca = msg[0] & 0x07; // Responder capabilities + if (mm->msgtype == 11 || mm->msgtype == 17) { if (mm->ca == 4) { mm->bFlags |= MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG; } else if (mm->ca == 5) { @@ -1810,8 +1833,9 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { } } - // Fields for DF17 squitter - if (mm->msgtype == 17) { + // Fields for DF17, DF18_CF0, DF18_CF1, DF18_CF6 squitters + if ( (mm->msgtype == 17) + || ((mm->msgtype == 18) && ((mm->ca == 0) || (mm->ca == 1) || (mm->ca == 6)) )) { int metype = mm->metype = msg[4] >> 3; // Extended squitter message type int mesub = mm->mesub = msg[4] & 7; // Extended squitter message subtype @@ -2104,6 +2128,65 @@ void displayModesMessage(struct modesMessage *mm) { } else if (mm->msgtype == 18) { // DF 18 printf("DF 18: Extended Squitter.\n"); + printf(" Control Field : %d (%s)\n", mm->ca, cf_str[mm->ca]); + if ((mm->ca == 0) || (mm->ca == 1) || (mm->ca == 6)) { + if (mm->ca == 1) { + printf(" Other Address : %06x\n", mm->addr); + } else { + printf(" ICAO Address : %06x\n", mm->addr); + } + printf(" Extended Squitter Type: %d\n", mm->metype); + printf(" Extended Squitter Sub : %d\n", mm->mesub); + printf(" Extended Squitter Name: %s\n", getMEDescription(mm->metype, mm->mesub)); + + // Decode the extended squitter message + if (mm->metype >= 1 && mm->metype <= 4) { // Aircraft identification + printf(" Aircraft Type : %c%d\n", ('A' + 4 - mm->metype), mm->mesub); + printf(" Identification : %s\n", mm->flight); + + //} else if (mm->metype >= 5 && mm->metype <= 8) { // Surface position + + } else if (mm->metype >= 9 && mm->metype <= 18) { // Airborne position Baro + printf(" F flag : %s\n", (mm->msg[6] & 0x04) ? "odd" : "even"); + printf(" T flag : %s\n", (mm->msg[6] & 0x08) ? "UTC" : "non-UTC"); + printf(" Altitude : %d feet\n", mm->altitude); + if (mm->bFlags & MODES_ACFLAGS_LATLON_VALID) { + printf(" Latitude : %f\n", mm->fLat); + printf(" Longitude: %f\n", mm->fLon); + } else { + printf(" Latitude : %d (not decoded)\n", mm->raw_latitude); + printf(" Longitude: %d (not decoded)\n", mm->raw_longitude); + } + + } else if (mm->metype == 19) { // Airborne Velocity + if (mm->mesub == 1 || mm->mesub == 2) { + printf(" EW status : %s\n", (mm->bFlags & MODES_ACFLAGS_EWSPEED_VALID) ? "Valid" : "Unavailable"); + printf(" EW velocity : %d\n", mm->ew_velocity); + printf(" NS status : %s\n", (mm->bFlags & MODES_ACFLAGS_NSSPEED_VALID) ? "Valid" : "Unavailable"); + printf(" NS velocity : %d\n", mm->ns_velocity); + printf(" Vertical status : %s\n", (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) ? "Valid" : "Unavailable"); + printf(" Vertical rate src : %d\n", ((mm->msg[8] >> 4) & 1)); + printf(" Vertical rate : %d\n", mm->vert_rate); + + } else if (mm->mesub == 3 || mm->mesub == 4) { + printf(" Heading status : %s\n", (mm->bFlags & MODES_ACFLAGS_HEADING_VALID) ? "Valid" : "Unavailable"); + printf(" Heading : %d\n", mm->heading); + printf(" Airspeed status : %s\n", (mm->bFlags & MODES_ACFLAGS_SPEED_VALID) ? "Valid" : "Unavailable"); + printf(" Airspeed : %d\n", mm->velocity); + printf(" Vertical status : %s\n", (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) ? "Valid" : "Unavailable"); + printf(" Vertical rate src : %d\n", ((mm->msg[8] >> 4) & 1)); + printf(" Vertical rate : %d\n", mm->vert_rate); + + } else { + printf(" Unrecognized ME subtype: %d subtype: %d\n", mm->metype, mm->mesub); + } + + //} else if (mm->metype >= 20 && mm->metype <= 22) { // Airborne position GNSS + + } else { + printf(" Unrecognized ME type: %d subtype: %d\n", mm->metype, mm->mesub); + } + } } else if (mm->msgtype == 19) { // DF 19 printf("DF 19: Military Extended Squitter.\n");