Merge pull request #81 from gtjoseph/dev-for-fa
Interactive mode updates
This commit is contained in:
commit
016cb8f9d2
19
dump1090.c
19
dump1090.c
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
159
interactive.c
159
interactive.c
|
|
@ -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
26
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));
|
||||
}
|
||||
|
||||
|
|
|
|||
8
track.h
8
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
|
||||
|
|
|
|||
23
view1090.c
23
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 <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]);
|
||||
|
|
|
|||
Loading…
Reference in New Issue