diff --git a/dump1090.c b/dump1090.c index 59a02e8..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.1405.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; @@ -296,7 +309,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 @@ -347,7 +360,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 +563,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 +611,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 ================================= */ @@ -992,7 +1011,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); @@ -1109,16 +1127,20 @@ 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. @@ -1258,28 +1280,24 @@ 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; + 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; + bitErrorTable[n].syndrome = crc; // single bit error case bitErrorTable[n].pos0 = i; bitErrorTable[n].pos1 = -1; n += 1; - } - /* Add also all 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; - 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; + msg[bytepos1] ^= mask1; // create error1 crc = modesChecksum(msg, MODES_LONG_MSG_BITS); if (n >= NERRORINFO) { /* @@ -1289,11 +1307,14 @@ 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); @@ -1319,10 +1340,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)) { @@ -1336,50 +1357,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 @@ -1653,6 +1665,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", @@ -1706,11 +1730,9 @@ 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)) { + 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 @@ -1723,9 +1745,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 @@ -1735,6 +1760,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. @@ -1744,15 +1770,20 @@ 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->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; + if (0 == mm->crc) { + // DF 17 : if crc == 0 try to populate our ICAO addresses whitelist. + addRecentlySeenICAOAddr(mm->addr); + } - } else if (0 == mm->crc) { - // DF 17 : if uncorrected and crc == 0 add this address to the whitelist of - // recently seen ICAO addresses. + } 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); } @@ -1773,8 +1804,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) { @@ -1813,8 +1843,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 @@ -1971,7 +2002,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--) { @@ -2107,6 +2138,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"); @@ -2208,11 +2298,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: * @@ -2238,7 +2331,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; @@ -2246,12 +2338,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 @@ -2449,24 +2547,54 @@ 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); // Update statistics if (Modes.stats) { - if (mm.crcok || use_correction) { - if (errors == 0) Modes.stat_demodulated++; + if (mm.crcok || use_correction || mm.correctedbits) { + + 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++; @@ -2495,9 +2623,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 @@ -2510,8 +2635,8 @@ void detectModeS(uint16_t *m, uint32_t mlen) { } } - // Retry with phase correction if possible. - if (!good_message && !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; @@ -2539,7 +2664,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->correctedbits)) { // not checking, ok or fixed // Track aircrafts if... if ( (Modes.interactive) // in interactive mode @@ -2913,7 +3038,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->correctedbits == 0)) + return NULL; // Loookup our aircraft or create a new one a = interactiveFindAircraft(mm->addr); @@ -3192,14 +3319,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. */ @@ -3354,14 +3481,14 @@ 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--) { 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++ = '*'; @@ -3426,7 +3553,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 @@ -3556,7 +3683,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 @@ -3569,7 +3696,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]) { @@ -3578,11 +3705,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 '*': @@ -3905,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" @@ -3983,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")) { @@ -4126,21 +4254,38 @@ 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); } - 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); }