diff --git a/dump1090.c b/dump1090.c index abce0dc..0c09300 100644 --- a/dump1090.c +++ b/dump1090.c @@ -436,6 +436,7 @@ void showHelp(void) { "--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" +"--stats-every Show and reset stats every seconds\n" "--onlyaddr Show only ICAO addresses (testing purposes)\n" "--metric Use metric units (meters, km/h, ...)\n" "--snip Strip IQ file removing samples < level\n" @@ -488,6 +489,86 @@ void showCopyright(void) { while (llTime >= time(NULL)) {} } #endif + + +static void display_stats(void) { + int j; + time_t now = time(NULL); + + printf("\n\n"); + if (Modes.interactive) + interactiveShowData(); + + printf("Statistics as at %s", ctime(&now)); + + printf("%d sample blocks processed\n", Modes.stat_blocks_processed); + printf("%d sample blocks dropped\n", Modes.stat_blocks_dropped); + + 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); + + 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"); + } + + 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_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); + fflush(stdout); + + Modes.stat_blocks_processed = + Modes.stat_blocks_dropped = 0; + + Modes.stat_ModeAC = + Modes.stat_valid_preamble = + Modes.stat_DF_Len_Corrected = + Modes.stat_DF_Type_Corrected = + Modes.stat_demodulated0 = + Modes.stat_demodulated1 = + Modes.stat_demodulated2 = + Modes.stat_demodulated3 = + Modes.stat_goodcrc = + Modes.stat_badcrc = + Modes.stat_fixed = 0; + + Modes.stat_out_of_phase = + Modes.stat_ph_demodulated0 = + Modes.stat_ph_demodulated1 = + Modes.stat_ph_demodulated2 = + Modes.stat_ph_demodulated3 = + Modes.stat_ph_goodcrc = + Modes.stat_ph_badcrc = + Modes.stat_ph_fixed = 0; + + for (j = 0; j < MODES_MAX_BITERRORS; j++) { + Modes.stat_ph_bit_fix[j] = 0; + Modes.stat_bit_fix[j] = 0; + } +} + + // //========================================================================= // @@ -496,6 +577,8 @@ void showCopyright(void) { // from the net, refreshing the screen in interactive mode, and so forth // void backgroundTasks(void) { + static time_t next_stats; + if (Modes.net) { modesReadFromClients(); showFlightsFATSV(); @@ -510,6 +593,15 @@ void backgroundTasks(void) { if (Modes.interactive) { interactiveShowData(); } + + if (Modes.stats > 0) { + time_t now = time(NULL); + if (now > next_stats) { + if (next_stats != 0) + display_stats(); + next_stats = now + Modes.stats; + } + } } // //========================================================================= @@ -590,7 +682,7 @@ int main(int argc, char **argv) { if (!strcmp(argv[j],"--device-index") && more) { Modes.dev_index = verbose_device_search(argv[++j]); } else if (!strcmp(argv[j],"--gain") && more) { - Modes.gain = (int) atof(argv[++j])*10; // Gain is in tens of DBs + Modes.gain = (int) (atof(argv[++j])*10); // Gain is in tens of DBs } else if (!strcmp(argv[j],"--enable-agc")) { Modes.enable_agc++; } else if (!strcmp(argv[j],"--freq") && more) { @@ -678,7 +770,9 @@ int main(int argc, char **argv) { f++; } } else if (!strcmp(argv[j],"--stats")) { - Modes.stats = 1; + Modes.stats = -1; + } else if (!strcmp(argv[j],"--stats-every") && more) { + Modes.stats = atoi(argv[++j]); } else if (!strcmp(argv[j],"--snip") && more) { snipMode(atoi(argv[++j])); exit(0); @@ -726,7 +820,13 @@ int main(int argc, char **argv) { } else { if (Modes.filename[0] == '-' && Modes.filename[1] == '\0') { Modes.fd = STDIN_FILENO; - } else if ((Modes.fd = open(Modes.filename,O_RDONLY)) == -1) { + } else if ((Modes.fd = open(Modes.filename, +#ifdef _WIN32 + (O_RDONLY | O_BINARY) +#else + (O_RDONLY) +#endif + )) == -1) { perror("Opening data file"); exit(1); } @@ -769,6 +869,7 @@ int main(int argc, char **argv) { // If we lost some blocks, correct the timestamp if (Modes.iDataLost) { Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES * 6 * Modes.iDataLost); + Modes.stat_blocks_dropped += Modes.iDataLost; Modes.iDataLost = 0; } @@ -783,7 +884,7 @@ int main(int argc, char **argv) { // Update the timestamp ready for the next block Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES*6); - + Modes.stat_blocks_processed++; } else { pthread_cond_signal (&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); @@ -795,37 +896,7 @@ int main(int argc, char **argv) { // If --stats were given, print statistics if (Modes.stats) { - printf("\n\n"); - if (Modes.interactive) - interactiveShowData(); - 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); - 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"); - } - 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_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); + display_stats(); } if (Modes.filename == NULL) { diff --git a/dump1090.h b/dump1090.h index 8b9d564..74158fd 100644 --- a/dump1090.h +++ b/dump1090.h @@ -377,6 +377,9 @@ struct { // Internal state unsigned int stat_DF_Len_Corrected; unsigned int stat_DF_Type_Corrected; unsigned int stat_ModeAC; + + unsigned int stat_blocks_processed; + unsigned int stat_blocks_dropped; } Modes; // The struct we use to store information about a decoded message. @@ -444,7 +447,7 @@ void decodeModesMessage (struct modesMessage *mm, unsigned char *msg); void displayModesMessage(struct modesMessage *mm); void useModesMessage (struct modesMessage *mm, struct client *c); void computeMagnitudeVector(uint16_t *pData); -void decodeCPR (struct aircraft *a, int fflag, int surface); +int decodeCPR (struct aircraft *a, int fflag, int surface); int decodeCPRrelative (struct aircraft *a, int fflag, int surface); void modesInitErrorInfo (); // diff --git a/interactive.c b/interactive.c index f0f7899..f9d8724 100644 --- a/interactive.c +++ b/interactive.c @@ -344,6 +344,7 @@ struct aircraft *interactiveReceiveData(struct modesMessage *mm, struct client * // If we've got a new cprlat or cprlon if (mm->bFlags & MODES_ACFLAGS_LLEITHER_VALID) { + int location_ok = 0; if (mm->bFlags & MODES_ACFLAGS_LLODD_VALID) { a->odd_cprlat = mm->raw_latitude; @@ -355,23 +356,23 @@ struct aircraft *interactiveReceiveData(struct modesMessage *mm, struct client * a->even_cprtime = mstime(); } - if (((mm->bFlags | a->bFlags) & MODES_ACFLAGS_LLEITHER_VALID) == MODES_ACFLAGS_LLBOTH_VALID) { - // If we now have both even and odd, decode the CPR - - // Try relative CPR first - if (decodeCPRrelative(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG))) { - // If relative CPR fails then try global if the two data are less than 10 seconds apart - if (abs((int)(a->even_cprtime - a->odd_cprtime)) <= 10000) { - decodeCPR(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG)); - } + // If we have enough recent data, try global CPR + if (((mm->bFlags | a->bFlags) & MODES_ACFLAGS_LLEITHER_VALID) == MODES_ACFLAGS_LLBOTH_VALID && abs((int)(a->even_cprtime - a->odd_cprtime)) <= 10000) { + if (decodeCPR(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG)) == 0) { + location_ok = 1; } + } - //If we sucessfully decoded, back copy the results to mm so that we can print them in list output - if (a->bFlags & MODES_ACFLAGS_LATLON_VALID) { - mm->bFlags |= MODES_ACFLAGS_LATLON_VALID; - mm->fLat = a->lat; - mm->fLon = a->lon; - } + // Otherwise try relative CPR. + if (!location_ok && decodeCPRrelative(a, (mm->bFlags & MODES_ACFLAGS_LLODD_VALID), (mm->bFlags & MODES_ACFLAGS_AOG)) == 0) { + location_ok = 1; + } + + //If we sucessfully decoded, back copy the results to mm so that we can print them in list output + if (location_ok) { + mm->bFlags |= MODES_ACFLAGS_LATLON_VALID; + mm->fLat = a->lat; + mm->fLon = a->lon; } } diff --git a/mode_s.c b/mode_s.c index 552183b..0f9d4dc 100644 --- a/mode_s.c +++ b/mode_s.c @@ -909,7 +909,7 @@ void decodeModesMessage(struct modesMessage *mm, unsigned char *msg) { // If we're checking CRC and the CRC is invalid, then we can't trust any // of the data contents, so save time and give up now. - if ((Modes.check_crc) && (!mm->crcok)) { return;} + if ((Modes.check_crc) && (!mm->crcok) && (!mm->correctedbits)) { return;} // Fields for DF0, DF16 if (mm->msgtype == 0 || mm->msgtype == 16) { @@ -2014,11 +2014,8 @@ double cprDlonFunction(double lat, int fflag, int surface) { // // A few remarks: // 1) 131072 is 2^17 since CPR latitude and longitude are encoded in 17 bits. -// 2) We assume that we always received the odd packet as last packet for -// simplicity. This may provide a position that is less fresh of a few -// seconds. // -void decodeCPR(struct aircraft *a, int fflag, int surface) { +int decodeCPR(struct aircraft *a, int fflag, int surface) { double AirDlat0 = (surface ? 90.0 : 360.0) / 60.0; double AirDlat1 = (surface ? 90.0 : 360.0) / 59.0; double lat0 = a->even_cprlat; @@ -2044,7 +2041,8 @@ void decodeCPR(struct aircraft *a, int fflag, int surface) { surface_rlat = Modes.fUserLat; surface_rlon = Modes.fUserLon; } else { - return; + // No local reference, give up + return (-1); } rlat0 += floor(surface_rlat / 90.0) * 90.0; // Move from 1st quadrant to our quadrant rlat1 += floor(surface_rlat / 90.0) * 90.0; @@ -2053,8 +2051,13 @@ void decodeCPR(struct aircraft *a, int fflag, int surface) { if (rlat1 >= 270) rlat1 -= 360; } + // Check to see that the latitude is in range: -90 .. +90 + if (rlat0 < -90 || rlat0 > 90 || rlat1 < -90 || rlat1 > 90) + return (-1); + // Check that both are in the same latitude zone, or abort. - if (cprNLFunction(rlat0) != cprNLFunction(rlat1)) return; + if (cprNLFunction(rlat0) != cprNLFunction(rlat1)) + return (-1); // Compute ni and the Longitude Index "m" if (fflag) { // Use odd packet. @@ -2080,6 +2083,8 @@ void decodeCPR(struct aircraft *a, int fflag, int surface) { a->seenLatLon = a->seen; a->timestampLatLon = a->timestamp; a->bFlags |= (MODES_ACFLAGS_LATLON_VALID | MODES_ACFLAGS_LATLON_REL_OK); + + return 0; } // //========================================================================= @@ -2129,6 +2134,12 @@ int decodeCPRrelative(struct aircraft *a, int fflag, int surface) { rlat = AirDlat * (j + lat/131072); if (rlat >= 270) rlat -= 360; + // Check to see that the latitude is in range: -90 .. +90 + if (rlat < -90 || rlat > 90) { + a->bFlags &= ~MODES_ACFLAGS_LATLON_REL_OK; // This will cause a quick exit next time if no global has been done + return (-1); // Time to give up - Latitude error + } + // Check to see that answer is reasonable - ie no more than 1/2 cell away if (fabs(rlat - a->lat) > (AirDlat/2)) { a->bFlags &= ~MODES_ACFLAGS_LATLON_REL_OK; // This will cause a quick exit next time if no global has been done diff --git a/net_io.c b/net_io.c index 7b06a8a..8469a90 100644 --- a/net_io.c +++ b/net_io.c @@ -89,7 +89,7 @@ void modesInitNet(void) { int s = anetTcpServer(Modes.aneterr, services[j].port, NULL); if (s == -1) { fprintf(stderr, "Error opening the listening port %d (%s): %s\n", - services[j].port, services[j].descr, strerror(errno)); + services[j].port, services[j].descr, Modes.aneterr); exit(1); } anetNonBlock(Modes.aneterr, s); @@ -297,8 +297,8 @@ void modesSendRawOutput(struct modesMessage *mm) { void modesSendSBSOutput(struct modesMessage *mm) { char msg[256], *p = msg; uint32_t offset; - struct timeb epocTime; - struct tm stTime; + struct timeb epocTime_receive, epocTime_now; + struct tm stTime_receive, stTime_now; int msgType; // @@ -340,26 +340,33 @@ void modesSendSBSOutput(struct modesMessage *mm) { // Fields 1 to 6 : SBS message type and ICAO address of the aircraft and some other stuff p += sprintf(p, "MSG,%d,111,11111,%06X,111111,", msgType, mm->addr); - // Fields 7 & 8 are the current time and date - 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 + // Find current system time + ftime(&epocTime_now); // get the current system time & date + stTime_now = *localtime(&epocTime_now.time); + + // Find message reception time + if (mm->timestampMsg && !mm->remote) { // Make sure the records' timestamp is valid before using it + epocTime_receive = 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 - epocTime.millitm += offset; // add on the offset time to the Block start time - if (epocTime.millitm > 999) // if we've caused an overflow into the next second... - {epocTime.millitm -= 1000; epocTime.time ++;} // ..correct the overflow - stTime = *localtime(&epocTime.time); // convert the time to year, month day, hours, min, sec - p += sprintf(p, "%04d/%02d/%02d,", (stTime.tm_year+1900),(stTime.tm_mon+1), stTime.tm_mday); - p += sprintf(p, "%02d:%02d:%02d.%03d,", stTime.tm_hour, stTime.tm_min, stTime.tm_sec, epocTime.millitm); + epocTime_receive.millitm += offset; // add on the offset time to the Block start time + if (epocTime_receive.millitm > 999) { // if we've caused an overflow into the next second... + epocTime_receive.millitm -= 1000; + epocTime_receive.time ++; // ..correct the overflow + } + stTime_receive = *localtime(&epocTime_receive.time); } else { - p += sprintf(p, ",,"); - } + epocTime_receive = epocTime_now; // We don't have a usable reception time; use the current system time + stTime_receive = stTime_now; + } + + // Fields 7 & 8 are the message reception time and date + p += sprintf(p, "%04d/%02d/%02d,", (stTime_receive.tm_year+1900),(stTime_receive.tm_mon+1), stTime_receive.tm_mday); + p += sprintf(p, "%02d:%02d:%02d.%03d,", stTime_receive.tm_hour, stTime_receive.tm_min, stTime_receive.tm_sec, epocTime_receive.millitm); // Fields 9 & 10 are the current time and date - ftime(&epocTime); // get the current system time & date - stTime = *localtime(&epocTime.time); // convert the time to year, month day, hours, min, sec - p += sprintf(p, "%04d/%02d/%02d,", (stTime.tm_year+1900),(stTime.tm_mon+1), stTime.tm_mday); - p += sprintf(p, "%02d:%02d:%02d.%03d", stTime.tm_hour, stTime.tm_min, stTime.tm_sec, epocTime.millitm); + p += sprintf(p, "%04d/%02d/%02d,", (stTime_now.tm_year+1900),(stTime_now.tm_mon+1), stTime_now.tm_mday); + p += sprintf(p, "%02d:%02d:%02d.%03d", stTime_now.tm_hour, stTime_now.tm_min, stTime_now.tm_sec, epocTime_now.millitm); // Field 11 is the callsign (if we have it) if (mm->bFlags & MODES_ACFLAGS_CALLSIGN_VALID) {p += sprintf(p, ",%s", mm->flight);} @@ -863,11 +870,12 @@ void modesReadFromClient(struct client *c, char *sep, bContinue = 0; } #ifndef _WIN32 - if ( (nread < 0) && (errno != EAGAIN)) { // Error, or end of file + if ( (nread < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || nread == 0 ) { // Error, or end of file #else if ( (nread < 0) && (errno != EWOULDBLOCK)) { // Error, or end of file #endif modesFreeClient(c); + return; } if (nread <= 0) { break; // Serve next client diff --git a/public_html/script.js b/public_html/script.js index fbb3128..265e30f 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -144,8 +144,12 @@ function initialize() { center: new google.maps.LatLng(CenterLat, CenterLon), zoom: ZoomLvl, mapTypeId: google.maps.MapTypeId.ROADMAP, + mapTypeControl: true, + streetViewControl: false, mapTypeControlOptions: { - mapTypeIds: mapTypeIds + mapTypeIds: mapTypeIds, + position: google.maps.ControlPosition.TOP_LEFT, + style: google.maps.MapTypeControlStyle.DROPDOWN_MENU } }; @@ -314,7 +318,7 @@ function refreshSelected() { html += 'Track: ' if (selected && selected.vTrack) { - html += selected.track + ' (' + normalizeTrack(selected.track, selected.vTrack)[1] +')'; + html += selected.track + '°' + ' (' + normalizeTrack(selected.track, selected.vTrack)[1] +')'; } else { html += 'n/a'; } diff --git a/public_html/style.css b/public_html/style.css index 63d0a45..86cb053 100644 --- a/public_html/style.css +++ b/public_html/style.css @@ -14,10 +14,9 @@ div#SpecialSquawkWarning { position: absolute; bottom: 25px; right: 430px; borde table#optionsTabs { width: 100%; font-size: small; font-family: monospace; background-color: #ddd; border: 1px; border-color: #000000;} -#tableinfo { font-size: x-small; font-family: monospace; } -#sudo_buttons { font-size: x-small; font-family: monospace; } +#tableinfo, #sudo_buttons { font-size: x-small; font-family: monospace; } -.vPosition { font-weight: bold; background-color: #f5fff5; } +.vPosition { font-weight: bold; background-color: #d5ffd5; } .squawk7500 { font-weight: bold; background-color: #ff5555; } .squawk7600 { font-weight: bold; background-color: #00ffff; } .squawk7700 { font-weight: bold; background-color: #ffff00; }