Merge pull request #81 from gtjoseph/dev-for-fa

Interactive mode updates
This commit is contained in:
Oliver Jowett 2020-10-01 00:47:42 -05:00 committed by GitHub
commit 016cb8f9d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 218 additions and 26 deletions

View File

@ -284,6 +284,10 @@ static void showHelp(void)
"--freq <hz> Set frequency (default: 1090 Mhz)\n"
"--interactive Interactive mode refreshing data on screen. Implies --throttle\n"
"--interactive-ttl <sec> Remove from list if idle for <sec> (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]);

View File

@ -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

View File

@ -50,6 +50,8 @@
#include "dump1090.h"
#include <curses.h>
#include <regex.h>
#include <sys/types.h>
//
//========================= 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();
}

26
track.c
View File

@ -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));
}

View File

@ -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

View File

@ -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 <sec> Remove from list if idle for <sec> (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 <IPv4> TCP Beast output listen IPv4 (default: 127.0.0.1)\n"
"--net-bo-port <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]);