From 92fd06bcd6af8d8458abf5aac6b34bc61e7bdd2c Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Tue, 21 May 2013 11:28:56 +0100 Subject: [PATCH 01/18] 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 02/18] 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 03/18] 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 04/18] 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 05/18] 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 06/18] 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 07/18] 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 08/18] 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 09/18] 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"); From b481c769094e2fb53ddce98097e2795c23683971 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Wed, 22 May 2013 11:49:03 +0100 Subject: [PATCH 10/18] mm structure initialisation Ideally we should clear down the mm structure every loop of our ModeA/C/S bit detector. However, we're getting 2Mbits of data per second, and the structure is several tens of bytes long. Clearing down every loop would require us to zero up to 100Mb per second. The memset function may be fast, but it's still going to take up valuable processor time. So instead of clearing the whole structure every loop, just clear the important parts. --- dump1090.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/dump1090.c b/dump1090.c index fec1f37..ab0138e 100644 --- a/dump1090.c +++ b/dump1090.c @@ -998,7 +998,6 @@ int detectModeA(uint16_t *m, struct modesMessage *mm) if ((ModeABits < 3) || (ModeABits & 0xFFFF8808) || (ModeAErrs) ) {return (ModeABits = 0);} - memset(mm, 0, sizeof(*mm)); fSig = (fSig + 0x7F) >> 8; mm->signalLevel = ((fSig < 255) ? fSig : 255); @@ -1718,8 +1717,6 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { // Get the message type ASAP as other operations depend on this mm->msgtype = msg[0] >> 3; // Downlink Format mm->msgbits = modesMessageLenByType(mm->msgtype); - mm->correctedbits = 0; // No errors fixed - mm->phase_corrected = 0; mm->crc = modesChecksum(msg, mm->msgbits); if ((mm->crc) && (Modes.fix_errors) && ((mm->msgtype == 17) || (mm->msgtype == 18))) { @@ -2288,11 +2285,14 @@ void applyPhaseCorrection(uint16_t *pPayload) { * size 'mlen' bytes. Every detected Mode S message is convert it into a * stream of bits and passed to the function to display it. */ void detectModeS(uint16_t *m, uint32_t mlen) { + struct modesMessage mm; unsigned char msg[MODES_LONG_MSG_BYTES], *pMsg; uint16_t aux[MODES_LONG_MSG_SAMPLES]; uint32_t j; int use_correction = 0; + memset(&mm, 0, sizeof(mm)); + /* The Mode S preamble is made of impulses of 0.5 microseconds at * the following time offsets: * @@ -2318,7 +2318,6 @@ void detectModeS(uint16_t *m, uint32_t mlen) { */ for (j = 0; j < mlen; j++) { int high, i, errors, errors56, errorsTy; - int good_message = 0; uint16_t *pPreamble, *pPayload, *pPtr; uint8_t theByte, theErrs; int msglen, scanlen, sigStrength; @@ -2326,12 +2325,18 @@ void detectModeS(uint16_t *m, uint32_t mlen) { pPreamble = &m[j]; pPayload = &m[j+MODES_PREAMBLE_SAMPLES]; + // Rather than clear the whole mm structure, just clear the parts which are required. The clear + // is required for every bit of the input stream, and we don't want to be memset-ing the whole + // modesMessage structure two million times per second if we don't have to.. + mm.bFlags = + mm.crcok = + mm.correctedbits = 0; + if (!use_correction) // This is not a re-try with phase correction { // so try to find a new preamble if (Modes.mode_ac) { - struct modesMessage mm; int ModeA = detectModeA(pPreamble, &mm); if (ModeA) // We have found a valid ModeA/C in the data @@ -2529,13 +2534,12 @@ void detectModeS(uint16_t *m, uint32_t mlen) { if ( (msglen) && (sigStrength > MODES_MSG_SQUELCH_LEVEL) && (errors <= MODES_MSG_ENCODER_ERRS) ) { - struct modesMessage mm; - memset(&mm, 0, sizeof(mm)); // Set initial mm structure details mm.timestampMsg = Modes.timestampBlk + (j*6); sigStrength = (sigStrength + 0x7F) >> 8; mm.signalLevel = ((sigStrength < 255) ? sigStrength : 255); + mm.phase_corrected = use_correction; // Decode the received message decodeModesMessage(&mm, msg); @@ -2575,9 +2579,6 @@ void detectModeS(uint16_t *m, uint32_t mlen) { // Skip this message if we are sure it's fine if (mm.crcok) { j += (MODES_PREAMBLE_US+msglen)*2; - good_message = 1; - if (use_correction) - mm.phase_corrected = 1; } // Pass data to the next layer @@ -2591,7 +2592,7 @@ void detectModeS(uint16_t *m, uint32_t mlen) { } // Retry with phase correction if possible. - if (!good_message && !use_correction && j && detectOutOfPhase(pPreamble)) { + if (!mm.crcok && !mm.correctedbits && !use_correction && j && detectOutOfPhase(pPreamble)) { use_correction = 1; j--; } else { use_correction = 0; From e50c2a5a54778144508bde860a0af21db994a965 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Wed, 22 May 2013 13:23:54 +0100 Subject: [PATCH 11/18] Phase Enhancement changes Phase enhancement is used to try and increase the signal amplitude when Nyquist sample aliasing is suspected. In previous versions, this was enabled by default. In this version, the default is off. There is now an additional command line switch --phase-enhance to turn it on. There are also additional debug statistics which count the number of phase demodulation failures in for both uncorrected and phase corrected passes. --- dump1090.c | 97 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 19 deletions(-) diff --git a/dump1090.c b/dump1090.c index ab0138e..8b191ae 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.2105.13" +#define MODES_DUMP1090_VERSION "1.06.2205.13" #define MODES_USER_LATITUDE_DFLT (0.0) #define MODES_USER_LONGITUDE_DFLT (0.0) @@ -227,6 +227,7 @@ struct { /* Configuration */ char *filename; /* Input form file, --ifile option. */ + int phase_enhance; /* Enable phase enhancement if true */ int fix_errors; /* Single bit error correction if true. */ int check_crc; /* Only display messages with good CRC. */ int raw; /* Raw output format. */ @@ -264,7 +265,10 @@ struct { /* Statistics */ unsigned int stat_valid_preamble; - unsigned int stat_demodulated; + unsigned int stat_demodulated0; + unsigned int stat_demodulated1; + unsigned int stat_demodulated2; + unsigned int stat_demodulated3; unsigned int stat_goodcrc; unsigned int stat_badcrc; unsigned int stat_fixed; @@ -273,6 +277,15 @@ struct { unsigned int stat_http_requests; unsigned int stat_sbs_connections; unsigned int stat_out_of_phase; + unsigned int stat_ph_demodulated0; + unsigned int stat_ph_demodulated1; + unsigned int stat_ph_demodulated2; + unsigned int stat_ph_demodulated3; + unsigned int stat_ph_goodcrc; + unsigned int stat_ph_badcrc; + unsigned int stat_ph_fixed; + unsigned int stat_ph_single_bit_fix; + unsigned int stat_ph_two_bits_fix; unsigned int stat_DF_Len_Corrected; unsigned int stat_DF_Type_Corrected; unsigned int stat_ModeAC; @@ -2547,10 +2560,41 @@ void detectModeS(uint16_t *m, uint32_t mlen) { // Update statistics if (Modes.stats) { if (mm.crcok || use_correction || mm.correctedbits) { - if (errors == 0) Modes.stat_demodulated++; + + if (use_correction) { + switch (errors) { + case 0: {Modes.stat_ph_demodulated0++; break;} + case 1: {Modes.stat_ph_demodulated1++; break;} + case 2: {Modes.stat_ph_demodulated2++; break;} + default:{Modes.stat_ph_demodulated3++; break;} + } + } else { + switch (errors) { + case 0: {Modes.stat_demodulated0++; break;} + case 1: {Modes.stat_demodulated1++; break;} + case 2: {Modes.stat_demodulated2++; break;} + default:{Modes.stat_demodulated3++; break;} + } + } + if (mm.correctedbits == 0) { - if (mm.crcok) {Modes.stat_goodcrc++;} - else {Modes.stat_badcrc++;} + if (use_correction) { + if (mm.crcok) {Modes.stat_ph_goodcrc++;} + else {Modes.stat_ph_badcrc++;} + } else { + if (mm.crcok) {Modes.stat_goodcrc++;} + else {Modes.stat_badcrc++;} + } + + } else if (use_correction) { + Modes.stat_ph_badcrc++; + Modes.stat_ph_fixed++; + if (mm.correctedbits == 1) { + Modes.stat_ph_single_bit_fix++; + } else if (mm.correctedbits == 2) { + Modes.stat_ph_two_bits_fix++; + } + } else { Modes.stat_badcrc++; Modes.stat_fixed++; @@ -2591,8 +2635,8 @@ void detectModeS(uint16_t *m, uint32_t mlen) { } } - // Retry with phase correction if possible. - if (!mm.crcok && !mm.correctedbits && !use_correction && j && detectOutOfPhase(pPreamble)) { + // Retry with phase correction if enabled, necessary and possible. + if (Modes.phase_enhance && !mm.crcok && !mm.correctedbits && !use_correction && j && detectOutOfPhase(pPreamble)) { use_correction = 1; j--; } else { use_correction = 0; @@ -3986,6 +4030,7 @@ void showHelp(void) { "--fix Enable single-bits error correction using CRC\n" "--no-fix Disable single-bits error correction using CRC\n" "--no-crc-check Disable messages with broken CRC (discouraged)\n" +"--phase-enhance Enable phase enhancement\n" "--aggressive More CPU for more messages (two bits fixes, ...)\n" "--mlat display raw messages in Beast ascii mode\n" "--stats With --ifile print stats at exit. No other output\n" @@ -4064,6 +4109,8 @@ int main(int argc, char **argv) { Modes.aggressive = 0; } else if (!strcmp(argv[j],"--no-crc-check")) { Modes.check_crc = 0; + } else if (!strcmp(argv[j],"--phase-enhance")) { + Modes.phase_enhance = 1; } else if (!strcmp(argv[j],"--raw")) { Modes.raw = 1; } else if (!strcmp(argv[j],"--net")) { @@ -4207,18 +4254,30 @@ int main(int argc, char **argv) { // If --stats were given, print statistics if (Modes.stats) { printf("\n\n"); - printf("%d ModeA/C detected\n", Modes.stat_ModeAC); - printf("%d valid preambles\n", Modes.stat_valid_preamble); - printf("%d DF-?? fields corrected for length\n", Modes.stat_DF_Len_Corrected); - printf("%d DF-?? fields corrected for type\n", Modes.stat_DF_Type_Corrected); - printf("%d demodulated again after phase correction\n", Modes.stat_out_of_phase); - printf("%d demodulated with zero errors\n", Modes.stat_demodulated); - printf("%d with good crc\n", Modes.stat_goodcrc); - printf("%d with bad crc\n", Modes.stat_badcrc); - printf("%d errors corrected\n", Modes.stat_fixed); - printf("%d single bit errors\n", Modes.stat_single_bit_fix); - printf("%d two bits errors\n", Modes.stat_two_bits_fix); - printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_fixed); + printf("%d ModeA/C detected\n", Modes.stat_ModeAC); + printf("%d valid Mode-S preambles\n", Modes.stat_valid_preamble); + printf("%d DF-?? fields corrected for length\n", Modes.stat_DF_Len_Corrected); + printf("%d DF-?? fields corrected for type\n", Modes.stat_DF_Type_Corrected); + printf("%d demodulated with 0 errors\n", Modes.stat_demodulated0); + printf("%d demodulated with 1 error\n", Modes.stat_demodulated1); + printf("%d demodulated with 2 errors\n", Modes.stat_demodulated2); + printf("%d demodulated with > 2 errors\n", Modes.stat_demodulated3); + printf("%d with good crc\n", Modes.stat_goodcrc); + printf("%d with bad crc\n", Modes.stat_badcrc); + printf("%d errors corrected\n", Modes.stat_fixed); + printf("%d single bit errors\n", Modes.stat_single_bit_fix); + printf("%d two bits errors\n", Modes.stat_two_bits_fix); + 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 1 error\n", Modes.stat_ph_demodulated1); + printf("%d phase enhanced demodulated with 2 errors\n", Modes.stat_ph_demodulated2); + printf("%d phase enhanced demodulated with > 2 errors\n", Modes.stat_ph_demodulated3); + printf("%d phase enhanced with good crc\n", Modes.stat_ph_goodcrc); + printf("%d phase enhanced with bad crc\n", Modes.stat_ph_badcrc); + printf("%d phase enhanced errors corrected\n", Modes.stat_ph_fixed); + printf("%d phase enhanced single bit errors\n", Modes.stat_ph_single_bit_fix); + printf("%d phase enhanced two bits errors\n", Modes.stat_ph_two_bits_fix); + printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_ph_goodcrc + Modes.stat_fixed + Modes.stat_ph_fixed); } if (Modes.filename == NULL) { From 77bd1f40dce0fd8b6dd0934201215c2becbabb71 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Fri, 24 May 2013 11:07:49 +0100 Subject: [PATCH 12/18] Include Vertical rate in aircraft structure --- dump1090.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dump1090.c b/dump1090.c index 8b191ae..243c21f 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.2205.13" +#define MODES_DUMP1090_VERSION "1.06.2305.13" #define MODES_USER_LATITUDE_DFLT (0.0) #define MODES_USER_LONGITUDE_DFLT (0.0) @@ -168,6 +168,7 @@ struct aircraft { int altitude; // Altitude int speed; // Velocity int track; // Angle of flight + int vert_rate; // Vertical rate. time_t seen; // Time at which the last packet was received time_t seenLatLon; // Time at which the last lat long was calculated uint64_t timestamp; // Timestamp at which the last packet was received @@ -3110,6 +3111,11 @@ struct aircraft *interactiveReceiveData(struct modesMessage *mm) { a->speed = mm->velocity; } + // If a (new) Vertical Descent rate has been received, copy it to the aircraft structure + if (mm->bFlags & MODES_ACFLAGS_VERTRATE_VALID) { + a->vert_rate = mm->vert_rate; + } + // if the Aircraft has landed or taken off since the last message, clear the even/odd CPR flags if ((mm->bFlags & MODES_ACFLAGS_AOG_VALID) && ((a->bFlags ^ mm->bFlags) & MODES_ACFLAGS_AOG)) { a->bFlags &= ~(MODES_ACFLAGS_LLBOTH_VALID | MODES_ACFLAGS_AOG); From 4c0ed6d5f1318d22269ffc450023d0e7f6778ae0 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Fri, 24 May 2013 11:10:16 +0100 Subject: [PATCH 13/18] Set AOG_VALID for DF-17/18 metype 19 --- dump1090.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dump1090.c b/dump1090.c index 243c21f..9543222 100644 --- a/dump1090.c +++ b/dump1090.c @@ -1898,6 +1898,9 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { } else if (metype == 19) { // Airborne Velocity Message + // Presumably airborne if we get an Airborne Velocity Message + mm->bFlags |= MODES_ACFLAGS_AOG_VALID; + if ( (mesub >= 1) && (mesub <= 4) ) { int vert_rate = ((msg[8] & 0x07) << 6) | (msg[9] >> 2); if (vert_rate) { From ee742cf8db66fff710f48d8680ad780ae4cc6f72 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Fri, 24 May 2013 12:26:06 +0100 Subject: [PATCH 14/18] SBS Output Format changes Bug fixes in the SBS output code as a result of an EMAIL from Liviu Some software gets upset if null fields are output where the software is expecting a valid value. This was being caused by DF0's outputting and SBS MSG5. MSG5 needs Atert and SPI flags, which are derived from the FS field. DF0 doesn't have an FS field, so cannot output a MSG5. Change so that DF0 results in an SBS MSG7. Also DF17/DF18 metypes 5 to 18 contain raw Lat/Lon data. However they cannot be decoded into real Lat/Lon values unless both even and odd parts are available Therefore, when we receive a DF17/DF18 we need to check that we have successfully decoded the Lat/Lon before we attempt to send an SBS MSG2 or MSG3. If we don't have a decoded Lat/Lon, send a MSG7 instead. --- dump1090.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/dump1090.c b/dump1090.c index 9543222..e7eb5b3 100644 --- a/dump1090.c +++ b/dump1090.c @@ -3534,22 +3534,28 @@ void modesSendSBSOutput(struct modesMessage *mm) { // // Decide on the basic SBS Message Type - if ((mm->msgtype == 0) || (mm->msgtype == 4) || (mm->msgtype == 20)) { + if ((mm->msgtype == 4) || (mm->msgtype == 20)) { msgType = 5; - } else if ((mm->msgtype == 5) || (mm->msgtype == 21)) { + } else if ((mm->msgtype == 5) || (mm->msgtype == 21)) { msgType = 6; - } else if (mm->msgtype == 16) { + } else if ((mm->msgtype == 0) || (mm->msgtype == 16)) { msgType = 7; - } else if (mm->msgtype == 11) { + } else if (mm->msgtype == 11) { msgType = 8; - } else if (mm->msgtype != 17) { + } else if ((mm->msgtype != 17) && (mm->msgtype != 18)) { return; - } else if (mm->metype == 4) { + } else if ((mm->metype >= 1) && (mm->metype <= 4)) { msgType = 1; } else if ((mm->metype >= 5) && (mm->metype <= 8)) { - msgType = 2; + if (mm->bFlags & MODES_ACFLAGS_LATLON_VALID) + {msgType = 2;} + else + {msgType = 7;} } else if ((mm->metype >= 9) && (mm->metype <= 18)) { - msgType = 3; + if (mm->bFlags & MODES_ACFLAGS_LATLON_VALID) + {msgType = 3;} + else + {msgType = 7;} } else if (mm->metype != 19) { return; } else if ((mm->mesub == 1) || (mm->mesub == 2)) { From 9edba9332aa475d364fe7363815cd57e7e677e6b Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Fri, 24 May 2013 21:24:16 +0100 Subject: [PATCH 15/18] 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 --- Makefile | 16 ++++++- README.md | 25 ++++++----- dump1090.c | 124 +++++++++++++++++++++++++++++++++-------------------- 3 files changed, 107 insertions(+), 58 deletions(-) diff --git a/Makefile b/Makefile index c6084a0..8382ff0 100644 --- a/Makefile +++ b/Makefile @@ -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` LIBS=`pkg-config --libs librtlsdr` -lpthread -lm CC=gcc -PROGNAME=dump1090 + all: dump1090 %.o: %.c - $(CC) $(CFLAGS) -c $< + $(CC) $(CFLAGS) $(EXTRACFLAGS) -c $< dump1090: dump1090.o anet.o $(CC) -g -o dump1090 dump1090.o anet.o $(LIBS) diff --git a/README.md b/README.md index 8a9f752..3fdd396 100644 --- a/README.md +++ b/README.md @@ -86,9 +86,13 @@ it without arguments at all is the best thing to do. Reliability --- -By default Dump1090 tries to fix single bit errors using the checksum. -Basically the program will try to flip every bit of the message and check if -the checksum of the resulting message matches. +By default Dump1090 checks for decoding errors using the 24-bit CRC checksum, +where available. Messages with errors are discarded. + +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, 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 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. The algorithm in aggressive mode is modified in the following ways: -* 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. +* 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 with CRC errors resulting from any two bit + errors. -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. +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 e7eb5b3..089fab3 100644 --- a/dump1090.c +++ b/dump1090.c @@ -72,6 +72,9 @@ #define MODES_MSG_SQUELCH_LEVEL 0x02FF /* Average signal strength limit */ #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_BYTES 2 #define MODEAC_MSG_SQUELCH_LEVEL 0x07FF /* Average signal strength limit */ @@ -150,6 +153,10 @@ #define MODES_CLIENT_BUF_SIZE 1024 #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) /* Structure used to describe a networking client. */ @@ -229,7 +236,7 @@ struct { /* Configuration */ char *filename; /* Input form file, --ifile option. */ 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 raw; /* Raw output format. */ int beast; /* Beast binary format output. */ @@ -273,8 +280,12 @@ struct { unsigned int stat_goodcrc; unsigned int stat_badcrc; 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_sbs_connections; unsigned int stat_out_of_phase; @@ -300,7 +311,8 @@ struct modesMessage { int msgtype; // Downlink format # int crcok; // True if CRC was valid 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 int phase_corrected; // True if phase correction was applied uint64_t timestampMsg; // Timestamp of the message @@ -341,7 +353,7 @@ void modesSendRawOutput(struct modesMessage *mm); void modesSendBeastOutput(struct modesMessage *mm); void modesSendSBSOutput(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 fixTwoBitsErrors(unsigned char *msg, int bits); 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 * loadable by debug.html. */ 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 start = offset - padding; @@ -680,6 +692,7 @@ void dumpRawMessageJS(char *descr, unsigned char *msg, FILE *fp; int j; + MODES_NOTUSED(fixable); if ((fp = fopen("frames.js","a")) == NULL) { fprintf(stderr, "Error opening frames.js: %s\n", strerror(errno)); exit(1); @@ -690,8 +703,8 @@ void dumpRawMessageJS(char *descr, unsigned char *msg, fprintf(fp,"%d", j < 0 ? 0 : m[j]); if (j != end) fprintf(fp,","); } - fprintf(fp,"], \"fixed\": %d, \"bits\": %d, \"hex\": \"", - fixable, modesMessageLenByType(msg[0]>>3)); + fprintf(fp,"], \"fix1\": %d, \"fix2\": %d, \"bits\": %d, \"hex\": \"", + bitpos[0], bitpos[1] , modesMessageLenByType(msg[0]>>3)); for (j = 0; j < MODES_LONG_MSG_BYTES; j++) fprintf(fp,"\\x%02x",msg[j]); fprintf(fp,"\"});\n"); @@ -716,13 +729,18 @@ void dumpRawMessage(char *descr, unsigned char *msg, int j; int msgtype = msg[0] >> 3; int fixable = 0; + int bitpos[MODES_MAX_BITERRORS]; + for (j = 0; j < MODES_MAX_BITERRORS; j++) { + bitpos[j] = -1; + } 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) { - dumpRawMessageJS(descr, msg, m, offset, fixable); + dumpRawMessageJS(descr, msg, m, offset, fixable, bitpos); return; } @@ -1253,8 +1271,8 @@ int fixTwoBitsErrors(unsigned char *msg, int bits) { */ struct errorinfo { uint32_t syndrome; /* CRC syndrome */ - int pos0; /* bit position of first error */ - int pos1; /* bit position of second error, or -1 */ + int bits; /* No of bit positions to fix */ + int pos[MODES_MAX_BITERRORS]; /* bit positions */ }; #define NERRORINFO \ @@ -1290,8 +1308,9 @@ void modesInitErrorInfo() { 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; + bitErrorTable[n].bits = 1; + bitErrorTable[n].pos[0] = i; + bitErrorTable[n].pos[1] = -1; n += 1; if (Modes.aggressive) { @@ -1308,9 +1327,10 @@ void modesInitErrorInfo() { */ break; } - bitErrorTable[n].syndrome = crc; // two bit error case - bitErrorTable[n].pos0 = i; - bitErrorTable[n].pos1 = j; + 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 } @@ -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 // bits. Make sure the indices fit into the array, and for 2-bit errors, // 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. // -int fixBitErrors(unsigned char *msg, int bits) { +int fixBitErrors(unsigned char *msg, int bits, + int maxfixable, int *fixedbitpos) { struct errorinfo *pei; 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.pos0 = -1; - ei.pos1 = -1; pei = bsearch(&ei, bitErrorTable, NERRORINFO, sizeof(struct errorinfo), cmpErrorInfo); if (pei == NULL) { return 0; // No syndrome found } + if (maxfixable < pei->bits) { + return 0; + } res = 0; offset = MODES_LONG_MSG_BITS-bits; - bitpos0 = pei->pos0 - offset; - if ((bitpos0 < 0) || (bitpos0 >= bits)) { - return 0; + /* Check that all bit positions are inside message boundaries */ + for (i = 0; i < pei->bits; i++) { + bitpos = pei->pos[i] - offset; + if ((bitpos < 0) || (bitpos >= 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++; + /* Fix the bits */ + for (i = 0; i < pei->bits; i++) { + bitpos = pei->pos[i] - offset; + msg[(bitpos >> 3)] ^= (1 << (7 - (bitpos & 7))); + if (fixedbitpos != NULL) { + fixedbitpos[res] = bitpos; + } + res++; } return res; } @@ -1492,7 +1520,8 @@ void testAndTimeBitCorrection() { inittmsg1(); gettimeofday(&starttv, NULL); 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); printf(" New code: 1-bit errors on %d msgs: %ld usecs\n", @@ -1511,7 +1540,8 @@ void testAndTimeBitCorrection() { inittmsg2(); gettimeofday(&starttv, NULL); 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); 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 // 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 (mm->correctedbits) { uint32_t addr = (msg[1] << 16) | (msg[2] << 8) | (msg[3]); @@ -2601,11 +2632,10 @@ void detectModeS(uint16_t *m, uint32_t mlen) { } else { Modes.stat_badcrc++; - Modes.stat_fixed++; - if (mm.correctedbits == 1) { - Modes.stat_single_bit_fix++; - } else if (mm.correctedbits == 2) { - Modes.stat_two_bits_fix++; + Modes.stat_fixed += 1; + if ((mm.correctedbits > 0) && + (mm.correctedbits <= MODES_MAX_BITERRORS)) { + Modes.stat_bit_fix[mm.correctedbits-1] += 1; } } } @@ -3858,9 +3888,10 @@ int handleHTTPRequest(struct client *c) { } 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 { - 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: @@ -4155,7 +4186,7 @@ int main(int argc, char **argv) { Modes.metric = 1; } else if (!strcmp(argv[j],"--aggressive")) { Modes.aggressive = 1; - Modes.fix_errors = 1; + Modes.fix_errors = MODES_MAX_BITERRORS; } else if (!strcmp(argv[j],"--interactive")) { Modes.interactive = 1; } 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 bad crc\n", Modes.stat_badcrc); printf("%d errors corrected\n", Modes.stat_fixed); - printf("%d single bit errors\n", Modes.stat_single_bit_fix); - printf("%d two bits errors\n", Modes.stat_two_bits_fix); + for (j = 0; j < MODES_MAX_BITERRORS; j++) { + 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 enhanced demodulated with 0 errors\n", Modes.stat_ph_demodulated0); printf("%d phase enhanced demodulated with 1 error\n", Modes.stat_ph_demodulated1); From f64a65b5a20075194206fca903e8e04e9913e090 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Fri, 24 May 2013 21:51:44 +0100 Subject: [PATCH 16/18] Tidy up of UKUEHN's improvements Resolves some merge conflicts that I couldn't find a way to fix during the previous merge. Remove a few Tabs that escaped in the edit/merge Rename the fix_errors flag variable to nFix_crc since it now represents the number of crc errors to attempt to fix. Remove the aggressive variable since it's now part of nFix_crc Only print phase correction statistics when phase correction is enabled. Add an additional Modes.stat_ph_bit_fix[] to count the bits fixed during phase correction --- dump1090.c | 309 ++++++++++++++++++++++++----------------------------- 1 file changed, 140 insertions(+), 169 deletions(-) diff --git a/dump1090.c b/dump1090.c index 089fab3..30b87f0 100644 --- a/dump1090.c +++ b/dump1090.c @@ -236,7 +236,7 @@ struct { /* Configuration */ char *filename; /* Input form file, --ifile option. */ int phase_enhance; /* Enable phase enhancement if true */ - int fix_errors; /* If > 0 no of bit errors to fix */ + int nfix_crc; /* Number of crc bit error(s) to correct */ int check_crc; /* Only display messages with good CRC. */ int raw; /* Raw output format. */ int beast; /* Beast binary format output. */ @@ -258,7 +258,6 @@ 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. */ int mlat; /* Use Beast ascii format for raw data output, i.e. @...; iso *...; */ int interactive_rtl1090; /* flight table in interactive mode is formatted like RTL1090 */ @@ -281,9 +280,8 @@ struct { unsigned int stat_badcrc; unsigned int stat_fixed; - /* Histogram of fixed bit errors: index 0 for single bit erros, - * index 1 for double bit errors etc. - */ + // 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; @@ -296,8 +294,10 @@ struct { unsigned int stat_ph_goodcrc; unsigned int stat_ph_badcrc; unsigned int stat_ph_fixed; - unsigned int stat_ph_single_bit_fix; - unsigned int stat_ph_two_bits_fix; + // Histogram of fixed bit errors: index 0 for single bit erros, + // index 1 for double bit errors etc. + unsigned int stat_ph_bit_fix[MODES_MAX_BITERRORS]; + unsigned int stat_DF_Len_Corrected; unsigned int stat_DF_Type_Corrected; unsigned int stat_ModeAC; @@ -306,17 +306,17 @@ struct { // The struct we use to store information about a decoded message. struct modesMessage { // Generic fields - unsigned char msg[MODES_LONG_MSG_BYTES]; // Binary message. - int msgbits; // Number of bits in message - int msgtype; // Downlink format # - int crcok; // True if CRC was valid - uint32_t crc; // Message CRC - 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 - int phase_corrected; // True if phase correction was applied - uint64_t timestampMsg; // Timestamp of the message - unsigned char signalLevel; // Signal Amplitude + unsigned char msg[MODES_LONG_MSG_BYTES]; // Binary message. + int msgbits; // Number of bits in message + int msgtype; // Downlink format # + int crcok; // True if CRC was valid + uint32_t crc; // Message CRC + int correctedbits; // No. of bits corrected + char corrected[MODES_MAX_BITERRORS]; // corrected bit positions + uint32_t addr; // ICAO Address from bytes 1 2 and 3 + int phase_corrected; // True if phase correction was applied + uint64_t timestampMsg; // Timestamp of the message + unsigned char signalLevel; // Signal Amplitude // DF 11 int ca; // Responder capabilities @@ -491,7 +491,7 @@ void modesInit(void) { } } - /* Prepare error correction tables */ + // Prepare error correction tables modesInitErrorInfo(); } @@ -684,7 +684,7 @@ void dumpMagnitudeVector(uint16_t *m, uint32_t offset) { /* Produce a raw representation of the message as a Javascript file * loadable by debug.html. */ void dumpRawMessageJS(char *descr, unsigned char *msg, - uint16_t *m, uint32_t offset, int fixable, int *bitpos) + uint16_t *m, uint32_t offset, int fixable, char *bitpos) { int padding = 5; /* Show a few samples before the actual start. */ int start = offset - padding; @@ -726,17 +726,16 @@ void dumpRawMessageJS(char *descr, unsigned char *msg, void dumpRawMessage(char *descr, unsigned char *msg, uint16_t *m, uint32_t offset) { - int j; - int msgtype = msg[0] >> 3; - int fixable = 0; - int bitpos[MODES_MAX_BITERRORS]; + int j; + int msgtype = msg[0] >> 3; + int fixable = 0; + char bitpos[MODES_MAX_BITERRORS]; for (j = 0; j < MODES_MAX_BITERRORS; j++) { bitpos[j] = -1; } if (msgtype == 17) { - fixable = fixBitErrors(msg, MODES_LONG_MSG_BITS, - MODES_MAX_BITERRORS, bitpos); + fixable = fixBitErrors(msg, MODES_LONG_MSG_BITS, MODES_MAX_BITERRORS, bitpos); } if (Modes.debug & MODES_DEBUG_JS) { @@ -1205,7 +1204,7 @@ int fixSingleBitErrors(unsigned char *msg, int bits) { // 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]; @@ -1245,7 +1244,7 @@ int fixTwoBitsErrors(unsigned char *msg, int bits) { } return (-1); } - +*/ /* Code for introducing a less CPU-intensive method of correcting * single bit errors. * @@ -1270,9 +1269,9 @@ int fixTwoBitsErrors(unsigned char *msg, int bits) { * */ struct errorinfo { - uint32_t syndrome; /* CRC syndrome */ - int bits; /* No of bit positions to fix */ - int pos[MODES_MAX_BITERRORS]; /* bit positions */ + 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 \ @@ -1281,114 +1280,87 @@ 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; - } + 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; + 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.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 - 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 - } + 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; } - msg[bytepos0] ^= mask0; // revert error0 + 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 + } } - 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); - } + 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); - } - */ + } + + for (i = 0; i < NERRORINFO; i++) { + printf("syndrome %06x bit0 %3d bit1 %3d\n", + bitErrorTable[i].syndrome, + bitErrorTable[i].pos0, bitErrorTable[i].pos1); + } + */ } // -// 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)) { - return 0; - } - if (bit < 5) { - return 0; - } - bytepos = (bit >> 3); - mask = 1 << (7 - (bit & 7)); - 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. +// 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 maxfixable, int *fixedbitpos) { +int fixBitErrors(unsigned char *msg, int bits, int maxfix, char *fixedbits) { struct errorinfo *pei; struct errorinfo ei; int bitpos, offset, res, i; @@ -1399,26 +1371,28 @@ int fixBitErrors(unsigned char *msg, int bits, if (pei == NULL) { return 0; // No syndrome found } - if (maxfixable < pei->bits) { - return 0; + + // Check if the syndrome fixes more bits than we allow + if (maxfix < pei->bits) { + return 0; } - res = 0; + + // Check that all bit positions lie inside the message length offset = MODES_LONG_MSG_BITS-bits; - /* Check that all bit positions are inside message boundaries */ for (i = 0; i < pei->bits; i++) { bitpos = pei->pos[i] - offset; if ((bitpos < 0) || (bitpos >= bits)) { return 0; } } - /* Fix the bits */ - for (i = 0; i < pei->bits; i++) { + + // Fix the bits + for (i = res = 0; i < pei->bits; i++) { bitpos = pei->pos[i] - offset; - msg[(bitpos >> 3)] ^= (1 << (7 - (bitpos & 7))); - if (fixedbitpos != NULL) { - fixedbitpos[res] = bitpos; + msg[bitpos >> 3] ^= (1 << (7 - (bitpos & 7))); + if (fixedbits) { + fixedbits[res++] = bitpos; } - res++; } return res; } @@ -1510,7 +1484,7 @@ void testAndTimeBitCorrection() { inittmsg1(); gettimeofday(&starttv, NULL); for (i = 0; i < MODES_LONG_MSG_BITS; i++) { - fixSingleBitErrors(&tmsg1[i][0], MODES_LONG_MSG_BITS); + fixSingleBitErrors(&tmsg1[i][0], MODES_LONG_MSG_BITS); } gettimeofday(&endtv, NULL); printf(" Old code: 1-bit errors on %d msgs: %ld usecs\n", @@ -1520,8 +1494,7 @@ void testAndTimeBitCorrection() { inittmsg1(); gettimeofday(&starttv, NULL); for (i = 0; i < MODES_LONG_MSG_BITS; i++) { - fixBitErrors(&tmsg1[i][0], MODES_LONG_MSG_BITS, - MODES_MAX_BITERRORS, NULL); + fixBitErrors(&tmsg1[i][0], MODES_LONG_MSG_BITS, MODES_MAX_BITERRORS, NULL); } gettimeofday(&endtv, NULL); printf(" New code: 1-bit errors on %d msgs: %ld usecs\n", @@ -1531,7 +1504,7 @@ void testAndTimeBitCorrection() { inittmsg2(); gettimeofday(&starttv, NULL); for (i = 0; i < NTWOBITS; i++) { - fixSingleBitErrors(&tmsg2[i][0], MODES_LONG_MSG_BITS); + fixSingleBitErrors(&tmsg2[i][0], MODES_LONG_MSG_BITS); } gettimeofday(&endtv, NULL); printf(" Old code: 2-bit errors on %d msgs: %ld usecs\n", @@ -1540,8 +1513,7 @@ void testAndTimeBitCorrection() { inittmsg2(); gettimeofday(&starttv, NULL); for (i = 0; i < NTWOBITS; i++) { - fixBitErrors(&tmsg2[i][0], MODES_LONG_MSG_BITS, - MODES_MAX_BITERRORS, NULL); + fixBitErrors(&tmsg2[i][0], MODES_LONG_MSG_BITS, MODES_MAX_BITERRORS, NULL); } gettimeofday(&endtv, NULL); printf(" New code: 2-bit errors on %d msgs: %ld usecs\n", @@ -1763,8 +1735,8 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { mm->msgbits = modesMessageLenByType(mm->msgtype); mm->crc = modesChecksum(msg, mm->msgbits); - if ((mm->crc) && (Modes.fix_errors) && ((mm->msgtype == 17) || (mm->msgtype == 18))) { -// if ((mm->crc) && (Modes.fix_errors) && ((mm->msgtype == 11) || (mm->msgtype == 17))) { + if ((mm->crc) && (Modes.nfix_crc) && ((mm->msgtype == 17) || (mm->msgtype == 18))) { +// if ((mm->crc) && (Modes.nfix_crc) && ((mm->msgtype == 11) || (mm->msgtype == 17))) { // // Fixing single bit errors in DF-11 is a bit dodgy because we have no way to // know for sure if the crc is supposed to be 0 or not - it could be any value @@ -1775,8 +1747,8 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { // using the results. Perhaps check the ICAO against known aircraft, and check // IID against known good IID's. That's a TODO. // - mm->correctedbits = fixBitErrors(msg, mm->msgbits, - Modes.fix_errors, mm->corrected); + mm->correctedbits = fixBitErrors(msg, mm->msgbits, Modes.nfix_crc, mm->corrected); + // 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]); @@ -2624,18 +2596,17 @@ void detectModeS(uint16_t *m, uint32_t mlen) { } else if (use_correction) { Modes.stat_ph_badcrc++; Modes.stat_ph_fixed++; - if (mm.correctedbits == 1) { - Modes.stat_ph_single_bit_fix++; - } else if (mm.correctedbits == 2) { - Modes.stat_ph_two_bits_fix++; + if ( (mm.correctedbits) + && (mm.correctedbits <= MODES_MAX_BITERRORS) ) { + Modes.stat_ph_bit_fix[mm.correctedbits-1] += 1; } } else { Modes.stat_badcrc++; - Modes.stat_fixed += 1; - if ((mm.correctedbits > 0) && - (mm.correctedbits <= MODES_MAX_BITERRORS)) { - Modes.stat_bit_fix[mm.correctedbits-1] += 1; + Modes.stat_fixed++; + if ( (mm.correctedbits) + && (mm.correctedbits <= MODES_MAX_BITERRORS) ) { + Modes.stat_bit_fix[mm.correctedbits-1] += 1; } } } @@ -3888,8 +3859,7 @@ int handleHTTPRequest(struct client *c) { } if (strlen(url) < 2) { - snprintf(getFile, sizeof getFile, "%s/%s", - HTMLPATH, "gmap.html"); // Default file + snprintf(getFile, sizeof getFile, "%s/gmap.html", HTMLPATH); // Default file } else { snprintf(getFile, sizeof getFile, "%s/%s", HTMLPATH, url); } @@ -4149,10 +4119,9 @@ int main(int argc, char **argv) { } else if (!strcmp(argv[j],"--ifile") && more) { Modes.filename = strdup(argv[++j]); } else if (!strcmp(argv[j],"--fix")) { - Modes.fix_errors = 1; + Modes.nfix_crc = 1; } else if (!strcmp(argv[j],"--no-fix")) { - Modes.fix_errors = 0; - Modes.aggressive = 0; + Modes.nfix_crc = 0; } else if (!strcmp(argv[j],"--no-crc-check")) { Modes.check_crc = 0; } else if (!strcmp(argv[j],"--phase-enhance")) { @@ -4185,8 +4154,7 @@ int main(int argc, char **argv) { } else if (!strcmp(argv[j],"--metric")) { Modes.metric = 1; } else if (!strcmp(argv[j],"--aggressive")) { - Modes.aggressive = 1; - Modes.fix_errors = MODES_MAX_BITERRORS; + Modes.nfix_crc = MODES_MAX_BITERRORS; } else if (!strcmp(argv[j],"--interactive")) { Modes.interactive = 1; } else if (!strcmp(argv[j],"--interactive-rows") && more) { @@ -4314,16 +4282,19 @@ int main(int argc, char **argv) { for (j = 0; j < MODES_MAX_BITERRORS; j++) { 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 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 2 errors\n", Modes.stat_ph_demodulated2); - printf("%d phase enhanced demodulated with > 2 errors\n", Modes.stat_ph_demodulated3); - printf("%d phase enhanced with good crc\n", Modes.stat_ph_goodcrc); - printf("%d phase enhanced with bad crc\n", Modes.stat_ph_badcrc); - printf("%d phase enhanced errors corrected\n", Modes.stat_ph_fixed); - printf("%d phase enhanced single bit errors\n", Modes.stat_ph_single_bit_fix); - printf("%d phase enhanced two bits errors\n", Modes.stat_ph_two_bits_fix); + if (Modes.phase_enhance) { + 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 1 error\n", Modes.stat_ph_demodulated1); + printf("%d phase enhanced demodulated with 2 errors\n", Modes.stat_ph_demodulated2); + printf("%d phase enhanced demodulated with > 2 errors\n", Modes.stat_ph_demodulated3); + printf("%d phase enhanced with good crc\n", Modes.stat_ph_goodcrc); + printf("%d phase enhanced with bad crc\n", Modes.stat_ph_badcrc); + printf("%d phase enhanced errors corrected\n", Modes.stat_ph_fixed); + for (j = 0; j < MODES_MAX_BITERRORS; j++) { + printf(" %d with %d bit %s\n", Modes.stat_bit_fix[j], j+1, (j==0)?"error":"errors"); + } + } printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_ph_goodcrc + Modes.stat_fixed + Modes.stat_ph_fixed); } From e86eb3921e135f62a35cc852fcd375f3d0fff7ce Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Fri, 24 May 2013 22:29:00 +0100 Subject: [PATCH 17/18] VK1ET : Numerous changes to Port handling Changes based on ideas from John VK1ET. His commit notes are as follows : 1. Change input socket handling to avoid unnecessary memmove (use pointers instead) 2. Add ability to read and decode binary beast format TCP. 3. Change output socket handling same as sbs_output - only call output handler if there is a current client connected use separate ports for beast in and out - no need for --net-beast flag. Will input/output format defined by socket connected to. avr raw, beast binary and sbs can be handled simultaneously. 4. Some comments changes, filtering of ModeAC to json,. --- dump1090.c | 397 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 260 insertions(+), 137 deletions(-) diff --git a/dump1090.c b/dump1090.c index 30b87f0..d758cef 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.2305.13" +#define MODES_DUMP1090_VERSION "1.07.2305.13" #define MODES_USER_LATITUDE_DFLT (0.0) #define MODES_USER_LONGITUDE_DFLT (0.0) @@ -146,11 +146,13 @@ #define MODES_INTERACTIVE_TTL 60 /* TTL before being removed */ #define MODES_NET_MAX_FD 1024 -#define MODES_NET_OUTPUT_SBS_PORT 30003 -#define MODES_NET_OUTPUT_RAW_PORT 30002 -#define MODES_NET_INPUT_RAW_PORT 30001 -#define MODES_NET_HTTP_PORT 8080 -#define MODES_CLIENT_BUF_SIZE 1024 +#define MODES_NET_INPUT_RAW_PORT 30001 +#define MODES_NET_OUTPUT_RAW_PORT 30002 +#define MODES_NET_OUTPUT_SBS_PORT 30003 +#define MODES_NET_INPUT_BEAST_PORT 30004 +#define MODES_NET_OUTPUT_BEAST_PORT 30005 +#define MODES_NET_HTTP_PORT 8080 +#define MODES_CLIENT_BUF_SIZE 1024 #define MODES_NET_SNDBUF_SIZE (1024*64) #ifndef HTMLPATH @@ -229,9 +231,13 @@ struct { int sbsos; /* SBS output listening socket. */ int ros; /* Raw output listening socket. */ int ris; /* Raw input listening socket. */ + int bos; /* Beast output listening socket */ + int bis; /* Beast input listening socket */ int https; /* HTTP listening socket. */ char * rawOut; /* Buffer for building raw output data */ int rawOutUsed; /* How much if the buffer is currently used */ + char *beastOut; /* Buffer for building beast output data */ + int beastOutUsed; /* How much if the buffer is currently used */ /* Configuration */ char *filename; /* Input form file, --ifile option. */ @@ -250,6 +256,8 @@ struct { int net_output_raw_rate_count; /* Rate (in 64mS increments) of output raw data */ int net_output_raw_port; /* Raw output TCP port. */ int net_input_raw_port; /* Raw input TCP port. */ + int net_output_beast_port; /* Beast output TCP port */ + int net_input_beast_port; /* Beast input TCP port */ int net_http_port; /* HTTP port. */ int quiet; /* Suppress stdout */ int interactive; /* Interactive mode */ @@ -286,6 +294,8 @@ struct { unsigned int stat_http_requests; unsigned int stat_sbs_connections; + unsigned int stat_raw_connections; + unsigned int stat_beast_connections; unsigned int stat_out_of_phase; unsigned int stat_ph_demodulated0; unsigned int stat_ph_demodulated1; @@ -316,6 +326,7 @@ struct modesMessage { uint32_t addr; // ICAO Address from bytes 1 2 and 3 int phase_corrected; // True if phase correction was applied uint64_t timestampMsg; // Timestamp of the message + int remote; // If set this message is from a remote station unsigned char signalLevel; // Signal Amplitude // DF 11 @@ -353,7 +364,7 @@ void modesSendRawOutput(struct modesMessage *mm); void modesSendBeastOutput(struct modesMessage *mm); void modesSendSBSOutput(struct modesMessage *mm); void useModesMessage(struct modesMessage *mm); -int fixBitErrors(unsigned char *msg, int bits, int maxfixable, int *bitpos); +int fixBitErrors(unsigned char *msg, int bits, int maxfix, char *fixedbits); int fixSingleBitErrors(unsigned char *msg, int bits); int fixTwoBitsErrors(unsigned char *msg, int bits); void modesInitErrorInfo(); @@ -384,17 +395,19 @@ void modesInitConfig(void) { memset(&Modes, 0, sizeof(Modes)); // Now initialise things that should not be 0/NULL to their defaults - Modes.gain = MODES_MAX_GAIN; - Modes.freq = MODES_DEFAULT_FREQ; - Modes.check_crc = 1; - Modes.net_output_sbs_port = MODES_NET_OUTPUT_SBS_PORT; - Modes.net_output_raw_port = MODES_NET_OUTPUT_RAW_PORT; - Modes.net_input_raw_port = MODES_NET_INPUT_RAW_PORT; - Modes.net_http_port = MODES_NET_HTTP_PORT; - Modes.interactive_rows = MODES_INTERACTIVE_ROWS; - Modes.interactive_ttl = MODES_INTERACTIVE_TTL; - Modes.fUserLat = MODES_USER_LATITUDE_DFLT; - Modes.fUserLon = MODES_USER_LONGITUDE_DFLT; + Modes.gain = MODES_MAX_GAIN; + Modes.freq = MODES_DEFAULT_FREQ; + Modes.check_crc = 1; + Modes.net_output_sbs_port = MODES_NET_OUTPUT_SBS_PORT; + Modes.net_output_raw_port = MODES_NET_OUTPUT_RAW_PORT; + Modes.net_input_raw_port = MODES_NET_INPUT_RAW_PORT; + Modes.net_output_beast_port = MODES_NET_OUTPUT_BEAST_PORT; + Modes.net_input_beast_port = MODES_NET_INPUT_BEAST_PORT; + Modes.net_http_port = MODES_NET_HTTP_PORT; + Modes.interactive_rows = MODES_INTERACTIVE_ROWS; + Modes.interactive_ttl = MODES_INTERACTIVE_TTL; + Modes.fUserLat = MODES_USER_LATITUDE_DFLT; + Modes.fUserLon = MODES_USER_LONGITUDE_DFLT; } void modesInit(void) { @@ -408,6 +421,7 @@ void modesInit(void) { ((Modes.data = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE) ) == NULL) || ((Modes.magnitude = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE+MODES_PREAMBLE_SIZE+MODES_LONG_MSG_SIZE) ) == NULL) || ((Modes.maglut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) || + ((Modes.beastOut = (char *) malloc(MODES_RAWOUT_BUF_SIZE) ) == NULL) || ((Modes.rawOut = (char *) malloc(MODES_RAWOUT_BUF_SIZE) ) == NULL) ) { fprintf(stderr, "Out of memory allocating data buffer.\n"); @@ -2649,13 +2663,19 @@ void detectModeS(uint16_t *m, uint32_t mlen) { } //Send any remaining partial raw buffers now - if (Modes.rawOutUsed) + if (Modes.rawOutUsed || Modes.beastOutUsed) { Modes.net_output_raw_rate_count++; if (Modes.net_output_raw_rate_count > Modes.net_output_raw_rate) { - modesSendAllClients(Modes.ros, Modes.rawOut, Modes.rawOutUsed); - Modes.rawOutUsed = 0; + if (Modes.rawOutUsed) { + modesSendAllClients(Modes.ros, Modes.rawOut, Modes.rawOutUsed); + Modes.rawOutUsed = 0; + } + if (Modes.beastOutUsed) { + modesSendAllClients(Modes.bos, Modes.beastOut, Modes.beastOutUsed); + Modes.beastOutUsed = 0; + } Modes.net_output_raw_rate_count = 0; } } @@ -2684,19 +2704,10 @@ void useModesMessage(struct modesMessage *mm) { displayModesMessage(mm); } - // Feed SBS output clients - if (Modes.stat_sbs_connections) { - modesSendSBSOutput(mm); - } - - // Send data to connected network clients - if (Modes.net) { - if (Modes.beast) { - modesSendBeastOutput(mm); - } else { - modesSendRawOutput(mm); - } - } + // Feed output clients + if (Modes.stat_sbs_connections) {modesSendSBSOutput(mm);} + if (Modes.stat_beast_connections) {modesSendBeastOutput(mm);} + if (Modes.stat_raw_connections) {modesSendRawOutput(mm);} } } @@ -3346,9 +3357,11 @@ void modesInitNet(void) { char *descr; int *socket; int port; - } services[4] = { + } services[6] = { {"Raw TCP output", &Modes.ros, Modes.net_output_raw_port}, {"Raw TCP input", &Modes.ris, Modes.net_input_raw_port}, + {"Beast TCP output", &Modes.bos, Modes.net_output_beast_port}, + {"Beast TCP input", &Modes.bis, Modes.net_input_beast_port}, {"HTTP server", &Modes.https, Modes.net_http_port}, {"Basestation TCP output", &Modes.sbsos, Modes.net_output_sbs_port} }; @@ -3357,7 +3370,7 @@ void modesInitNet(void) { memset(Modes.clients,0,sizeof(Modes.clients)); Modes.maxfd = -1; - for (j = 0; j < 4; j++) { + for (j = 0; j < 6; j++) { int s = anetTcpServer(Modes.aneterr, services[j].port, NULL); if (s == -1) { fprintf(stderr, "Error opening the listening port %d (%s): %s\n", @@ -3378,12 +3391,14 @@ void modesAcceptClients(void) { int fd, port; unsigned int j; struct client *c; - int services[4]; + int services[6]; services[0] = Modes.ros; services[1] = Modes.ris; - services[2] = Modes.https; - services[3] = Modes.sbsos; + services[2] = Modes.bos; + services[3] = Modes.bis; + services[4] = Modes.https; + services[5] = Modes.sbsos; for (j = 0; j < sizeof(services)/sizeof(int); j++) { fd = anetTcpAccept(Modes.aneterr, services[j], NULL, &port); @@ -3404,6 +3419,8 @@ void modesAcceptClients(void) { if (Modes.maxfd < fd) Modes.maxfd = fd; if (services[j] == Modes.sbsos) Modes.stat_sbs_connections++; + if (services[j] == Modes.ros) Modes.stat_raw_connections++; + if (services[j] == Modes.bos) Modes.stat_beast_connections++; j--; /* Try again with the same listening port. */ @@ -3415,6 +3432,15 @@ void modesAcceptClients(void) { /* On error free the client, collect the structure, adjust maxfd if needed. */ void modesFreeClient(int fd) { close(fd); + if (Modes.clients[fd]->service == Modes.sbsos) { + if (Modes.stat_sbs_connections) Modes.stat_sbs_connections--; + } + else if (Modes.clients[fd]->service == Modes.ros) { + if (Modes.stat_raw_connections) Modes.stat_raw_connections--; + } + else if (Modes.clients[fd]->service == Modes.bos) { + if (Modes.stat_beast_connections) Modes.stat_beast_connections--; + } free(Modes.clients[fd]); Modes.clients[fd] = NULL; @@ -3451,7 +3477,7 @@ void modesSendAllClients(int service, void *msg, int len) { /* Write raw output in Beast Binary format with Timestamp to TCP clients */ void modesSendBeastOutput(struct modesMessage *mm) { - char *p = &Modes.rawOut[Modes.rawOutUsed]; + char *p = &Modes.beastOut[Modes.beastOutUsed]; int msgLen = mm->msgbits / 8; char * pTimeStamp; int j; @@ -3475,11 +3501,11 @@ void modesSendBeastOutput(struct modesMessage *mm) { memcpy(p, mm->msg, msgLen); - Modes.rawOutUsed += (msgLen + 9); - if (Modes.rawOutUsed >= Modes.net_output_raw_size) + Modes.beastOutUsed += (msgLen + 9); + if (Modes.beastOutUsed >= Modes.net_output_raw_size) { - modesSendAllClients(Modes.ros, Modes.rawOut, Modes.rawOutUsed); - Modes.rawOutUsed = 0; + modesSendAllClients(Modes.bos, Modes.beastOut, Modes.beastOutUsed); + Modes.beastOutUsed = 0; Modes.net_output_raw_rate_count = 0; } } @@ -3665,42 +3691,80 @@ void modesSendSBSOutput(struct modesMessage *mm) { p += sprintf(p, "\r\n"); modesSendAllClients(Modes.sbsos, msg, p-msg); } +// +// This function decodes a Beast binary format message +// +// The message is passed to the higher level layers, so it feeds +// the selected screen output, the network output and so forth. +// +// If the message looks invalid it is silently discarded. +// +// The function always returns 0 (success) to the caller as there is no +// case where we want broken messages here to close the client connection. +int decodeBinMessage(struct client *c, char *p) { + int msgLen = 0; + unsigned char msg[MODES_LONG_MSG_BYTES]; + struct modesMessage mm; + MODES_NOTUSED(c); + memset(&mm, 0, sizeof(mm)); -/* Turn an hex digit into its 4 bit decimal value. - * Returns -1 if the digit is not in the 0-F range. */ + if ((*p == '1') && (Modes.mode_ac)) { // skip ModeA/C unless user enables --modes-ac + msgLen = MODEAC_MSG_BYTES; + } else if (*p == '2') { + msgLen = MODES_SHORT_MSG_BYTES; + } else if (*p == '3') { + msgLen = MODES_LONG_MSG_BYTES; + } + + if (msgLen) { + // Mark messages received over the internet as remote so that we don't try to + // pass them off as being received by this instance when forwarding them + mm.remote = 1; + p += 7; // Skip the timestamp + mm.signalLevel = *p++; // Grab the signal level + memcpy(msg, p, msgLen); // and the data + + if (msgLen == MODEAC_MSG_BYTES) { // ModeA or ModeC + decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1])); + } else { + decodeModesMessage(&mm, msg); + } + + useModesMessage(&mm); + } + return (0); +} +// +// Turn an hex digit into its 4 bit decimal value. +// Returns -1 if the digit is not in the 0-F range. int hexDigitVal(int c) { c = tolower(c); if (c >= '0' && c <= '9') return c-'0'; else if (c >= 'a' && c <= 'f') return c-'a'+10; else return -1; } - -/* This function decodes a string representing a Mode S message in - * raw hex format like: *8D4B969699155600E87406F5B69F; - * The string is supposed to be at the start of the client buffer - * and null-terminated. - * - * The message is passed to the higher level layers, so it feeds - * the selected screen output, the network output and so forth. - * - * If the message looks invalid is silently discarded. - * - * The function always returns 0 (success) to the caller as there is - * no case where we want broken messages here to close the client - * connection. */ -int decodeHexMessage(struct client *c) { - char *hex = c->buf; +// +// This function decodes a string representing message in raw hex format +// like: *8D4B969699155600E87406F5B69F; The string is null-terminated. +// +// The message is passed to the higher level layers, so it feeds +// the selected screen output, the network output and so forth. +// +// If the message looks invalid it is silently discarded. +// +// The function always returns 0 (success) to the caller as there is no +// case where we want broken messages here to close the client connection. +int decodeHexMessage(struct client *c, char *hex) { int l = strlen(hex), j; unsigned char msg[MODES_LONG_MSG_BYTES]; struct modesMessage mm; + MODES_NOTUSED(c); memset(&mm, 0, sizeof(mm)); - // Always mark the timestamp as invalid for packets received over the internet - // 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 = 0; - mm.signalLevel = -1; + // Mark messages received over the internet as remote so that we don't try to + // pass them off as being received by this instance when forwarding them + mm.remote = 1; + mm.signalLevel = 0xFF; // Remove spaces on the left and on the right while(l && isspace(hex[l-1])) { @@ -3736,7 +3800,15 @@ int decodeHexMessage(struct client *c) { break;} } - if ( (l < 4) || (l > MODES_LONG_MSG_BYTES*2) ) return (0); // Too short or long message... broken + if ( (l != (MODEAC_MSG_BYTES * 2)) + && (l != (MODES_SHORT_MSG_BYTES * 2)) + && (l != (MODES_LONG_MSG_BYTES * 2)) ) + {return (0);} // Too short or long message... broken + + if ( (0 == Modes.mode_ac) + && (l == (MODEAC_MSG_BYTES * 2)) ) + {return (0);} // Right length for ModeA/C, but not enabled + for (j = 0; j < l; j += 2) { int high = hexDigitVal(hex[j]); int low = hexDigitVal(hex[j+1]); @@ -3745,8 +3817,11 @@ int decodeHexMessage(struct client *c) { msg[j/2] = (high << 4) | low; } - if (l < 5) {decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1]));} // ModeA or ModeC - else {decodeModesMessage(&mm, msg);} + if (l == (MODEAC_MSG_BYTES * 2)) { // ModeA or ModeC + decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1])); + } else { // Assume ModeS + decodeModesMessage(&mm, msg); + } useModesMessage(&mm); return (0); @@ -3766,6 +3841,11 @@ char *aircraftsToJson(int *len) { int altitude = a->altitude, speed = a->speed; int position = 0; int track = 0; + + if (a->modeACflags & MODEAC_MSG_FLAG) { // skip any fudged ICAO records Mode A/C + a = a->next; + continue; + } /* Convert units to metric if --metric was specified. */ if (Modes.metric) { @@ -3823,11 +3903,11 @@ char *aircraftsToJson(int *len) { * * Returns 1 on error to signal the caller the client connection should * be closed. */ -int handleHTTPRequest(struct client *c) { +int handleHTTPRequest(struct client *c, char *p) { char hdr[512]; int clen, hdrlen; int httpver, keepalive; - char *p, *url, *content; + char *url, *content; char ctype[48]; char getFile[1024]; char *ext; @@ -3836,17 +3916,17 @@ int handleHTTPRequest(struct client *c) { printf("\nHTTP request: %s\n", c->buf); // Minimally parse the request. - httpver = (strstr(c->buf, "HTTP/1.1") != NULL) ? 11 : 10; + httpver = (strstr(p, "HTTP/1.1") != NULL) ? 11 : 10; if (httpver == 10) { // HTTP 1.0 defaults to close, unless otherwise specified. - keepalive = strstr(c->buf, "Connection: keep-alive") != NULL; + keepalive = strstr(p, "Connection: keep-alive") != NULL; } else if (httpver == 11) { // HTTP 1.1 defaults to keep-alive, unless close is specified. - keepalive = strstr(c->buf, "Connection: close") == NULL; + keepalive = strstr(p, "Connection: close") == NULL; } // Identify he URL. - p = strchr(c->buf,' '); + p = strchr(p,' '); if (!p) return 1; /* There should be the method and a space... */ url = ++p; /* Now this should point to the requested URL. */ p = strchr(p, ' '); @@ -3930,77 +4010,110 @@ int handleHTTPRequest(struct client *c) { Modes.stat_http_requests++; return !keepalive; } - -/* This function polls the clients using read() in order to receive new - * messages from the net. - * - * The message is supposed to be separated by the next message by the - * separator 'sep', that is a null-terminated C string. - * - * Every full message received is decoded and passed to the higher layers - * calling the function 'handler'. - * - * The handelr returns 0 on success, or 1 to signal this function we - * should close the connection with the client in case of non-recoverable - * errors. */ +// +// This function polls the clients using read() in order to receive new +// messages from the net. +// +// The message is supposed to be separated from the next message by the +// separator 'sep', which is a null-terminated C string. +// +// Every full message received is decoded and passed to the higher layers +// calling the function's 'handler'. +// +// The handler returns 0 on success, or 1 to signal this function we should +// close the connection with the client in case of non-recoverable errors. void modesReadFromClient(struct client *c, char *sep, - int(*handler)(struct client *)) -{ + int(*handler)(struct client *, char *)) { + int left; + int nread; + int fullmsg; + char *s, *e; + while(1) { - int left = MODES_CLIENT_BUF_SIZE - c->buflen; - int nread = read(c->fd, c->buf+c->buflen, left); - int fullmsg = 0; - int i; - char *p; + + fullmsg = 0; + left = MODES_CLIENT_BUF_SIZE - c->buflen; + // If our buffer is full discard it, this is some badly formatted shit + if (left == 0) { + c->buflen = 0; + left = MODES_CLIENT_BUF_SIZE; + // If there is garbage, read more to discard it ASAP + } + nread = read(c->fd, c->buf+c->buflen, left); if (nread <= 0) { - if (nread == 0 || errno != EAGAIN) { - /* Error, or end of file. */ + if (nread == 0 || errno != EAGAIN) { // Error, or end of file modesFreeClient(c->fd); } - break; /* Serve next client. */ + break; // Serve next client } c->buflen += nread; - /* Always null-term so we are free to use strstr() */ + // Always null-term so we are free to use strstr() (it won't affect binary case) c->buf[c->buflen] = '\0'; - /* If there is a complete message there must be the separator 'sep' - * in the buffer, note that we full-scan the buffer at every read - * for simplicity. */ - while ((p = strstr(c->buf, sep)) != NULL) { - i = p - c->buf; /* Turn it as an index inside the buffer. */ - c->buf[i] = '\0'; /* Te handler expects null terminated strings. */ - /* Call the function to process the message. It returns 1 - * on error to signal we should close the client connection. */ - if (handler(c)) { - modesFreeClient(c->fd); - return; + e = s = c->buf; // Start with the start of buffer, first message + + if (c->service == Modes.bis) { + // This is the Bease Binary scanning case. + // If there is a complete message still in the buffer, there must be the separator 'sep' + // in the buffer, note that we full-scan the buffer at every read for simplicity. + + left = c->buflen; // Length of valid search for memchr() + while (left && ((s = memchr(e, (char) 0x1a, left)) != NULL)) { // In reality the first byte of buffer 'should' be 0x1a + s++; // skip the 0x1a + if (*s == '1') { + e = s + MODEAC_MSG_BYTES + 8; // point past remainder of message + } else if (*s == '2') { + e = s + MODES_SHORT_MSG_BYTES + 8; + } else if (*s == '3') { + e = s + MODES_LONG_MSG_BYTES + 8; + } else { + e = s; // Not a valid beast message, skip + left = &(c->buf[c->buflen]) - e; + continue; + } + left = &(c->buf[c->buflen]) - e; + if (left < 0) { // Incomplete message in buffer + e = s - 1; // point back at last found 0x1a. + break; + } + // Have a 0x1a followed by 1, 2 or 3 - pass message less 0x1a to handler. + if (handler(c, s)) { + modesFreeClient(c->fd); + return; + } + fullmsg = 1; + } + s = e; // For the buffer remainder below + + } else { + // This is the ASCII scanning case, AVR RAW or HTTP at present + // If there is a complete message still in the buffer, there must be the separator 'sep' + // in the buffer, note that we full-scan the buffer at every read for simplicity. + + while ((e = strstr(s, sep)) != NULL) { // end of first message if found + *e = '\0'; // The handler expects null terminated strings + if (handler(c, s)) { // Pass message to handler. + modesFreeClient(c->fd); // Handler returns 1 on error to signal we . + return; // should close the client connection + } + s = e + strlen(sep); // Move to start of next message + fullmsg = 1; } - /* Move what's left at the start of the buffer. */ - i += strlen(sep); /* The separator is part of the previous msg. */ - memmove(c->buf,c->buf+i,c->buflen-i); - c->buflen -= i; - c->buf[c->buflen] = '\0'; - /* Maybe there are more messages inside the buffer. - * Start looping from the start again. */ - fullmsg = 1; } - /* If our buffer is full discard it, this is some badly - * formatted shit. */ - if (c->buflen == MODES_CLIENT_BUF_SIZE) { - c->buflen = 0; - /* If there is garbage, read more to discard it ASAP. */ - continue; + + if (fullmsg) { // We processed something - so + c->buflen = &(c->buf[c->buflen]) - s; // The unprocessed buffer length + memmove(c->buf, s, c->buflen); // move what's remaining to the start of the buffer + } else { // If no message was decoded process the next client + break; } - /* If no message was decoded process the next client, otherwise - * read more data from the same client. */ - if (!fullmsg) break; } } - -/* Read data from clients. This function actually delegates a lower-level - * function that depends on the kind of service (raw, http, ...). */ +// +// Read data from clients. This function actually delegates a lower-level +// function that depends on the kind of service (raw, http, ...). void modesReadFromClients(void) { int j; struct client *c; @@ -4009,6 +4122,8 @@ void modesReadFromClients(void) { if ((c = Modes.clients[j]) == NULL) continue; if (c->service == Modes.ris) modesReadFromClient(c,"\n",decodeHexMessage); + else if (c->service == Modes.bis) + modesReadFromClient(c,"",decodeBinMessage); else if (c->service == Modes.https) modesReadFromClient(c,"\r\n\r\n",handleHTTPRequest); } @@ -4035,12 +4150,14 @@ void showHelp(void) { "--modeac Enable decoding of SSR Modes 3/A & 3/C\n" "--net-beast TCP raw output in Beast binary format\n" "--net-only Enable just networking, no RTL device or file used\n" +"--net-http-port HTTP server port (default: 8080)\n" +"--net-ri-port TCP raw input listen port (default: 30001)\n" +"--net-ro-port TCP raw output listen port (default: 30002)\n" +"--net-sbs-port TCP BaseStation output listen port (default: 30003)\n" +"--net-bi-port TCP Beast input listen port (default: 30004)\n" +"--net-bo-port TCP Beast output listen port (default: 30005)\n" "--net-ro-size TCP raw output minimum size (default: 0)\n" "--net-ro-rate TCP raw output memory flush rate (default: 0)\n" -"--net-ro-port TCP raw output listen port (default: 30002)\n" -"--net-ri-port TCP raw input listen port (default: 30001)\n" -"--net-http-port HTTP server port (default: 8080)\n" -"--net-sbs-port TCP BaseStation output listen port (default: 30003)\n" "--lat Reference/receiver latitide for surface posn (opt)\n" "--lon Reference/receiver longitude for surface posn (opt)\n" "--fix Enable single-bits error correction using CRC\n" @@ -4143,8 +4260,14 @@ int main(int argc, char **argv) { Modes.net_output_raw_rate = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-ro-port") && more) { Modes.net_output_raw_port = atoi(argv[++j]); + if (Modes.beast) // Required for legacy backward compatibility + {Modes.net_output_beast_port = Modes.net_output_raw_port;} } else if (!strcmp(argv[j],"--net-ri-port") && more) { Modes.net_input_raw_port = atoi(argv[++j]); + } else if (!strcmp(argv[j],"--net-bo-port") && more) { + Modes.net_output_beast_port = atoi(argv[++j]); + } else if (!strcmp(argv[j],"--net-bi-port") && more) { + Modes.net_input_beast_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-http-port") && more) { Modes.net_http_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-sbs-port") && more) { @@ -4292,7 +4415,7 @@ int main(int argc, char **argv) { printf("%d phase enhanced with bad crc\n", Modes.stat_ph_badcrc); printf("%d phase enhanced errors corrected\n", Modes.stat_ph_fixed); for (j = 0; j < MODES_MAX_BITERRORS; j++) { - printf(" %d with %d bit %s\n", Modes.stat_bit_fix[j], j+1, (j==0)?"error":"errors"); + printf(" %d with %d bit %s\n", Modes.stat_ph_bit_fix[j], j+1, (j==0)?"error":"errors"); } } printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_ph_goodcrc + Modes.stat_fixed + Modes.stat_ph_fixed); From 228b770be8dddfbf60b8d46d5ffa0deb619184e4 Mon Sep 17 00:00:00 2001 From: Malcolm Robb Date: Fri, 24 May 2013 23:32:12 +0100 Subject: [PATCH 18/18] Move declarations into a headed file This is the start of breaking the main dump109.c file into smaller modules to make it a bit more maintainable. Move all the #define and structure declarations into dump1090.h --- dump1090.c | 347 +-------------------------------------------- dump1090.h | 403 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 407 insertions(+), 343 deletions(-) create mode 100644 dump1090.h diff --git a/dump1090.c b/dump1090.c index d758cef..c6f41f1 100644 --- a/dump1090.c +++ b/dump1090.c @@ -27,348 +27,8 @@ * (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 _WIN32 - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include "rtl-sdr.h" - #include "anet.h" -#else - #include "dump1090.h" //Put everything Windows specific in here - #include "rtl-sdr.h" -#endif -// File Version number -// ==================== -// Format is : MajorVer.MinorVer.DayMonth.Year" -// MajorVer changes only with significant changes -// 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.07.2305.13" -#define MODES_USER_LATITUDE_DFLT (0.0) -#define MODES_USER_LONGITUDE_DFLT (0.0) - -#define MODES_DEFAULT_RATE 2000000 -#define MODES_DEFAULT_FREQ 1090000000 -#define MODES_DEFAULT_WIDTH 1000 -#define MODES_DEFAULT_HEIGHT 700 -#define MODES_ASYNC_BUF_NUMBER 12 -#define MODES_ASYNC_BUF_SIZE (16*16384) /* 256k */ -#define MODES_ASYNC_BUF_SAMPLES (MODES_ASYNC_BUF_SIZE / 2) /* Each sample is 2 bytes */ -#define MODES_AUTO_GAIN -100 /* Use automatic gain. */ -#define MODES_MAX_GAIN 999999 /* Use max available gain. */ -#define MODES_MSG_SQUELCH_LEVEL 0x02FF /* Average signal strength limit */ -#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_BYTES 2 -#define MODEAC_MSG_SQUELCH_LEVEL 0x07FF /* Average signal strength limit */ -#define MODEAC_MSG_FLAG (1<<0) -#define MODEAC_MSG_MODES_HIT (1<<1) -#define MODEAC_MSG_MODEA_HIT (1<<2) -#define MODEAC_MSG_MODEC_HIT (1<<3) -#define MODEAC_MSG_MODEA_ONLY (1<<4) -#define MODEAC_MSG_MODEC_OLD (1<<5) - -#define MODES_PREAMBLE_US 8 /* microseconds = bits */ -#define MODES_PREAMBLE_SAMPLES (MODES_PREAMBLE_US * 2) -#define MODES_PREAMBLE_SIZE (MODES_PREAMBLE_SAMPLES * sizeof(uint16_t)) -#define MODES_LONG_MSG_BYTES 14 -#define MODES_SHORT_MSG_BYTES 7 -#define MODES_LONG_MSG_BITS (MODES_LONG_MSG_BYTES * 8) -#define MODES_SHORT_MSG_BITS (MODES_SHORT_MSG_BYTES * 8) -#define MODES_LONG_MSG_SAMPLES (MODES_LONG_MSG_BITS * 2) -#define MODES_SHORT_MSG_SAMPLES (MODES_SHORT_MSG_BITS * 2) -#define MODES_LONG_MSG_SIZE (MODES_LONG_MSG_SAMPLES * sizeof(uint16_t)) -#define MODES_SHORT_MSG_SIZE (MODES_SHORT_MSG_SAMPLES * sizeof(uint16_t)) - -#define MODES_RAWOUT_BUF_SIZE (1500) -#define MODES_RAWOUT_BUF_FLUSH (MODES_RAWOUT_BUF_SIZE - 200) -#define MODES_RAWOUT_BUF_RATE (1000) // 1000 * 64mS = 1 Min approx - -#define MODES_ICAO_CACHE_LEN 1024 /* Power of two required. */ -#define MODES_ICAO_CACHE_TTL 60 /* Time to live of cached addresses. */ -#define MODES_UNIT_FEET 0 -#define MODES_UNIT_METERS 1 - -#define MODES_USER_LATLON_VALID (1<<0) - -#define MODES_ACFLAGS_LATLON_VALID (1<<0) // Aircraft Lat/Lon is decoded -#define MODES_ACFLAGS_ALTITUDE_VALID (1<<1) // Aircraft altitude is known -#define MODES_ACFLAGS_HEADING_VALID (1<<2) // Aircraft heading is known -#define MODES_ACFLAGS_SPEED_VALID (1<<3) // Aircraft speed is known -#define MODES_ACFLAGS_VERTRATE_VALID (1<<4) // Aircraft vertical rate is known -#define MODES_ACFLAGS_SQUAWK_VALID (1<<5) // Aircraft Mode A Squawk is known -#define MODES_ACFLAGS_CALLSIGN_VALID (1<<6) // Aircraft Callsign Identity -#define MODES_ACFLAGS_EWSPEED_VALID (1<<7) // Aircraft East West Speed is known -#define MODES_ACFLAGS_NSSPEED_VALID (1<<8) // Aircraft North South Speed is known -#define MODES_ACFLAGS_AOG (1<<9) // Aircraft is On the Ground -#define MODES_ACFLAGS_LLEVEN_VALID (1<<10) // Aircraft Even Lot/Lon is known -#define MODES_ACFLAGS_LLODD_VALID (1<<11) // Aircraft Odd Lot/Lon is known -#define MODES_ACFLAGS_AOG_VALID (1<<12) // MODES_ACFLAGS_AOG is valid -#define MODES_ACFLAGS_FS_VALID (1<<13) // Aircraft Flight Status is known -#define MODES_ACFLAGS_NSEWSPD_VALID (1<<14) // Aircraft EW and NS Speed is known -#define MODES_ACFLAGS_LATLON_REL_OK (1<<15) // Indicates it's OK to do a relative CPR - -#define MODES_ACFLAGS_LLEITHER_VALID (MODES_ACFLAGS_LLEVEN_VALID | MODES_ACFLAGS_LLODD_VALID) -#define MODES_ACFLAGS_LLBOTH_VALID (MODES_ACFLAGS_LLEVEN_VALID | MODES_ACFLAGS_LLODD_VALID) -#define MODES_ACFLAGS_AOG_GROUND (MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG) - -#define MODES_DEBUG_DEMOD (1<<0) -#define MODES_DEBUG_DEMODERR (1<<1) -#define MODES_DEBUG_BADCRC (1<<2) -#define MODES_DEBUG_GOODCRC (1<<3) -#define MODES_DEBUG_NOPREAMBLE (1<<4) -#define MODES_DEBUG_NET (1<<5) -#define MODES_DEBUG_JS (1<<6) - -/* When debug is set to MODES_DEBUG_NOPREAMBLE, the first sample must be - * at least greater than a given level for us to dump the signal. */ -#define MODES_DEBUG_NOPREAMBLE_LEVEL 25 - -#define MODES_INTERACTIVE_REFRESH_TIME 250 /* Milliseconds */ -#define MODES_INTERACTIVE_ROWS 15 /* Rows on screen */ -#define MODES_INTERACTIVE_TTL 60 /* TTL before being removed */ - -#define MODES_NET_MAX_FD 1024 -#define MODES_NET_INPUT_RAW_PORT 30001 -#define MODES_NET_OUTPUT_RAW_PORT 30002 -#define MODES_NET_OUTPUT_SBS_PORT 30003 -#define MODES_NET_INPUT_BEAST_PORT 30004 -#define MODES_NET_OUTPUT_BEAST_PORT 30005 -#define MODES_NET_HTTP_PORT 8080 -#define MODES_CLIENT_BUF_SIZE 1024 -#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) - -/* Structure used to describe a networking client. */ -struct client { - int fd; /* File descriptor. */ - int service; /* TCP port the client is connected to. */ - char buf[MODES_CLIENT_BUF_SIZE+1]; /* Read buffer. */ - int buflen; /* Amount of data on buffer. */ -}; - -// Structure used to describe an aircraft in iteractive mode -struct aircraft { - uint32_t addr; // ICAO address - char flight[16]; // Flight number - unsigned char signalLevel[8]; // Last 8 Signal Amplitudes - int altitude; // Altitude - int speed; // Velocity - int track; // Angle of flight - int vert_rate; // Vertical rate. - time_t seen; // Time at which the last packet was received - time_t seenLatLon; // Time at which the last lat long was calculated - uint64_t timestamp; // Timestamp at which the last packet was received - uint64_t timestampLatLon; // Timestamp at which the last lat long was calculated - long messages; // Number of Mode S messages received - int modeA; // Squawk - int modeC; // Altitude - long modeAcount; // Mode A Squawk hit Count - long modeCcount; // Mode C Altitude hit Count - int modeACflags; // Flags for mode A/C recognition - // Encoded latitude and longitude as extracted by odd and even CPR encoded messages - int odd_cprlat; - int odd_cprlon; - int even_cprlat; - int even_cprlon; - double lat, lon; // Coordinated obtained from CPR encoded data - int bFlags; // Flags related to valid fields in this structure - uint64_t odd_cprtime, even_cprtime; - struct aircraft *next; // Next aircraft in our linked list -}; - -/* Program global state. */ -struct { - /* Internal state */ - pthread_t reader_thread; - pthread_mutex_t data_mutex; /* Mutex to synchronize buffer access. */ - pthread_cond_t data_cond; /* Conditional variable associated. */ - uint16_t *data; /* Raw IQ samples buffer */ - uint16_t *magnitude; /* Magnitude vector */ - struct timeb stSystemTimeRTL; /* System time when RTL passed us the Latest block */ - uint64_t timestampBlk; /* Timestamp of the start of the current block */ - struct timeb stSystemTimeBlk; /* System time when RTL passed us currently processing this block */ - int fd; /* --ifile option file descriptor. */ - int data_ready; /* Data ready to be processed. */ - uint32_t *icao_cache; /* Recently seen ICAO addresses cache. */ - uint16_t *maglut; /* I/Q -> Magnitude lookup table. */ - int exit; /* Exit from the main loop when true. */ - - /* RTLSDR */ - int dev_index; - int gain; - int enable_agc; - rtlsdr_dev_t *dev; - int freq; - int ppm_error; - - /* Networking */ - char aneterr[ANET_ERR_LEN]; - struct client *clients[MODES_NET_MAX_FD]; /* Our clients. */ - int maxfd; /* Greatest fd currently active. */ - int sbsos; /* SBS output listening socket. */ - int ros; /* Raw output listening socket. */ - int ris; /* Raw input listening socket. */ - int bos; /* Beast output listening socket */ - int bis; /* Beast input listening socket */ - int https; /* HTTP listening socket. */ - char * rawOut; /* Buffer for building raw output data */ - int rawOutUsed; /* How much if the buffer is currently used */ - char *beastOut; /* Buffer for building beast output data */ - int beastOutUsed; /* How much if the buffer is currently used */ - - /* Configuration */ - char *filename; /* Input form file, --ifile option. */ - int phase_enhance; /* Enable phase enhancement if true */ - int nfix_crc; /* Number of crc bit error(s) to correct */ - int check_crc; /* Only display messages with good CRC. */ - int raw; /* Raw output format. */ - int beast; /* Beast binary format output. */ - int mode_ac; /* Enable decoding of SSR Modes A & C. */ - int debug; /* Debugging mode. */ - int net; /* Enable networking. */ - int net_only; /* Enable just networking. */ - int net_output_sbs_port; /* SBS output TCP port. */ - int net_output_raw_size; /* Minimum Size of the output raw data */ - int net_output_raw_rate; /* Rate (in 64mS increments) of output raw data */ - int net_output_raw_rate_count; /* Rate (in 64mS increments) of output raw data */ - int net_output_raw_port; /* Raw output TCP port. */ - int net_input_raw_port; /* Raw input TCP port. */ - int net_output_beast_port; /* Beast output TCP port */ - int net_input_beast_port; /* Beast input TCP port */ - int net_http_port; /* HTTP port. */ - int quiet; /* Suppress stdout */ - int interactive; /* Interactive mode */ - int interactive_rows; /* Interactive mode: max number of rows. */ - int interactive_ttl; /* Interactive mode: TTL before deletion. */ - int stats; /* Print stats at exit in --ifile mode. */ - int onlyaddr; /* Print only ICAO addresses. */ - int metric; /* Use metric units. */ - int mlat; /* Use Beast ascii format for raw data output, i.e. @...; iso *...; */ - int interactive_rtl1090; /* flight table in interactive mode is formatted like RTL1090 */ - - // User details - double fUserLat; // Users receiver/antenna lat/lon needed for initial surface location - double fUserLon; // Users receiver/antenna lat/lon needed for initial surface location - int bUserFlags; // Flags relating to the user details - - /* Interactive mode */ - struct aircraft *aircrafts; - uint64_t interactive_last_update; /* Last screen update in milliseconds */ - - /* Statistics */ - unsigned int stat_valid_preamble; - unsigned int stat_demodulated0; - unsigned int stat_demodulated1; - unsigned int stat_demodulated2; - unsigned int stat_demodulated3; - unsigned int stat_goodcrc; - unsigned int stat_badcrc; - unsigned int stat_fixed; - - // 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_sbs_connections; - unsigned int stat_raw_connections; - unsigned int stat_beast_connections; - unsigned int stat_out_of_phase; - unsigned int stat_ph_demodulated0; - unsigned int stat_ph_demodulated1; - unsigned int stat_ph_demodulated2; - unsigned int stat_ph_demodulated3; - unsigned int stat_ph_goodcrc; - unsigned int stat_ph_badcrc; - unsigned int stat_ph_fixed; - // Histogram of fixed bit errors: index 0 for single bit erros, - // index 1 for double bit errors etc. - unsigned int stat_ph_bit_fix[MODES_MAX_BITERRORS]; - - unsigned int stat_DF_Len_Corrected; - unsigned int stat_DF_Type_Corrected; - unsigned int stat_ModeAC; -} Modes; - -// The struct we use to store information about a decoded message. -struct modesMessage { - // Generic fields - unsigned char msg[MODES_LONG_MSG_BYTES]; // Binary message. - int msgbits; // Number of bits in message - int msgtype; // Downlink format # - int crcok; // True if CRC was valid - uint32_t crc; // Message CRC - int correctedbits; // No. of bits corrected - char corrected[MODES_MAX_BITERRORS]; // corrected bit positions - uint32_t addr; // ICAO Address from bytes 1 2 and 3 - int phase_corrected; // True if phase correction was applied - uint64_t timestampMsg; // Timestamp of the message - int remote; // If set this message is from a remote station - unsigned char signalLevel; // Signal Amplitude - - // DF 11 - int ca; // Responder capabilities - int iid; - - // 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 - int raw_latitude; // Non decoded latitude. - int raw_longitude; // Non decoded longitude. - double fLat; // Coordinates obtained from CPR encoded data if/when decoded - double fLon; // Coordinates obtained from CPR encoded data if/when decoded - char flight[16]; // 8 chars flight number. - int ew_velocity; // E/W velocity. - int ns_velocity; // N/S velocity. - int vert_rate; // Vertical rate. - int velocity; // Reported by aircraft, or computed from from EW and NS velocity - - // DF4, DF5, DF20, DF21 - int fs; // Flight status for DF4,5,20,21 - int modeA; // 13 bits identity (Squawk). - - // Fields used by multiple message types. - int altitude; - int unit; - int bFlags; // Flags related to fields in this structure -}; - -void interactiveShowData(void); -struct aircraft* interactiveReceiveData(struct modesMessage *mm); -void modesSendAllClients(int service, void *msg, int len); -void modesSendRawOutput(struct modesMessage *mm); -void modesSendBeastOutput(struct modesMessage *mm); -void modesSendSBSOutput(struct modesMessage *mm); -void useModesMessage(struct modesMessage *mm); -int fixBitErrors(unsigned char *msg, int bits, int maxfix, char *fixedbits); -int fixSingleBitErrors(unsigned char *msg, int bits); -int fixTwoBitsErrors(unsigned char *msg, int bits); -void modesInitErrorInfo(); -int modesMessageLenByType(int type); +#include "dump1090.h" /* ============================= Utility functions ========================== */ @@ -4259,9 +3919,10 @@ int main(int argc, char **argv) { } else if (!strcmp(argv[j],"--net-ro-rate") && more) { Modes.net_output_raw_rate = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-ro-port") && more) { - Modes.net_output_raw_port = atoi(argv[++j]); if (Modes.beast) // Required for legacy backward compatibility - {Modes.net_output_beast_port = Modes.net_output_raw_port;} + {Modes.net_output_beast_port = atoi(argv[++j]);;} + else + {Modes.net_output_raw_port = atoi(argv[++j]);} } else if (!strcmp(argv[j],"--net-ri-port") && more) { Modes.net_input_raw_port = atoi(argv[++j]); } else if (!strcmp(argv[j],"--net-bo-port") && more) { diff --git a/dump1090.h b/dump1090.h new file mode 100644 index 0000000..e2f6ff7 --- /dev/null +++ b/dump1090.h @@ -0,0 +1,403 @@ +/* dump1090, a Mode S messages decoder for RTLSDR devices. + * + * Copyright (C) 2012 by Salvatore Sanfilippo + * + * 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_H +#define __DUMP1090_H + +// File Version number +// ==================== +// Format is : MajorVer.MinorVer.DayMonth.Year" +// MajorVer changes only with significant changes +// 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.07.2305.13" + +/* ============================= Include files ========================== */ + +#ifndef _WIN32 + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include "rtl-sdr.h" + #include "anet.h" +#else + #include "winstubs.h" //Put everything Windows specific in here + #include "rtl-sdr.h" +#endif + +/* ============================= #defines =============================== */ + +#ifdef USER_LATITUDE + #define MODES_USER_LATITUDE_DFLT (USER_LATITUDE) + #define MODES_USER_LONGITUDE_DFLT (USER_LONGITUDE) +#else + #define MODES_USER_LATITUDE_DFLT (0.0) + #define MODES_USER_LONGITUDE_DFLT (0.0) +#endif + +#define MODES_DEFAULT_RATE 2000000 +#define MODES_DEFAULT_FREQ 1090000000 +#define MODES_DEFAULT_WIDTH 1000 +#define MODES_DEFAULT_HEIGHT 700 +#define MODES_ASYNC_BUF_NUMBER 12 +#define MODES_ASYNC_BUF_SIZE (16*16384) // 256k +#define MODES_ASYNC_BUF_SAMPLES (MODES_ASYNC_BUF_SIZE / 2) // Each sample is 2 bytes +#define MODES_AUTO_GAIN -100 // Use automatic gain +#define MODES_MAX_GAIN 999999 // Use max available gain +#define MODES_MSG_SQUELCH_LEVEL 0x02FF // Average signal strength limit +#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_BYTES 2 +#define MODEAC_MSG_SQUELCH_LEVEL 0x07FF // Average signal strength limit +#define MODEAC_MSG_FLAG (1<<0) +#define MODEAC_MSG_MODES_HIT (1<<1) +#define MODEAC_MSG_MODEA_HIT (1<<2) +#define MODEAC_MSG_MODEC_HIT (1<<3) +#define MODEAC_MSG_MODEA_ONLY (1<<4) +#define MODEAC_MSG_MODEC_OLD (1<<5) + +#define MODES_PREAMBLE_US 8 // microseconds = bits +#define MODES_PREAMBLE_SAMPLES (MODES_PREAMBLE_US * 2) +#define MODES_PREAMBLE_SIZE (MODES_PREAMBLE_SAMPLES * sizeof(uint16_t)) +#define MODES_LONG_MSG_BYTES 14 +#define MODES_SHORT_MSG_BYTES 7 +#define MODES_LONG_MSG_BITS (MODES_LONG_MSG_BYTES * 8) +#define MODES_SHORT_MSG_BITS (MODES_SHORT_MSG_BYTES * 8) +#define MODES_LONG_MSG_SAMPLES (MODES_LONG_MSG_BITS * 2) +#define MODES_SHORT_MSG_SAMPLES (MODES_SHORT_MSG_BITS * 2) +#define MODES_LONG_MSG_SIZE (MODES_LONG_MSG_SAMPLES * sizeof(uint16_t)) +#define MODES_SHORT_MSG_SIZE (MODES_SHORT_MSG_SAMPLES * sizeof(uint16_t)) + +#define MODES_RAWOUT_BUF_SIZE (1500) +#define MODES_RAWOUT_BUF_FLUSH (MODES_RAWOUT_BUF_SIZE - 200) +#define MODES_RAWOUT_BUF_RATE (1000) // 1000 * 64mS = 1 Min approx + +#define MODES_ICAO_CACHE_LEN 1024 // Power of two required +#define MODES_ICAO_CACHE_TTL 60 // Time to live of cached addresses +#define MODES_UNIT_FEET 0 +#define MODES_UNIT_METERS 1 + +#define MODES_USER_LATLON_VALID (1<<0) + +#define MODES_ACFLAGS_LATLON_VALID (1<<0) // Aircraft Lat/Lon is decoded +#define MODES_ACFLAGS_ALTITUDE_VALID (1<<1) // Aircraft altitude is known +#define MODES_ACFLAGS_HEADING_VALID (1<<2) // Aircraft heading is known +#define MODES_ACFLAGS_SPEED_VALID (1<<3) // Aircraft speed is known +#define MODES_ACFLAGS_VERTRATE_VALID (1<<4) // Aircraft vertical rate is known +#define MODES_ACFLAGS_SQUAWK_VALID (1<<5) // Aircraft Mode A Squawk is known +#define MODES_ACFLAGS_CALLSIGN_VALID (1<<6) // Aircraft Callsign Identity +#define MODES_ACFLAGS_EWSPEED_VALID (1<<7) // Aircraft East West Speed is known +#define MODES_ACFLAGS_NSSPEED_VALID (1<<8) // Aircraft North South Speed is known +#define MODES_ACFLAGS_AOG (1<<9) // Aircraft is On the Ground +#define MODES_ACFLAGS_LLEVEN_VALID (1<<10) // Aircraft Even Lot/Lon is known +#define MODES_ACFLAGS_LLODD_VALID (1<<11) // Aircraft Odd Lot/Lon is known +#define MODES_ACFLAGS_AOG_VALID (1<<12) // MODES_ACFLAGS_AOG is valid +#define MODES_ACFLAGS_FS_VALID (1<<13) // Aircraft Flight Status is known +#define MODES_ACFLAGS_NSEWSPD_VALID (1<<14) // Aircraft EW and NS Speed is known +#define MODES_ACFLAGS_LATLON_REL_OK (1<<15) // Indicates it's OK to do a relative CPR + +#define MODES_ACFLAGS_LLEITHER_VALID (MODES_ACFLAGS_LLEVEN_VALID | MODES_ACFLAGS_LLODD_VALID) +#define MODES_ACFLAGS_LLBOTH_VALID (MODES_ACFLAGS_LLEVEN_VALID | MODES_ACFLAGS_LLODD_VALID) +#define MODES_ACFLAGS_AOG_GROUND (MODES_ACFLAGS_AOG_VALID | MODES_ACFLAGS_AOG) + +#define MODES_DEBUG_DEMOD (1<<0) +#define MODES_DEBUG_DEMODERR (1<<1) +#define MODES_DEBUG_BADCRC (1<<2) +#define MODES_DEBUG_GOODCRC (1<<3) +#define MODES_DEBUG_NOPREAMBLE (1<<4) +#define MODES_DEBUG_NET (1<<5) +#define MODES_DEBUG_JS (1<<6) + +// When debug is set to MODES_DEBUG_NOPREAMBLE, the first sample must be +// at least greater than a given level for us to dump the signal. +#define MODES_DEBUG_NOPREAMBLE_LEVEL 25 + +#define MODES_INTERACTIVE_REFRESH_TIME 250 // Milliseconds +#define MODES_INTERACTIVE_ROWS 15 // Rows on screen +#define MODES_INTERACTIVE_TTL 60 // TTL before being removed + +#define MODES_NET_MAX_FD 1024 +#define MODES_NET_INPUT_RAW_PORT 30001 +#define MODES_NET_OUTPUT_RAW_PORT 30002 +#define MODES_NET_OUTPUT_SBS_PORT 30003 +#define MODES_NET_INPUT_BEAST_PORT 30004 +#define MODES_NET_OUTPUT_BEAST_PORT 30005 +#define MODES_NET_HTTP_PORT 8080 +#define MODES_CLIENT_BUF_SIZE 1024 +#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) + +/* ======================== structure declarations ========================= */ + +// Structure used to describe a networking client +struct client { + int fd; // File descriptor + int service; // TCP port the client is connected to + char buf[MODES_CLIENT_BUF_SIZE+1]; // Read buffer + int buflen; // Amount of data on buffer +}; + +// Structure used to describe an aircraft in iteractive mode +struct aircraft { + uint32_t addr; // ICAO address + char flight[16]; // Flight number + unsigned char signalLevel[8]; // Last 8 Signal Amplitudes + int altitude; // Altitude + int speed; // Velocity + int track; // Angle of flight + int vert_rate; // Vertical rate. + time_t seen; // Time at which the last packet was received + time_t seenLatLon; // Time at which the last lat long was calculated + uint64_t timestamp; // Timestamp at which the last packet was received + uint64_t timestampLatLon;// Timestamp at which the last lat long was calculated + long messages; // Number of Mode S messages received + int modeA; // Squawk + int modeC; // Altitude + long modeAcount; // Mode A Squawk hit Count + long modeCcount; // Mode C Altitude hit Count + int modeACflags; // Flags for mode A/C recognition + + // Encoded latitude and longitude as extracted by odd and even CPR encoded messages + int odd_cprlat; + int odd_cprlon; + int even_cprlat; + int even_cprlon; + uint64_t odd_cprtime; + uint64_t even_cprtime; + double lat, lon; // Coordinated obtained from CPR encoded data + int bFlags; // Flags related to valid fields in this structure + struct aircraft *next; // Next aircraft in our linked list +}; + +// Program global state +struct { // Internal state + pthread_t reader_thread; + pthread_mutex_t data_mutex; // Mutex to synchronize buffer access + pthread_cond_t data_cond; // Conditional variable associated + uint16_t *data; // Raw IQ samples buffer + uint16_t *magnitude; // Magnitude vector + struct timeb stSystemTimeRTL; // System time when RTL passed us the Latest block + uint64_t timestampBlk; // Timestamp of the start of the current block + struct timeb stSystemTimeBlk; // System time when RTL passed us currently processing this block + int fd; // --ifile option file descriptor + int data_ready; // Data ready to be processed + uint32_t *icao_cache; // Recently seen ICAO addresses cache + uint16_t *maglut; // I/Q -> Magnitude lookup table + int exit; // Exit from the main loop when true + + // RTLSDR + int dev_index; + int gain; + int enable_agc; + rtlsdr_dev_t *dev; + int freq; + int ppm_error; + + // Networking + char aneterr[ANET_ERR_LEN]; + struct client *clients[MODES_NET_MAX_FD]; // Our clients + int maxfd; // Greatest fd currently active + int sbsos; // SBS output listening socket + int ros; // Raw output listening socket + int ris; // Raw input listening socket + int bos; // Beast output listening socket + int bis; // Beast input listening socket + int https; // HTTP listening socket + char *rawOut; // Buffer for building raw output data + int rawOutUsed; // How much of the buffer is currently used + char *beastOut; // Buffer for building beast output data + int beastOutUsed; // How much if the buffer is currently used + + // Configuration + char *filename; // Input form file, --ifile option + int phase_enhance; // Enable phase enhancement if true + int nfix_crc; // Number of crc bit error(s) to correct + int check_crc; // Only display messages with good CRC + int raw; // Raw output format + int beast; // Beast binary format output + int mode_ac; // Enable decoding of SSR Modes A & C + int debug; // Debugging mode + int net; // Enable networking + int net_only; // Enable just networking + int net_output_sbs_port; // SBS output TCP port + int net_output_raw_size; // Minimum Size of the output raw data + int net_output_raw_rate; // Rate (in 64mS increments) of output raw data + int net_output_raw_rate_count; // Rate (in 64mS increments) of output raw data + int net_output_raw_port; // Raw output TCP port + int net_input_raw_port; // Raw input TCP port + int net_output_beast_port; // Beast output TCP port + int net_input_beast_port; // Beast input TCP port + int net_http_port; // HTTP port + int quiet; // Suppress stdout + int interactive; // Interactive mode + int interactive_rows; // Interactive mode: max number of rows + int interactive_ttl; // Interactive mode: TTL before deletion + int stats; // Print stats at exit in --ifile mode + int onlyaddr; // Print only ICAO addresses + int metric; // Use metric units + int mlat; // Use Beast ascii format for raw data output, i.e. @...; iso *...; + int interactive_rtl1090; // flight table in interactive mode is formatted like RTL1090 + + // User details + double fUserLat; // Users receiver/antenna lat/lon needed for initial surface location + double fUserLon; // Users receiver/antenna lat/lon needed for initial surface location + int bUserFlags; // Flags relating to the user details + + // Interactive mode + struct aircraft *aircrafts; + uint64_t interactive_last_update; // Last screen update in milliseconds + + // Statistics + unsigned int stat_valid_preamble; + unsigned int stat_demodulated0; + unsigned int stat_demodulated1; + unsigned int stat_demodulated2; + unsigned int stat_demodulated3; + unsigned int stat_goodcrc; + unsigned int stat_badcrc; + unsigned int stat_fixed; + + // 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_sbs_connections; + unsigned int stat_raw_connections; + unsigned int stat_beast_connections; + unsigned int stat_out_of_phase; + unsigned int stat_ph_demodulated0; + unsigned int stat_ph_demodulated1; + unsigned int stat_ph_demodulated2; + unsigned int stat_ph_demodulated3; + unsigned int stat_ph_goodcrc; + unsigned int stat_ph_badcrc; + unsigned int stat_ph_fixed; + // Histogram of fixed bit errors: index 0 for single bit erros, + // index 1 for double bit errors etc. + unsigned int stat_ph_bit_fix[MODES_MAX_BITERRORS]; + + unsigned int stat_DF_Len_Corrected; + unsigned int stat_DF_Type_Corrected; + unsigned int stat_ModeAC; +} Modes; + +// The struct we use to store information about a decoded message. +struct modesMessage { + // Generic fields + unsigned char msg[MODES_LONG_MSG_BYTES]; // Binary message. + int msgbits; // Number of bits in message + int msgtype; // Downlink format # + int crcok; // True if CRC was valid + uint32_t crc; // Message CRC + int correctedbits; // No. of bits corrected + char corrected[MODES_MAX_BITERRORS]; // corrected bit positions + uint32_t addr; // ICAO Address from bytes 1 2 and 3 + int phase_corrected; // True if phase correction was applied + uint64_t timestampMsg; // Timestamp of the message + int remote; // If set this message is from a remote station + unsigned char signalLevel; // Signal Amplitude + + // DF 11 + int ca; // Responder capabilities + int iid; + + // 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 + int raw_latitude; // Non decoded latitude. + int raw_longitude; // Non decoded longitude. + double fLat; // Coordinates obtained from CPR encoded data if/when decoded + double fLon; // Coordinates obtained from CPR encoded data if/when decoded + char flight[16]; // 8 chars flight number. + int ew_velocity; // E/W velocity. + int ns_velocity; // N/S velocity. + int vert_rate; // Vertical rate. + int velocity; // Reported by aircraft, or computed from from EW and NS velocity + + // DF4, DF5, DF20, DF21 + int fs; // Flight status for DF4,5,20,21 + int modeA; // 13 bits identity (Squawk). + + // Fields used by multiple message types. + int altitude; + int unit; + int bFlags; // Flags related to fields in this structure +}; + +/* ======================== function declarations ========================= */ + +#ifdef __cplusplus +extern "C" { +#endif + +int detectModeA (uint16_t *m, struct modesMessage *mm); +void decodeModeAMessage(struct modesMessage *mm, int ModeA); +int ModeAToModeC (unsigned int ModeA); + +void interactiveShowData(void); +struct aircraft* interactiveReceiveData(struct modesMessage *mm); +void modesSendAllClients (int service, void *msg, int len); +void modesSendRawOutput (struct modesMessage *mm); +void modesSendBeastOutput (struct modesMessage *mm); +void modesSendSBSOutput (struct modesMessage *mm); +void useModesMessage (struct modesMessage *mm); + +int fixBitErrors (unsigned char *msg, int bits, int maxfix, char *fixedbits); + +void modesInitErrorInfo (); +int modesMessageLenByType(int type); + +#ifdef __cplusplus +} +#endif + +#endif // __DUMP1090_H