From 68e95c06cc46937deeb0776c0a9bd1da8db6ccdc Mon Sep 17 00:00:00 2001 From: George Joseph Date: Mon, 21 Sep 2020 16:00:44 -0600 Subject: [PATCH 01/33] Interactive mode updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These updates were designed to assist those using interactive mode to tune antennas and SDR gain. * Add options to display distance and bearing in interactive mode Distance and bearing instead of latitude and longitude can now be displayed in interactive mode using the following options to dump1090-fa and view1090-fa. --interactive-show-distance Show aircraft distance and bearing instead of aircraft lat/lon (requires --lat and --lon) --interactive-distance-units Distance units ('km', 'sm', 'nm') (default: 'nm')" You have to specify a reference --lat and --lon for this to work of course. * A new line now shows at the top of the interactive display that has for the current sample: Total valid aircraft count Vidible aircraft count Will be less than total if the screen hasn't enough lines to show them all. Max RSSI Min RSSI Mean RSSI Max Distance Tot: 47 Vis: 47 RSSI: Max 25.4+ Mean -29.5 Min -36.9- MaxD: 197.3nm+ * Add max distance and min/max RSSI indicators A '+' after the distance in a row indicates it's the row with the maximum distance. A '+' after the RSSI in a row indicates it's the row with the highest RSSI. A '-' after the RSSI in a row indicates it's the row with the lowest RSSI. The summary line at the top of the screen always shows the values for ALL aircraft, even those not visible. The row indicators only mark visible rows though. In this example, the first aircraft is both the farthest away and has the weakest RSSI. The second aircraft has the strongest RSSI. Tot: 47 Vis: 47 RSSI: Max 25.4+ Mean -29.5 Min -36.9- MaxD: 197.3nm+ - Hex Mode Sqwk Flight Alt Spd Hdg Dist(nm) Bearing RSSI Msgs Ti ──────────────────────────────────────────────────────────────────────────────── A8D5A4 S2 34000 438 252 197.3+ 85 -36.1- 26 2 A39A13 S2ac 5740 FFT525 30750 439 256 98.8 68 -25.4+ 123 0 A70B23 S2ac 2744 LXJ553 43000 419 258 136.1 39 -33.6 174 0 * Finally, a new option '--interactive-callsign-filter' has been added to allow filtering interactive by callsign. The value can be a simple string, in which case aircraft with that string anywhere in its callsign will be displayed, or a regular expression should you want a more precise match. Examples: --interactive-callsign-filter UAL will match all aircraft with UAL anywhere in its callsign. --interactive-callsign-filter "^UAL" will match only those callsigns that start with UAL. --interactive-callsign-filter "^(UAL|AAL)" will match only those callsigns that start with UAL or AAL. --interactive-callsign-filter "^N[0-9]" or "^N[[:digit:]]" will match only those callsigns that start with "N" and a number If you need more info on regular expressions, see this link: https://en.wikipedia.org/wiki/Regular_expression --- dump1090.c | 19 +++++- dump1090.h | 9 +++ interactive.c | 159 +++++++++++++++++++++++++++++++++++++++++++------- track.c | 26 ++++++++- track.h | 8 +++ view1090.c | 23 +++++++- 6 files changed, 218 insertions(+), 26 deletions(-) diff --git a/dump1090.c b/dump1090.c index aa23b73..2df4041 100644 --- a/dump1090.c +++ b/dump1090.c @@ -284,6 +284,10 @@ static void showHelp(void) "--freq Set frequency (default: 1090 Mhz)\n" "--interactive Interactive mode refreshing data on screen. Implies --throttle\n" "--interactive-ttl Remove from list if idle for (default: 60)\n" +"--interactive-show-distance Show aircraft distance and bearing instead of lat/lon\n" +" (requires --lat and --lon)\n" +"--interactive-distance-units Distance units ('km', 'sm', 'nm') (default: 'nm')\n" +"--interactive-callsign-filter Only callsigns that match the prefix or regex will be displayed\n" "--raw Show only messages hex values\n" "--net Enable networking with default ports unless overridden\n" "--modeac Enable decoding of SSR Modes 3/A & 3/C\n" @@ -571,7 +575,20 @@ int main(int argc, char **argv) { Modes.interactive = 1; } else if (!strcmp(argv[j],"--interactive-ttl") && more) { Modes.interactive_display_ttl = (uint64_t)(1000 * atof(argv[++j])); - } else if (!strcmp(argv[j],"--lat") && more) { + } else if (!strcmp(argv[j],"--interactive-show-distance")) { + Modes.interactive_show_distance = 1; + } else if (!strcmp(argv[j], "--interactive-distance-units") && more) { + char *units = argv[++j]; + if (!strcmp(units, "km")) { + Modes.interactive_distance_units = UNIT_KILOMETERS; + } else if (!strcmp(units, "sm")) { + Modes.interactive_distance_units = UNIT_STATUTE_MILES; + } else { + Modes.interactive_distance_units = UNIT_NAUTICAL_MILES; + } + } else if (!strcmp(argv[j], "--interactive-callsign-filter") && more) { + Modes.interactive_callsign_filter = strdup(argv[++j]); + } else if (!strcmp(argv[j], "--lat") && more) { Modes.fUserLat = atof(argv[++j]); } else if (!strcmp(argv[j],"--lon") && more) { Modes.fUserLon = atof(argv[++j]); diff --git a/dump1090.h b/dump1090.h index 088d3f6..3068ea0 100644 --- a/dump1090.h +++ b/dump1090.h @@ -163,6 +163,12 @@ typedef enum { UNIT_METERS } altitude_unit_t; +typedef enum { + UNIT_NAUTICAL_MILES, + UNIT_STATUTE_MILES, + UNIT_KILOMETERS, +} interactive_distance_unit_t; + typedef enum { ALTITUDE_BARO, ALTITUDE_GEOM @@ -336,6 +342,9 @@ struct _Modes { // Internal state uint32_t show_only; // Only show messages from this ICAO int interactive; // Interactive mode uint64_t interactive_display_ttl;// Interactive mode: TTL display + int interactive_show_distance; // Show aircraft distance and bearing instead of lat/lon + interactive_distance_unit_t interactive_distance_units; // Units for interactive distance display + char *interactive_callsign_filter; // Filter for interactive display callsigns uint64_t stats; // Interval (millis) between stats dumps, int stats_range_histo; // Collect/show a range histogram? int onlyaddr; // Print only ICAO addresses diff --git a/interactive.c b/interactive.c index 3e36448..9b55ff3 100644 --- a/interactive.c +++ b/interactive.c @@ -50,6 +50,8 @@ #include "dump1090.h" #include +#include +#include // //========================= Interactive mode =============================== @@ -77,9 +79,40 @@ static int convert_speed(int kts) // Show the currently captured interactive data on screen. // +double distance_units_conversion; +char *distance_units_suffix; +regex_t callsign_filter_regex; + void interactiveInit() { - if (!Modes.interactive) + if (!Modes.interactive) { return; + } + + switch(Modes.interactive_distance_units) { + case UNIT_NAUTICAL_MILES: + distance_units_conversion = 0.53996; + distance_units_suffix = "nm"; + break; + case UNIT_STATUTE_MILES: + distance_units_conversion = 0.621371; + distance_units_suffix = "sm"; + break; + case UNIT_KILOMETERS: + distance_units_conversion = 1.0; + distance_units_suffix = "km"; + break; + } + + if (Modes.interactive_callsign_filter) { + int rc = regcomp(&callsign_filter_regex, Modes.interactive_callsign_filter, + REG_EXTENDED | REG_NOSUB | REG_ICASE); + if (rc != 0) { + char msg[256]; + regerror(rc, &callsign_filter_regex, msg, sizeof(msg)); + fprintf(stderr, "Unable to parse filter '%s': %s\n", Modes.interactive_callsign_filter, msg); + exit(1); + } + } initscr(); clear(); @@ -88,6 +121,7 @@ void interactiveInit() { void interactiveCleanup(void) { if (Modes.interactive) { + regfree(&callsign_filter_regex); endwin(); } } @@ -106,6 +140,11 @@ void interactiveShowData(void) { uint64_t now = mstime(); char progress; char spinner[4] = "|/-\\"; + int valid = 0; + double signalMax = -100.0; + double signalMin = +100.0; + double signalMean = 0.0; + double distanceMax = 0.0; if (!Modes.interactive) return; @@ -116,39 +155,58 @@ void interactiveShowData(void) { next_update = now + MODES_INTERACTIVE_REFRESH_TIME; - mvprintw(0, 0, " Hex Mode Sqwk Flight Alt Spd Hdg Lat Long RSSI Msgs Ti"); - mvhline(1, 0, ACS_HLINE, 80); + if (Modes.interactive_show_distance) { + mvprintw(1, 0, " Hex Mode Sqwk Flight Alt Spd Hdg Dist(%s) Bearing RSSI Msgs Ti", + distance_units_suffix); + } else { + mvprintw(1, 0, " Hex Mode Sqwk Flight Alt Spd Hdg Lat Long RSSI Msgs Ti"); + } + + mvhline(2, 0, ACS_HLINE, 80); progress = spinner[(now/1000)%4]; mvaddch(0, 79, progress); int rows = getmaxy(stdscr); - int row = 2; + int row = 3; + int rowMaxd = 0; + int rowMaxRSSI = 0; + int rowMinRSSI = 0; - while (a && row < rows) { - if (a->reliable && (now - a->seen) < Modes.interactive_display_ttl) { + while (a) { + + if (a->reliable && (now - a->seen) < Modes.interactive_display_ttl + && (Modes.interactive_callsign_filter == NULL || a->callsign_matched + || regexec(&callsign_filter_regex, a->callsign, 0, NULL, 0) == 0)) { char strSquawk[5] = " "; char strFl[7] = " "; char strTt[5] = " "; char strGs[5] = " "; int msgs = a->messages; + a->callsign_matched = 1; + valid++; + if (trackDataValid(&a->squawk_valid)) { - snprintf(strSquawk,5,"%04x", a->squawk); + snprintf(strSquawk, sizeof(strSquawk), "%04x", a->squawk); } if (trackDataValid(&a->gs_valid)) { - snprintf (strGs, 5,"%3d", convert_speed(a->gs)); + snprintf (strGs, sizeof(strGs), "%3d", convert_speed(a->gs)); } if (trackDataValid(&a->track_valid)) { - snprintf (strTt, 5,"%03.0f", a->track); + snprintf (strTt, sizeof(strTt), "%03.0f", a->track); } if (msgs > 99999) { msgs = 99999; } + double distance = 0.0; + char strDistance[8] = " "; + double bearing = 0.0; + char strBearing[9] = " "; char strMode[5] = " "; char strLat[8] = " "; char strLon[9] = " "; @@ -168,28 +226,70 @@ void interactiveShowData(void) { } if (trackDataValid(&a->position_valid)) { - snprintf(strLat, 8,"%7.03f", a->lat); - snprintf(strLon, 9,"%8.03f", a->lon); + snprintf(strLat, sizeof(strLat), "%7.03f", a->lat); + snprintf(strLon, sizeof(strLon), "%8.03f", a->lon); } if (trackDataValid(&a->airground_valid) && a->airground == AG_GROUND) { - snprintf(strFl, 7," grnd"); + snprintf(strFl, sizeof(strFl), "grnd "); } else if (Modes.use_gnss && trackDataValid(&a->altitude_geom_valid)) { - snprintf(strFl, 7, "%5dH", convert_altitude(a->altitude_geom)); + snprintf(strFl, sizeof(strFl), "%5dH", convert_altitude(a->altitude_geom)); } else if (trackDataValid(&a->altitude_baro_valid)) { - snprintf(strFl, 7, "%5d ", convert_altitude(a->altitude_baro)); + snprintf(strFl, sizeof(strFl), "%5d ", convert_altitude(a->altitude_baro)); + } + double signalDisplay = 10.0 * log10(signalAverage); + + + if ((Modes.bUserFlags & MODES_USER_LATLON_VALID) && trackDataValid(&a->position_valid)) { + distance = greatcircle(Modes.fUserLat, Modes.fUserLon, + a->lat, a->lon); + + distance /= 1000.0; + + distance *= distance_units_conversion; + if (distance > distanceMax) { + distanceMax = distance; + } + snprintf(strDistance, sizeof(strDistance), "%5.1f ", distance); + bearing = get_bearing(Modes.fUserLat, Modes.fUserLon, a->lat, a->lon); + snprintf(strBearing, sizeof(strBearing), "%5.0f ", bearing); } - mvprintw(row, 0, "%s%06X %-4s %-4s %-8s %6s %3s %3s %7s %8s %5.1f %5d %2.0f", + if (signalDisplay > signalMax) { + signalMax = signalDisplay; + } + if (signalDisplay < signalMin) { + signalMin = signalDisplay; + } + signalMean += signalDisplay; + + if (row < rows) { + mvprintw(row, 0, "%s%06X %-4s %-4s %-8s %6s %3s %3s %7s %8s %5.1f %5d %2.0f", (a->addr & MODES_NON_ICAO_ADDRESS) ? "~" : " ", (a->addr & 0xffffff), strMode, strSquawk, a->callsign, strFl, strGs, strTt, - strLat, strLon, 10 * log10(signalAverage), msgs, (now - a->seen)/1000.0); - ++row; + Modes.interactive_show_distance ? strDistance : strLat, + Modes.interactive_show_distance ? strBearing : strLon, + signalDisplay, msgs, (now - a->seen)/1000.0); + + if (signalDisplay >= signalMax) { + rowMaxRSSI = row; + } + if (signalDisplay <= signalMin) { + rowMinRSSI = row; + } + if (distance >= distanceMax) { + rowMaxd = row; + } + + ++row; + } + } a = a->next; } - if (Modes.mode_ac) { + + if (Modes.mode_ac && !Modes.interactive_callsign_filter) { for (unsigned i = 1; i < 4096 && row < rows; ++i) { if (modeAC_match[i] || modeAC_count[i] < 50 || modeAC_age[i] > 5) continue; @@ -200,8 +300,9 @@ void interactiveShowData(void) { int modeC = modeAToModeC(modeA); if (modeC != INVALID_ALTITUDE) { strMode[3] = 'C'; - snprintf(strFl, 7, "%5d ", convert_altitude(modeC * 100)); + snprintf(strFl, sizeof(strFl), "%5d ", convert_altitude(modeC * 100)); } + valid++; mvprintw(row, 0, "%7s %-4s %04x %-8s %6s %3s %3s %7s %8s %5s %5d %2d\n", @@ -221,8 +322,24 @@ void interactiveShowData(void) { } } - move(row, 0); - clrtobot(); + if (rowMaxd > 3 && Modes.interactive_show_distance) { + mvprintw(rowMaxd, 52, "^"); + } + + mvprintw(rowMaxd, 52, "+"); + mvprintw(rowMaxRSSI, 68, "+"); + mvprintw(rowMinRSSI, 68, "-"); + + mvprintw(0, 0, " Tot: %3d Vis: %3d RSSI: Max %5.1f+ Mean %5.1f Min %5.1f- MaxD: %6.1f%s+ ", + valid, (rows-3) < valid ? (rows-3) : valid, signalMax, signalMean / valid, signalMin, distanceMax, + distance_units_suffix); + + if (row < rows) { + move(row, 0); + clrtobot(); + } + move(0, 0); + refresh(); } diff --git a/track.c b/track.c index d18b11d..b5419b8 100644 --- a/track.c +++ b/track.c @@ -207,7 +207,7 @@ static int compare_validity(const data_validity *lhs, const data_validity *rhs) // Distance between points on a spherical earth. // This has up to 0.5% error because the earth isn't actually spherical // (but we don't use it in situations where that matters) -static double greatcircle(double lat0, double lon0, double lat1, double lon1) +double greatcircle(double lat0, double lon0, double lat1, double lon1) { double dlat, dlon; @@ -229,6 +229,25 @@ static double greatcircle(double lat0, double lon0, double lat1, double lon1) return 6371e3 * acos(sin(lat0) * sin(lat1) + cos(lat0) * cos(lat1) * cos(dlon)); } +double get_bearing(double lat0, double lon0, double lat1, double lon1) +{ + double dlon; + + lat0 = lat0 * M_PI / 180.0; + lon0 = lon0 * M_PI / 180.0; + lat1 = lat1 * M_PI / 180.0; + lon1 = lon1 * M_PI / 180.0; + + dlon = (lon1 - lon0); + + double x = (cos(lat0) * sin(lat1)) - + (sin(lat0) * cos(lat1) * cos(dlon)); + double y = sin(dlon) * cos(lat1); + double degree = atan2(y, x) * 180 / M_PI; + + return (degree >= 0)? degree : (degree + 360); +} + static void update_range_histogram(double lat, double lon) { if (Modes.stats_range_histo && (Modes.bUserFlags & MODES_USER_LATLON_VALID)) { @@ -1128,6 +1147,11 @@ struct aircraft *trackUpdateFromMessage(struct modesMessage *mm) } if (mm->callsign_valid && accept_data(&a->callsign_valid, mm->source)) { + if (strcmp(a->callsign, mm->callsign) != 0) { + // The callsign changed so tell interactive to + // re-evaluate its callsign filter regex if it has one + a->callsign_matched = 0; + } memcpy(a->callsign, mm->callsign, sizeof(a->callsign)); } diff --git a/track.h b/track.h index dc4f851..ade1267 100644 --- a/track.h +++ b/track.h @@ -108,6 +108,7 @@ struct aircraft { data_validity callsign_valid; char callsign[9]; // Flight number + int callsign_matched; // Interactive callsign filter matched data_validity altitude_baro_valid; int altitude_baro; // Altitude (Baro) @@ -321,4 +322,11 @@ static inline unsigned indexToModeA(unsigned index) return (index & 0007) | ((index & 0070) << 1) | ((index & 0700) << 2) | ((index & 07000) << 3); } +/* Great Circle distance in m */ +double greatcircle(double lat0, double lon0, double lat1, double lon1); + +/* Get bearing from 2 points */ +double get_bearing(double lat0, double lon0, double lat1, double lon1); + + #endif diff --git a/view1090.c b/view1090.c index c27a47f..1912590 100644 --- a/view1090.c +++ b/view1090.c @@ -107,11 +107,15 @@ static void view1090Init(void) { // static void showHelp(void) { printf( -"-----------------------------------------------------------------------------\n" +"-------------------------------------------------------------------------------------\n" "| view1090 ModeS Viewer %45s |\n" -"-----------------------------------------------------------------------------\n" +"-------------------------------------------------------------------------------------\n" "--no-interactive Disable interactive mode, print messages to stdout\n" "--interactive-ttl Remove from list if idle for (default: 60)\n" + "--interactive-show-distance Show aircraft distance and bearing instead of lat/lon\n" + " (requires --lat and --lon)\n" + "--interactive-distance-units Distance units ('km', 'sm', 'nm') (default: 'nm')\n" + "--interactive-callsign-filter Only callsigns that match the prefix or regex will be displayed\n" "--modeac Enable decoding of SSR modes 3/A & 3/C\n" "--net-bo-ipaddr TCP Beast output listen IPv4 (default: 127.0.0.1)\n" "--net-bo-port TCP Beast output listen port (default: 30005)\n" @@ -168,7 +172,20 @@ int main(int argc, char **argv) { Modes.interactive = 0; } else if (!strcmp(argv[j],"--interactive-ttl") && more) { Modes.interactive_display_ttl = (uint64_t)(1000 * atof(argv[++j])); - } else if (!strcmp(argv[j],"--lat") && more) { + } else if (!strcmp(argv[j], "--interactive-show-distance")) { + Modes.interactive_show_distance = 1; + } else if (!strcmp(argv[j], "--interactive-distance-units") && more) { + char *units = argv[++j]; + if (!strcmp(units, "km")) { + Modes.interactive_distance_units = UNIT_KILOMETERS; + } else if (!strcmp(units, "sm")) { + Modes.interactive_distance_units = UNIT_STATUTE_MILES; + } else { + Modes.interactive_distance_units = UNIT_NAUTICAL_MILES; + } + } else if (!strcmp(argv[j], "--interactive-callsign-filter") && more) { + Modes.interactive_callsign_filter = strdup(argv[++j]); + } else if (!strcmp(argv[j], "--lat") && more) { Modes.fUserLat = atof(argv[++j]); } else if (!strcmp(argv[j],"--lon") && more) { Modes.fUserLon = atof(argv[++j]); From dc2f47796cc0e7addd858b09b69c16f84cc284fc Mon Sep 17 00:00:00 2001 From: Oliver Jowett Date: Thu, 1 Oct 2020 13:46:22 +0800 Subject: [PATCH 02/33] 4.1~dev for the dev branch --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 122ba58..08acd6a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +dump1090-fa (4.1~dev) UNRELEASED; urgency=medium + + * in development + + -- Oliver Jowett Thu, 01 Oct 2020 13:46:07 +0800 + dump1090-fa (4.0) stable; urgency=medium * dump1090: Build support for OS X, FreeBSD, OpenBSD [courtesy @mikenor / @apparentorder on Github, PRs #33 / #38] From c3cd1ec0de263348aed85a66a584f3fbca16afd1 Mon Sep 17 00:00:00 2001 From: Oliver Jowett Date: Thu, 1 Oct 2020 13:53:50 +0800 Subject: [PATCH 03/33] limesdr: use --gain (in dB) if --limesdr-gain was not specified --- sdr_limesdr.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/sdr_limesdr.c b/sdr_limesdr.c index 07cbdef..8809aa0 100644 --- a/sdr_limesdr.c +++ b/sdr_limesdr.c @@ -105,7 +105,7 @@ void limesdrInitConfig() LimeSDR.is_stop = false; LimeSDR.verbosity = LMS_LOG_INFO; LimeSDR.oversample = 0; // default oversample - LimeSDR.gain = 0.75; + LimeSDR.gain = -1; LimeSDR.lpfbw = 2400000.0; LimeSDR.bw = 2.5e6; // the minimal supported value LimeSDR.serial[0] = '\0'; @@ -122,7 +122,7 @@ void limesdrShowHelp() printf("--limesdr-serial serial number of desired device\n"); printf("--limesdr-channel set number of an RX channel\n"); printf("--limesdr-oversample set RF oversampling ratio\n"); - printf("--limesdr-gain set normalized gain\n"); + printf("--limesdr-gain set normalized gain (range: 0.0 to 1.0)\n"); printf("--limesdr-lpfbw set LPF bandwidth\n"); printf("--limesdr-bw set bandwidth\n"); printf("\n"); @@ -273,9 +273,23 @@ bool limesdrOpen(void) goto error; } - if (LMS_SetNormalizedGain(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, LimeSDR.gain)) { - limesdrLogHandler(LMS_LOG_ERROR, "unable to set gain"); - goto error; + if (LimeSDR.gain >= 0) { + if (LMS_SetNormalizedGain(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, LimeSDR.gain)) { + limesdrLogHandler(LMS_LOG_ERROR, "unable to set gain"); + goto error; + } + } else { + if (Modes.gain == MODES_MAX_GAIN) { + if (LMS_SetNormalizedGain(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, 1.0)) { + limesdrLogHandler(LMS_LOG_ERROR, "unable to set gain"); + goto error; + } + } else { + if (LMS_SetGaindB(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, Modes.gain / 10)) { + limesdrLogHandler(LMS_LOG_ERROR, "unable to set gain"); + goto error; + } + } } if (LMS_SetLPFBW(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, LimeSDR.lpfbw)) { From 9fb1e5b9e859ae88ca7d309317b5b114134b0aba Mon Sep 17 00:00:00 2001 From: MAUGIN Thomas Date: Fri, 2 Oct 2020 17:52:51 +0200 Subject: [PATCH 04/33] fix(html): add empty coordinates to constructor (#82) - Change LineString constructor creation, see deprecated null constructor https://github.com/openlayers/openlayers/blob/main/changelog/upgrade-notes.md#v510 --- public_html/script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public_html/script.js b/public_html/script.js index b0c09c1..99ed274 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -944,7 +944,7 @@ function initialize_map() { }); for (var i = 0; i < data.rings.length; ++i) { - var geom = new ol.geom.LineString(); + var geom = new ol.geom.LineString([]); var points = data.rings[i].points; if (points.length > 0) { for (var j = 0; j < points.length; ++j) { From f0055c978dadc7a730fca3d48338286a8e630781 Mon Sep 17 00:00:00 2001 From: Oliver Jowett Date: Thu, 8 Oct 2020 19:30:06 +0800 Subject: [PATCH 05/33] Avoid false positives for address 000000 in the icao filter hashtable --- icao_filter.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/icao_filter.c b/icao_filter.c index 38f7b5c..0d3ee7e 100644 --- a/icao_filter.c +++ b/icao_filter.c @@ -35,6 +35,8 @@ static uint32_t icao_filter_a[ICAO_FILTER_SIZE]; static uint32_t icao_filter_b[ICAO_FILTER_SIZE]; static uint32_t *icao_filter_active; +#define EMPTY 0xFFFFFFFF + static uint32_t icaoHash(uint32_t a) { // Jenkins one-at-a-time hash, unrolled for 3 bytes @@ -61,8 +63,8 @@ static uint32_t icaoHash(uint32_t a) void icaoFilterInit() { - memset(icao_filter_a, 0, sizeof(icao_filter_a)); - memset(icao_filter_b, 0, sizeof(icao_filter_b)); + memset(icao_filter_a, 0xFF, sizeof(icao_filter_a)); + memset(icao_filter_b, 0xFF, sizeof(icao_filter_b)); icao_filter_active = icao_filter_a; } @@ -70,26 +72,26 @@ void icaoFilterAdd(uint32_t addr) { uint32_t h, h0; h0 = h = icaoHash(addr); - while (icao_filter_active[h] && icao_filter_active[h] != addr) { + while (icao_filter_active[h] != EMPTY && icao_filter_active[h] != addr) { h = (h+1) & (ICAO_FILTER_SIZE-1); if (h == h0) { fprintf(stderr, "ICAO hash table full, increase ICAO_FILTER_SIZE\n"); return; } } - if (!icao_filter_active[h]) + if (icao_filter_active[h] == EMPTY) icao_filter_active[h] = addr; // also add with a zeroed top byte, for handling DF20/21 with Data Parity h0 = h = icaoHash(addr & 0x00ffff); - while (icao_filter_active[h] && (icao_filter_active[h] & 0x00ffff) != (addr & 0x00ffff)) { + while (icao_filter_active[h] != EMPTY && (icao_filter_active[h] & 0x00ffff) != (addr & 0x00ffff)) { h = (h+1) & (ICAO_FILTER_SIZE-1); if (h == h0) { fprintf(stderr, "ICAO hash table full, increase ICAO_FILTER_SIZE\n"); return; } } - if (!icao_filter_active[h]) + if (icao_filter_active[h] == EMPTY) icao_filter_active[h] = addr; } @@ -98,7 +100,7 @@ int icaoFilterTest(uint32_t addr) uint32_t h, h0; h0 = h = icaoHash(addr); - while (icao_filter_a[h] && icao_filter_a[h] != addr) { + while (icao_filter_a[h] != EMPTY && icao_filter_a[h] != addr) { h = (h+1) & (ICAO_FILTER_SIZE-1); if (h == h0) break; @@ -107,7 +109,7 @@ int icaoFilterTest(uint32_t addr) return 1; h = h0; - while (icao_filter_b[h] && icao_filter_b[h] != addr) { + while (icao_filter_b[h] != EMPTY && icao_filter_b[h] != addr) { h = (h+1) & (ICAO_FILTER_SIZE-1); if (h == h0) break; @@ -124,21 +126,21 @@ uint32_t icaoFilterTestFuzzy(uint32_t partial) partial &= 0x00ffff; h0 = h = icaoHash(partial); - while (icao_filter_a[h] && (icao_filter_a[h] & 0x00ffff) != partial) { + while (icao_filter_a[h] != EMPTY && (icao_filter_a[h] & 0x00ffff) != partial) { h = (h+1) & (ICAO_FILTER_SIZE-1); if (h == h0) break; } - if ((icao_filter_a[h] & 0x00ffff) == partial) + if (icao_filter_a[h] != EMPTY && (icao_filter_a[h] & 0x00ffff) == partial) return icao_filter_a[h]; h = h0; - while (icao_filter_b[h] && (icao_filter_b[h] & 0x00ffff) != partial) { + while (icao_filter_b[h] != EMPTY && (icao_filter_b[h] & 0x00ffff) != partial) { h = (h+1) & (ICAO_FILTER_SIZE-1); if (h == h0) break; } - if ((icao_filter_b[h] & 0x00ffff) == partial) + if (icao_filter_b[h] != EMPTY && (icao_filter_b[h] & 0x00ffff) == partial) return icao_filter_b[h]; return 0; @@ -152,10 +154,10 @@ void icaoFilterExpire() if (now >= next_flip) { if (icao_filter_active == icao_filter_a) { - memset(icao_filter_b, 0, sizeof(icao_filter_b)); + memset(icao_filter_b, 0xFF, sizeof(icao_filter_b)); icao_filter_active = icao_filter_b; } else { - memset(icao_filter_a, 0, sizeof(icao_filter_a)); + memset(icao_filter_a, 0xFF, sizeof(icao_filter_a)); icao_filter_active = icao_filter_a; } next_flip = now + MODES_ICAO_FILTER_TTL; From e48006311b0b5fb4c8e899c078268d951a9fc571 Mon Sep 17 00:00:00 2001 From: Eric Tran Date: Mon, 12 Oct 2020 03:08:41 +0000 Subject: [PATCH 06/33] Fix type on SkyAware README --- public_html/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public_html/README.md b/public_html/README.md index 08cb7a8..2a5a754 100644 --- a/public_html/README.md +++ b/public_html/README.md @@ -31,7 +31,7 @@ Examples: | rangeRings | show/hide | | ringCount | integer | | ringBaseDistance | integer | -| ringInteval | integer | +| ringInterval | integer | From 5c043e849604a193eded6f09e17795ed1ac03ef4 Mon Sep 17 00:00:00 2001 From: Oliver Jowett Date: Tue, 17 Nov 2020 19:59:47 +0800 Subject: [PATCH 07/33] normalize_timespec: handle tv_nsec == 1000000000 correctly --- util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.c b/util.c index 43a1674..d0d2d07 100644 --- a/util.c +++ b/util.c @@ -80,7 +80,7 @@ int64_t receiveclock_ms_elapsed(uint64_t t1, uint64_t t2) void normalize_timespec(struct timespec *ts) { - if (ts->tv_nsec > 1000000000) { + if (ts->tv_nsec >= 1000000000) { ts->tv_sec += ts->tv_nsec / 1000000000; ts->tv_nsec = ts->tv_nsec % 1000000000; } else if (ts->tv_nsec < 0) { From c1eeda612e2c27f4873652183a482481a1a2d8f3 Mon Sep 17 00:00:00 2001 From: Oliver Jowett Date: Tue, 17 Nov 2020 19:59:59 +0800 Subject: [PATCH 08/33] fifo_acquire / fifo_dequeue: maybe fix pthread_cond_timedwait error handling It was possible, due to an off-by-one error in normalize_timespec, that the computed deadline passed to pthread_cond_timedwait had tv_nsec == 1000000000. glibc would reject this with EINVAL. While I never caught this in the act, there seem to be two follow-on problems from this: 1) we were looking for a negative return from pthread_cond_timedwait and testing errno. This is not how errors are reported, instead pthread functions return the error value directly. So the enclosing loop could spin forever, repeatedly passing the bad deadline value. 2) even if the error handling caught the EINVAL return, it assumed that the mutex was no longer held and didn't release it; but on error returns, the mutex state is actually untouched. Fix both cases (probably), and log about unusual returns from pthread_cond_timedwait --- fifo.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/fifo.c b/fifo.c index f7675f2..e33a4e2 100644 --- a/fifo.c +++ b/fifo.c @@ -140,11 +140,13 @@ struct mag_buf *fifo_acquire(uint32_t timeout_ms) } // No free buffers, wait for one - if (pthread_cond_timedwait(&fifo_free_cond, &fifo_mutex, &deadline) < 0) { - if (errno != ETIMEDOUT) - return NULL; // unexpected error, mutex no longer held! + int err = pthread_cond_timedwait(&fifo_free_cond, &fifo_mutex, &deadline); + if (err) { + if (err != ETIMEDOUT) { + fprintf(stderr, "fifo_acquire: pthread_cond_timedwait unexpectedly returned %s\n", strerror(err)); + } - goto done; // timed out + goto done; // done waiting } } @@ -219,11 +221,13 @@ struct mag_buf *fifo_dequeue(uint32_t timeout_ms) } // No data pending, wait for some - if (pthread_cond_timedwait(&fifo_notempty_cond, &fifo_mutex, &deadline) < 0) { - if (errno != ETIMEDOUT) - return NULL; // unexpected error, mutex no longer held! + int err = pthread_cond_timedwait(&fifo_notempty_cond, &fifo_mutex, &deadline); + if (err) { + if (err != ETIMEDOUT) { + fprintf(stderr, "fifo_dequeue: pthread_cond_timedwait unexpectedly returned %s\n", strerror(err)); + } - goto done; // timed out + goto done; // done waiting } } From f4f2f3ddad3cecb4d59a26c6eef5c2db040ac537 Mon Sep 17 00:00:00 2001 From: eric1tran Date: Wed, 2 Dec 2020 21:26:45 +0000 Subject: [PATCH 09/33] Add filtering by aircraft type --- public_html/index.html | 6 ++++++ public_html/planeObject.js | 7 +++++++ public_html/script.js | 23 +++++++++++++++++++++++ public_html/style.css | 2 +- 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/public_html/index.html b/public_html/index.html index 1e54d3a..66d584b 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -223,6 +223,12 @@ +
+ + + + +
diff --git a/public_html/planeObject.js b/public_html/planeObject.js index c55677c..dd7b6d2 100644 --- a/public_html/planeObject.js +++ b/public_html/planeObject.js @@ -109,6 +109,13 @@ function PlaneObject(icao) { } PlaneObject.prototype.isFiltered = function() { + // aircraft type filter + if (this.filter.aircraftTypeCode && this.icaotype !== null) { + if (typeof this.icaotype === 'string' && this.icaotype !== this.filter.aircraftTypeCode) { + return true; + } + } + if (this.filter.minAltitude !== undefined && this.filter.maxAltitude !== undefined) { if (this.altitude === null || this.altitude === undefined) { return true; diff --git a/public_html/script.js b/public_html/script.js index 99ed274..8c5010e 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -323,6 +323,10 @@ function initialize() { $("#altitude_filter_reset_button").click(onResetAltitudeFilter); + $("#aircraft_type_filter_form").submit(onFilterByAircraftType); + $("#aircraft_type_filter_reset_button").click(onResetAircraftTypeFilter); + + $('#settingsCog').on('click', function() { $('#settings_infoblock').toggle(); }); @@ -1977,6 +1981,18 @@ function onFilterByAltitude(e) { } } +function onFilterByAircraftType(e) { + e.preventDefault(); + updatePlaneFilter(); + refreshTableInfo(); +} + +function onResetAircraftTypeFilter(e) { + $("#aircraft_type_filter").val(""); + updatePlaneFilter(); + refreshTableInfo(); +} + function filterGroundVehicles(switchFilter) { if (typeof localStorage['groundVehicleFilter'] === 'undefined') { localStorage.setItem('groundVehicleFilter' , 'not_filtered'); @@ -2065,6 +2081,13 @@ function updatePlaneFilter() { PlaneFilter.minAltitude = minAltitude; PlaneFilter.maxAltitude = maxAltitude; PlaneFilter.altitudeUnits = DisplayUnits; + + var aircraftTypeCode = $("#aircraft_type_filter").val().trim() + if (aircraftTypeCode === "") { + aircraftTypeCode = undefined + } + + PlaneFilter.aircraftTypeCode = aircraftTypeCode; } function getFlightAwareIdentLink(ident, linkText) { diff --git a/public_html/style.css b/public_html/style.css index 9b2c66f..53aee08 100644 --- a/public_html/style.css +++ b/public_html/style.css @@ -329,7 +329,7 @@ div#loader { z-index: 99; position: absolute; left: 0; top: 0; bottom: 0; right: background-color: #3c6ea3; } -.altitudeFilterInput { +.altitudeFilterInput, .aircraftTypeFilterInput { width: 50px; } From 0fddde5126fc32b83ae2fef3c5eca71478103001 Mon Sep 17 00:00:00 2001 From: eric1tran Date: Mon, 7 Dec 2020 15:22:42 +0000 Subject: [PATCH 10/33] Make aircraft type filter case insensitive --- public_html/planeObject.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public_html/planeObject.js b/public_html/planeObject.js index dd7b6d2..4456600 100644 --- a/public_html/planeObject.js +++ b/public_html/planeObject.js @@ -110,8 +110,8 @@ function PlaneObject(icao) { PlaneObject.prototype.isFiltered = function() { // aircraft type filter - if (this.filter.aircraftTypeCode && this.icaotype !== null) { - if (typeof this.icaotype === 'string' && this.icaotype !== this.filter.aircraftTypeCode) { + if (this.filter.aircraftTypeCode) { + if (this.icaotype === null || (typeof this.icaotype === 'string' && this.icaotype.toUpperCase() !== this.filter.aircraftTypeCode.toUpperCase())) { return true; } } From d3459b1697970d385e32062875ab325acbd5349c Mon Sep 17 00:00:00 2001 From: eric1tran Date: Mon, 7 Dec 2020 16:26:56 +0000 Subject: [PATCH 11/33] Adding filtering by aircraft ident --- public_html/index.html | 10 +++++++++- public_html/planeObject.js | 6 ++++++ public_html/script.js | 23 +++++++++++++++++++++++ public_html/style.css | 6 +++++- 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/public_html/index.html b/public_html/index.html index 66d584b..b3e7912 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -223,12 +223,20 @@ +
- +
+ +
+ + + + +
diff --git a/public_html/planeObject.js b/public_html/planeObject.js index 4456600..41ff0ef 100644 --- a/public_html/planeObject.js +++ b/public_html/planeObject.js @@ -116,6 +116,12 @@ PlaneObject.prototype.isFiltered = function() { } } + if (this.filter.aircraftIdent) { + if (this.flight === null || (typeof this.flight === 'string' && this.flight.toUpperCase().trim() !== this.filter.aircraftIdent.toUpperCase())) { + return true; + } + } + if (this.filter.minAltitude !== undefined && this.filter.maxAltitude !== undefined) { if (this.altitude === null || this.altitude === undefined) { return true; diff --git a/public_html/script.js b/public_html/script.js index 8c5010e..0585967 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -327,6 +327,10 @@ function initialize() { $("#aircraft_type_filter_reset_button").click(onResetAircraftTypeFilter); + $("#aircraft_ident_filter_form").submit(onFilterByAircraftIdent); + $("#aircraft_ident_filter_reset_button").click(onResetAircraftIdentFilter); + + $('#settingsCog').on('click', function() { $('#settings_infoblock').toggle(); }); @@ -1993,6 +1997,19 @@ function onResetAircraftTypeFilter(e) { refreshTableInfo(); } + +function onFilterByAircraftIdent(e) { + e.preventDefault(); + updatePlaneFilter(); + refreshTableInfo(); +} + +function onResetAircraftIdentFilter(e) { + $("#aircraft_ident_filter").val(""); + updatePlaneFilter(); + refreshTableInfo(); +} + function filterGroundVehicles(switchFilter) { if (typeof localStorage['groundVehicleFilter'] === 'undefined') { localStorage.setItem('groundVehicleFilter' , 'not_filtered'); @@ -2087,7 +2104,13 @@ function updatePlaneFilter() { aircraftTypeCode = undefined } + var aircraftIdent = $("#aircraft_ident_filter").val().trim() + if (aircraftIdent === "") { + aircraftIdent = undefined + } + PlaneFilter.aircraftTypeCode = aircraftTypeCode; + PlaneFilter.aircraftIdent = aircraftIdent; } function getFlightAwareIdentLink(ident, linkText) { diff --git a/public_html/style.css b/public_html/style.css index 53aee08..dd8cda6 100644 --- a/public_html/style.css +++ b/public_html/style.css @@ -329,10 +329,14 @@ div#loader { z-index: 99; position: absolute; left: 0; top: 0; bottom: 0; right: background-color: #3c6ea3; } -.altitudeFilterInput, .aircraftTypeFilterInput { +.altitudeFilterInput { width: 50px; } +.aircraftFilterInput { + width: 80px; +} + .rangeRingsInput { width: 30px; float: right; From e2b2ce3f63331d694dbcf2bec48177639dbb3853 Mon Sep 17 00:00:00 2001 From: eric1tran Date: Mon, 7 Dec 2020 19:37:04 +0000 Subject: [PATCH 12/33] Add checkboxes next to data source legend and css styling --- public_html/index.html | 16 ++++---- public_html/script.js | 88 ++++++++++++++++++++++++++++++++++++++++++ public_html/style.css | 24 +++++++++++- 3 files changed, 118 insertions(+), 10 deletions(-) diff --git a/public_html/index.html b/public_html/index.html index b3e7912..7c03c37 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -386,14 +386,14 @@
-
-
ADS-B
-
-
MLAT
-
-
Other
-
-
TIS-B
+
+
ADS-B
+
+
MLAT
+
+
Other
+
+
TIS-B
diff --git a/public_html/script.js b/public_html/script.js index 0585967..384261c 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -377,6 +377,22 @@ function initialize() { toggleAllColumns(true); }) + $('#adsb_datasource_checkbox').on('click', function() { + toggleADSBAircraft(true); + }) + + $('#mlat_datasource_checkbox').on('click', function() { + toggleMLATAircraft(true); + }) + + $('#other_datasource_checkbox').on('click', function() { + toggleOtherAircraft(true); + }) + + $('#tisb_datasource_checkbox').on('click', function() { + toggleTISBAircraft(true); + }) + // Event handlers for to column checkboxes checkbox_div_map.forEach(function (checkbox, div) { $(div).on('click', function() { @@ -397,6 +413,10 @@ function initialize() { toggleAllPlanes(false); toggleGroupByDataType(false); toggleAllColumns(false); + toggleADSBAircraft(false); + toggleMLATAircraft(false); + toggleOtherAircraft(false); + toggleTISBAircraft(false); // Get receiver metadata, reconfigure using it, then continue // with initialization @@ -2403,3 +2423,71 @@ function toggleAllColumns(switchToggle) { localStorage.setItem('selectAllColumnsCheckbox', selectAllColumnsCheckbox); } + +function toggleADSBAircraft(switchFilter) { + if (typeof localStorage['sourceADSBFilter'] === 'undefined') { + localStorage.setItem('sourceADSBFilter','not_filtered'); + } + + var sourceADSBFilter = localStorage.getItem('sourceADSBFilter'); + if (switchFilter === true) { + sourceADSBFilter = (sourceADSBFilter === 'not_filtered') ? 'filtered' : 'not_filtered'; + } + if (sourceADSBFilter === 'not_filtered') { + $('#adsb_datasource_checkbox').removeClass('sourceCheckboxChecked'); + } else { + $('#adsb_datasource_checkbox').addClass('sourceCheckboxChecked'); + } + localStorage.setItem('sourceADSBFilter', sourceADSBFilter); +} + +function toggleMLATAircraft(switchFilter) { + if (typeof localStorage['sourceMLATFilter'] === 'undefined') { + localStorage.setItem('sourceMLATFilter','not_filtered'); + } + + var sourceMLATFilter = localStorage.getItem('sourceMLATFilter'); + if (switchFilter === true) { + sourceMLATFilter = (sourceMLATFilter === 'not_filtered') ? 'filtered' : 'not_filtered'; + } + if (sourceMLATFilter === 'not_filtered') { + $('#mlat_datasource_checkbox').removeClass('sourceCheckboxChecked'); + } else { + $('#mlat_datasource_checkbox').addClass('sourceCheckboxChecked'); + } + localStorage.setItem('sourceMLATFilter', sourceMLATFilter); +} + +function toggleOtherAircraft(switchFilter) { + if (typeof localStorage['sourceOtherFilter'] === 'undefined') { + localStorage.setItem('sourceOtherFilter','not_filtered'); + } + + var sourceOtherFilter = localStorage.getItem('sourceOtherFilter'); + if (switchFilter === true) { + sourceOtherFilter = (sourceOtherFilter === 'not_filtered') ? 'filtered' : 'not_filtered'; + } + if (sourceOtherFilter === 'not_filtered') { + $('#other_datasource_checkbox').removeClass('sourceCheckboxChecked'); + } else { + $('#other_datasource_checkbox').addClass('sourceCheckboxChecked'); + } + localStorage.setItem('sourceOtherFilter', sourceOtherFilter); +} + +function toggleTISBAircraft(switchFilter) { + if (typeof localStorage['sourceTISBFilter'] === 'undefined') { + localStorage.setItem('sourceTISBFilter','not_filtered'); + } + + var sourceTISBFilter = localStorage.getItem('sourceTISBFilter'); + if (switchFilter === true) { + sourceTISBFilter = (sourceTISBFilter === 'not_filtered') ? 'filtered' : 'not_filtered'; + } + if (sourceTISBFilter === 'not_filtered') { + $('#tisb_datasource_checkbox').removeClass('sourceCheckboxChecked'); + } else { + $('#tisb_datasource_checkbox').addClass('sourceCheckboxChecked'); + } + localStorage.setItem('sourceTISBFilter', sourceTISBFilter); +} diff --git a/public_html/style.css b/public_html/style.css index dd8cda6..98254f1 100644 --- a/public_html/style.css +++ b/public_html/style.css @@ -271,7 +271,9 @@ div#loader { z-index: 99; position: absolute; left: 0; top: 0; bottom: 0; right: } #units_container, -#altitude_filter_form { +#altitude_filter_form, +#aircraft_type_filter_form, +#aircraft_ident_filter_form { font-size: small; margin: 10px 0 10px 0; } @@ -687,8 +689,10 @@ select.error, textarea.error, input.error { .legendTitle { line-height: 19px; display: inline-block; - padding-right: 20px; + padding-right: 5px; padding-left: 5px; + border-radius: 5px; + margin-right: 20px; } #settings_infoblock { @@ -727,6 +731,22 @@ select.error, textarea.error, input.error { background-image: url('images/box-checked.png') !important; } +.sourceCheckbox { + width: 13px; + height: 13px; + background-image: url('images/box-empty.png'); + background-repeat: no-repeat; + background-position: center; + background-size: contain; + cursor: pointer; + margin-top: 3px; + margin-right: 3px; +} + +.sourceCheckboxChecked { + background-image: url('images/box-checked.png') !important; +} + .settingsCloseBox { position: absolute; right: 8px; From c466a4724f8f078c2bb84e512a5d2fb52db89853 Mon Sep 17 00:00:00 2001 From: eric1tran Date: Mon, 7 Dec 2020 22:18:16 +0000 Subject: [PATCH 13/33] Add filtering on data source --- public_html/planeObject.js | 12 ++++++++++++ public_html/script.js | 38 +++++++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/public_html/planeObject.js b/public_html/planeObject.js index 41ff0ef..a5847ce 100644 --- a/public_html/planeObject.js +++ b/public_html/planeObject.js @@ -116,12 +116,24 @@ PlaneObject.prototype.isFiltered = function() { } } + // aircraft ident filter if (this.filter.aircraftIdent) { if (this.flight === null || (typeof this.flight === 'string' && this.flight.toUpperCase().trim() !== this.filter.aircraftIdent.toUpperCase())) { return true; } } + var dataSource = this.getDataSource(); + if (dataSource === 'adsb_icao') { + if (!this.filter.ADSB) return true; + } else if (dataSource === 'mlat') { + if (!this.filter.MLAT) return true; + } else if (dataSource === 'tisb_trackfile' || dataSource === 'tisb_icao' || dataSource === 'tisb_other') { + if (!this.filter.TISB) return true; + } else { + if (!this.filter.Other) return true; + } + if (this.filter.minAltitude !== undefined && this.filter.maxAltitude !== undefined) { if (this.altitude === null || this.altitude === undefined) { return true; diff --git a/public_html/script.js b/public_html/script.js index 384261c..ca9b51e 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -379,18 +379,22 @@ function initialize() { $('#adsb_datasource_checkbox').on('click', function() { toggleADSBAircraft(true); + refreshDataSourceFilters(); }) $('#mlat_datasource_checkbox').on('click', function() { toggleMLATAircraft(true); + refreshDataSourceFilters(); }) $('#other_datasource_checkbox').on('click', function() { toggleOtherAircraft(true); + refreshDataSourceFilters(); }) $('#tisb_datasource_checkbox').on('click', function() { toggleTISBAircraft(true); + refreshDataSourceFilters(); }) // Event handlers for to column checkboxes @@ -417,6 +421,7 @@ function initialize() { toggleMLATAircraft(false); toggleOtherAircraft(false); toggleTISBAircraft(false); + refreshDataSourceFilters(); // Get receiver metadata, reconfigure using it, then continue // with initialization @@ -2121,7 +2126,7 @@ function updatePlaneFilter() { var aircraftTypeCode = $("#aircraft_type_filter").val().trim() if (aircraftTypeCode === "") { - aircraftTypeCode = undefined + aircraftTypeCode = undefined } var aircraftIdent = $("#aircraft_ident_filter").val().trim() @@ -2133,6 +2138,13 @@ function updatePlaneFilter() { PlaneFilter.aircraftIdent = aircraftIdent; } +function refreshDataSourceFilters () { + PlaneFilter.ADSB = (localStorage.getItem('sourceADSBFilter') === 'selected') ? true : false; + PlaneFilter.MLAT = (localStorage.getItem('sourceMLATFilter') === 'selected') ? true : false; + PlaneFilter.Other = (localStorage.getItem('sourceOtherFilter') === 'selected') ? true : false; + PlaneFilter.TISB = (localStorage.getItem('sourceTISBFilter') === 'selected') ? true : false; +} + function getFlightAwareIdentLink(ident, linkText) { if (ident !== null && ident !== "") { if (!linkText) { @@ -2426,14 +2438,14 @@ function toggleAllColumns(switchToggle) { function toggleADSBAircraft(switchFilter) { if (typeof localStorage['sourceADSBFilter'] === 'undefined') { - localStorage.setItem('sourceADSBFilter','not_filtered'); + localStorage.setItem('sourceADSBFilter','deselected'); } var sourceADSBFilter = localStorage.getItem('sourceADSBFilter'); if (switchFilter === true) { - sourceADSBFilter = (sourceADSBFilter === 'not_filtered') ? 'filtered' : 'not_filtered'; + sourceADSBFilter = (sourceADSBFilter === 'deselected') ? 'selected' : 'deselected'; } - if (sourceADSBFilter === 'not_filtered') { + if (sourceADSBFilter === 'deselected') { $('#adsb_datasource_checkbox').removeClass('sourceCheckboxChecked'); } else { $('#adsb_datasource_checkbox').addClass('sourceCheckboxChecked'); @@ -2443,14 +2455,14 @@ function toggleADSBAircraft(switchFilter) { function toggleMLATAircraft(switchFilter) { if (typeof localStorage['sourceMLATFilter'] === 'undefined') { - localStorage.setItem('sourceMLATFilter','not_filtered'); + localStorage.setItem('sourceMLATFilter','deselected'); } var sourceMLATFilter = localStorage.getItem('sourceMLATFilter'); if (switchFilter === true) { - sourceMLATFilter = (sourceMLATFilter === 'not_filtered') ? 'filtered' : 'not_filtered'; + sourceMLATFilter = (sourceMLATFilter === 'deselected') ? 'selected' : 'deselected'; } - if (sourceMLATFilter === 'not_filtered') { + if (sourceMLATFilter === 'deselected') { $('#mlat_datasource_checkbox').removeClass('sourceCheckboxChecked'); } else { $('#mlat_datasource_checkbox').addClass('sourceCheckboxChecked'); @@ -2460,14 +2472,14 @@ function toggleMLATAircraft(switchFilter) { function toggleOtherAircraft(switchFilter) { if (typeof localStorage['sourceOtherFilter'] === 'undefined') { - localStorage.setItem('sourceOtherFilter','not_filtered'); + localStorage.setItem('sourceOtherFilter','deselected'); } var sourceOtherFilter = localStorage.getItem('sourceOtherFilter'); if (switchFilter === true) { - sourceOtherFilter = (sourceOtherFilter === 'not_filtered') ? 'filtered' : 'not_filtered'; + sourceOtherFilter = (sourceOtherFilter === 'deselected') ? 'selected' : 'deselected'; } - if (sourceOtherFilter === 'not_filtered') { + if (sourceOtherFilter === 'deselected') { $('#other_datasource_checkbox').removeClass('sourceCheckboxChecked'); } else { $('#other_datasource_checkbox').addClass('sourceCheckboxChecked'); @@ -2477,14 +2489,14 @@ function toggleOtherAircraft(switchFilter) { function toggleTISBAircraft(switchFilter) { if (typeof localStorage['sourceTISBFilter'] === 'undefined') { - localStorage.setItem('sourceTISBFilter','not_filtered'); + localStorage.setItem('sourceTISBFilter','deselected'); } var sourceTISBFilter = localStorage.getItem('sourceTISBFilter'); if (switchFilter === true) { - sourceTISBFilter = (sourceTISBFilter === 'not_filtered') ? 'filtered' : 'not_filtered'; + sourceTISBFilter = (sourceTISBFilter === 'deselected') ? 'selected' : 'deselected'; } - if (sourceTISBFilter === 'not_filtered') { + if (sourceTISBFilter === 'deselected') { $('#tisb_datasource_checkbox').removeClass('sourceCheckboxChecked'); } else { $('#tisb_datasource_checkbox').addClass('sourceCheckboxChecked'); From cd6d3a373bce40fd0175762e711c19dd225474bd Mon Sep 17 00:00:00 2001 From: eric1tran Date: Tue, 8 Dec 2020 17:15:17 +0000 Subject: [PATCH 14/33] Comments and spacing --- public_html/script.js | 51 ++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/public_html/script.js b/public_html/script.js index ca9b51e..5cd89c3 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -411,6 +411,7 @@ function initialize() { mapResizeTimeout = setTimeout(updateMapSize, 10); }); + // Initialize settings from local storage filterGroundVehicles(false); filterBlockedMLAT(false); toggleAltitudeChart(false); @@ -1151,24 +1152,23 @@ function refreshSelected() { // emerg.className = 'hidden'; // } - $("#selected_altitude").text(format_altitude_long(selected.altitude, selected.vert_rate, DisplayUnits)); - - $('#selected_onground').text(format_onground(selected.altitude)); + $("#selected_altitude").text(format_altitude_long(selected.altitude, selected.vert_rate, DisplayUnits)); + $('#selected_onground').text(format_onground(selected.altitude)); if (selected.squawk === null || selected.squawk === '0000') { $('#selected_squawk').text('n/a'); } else { $('#selected_squawk').text(selected.squawk); } - - $('#selected_speed').text(format_speed_long(selected.gs, DisplayUnits)); - $('#selected_ias').text(format_speed_long(selected.ias, DisplayUnits)); - $('#selected_tas').text(format_speed_long(selected.tas, DisplayUnits)); - $('#selected_vertical_rate').text(format_vert_rate_long(selected.baro_rate, DisplayUnits)); - $('#selected_vertical_rate_geo').text(format_vert_rate_long(selected.geom_rate, DisplayUnits)); + + $('#selected_speed').text(format_speed_long(selected.gs, DisplayUnits)); + $('#selected_ias').text(format_speed_long(selected.ias, DisplayUnits)); + $('#selected_tas').text(format_speed_long(selected.tas, DisplayUnits)); + $('#selected_vertical_rate').text(format_vert_rate_long(selected.baro_rate, DisplayUnits)); + $('#selected_vertical_rate_geo').text(format_vert_rate_long(selected.geom_rate, DisplayUnits)); $('#selected_icao').text(selected.icao.toUpperCase()); $('#airframes_post_icao').attr('value',selected.icao); - $('#selected_track').text(format_track_long(selected.track)); + $('#selected_track').text(format_track_long(selected.track)); if (selected.seen <= 1) { $('#selected_seen').text('now'); @@ -1191,7 +1191,7 @@ function refreshSelected() { $('#selected_flag').addClass('hidden'); } - if (selected.position === null) { + if (selected.position === null) { $('#selected_position').text('n/a'); $('#selected_follow').addClass('hidden'); } else { @@ -1204,23 +1204,24 @@ function refreshSelected() { } else { $('#selected_follow').css('font-weight', 'normal'); } - } - if (selected.getDataSource() === "adsb_icao") { - $('#selected_source').text("ADS-B"); - } else if (selected.getDataSource() === "tisb_trackfile" || selected.getDataSource() === "tisb_icao" || selected.getDataSource() === "tisb_other") { - $('#selected_source').text("TIS-B"); - } else if (selected.getDataSource() === "mlat") { - $('#selected_source').text("MLAT"); - } else { - $('#selected_source').text("Other"); - } - $('#selected_category').text(selected.category ? selected.category : "n/a"); + } + + if (selected.getDataSource() === "adsb_icao") { + $('#selected_source').text("ADS-B"); + } else if (selected.getDataSource() === "tisb_trackfile" || selected.getDataSource() === "tisb_icao" || selected.getDataSource() === "tisb_other") { + $('#selected_source').text("TIS-B"); + } else if (selected.getDataSource() === "mlat") { + $('#selected_source').text("MLAT"); + } else { + $('#selected_source').text("Other"); + } + + $('#selected_category').text(selected.category ? selected.category : "n/a"); $('#selected_sitedist').text(format_distance_long(selected.sitedist, DisplayUnits)); $('#selected_rssi').text(selected.rssi.toFixed(1) + ' dBFS'); $('#selected_message_count').text(selected.messages); - $('#selected_photo_link').html(getFlightAwarePhotoLink(selected.registration)); - - $('#selected_altitude_geom').text(format_altitude_long(selected.alt_geom, selected.geom_rate, DisplayUnits)); + $('#selected_photo_link').html(getFlightAwarePhotoLink(selected.registration)); + $('#selected_altitude_geom').text(format_altitude_long(selected.alt_geom, selected.geom_rate, DisplayUnits)); $('#selected_mag_heading').text(format_track_long(selected.mag_heading)); $('#selected_true_heading').text(format_track_long(selected.true_heading)); $('#selected_ias').text(format_speed_long(selected.ias, DisplayUnits)); From 9b85a30c9144b1ba68af00507c5afc0cee92b02d Mon Sep 17 00:00:00 2001 From: eric1tran Date: Tue, 8 Dec 2020 20:34:04 +0000 Subject: [PATCH 15/33] Enable all data source checkboxes by default --- public_html/script.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/public_html/script.js b/public_html/script.js index 5cd89c3..e520b72 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -2439,7 +2439,7 @@ function toggleAllColumns(switchToggle) { function toggleADSBAircraft(switchFilter) { if (typeof localStorage['sourceADSBFilter'] === 'undefined') { - localStorage.setItem('sourceADSBFilter','deselected'); + localStorage.setItem('sourceADSBFilter','selected'); } var sourceADSBFilter = localStorage.getItem('sourceADSBFilter'); @@ -2456,7 +2456,7 @@ function toggleADSBAircraft(switchFilter) { function toggleMLATAircraft(switchFilter) { if (typeof localStorage['sourceMLATFilter'] === 'undefined') { - localStorage.setItem('sourceMLATFilter','deselected'); + localStorage.setItem('sourceMLATFilter','selected'); } var sourceMLATFilter = localStorage.getItem('sourceMLATFilter'); @@ -2473,7 +2473,7 @@ function toggleMLATAircraft(switchFilter) { function toggleOtherAircraft(switchFilter) { if (typeof localStorage['sourceOtherFilter'] === 'undefined') { - localStorage.setItem('sourceOtherFilter','deselected'); + localStorage.setItem('sourceOtherFilter','selected'); } var sourceOtherFilter = localStorage.getItem('sourceOtherFilter'); @@ -2490,7 +2490,7 @@ function toggleOtherAircraft(switchFilter) { function toggleTISBAircraft(switchFilter) { if (typeof localStorage['sourceTISBFilter'] === 'undefined') { - localStorage.setItem('sourceTISBFilter','deselected'); + localStorage.setItem('sourceTISBFilter','selected'); } var sourceTISBFilter = localStorage.getItem('sourceTISBFilter'); From ad56c1363b4016310bebfe626a51bf539d98bb26 Mon Sep 17 00:00:00 2001 From: eric1tran Date: Tue, 8 Dec 2020 20:44:14 +0000 Subject: [PATCH 16/33] Include SkyAware in version display --- public_html/index.html | 2 +- public_html/script.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public_html/index.html b/public_html/index.html index 1e54d3a..38180fb 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -197,7 +197,7 @@
Show Map
- + diff --git a/public_html/script.js b/public_html/script.js index 99ed274..09cb14a 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -26,7 +26,7 @@ var SpecialSquawks = { // Get current map settings var CenterLat, CenterLon, ZoomLvl, MapType, SiteCirclesCount, SiteCirclesBaseDistance, SiteCirclesInterval; -var Dump1090Version = "unknown version"; +var SkyAwareVersion = "unknown version"; var RefreshInterval = 1000; var PlaneRowTemplate = null; @@ -406,7 +406,7 @@ function initialize() { DefaultCenterLon = data.lon; } - Dump1090Version = data.version; + SkyAwareVersion = data.version; RefreshInterval = data.refresh; PositionHistorySize = data.history; }) @@ -1073,7 +1073,7 @@ function refreshSelected() { } $('#dump1090_infoblock').css('display','block'); - $('#dump1090_version').text(Dump1090Version); + $('#skyaware_version').text('SkyAware ' + SkyAwareVersion); $('#dump1090_total_ac').text(TrackedAircraft); $('#dump1090_total_ac_positions').text(TrackedAircraftPositions); $('#dump1090_total_history').text(TrackedHistorySize); From 1916fc664811ddb9febb9c2761605993a2c784bc Mon Sep 17 00:00:00 2001 From: eric1tran Date: Wed, 9 Dec 2020 15:18:05 +0000 Subject: [PATCH 17/33] Use regex match for filter comparisons --- public_html/planeObject.js | 6 +++--- public_html/script.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/public_html/planeObject.js b/public_html/planeObject.js index a5847ce..a02c2ac 100644 --- a/public_html/planeObject.js +++ b/public_html/planeObject.js @@ -111,15 +111,15 @@ function PlaneObject(icao) { PlaneObject.prototype.isFiltered = function() { // aircraft type filter if (this.filter.aircraftTypeCode) { - if (this.icaotype === null || (typeof this.icaotype === 'string' && this.icaotype.toUpperCase() !== this.filter.aircraftTypeCode.toUpperCase())) { + if (this.icaotype === null || (typeof this.icaotype === 'string' && !this.icaotype.toUpperCase().trim().match(this.filter.aircraftTypeCode))) { return true; } } // aircraft ident filter if (this.filter.aircraftIdent) { - if (this.flight === null || (typeof this.flight === 'string' && this.flight.toUpperCase().trim() !== this.filter.aircraftIdent.toUpperCase())) { - return true; + if (this.flight === null || (typeof this.flight === 'string' && !this.flight.toUpperCase().trim().match(this.filter.aircraftIdent))) { + return true; } } diff --git a/public_html/script.js b/public_html/script.js index e520b72..a0044c7 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -2125,12 +2125,12 @@ function updatePlaneFilter() { PlaneFilter.maxAltitude = maxAltitude; PlaneFilter.altitudeUnits = DisplayUnits; - var aircraftTypeCode = $("#aircraft_type_filter").val().trim() + var aircraftTypeCode = $("#aircraft_type_filter").val().trim().toUpperCase() if (aircraftTypeCode === "") { aircraftTypeCode = undefined } - var aircraftIdent = $("#aircraft_ident_filter").val().trim() + var aircraftIdent = $("#aircraft_ident_filter").val().trim().toUpperCase() if (aircraftIdent === "") { aircraftIdent = undefined } From 47e4df2b7bdbd46c9cb7c9d51b46212f99e2aa56 Mon Sep 17 00:00:00 2001 From: eric1tran Date: Wed, 9 Dec 2020 18:22:15 +0000 Subject: [PATCH 18/33] Put filters into an accordion style dropdown --- public_html/index.html | 51 +++++++++++++++++++++--------------------- public_html/script.js | 19 ++++++++++++++++ public_html/style.css | 27 ++++++++++++++++++++++ 3 files changed, 72 insertions(+), 25 deletions(-) diff --git a/public_html/index.html b/public_html/index.html index 7c03c37..17a2151 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -213,32 +213,33 @@ -
- - - - to - - - - -
- -
- - - - -
- -
- - - - -
+
+ +
+
+ + + + to + + + + +
+
+ + + + +
-
+
+ + + + +
+
diff --git a/public_html/script.js b/public_html/script.js index a0044c7..b8aec7d 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -320,6 +320,25 @@ function initialize() { customAltitudeColors = false; } + // Accordian display logic for additional config buttons + var acc = document.getElementsByClassName("accordion"); + var i; + + for (i = 0; i < acc.length; i++) { + acc[i].addEventListener("click", function() { + /* Toggle between adding and removing the "active" class, + to highlight the button that controls the panel */ + this.classList.toggle("active"); + + /* Toggle between hiding and showing the active panel */ + var panel = this.nextElementSibling; + if (panel.style.display === "block") { + panel.style.display = "none"; + } else { + panel.style.display = "block"; + } + }); + } $("#altitude_filter_reset_button").click(onResetAltitudeFilter); diff --git a/public_html/style.css b/public_html/style.css index 98254f1..472fc09 100644 --- a/public_html/style.css +++ b/public_html/style.css @@ -60,6 +60,7 @@ html, body { float: right; background-color: #002F5D; color: #FFFFFF; + width: 125px; } #column_select_window { @@ -885,3 +886,29 @@ select.error, textarea.error, input.error { background-image: url("images/map-icon@3x.png"); } } + +/* Style the buttons that are used to open and close the accordion panel */ +.accordion { + position: relative; + background-color: #002F5D; + color: #FFFFFF; + cursor: pointer; + text-align: center; + width: 125px; +} + +.active, .accordion:hover, #column_select:hover { + background-color: #abcad8; +} + + /* Style the accordion panel. Note: hidden by default */ +.panel { + padding: 0 2px; + background-color: #E5F6FC; + display: none; + overflow: hidden; +} + +.config_button_row { + margin-top: 5px; +} \ No newline at end of file From 829fe1b5e2996a9f5c10357b395077c94bdbd429 Mon Sep 17 00:00:00 2001 From: eric1tran Date: Wed, 9 Dec 2020 23:34:32 +0000 Subject: [PATCH 19/33] Filter and Column buttons to expand panels and styling cleanup --- public_html/index.html | 231 +++++++++++++++++++++-------------------- public_html/script.js | 35 ++----- public_html/style.css | 78 ++++---------- 3 files changed, 147 insertions(+), 197 deletions(-) diff --git a/public_html/index.html b/public_html/index.html index 17a2151..ad56ad2 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -212,124 +212,125 @@
- +
- -
-
- - - - to - - - - -
-
- - - - -
- -
- - - - -
-
- + +
-