Merge branch 'dev' into build-instructions

This commit is contained in:
Joe Prochazka 2019-04-29 09:27:49 -04:00 committed by GitHub
commit f573b843c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 351 additions and 103 deletions

View file

@ -16,7 +16,7 @@ matrix:
before_install: before_install:
- if [ `uname` = "Linux" ]; then - if [ `uname` = "Linux" ]; then
sudo apt-get update -qq; sudo apt-get update -qq;
sudo apt-get install -y build-essential debhelper librtlsdr-dev libusb-1.0-0-dev pkg-config; sudo apt-get install -y build-essential debhelper librtlsdr-dev libusb-1.0-0-dev pkg-config fakeroot libbladerf-dev dh-systemd;
elif [ `uname` = "Darwin" ]; then elif [ `uname` = "Darwin" ]; then
brew update; brew update;
brew install -v librtlsdr; brew install -v librtlsdr;

View file

@ -15,16 +15,20 @@ ifeq ($(RTLSDR), yes)
ifdef RTLSDR_PREFIX ifdef RTLSDR_PREFIX
CPPFLAGS += -I$(RTLSDR_PREFIX)/include CPPFLAGS += -I$(RTLSDR_PREFIX)/include
LDFLAGS += -L$(RTLSDR_PREFIX)/lib ifeq ($(STATIC), yes)
LIBS_SDR += -L$(RTLSDR_PREFIX)/lib -Wl,-Bstatic -lrtlsdr -Wl,-Bdynamic -lusb-1.0
else
LIBS_SDR += -L$(RTLSDR_PREFIX)/lib -lrtlsdr -lusb-1.0
endif
else else
CFLAGS += $(shell pkg-config --cflags librtlsdr) CFLAGS += $(shell pkg-config --cflags librtlsdr)
LDFLAGS += $(shell pkg-config --libs-only-L librtlsdr) # some packaged .pc files are massively broken, try to handle it
endif RTLSDR_LFLAGS := $(shell pkg-config --libs-only-L librtlsdr)
ifeq ($(RTLSDR_LFLAGS),-L)
ifeq ($(STATIC), yes) LIBS_SDR += $(shell pkg-config --libs-only-l --libs-only-other librtlsdr)
LIBS_SDR += -Wl,-Bstatic -lrtlsdr -Wl,-Bdynamic -lusb-1.0 else
else LIBS_SDR += $(shell pkg-config --libs librtlsdr)
LIBS_SDR += -lrtlsdr -lusb-1.0 endif
endif endif
endif endif

View file

@ -6,6 +6,14 @@ customized for use within [FlightAware](http://flightaware.com)'s
It is designed to build as a Debian package. It is designed to build as a Debian package.
## Building under stretch
```bash
$ sudo apt-get install build-essential debhelper librtlsdr-dev pkg-config dh-systemd libncurses5-dev libbladerf-dev
$ dpkg-buildpackage -b
```
## Building under jessie ## Building under jessie
### Dependencies - bladeRF ### Dependencies - bladeRF
@ -44,8 +52,8 @@ You can probably just run "make" after installing the required dependencies.
Binaries are built in the source directory; you will need to arrange to Binaries are built in the source directory; you will need to arrange to
install them (and a method for starting them) yourself. install them (and a method for starting them) yourself.
"make BLADERF=no" will disable bladeRF support and remove the dependency on ``make BLADERF=no`` will disable bladeRF support and remove the dependency on
libbladeRF. libbladeRF.
"make RTLSDR=no" will disable rtl-sdr support and remove the dependency on ``make RTLSDR=no`` will disable rtl-sdr support and remove the dependency on
librtlsdr. librtlsdr.

34
debian/changelog vendored
View file

@ -1,3 +1,37 @@
dump1090-fa (3.7.1~dev) UNRELEASED; urgency=medium
* in development
-- Eric Tran <eric.tran@flightaware.com> Mon, 15 Apr 2019 11:23:00 -6000
dump1090-fa (3.7.0.1) stable; urgency=medium
* dump1090: Fix piaware lat/lon variable
-- Eric Tran <eric.tran@flightaware.com> Fri, 29 Mar 2019 7:04:00 -6000
dump1090-fa (3.7.0) stable; urgency=medium
* dump1090: Fix Rc decoding errors
* dump1090: Compute ADS-B v0 NACp/SIL
* dump1090: When generating aircraft.json, leave space for the final line;
otherwise the generated json may have trailing garbage
* dump1090: Don't update the known-address-set from DF18 messages
* Skyview: use heading data for icon orientation if track data is unavailable
* Skyview: don't spin forever if there's no history to load / receiver.json
is missing
* dump1090: Bail out if rtlsdr_read_async() returns early; it probably means we lost
the USB device. There was a workaround for this (originally implemented
in dump1090-mutability) that got lost in the refactoring needed to support
different SDRs. librtlsdr can still be flaky under disconnect conditions, so
this won't catch everything.
* dump1090: add ENABLED to /etc/default/dump1090-fa
* dump1090: track FMS and MCP selected altitudes separately
* skyview: use whichever selected altitude is available
* faup1090: updates to support PiAware 3.7.0
-- Oliver Jowett <oliver@mutability.co.uk> Fri, 22 Mar 2019 15:58:04 +0000
dump1090-fa (3.6.3) stable; urgency=medium dump1090-fa (3.6.3) stable; urgency=medium
* Fix port 30003 output (Basestation) timestamp formatting broken in 3.6.0 * Fix port 30003 output (Basestation) timestamp formatting broken in 3.6.0

View file

@ -1,11 +1,14 @@
# dump1090-fa configuration # dump1090-fa configuration
# This is read by the systemd service file as an environment file, # This is sourced by /usr/share/dump1090-fa/start-dump1090-fa as a
# and evaluated by some scripts as a POSIX shell fragment. # shellscript fragment.
# If you are using a PiAware sdcard image, this config file is regenerated # If you are using a PiAware sdcard image, this config file is regenerated
# on boot based on the contents of piaware-config.txt; any changes made to this # on boot based on the contents of piaware-config.txt; any changes made to this
# file will be lost. # file will be lost.
# dump1090-fa won't automatically start unless ENABLED=yes
ENABLED=yes
RECEIVER_OPTIONS="--device-index 0 --gain -10 --ppm 0 --net-bo-port 30005" RECEIVER_OPTIONS="--device-index 0 --gain -10 --ppm 0 --net-bo-port 30005"
DECODER_OPTIONS="--max-range 360" DECODER_OPTIONS="--max-range 360"
NET_OPTIONS="--net --net-heartbeat 60 --net-ro-size 1000 --net-ro-interval 1 --net-ri-port 0 --net-ro-port 30002 --net-sbs-port 30003 --net-bi-port 30004,30104 --net-bo-port 30005" NET_OPTIONS="--net --net-heartbeat 60 --net-ro-size 1000 --net-ro-interval 1 --net-ri-port 0 --net-ro-port 30002 --net-sbs-port 30003 --net-bi-port 30004,30104 --net-bo-port 30005"

View file

@ -1,3 +1,4 @@
public_html/* usr/share/dump1090-fa/html public_html/* usr/share/dump1090-fa/html
debian/lighttpd/* etc/lighttpd/conf-available debian/lighttpd/* etc/lighttpd/conf-available
bladerf/* /usr/share/dump1090-fa/bladerf bladerf/* usr/share/dump1090-fa/bladerf
debian/start-dump1090-fa usr/share/dump1090-fa/

View file

@ -49,6 +49,20 @@ case "$1" in
fi fi
fi fi
# on upgrade, add an ENABLED line if it's not already present
if dpkg --compare-versions "$2" lt-nl "3.7.0"
then
if [ -f /etc/default/dump1090-fa ]
then
if ! grep -q -E '^ENABLED=' /etc/default/dump1090-fa
then
echo "Setting ENABLED=yes in /etc/default/dump1090-fa.." >&2
echo "# Automatically added by upgrade from $2" >>/etc/default/dump1090-fa
echo "ENABLED=yes" >>/etc/default/dump1090-fa
fi
fi
fi
echo "Restarting lighttpd.." >&2 echo "Restarting lighttpd.." >&2
invoke-rc.d lighttpd restart || true invoke-rc.d lighttpd restart || true
;; ;;

View file

@ -7,17 +7,15 @@ Wants=network.target
After=network.target After=network.target
[Service] [Service]
EnvironmentFile=/etc/default/dump1090-fa
EnvironmentFile=-/var/cache/piaware/location.env
User=dump1090 User=dump1090
RuntimeDirectory=dump1090-fa RuntimeDirectory=dump1090-fa
RuntimeDirectoryMode=0755 RuntimeDirectoryMode=0755
ExecStart=/usr/bin/dump1090-fa \ ExecStart=/usr/share/dump1090-fa/start-dump1090-fa --write-json %t/dump1090-fa --quiet
$RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS $PIAWARE_DUMP1090_LOCATION_OPTIONS \ SyslogIdentifier=dump1090-fa
--write-json /run/dump1090-fa --quiet
Type=simple Type=simple
Restart=on-failure Restart=on-failure
RestartSec=30 RestartSec=30
RestartPreventExitStatus=64
Nice=-5 Nice=-5
[Install] [Install]

33
debian/start-dump1090-fa vendored Executable file
View file

@ -0,0 +1,33 @@
#!/bin/sh
# Helper script that reads /etc/default/dump1090-fa
# and either starts dump1090-fa with the configured
# arguments, or exits with status 64 to tell systemd
# not to auto-restart the service.
if [ -f /etc/default/dump1090-fa ]
then
. /etc/default/dump1090-fa
fi
if [ -f /var/cache/piaware/location.env ]
then
. /var/cache/piaware/location.env
fi
if [ "x$ENABLED" != "xyes" ]
then
echo "dump1090-fa not enabled in /etc/default/dump1090-fa" >&2
exit 64
fi
if [ -n "$PIAWARE_LAT" -a -n "$PIAWARE_LON" ]
then
POSITION="--lat $PIAWARE_LAT --lon $PIAWARE_LON"
fi
exec /usr/bin/dump1090-fa \
$RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS $POSITION \
"$@"
# exec failed, do not restart
exit 64

View file

@ -224,15 +224,12 @@ void *readerThreadEntryPoint(void *arg)
// Wake the main thread (if it's still waiting) // Wake the main thread (if it's still waiting)
pthread_mutex_lock(&Modes.data_mutex); pthread_mutex_lock(&Modes.data_mutex);
Modes.exit = 1; // just in case if (!Modes.exit)
Modes.exit = 2; // unexpected exit
pthread_cond_signal(&Modes.data_cond); pthread_cond_signal(&Modes.data_cond);
pthread_mutex_unlock(&Modes.data_mutex); pthread_mutex_unlock(&Modes.data_mutex);
#ifndef _WIN32
pthread_exit(NULL);
#else
return NULL; return NULL;
#endif
} }
// //
// ============================== Snip mode ================================= // ============================== Snip mode =================================
@ -760,15 +757,15 @@ int main(int argc, char **argv) {
display_total_stats(); display_total_stats();
} }
log_with_timestamp("Normal exit.");
sdrClose(); sdrClose();
#ifndef _WIN32 if (Modes.exit == 1) {
pthread_exit(0); log_with_timestamp("Normal exit.");
#else return 0;
return (0); } else {
#endif log_with_timestamp("Abnormal exit.");
return 1;
}
} }
// //
//========================================================================= //=========================================================================

View file

@ -227,6 +227,10 @@ typedef enum {
EMERGENCY_RESERVED = 7 EMERGENCY_RESERVED = 7
} emergency_t; } emergency_t;
typedef enum {
NAV_ALT_INVALID, NAV_ALT_UNKNOWN, NAV_ALT_AIRCRAFT, NAV_ALT_MCP, NAV_ALT_FMS
} nav_altitude_source_t;
#define MODES_NON_ICAO_ADDRESS (1<<24) // Set on addresses to indicate they are not ICAO addresses #define MODES_NON_ICAO_ADDRESS (1<<24) // Set on addresses to indicate they are not ICAO addresses
#define MODES_DEBUG_DEMOD (1<<0) #define MODES_DEBUG_DEMOD (1<<0)
@ -304,7 +308,7 @@ struct { // Internal state
double sample_rate; // actual sample rate in use (in hz) double sample_rate; // actual sample rate in use (in hz)
uint16_t *log10lut; // Magnitude -> log10 lookup table uint16_t *log10lut; // Magnitude -> log10 lookup table
int exit; // Exit from the main loop when true int exit; // Exit from the main loop when true (2 = unclean exit)
// Sample conversion // Sample conversion
int dc_filter; // should we apply a DC filter? int dc_filter; // should we apply a DC filter?
@ -581,7 +585,7 @@ struct modesMessage {
unsigned mcp_altitude; // MCP/FCU selected altitude unsigned mcp_altitude; // MCP/FCU selected altitude
float qnh; // altimeter setting (QFE or QNH/QNE), millibars float qnh; // altimeter setting (QFE or QNH/QNE), millibars
enum { NAV_ALT_INVALID, NAV_ALT_UNKNOWN, NAV_ALT_AIRCRAFT, NAV_ALT_MCP, NAV_ALT_FMS } altitude_source; nav_altitude_source_t altitude_source;
nav_modes_t modes; nav_modes_t modes;
} nav; } nav;

View file

@ -204,7 +204,6 @@ int main(int argc, char **argv) {
// Set up output connection on stdout // Set up output connection on stdout
fatsv_output = makeFatsvOutputService(); fatsv_output = makeFatsvOutputService();
createGenericClient(fatsv_output, STDOUT_FILENO); createGenericClient(fatsv_output, STDOUT_FILENO);
writeFATSVHeader();
// Run it until we've lost either connection // Run it until we've lost either connection
while (!Modes.exit && beast_input->connections && fatsv_output->connections) { while (!Modes.exit && beast_input->connections && fatsv_output->connections) {

View file

@ -568,9 +568,9 @@ int decodeModesMessage(struct modesMessage *mm, unsigned char *msg)
mm->CC = getbit(msg, 7); mm->CC = getbit(msg, 7);
} }
// CF (Control field) // CF (Control field, see Figure 2-2 ADS-B Message BaselineFormat Structure)
if (mm->msgtype == 18) { if (mm->msgtype == 18) {
mm->CF = getbits(msg, 5, 8); mm->CF = getbits(msg, 6, 8);
} }
// DR (Downlink Request) // DR (Downlink Request)
@ -1053,7 +1053,7 @@ static void decodeESTargetStatus(struct modesMessage *mm, int check_imf)
// nothing // nothing
break; break;
} }
// 10: target altitude type (ignored) // 10: target altitude type (MSL or Baro, ignored)
// 11: backward compatibility bit, always 0 // 11: backward compatibility bit, always 0
// 12-13: target alt capabilities (ignored) // 12-13: target alt capabilities (ignored)
// 14-15: vertical mode // 14-15: vertical mode
@ -1081,7 +1081,7 @@ static void decodeESTargetStatus(struct modesMessage *mm, int check_imf)
break; break;
} }
// 16-25: altitude // 16-25: target altitude
int alt = -1000 + 100 * getbits(me, 16, 25); int alt = -1000 + 100 * getbits(me, 16, 25);
switch (mm->nav.altitude_source) { switch (mm->nav.altitude_source) {
case NAV_ALT_MCP: case NAV_ALT_MCP:
@ -1109,7 +1109,7 @@ static void decodeESTargetStatus(struct modesMessage *mm, int check_imf)
mm->nav.heading_type = HEADING_MAGNETIC_OR_TRUE; mm->nav.heading_type = HEADING_MAGNETIC_OR_TRUE;
} }
} }
// 38-39: horiontal mode // 38-39: horizontal mode
switch (getbits(me, 38, 39)) { switch (getbits(me, 38, 39)) {
case 1: // acquiring case 1: // acquiring
case 2: // maintaining case 2: // maintaining

View file

@ -1155,8 +1155,10 @@ static char *append_flags(char *p, char *end, struct aircraft *a, datasource_t s
p = safe_snprintf(p, end, "\"emergency\","); p = safe_snprintf(p, end, "\"emergency\",");
if (a->nav_qnh_valid.source == source) if (a->nav_qnh_valid.source == source)
p = safe_snprintf(p, end, "\"nav_qnh\","); p = safe_snprintf(p, end, "\"nav_qnh\",");
if (a->nav_altitude_valid.source == source) if (a->nav_altitude_mcp_valid.source == source)
p = safe_snprintf(p, end, "\"nav_altitude\","); p = safe_snprintf(p, end, "\"nav_altitude_mcp\",");
if (a->nav_altitude_fms_valid.source == source)
p = safe_snprintf(p, end, "\"nav_altitude_fms\",");
if (a->nav_heading_valid.source == source) if (a->nav_heading_valid.source == source)
p = safe_snprintf(p, end, "\"nav_heading\","); p = safe_snprintf(p, end, "\"nav_heading\",");
if (a->nav_modes_valid.source == source) if (a->nav_modes_valid.source == source)
@ -1267,6 +1269,18 @@ static const char *sil_type_enum_string(sil_type_t type)
} }
} }
static const char *nav_altitude_source_enum_string(nav_altitude_source_t src)
{
switch (src) {
case NAV_ALT_INVALID: return "invalid";
case NAV_ALT_UNKNOWN: return "unknown";
case NAV_ALT_AIRCRAFT: return "aircraft";
case NAV_ALT_MCP: return "mcp";
case NAV_ALT_FMS: return "fms";
default: return "invalid";
}
}
char *generateAircraftJson(const char *url_path, int *len) { char *generateAircraftJson(const char *url_path, int *len) {
uint64_t now = mstime(); uint64_t now = mstime();
struct aircraft *a; struct aircraft *a;
@ -1341,8 +1355,10 @@ char *generateAircraftJson(const char *url_path, int *len) {
p = safe_snprintf(p, end, ",\"category\":\"%02X\"", a->category); p = safe_snprintf(p, end, ",\"category\":\"%02X\"", a->category);
if (trackDataValid(&a->nav_qnh_valid)) if (trackDataValid(&a->nav_qnh_valid))
p = safe_snprintf(p, end, ",\"nav_qnh\":%.1f", a->nav_qnh); p = safe_snprintf(p, end, ",\"nav_qnh\":%.1f", a->nav_qnh);
if (trackDataValid(&a->nav_altitude_valid)) if (trackDataValid(&a->nav_altitude_mcp_valid))
p = safe_snprintf(p, end, ",\"nav_altitude\":%d", a->nav_altitude); p = safe_snprintf(p, end, ",\"nav_altitude_mcp\":%d", a->nav_altitude_mcp);
if (trackDataValid(&a->nav_altitude_fms_valid))
p = safe_snprintf(p, end, ",\"nav_altitude_fms\":%d", a->nav_altitude_fms);
if (trackDataValid(&a->nav_heading_valid)) if (trackDataValid(&a->nav_heading_valid))
p = safe_snprintf(p, end, ",\"nav_heading\":%.1f", a->nav_heading); p = safe_snprintf(p, end, ",\"nav_heading\":%.1f", a->nav_heading);
if (trackDataValid(&a->nav_modes_valid)) { if (trackDataValid(&a->nav_modes_valid)) {
@ -1534,7 +1550,7 @@ char *generateStatsJson(const char *url_path, int *len) {
p = appendStatsJson(p, end, &add, "total"); p = appendStatsJson(p, end, &add, "total");
p = safe_snprintf(p, end, "\n}\n"); p = safe_snprintf(p, end, "\n}\n");
assert(p <= end); assert(p < end);
*len = p-buf; *len = p-buf;
return buf; return buf;
@ -1862,27 +1878,8 @@ __attribute__ ((format (printf,4,5))) static char *appendFATSV(char *p, char *en
return p; return p;
} }
#define TSV_MAX_PACKET_SIZE 600 #define TSV_MAX_PACKET_SIZE 800
#define TSV_VERSION 3 #define TSV_VERSION "4E"
void writeFATSVHeader()
{
char *p = prepareWrite(&Modes.fatsv_out, TSV_MAX_PACKET_SIZE);
if (!p)
return;
char *end = p + TSV_MAX_PACKET_SIZE;
p = appendFATSV(p, end, "clock", "%" PRIu64, mstime() / 1000);
p = appendFATSV(p, end, "tsv_version", "%u", TSV_VERSION);
--p; // remove last tab
p = safe_snprintf(p, end, "\n");
if (p <= end)
completeWrite(&Modes.fatsv_out, p);
else
fprintf(stderr, "fatsv: output too large (max %d, overran by %d)\n", TSV_MAX_PACKET_SIZE, (int) (p - end));
}
static void writeFATSVPositionUpdate(float lat, float lon, float alt) static void writeFATSVPositionUpdate(float lat, float lon, float alt)
{ {
@ -1901,6 +1898,7 @@ static void writeFATSVPositionUpdate(float lat, float lon, float alt)
char *end = p + TSV_MAX_PACKET_SIZE; char *end = p + TSV_MAX_PACKET_SIZE;
p = appendFATSV(p, end, "_v", "%s", TSV_VERSION);
p = appendFATSV(p, end, "clock", "%" PRIu64, messageNow() / 1000); p = appendFATSV(p, end, "clock", "%" PRIu64, messageNow() / 1000);
p = appendFATSV(p, end, "type", "%s", "location_update"); p = appendFATSV(p, end, "type", "%s", "location_update");
p = appendFATSV(p, end, "lat", "%.5f", lat); p = appendFATSV(p, end, "lat", "%.5f", lat);
@ -1910,7 +1908,7 @@ static void writeFATSVPositionUpdate(float lat, float lon, float alt)
--p; // remove last tab --p; // remove last tab
p = safe_snprintf(p, end, "\n"); p = safe_snprintf(p, end, "\n");
if (p <= end) if (p < end)
completeWrite(&Modes.fatsv_out, p); completeWrite(&Modes.fatsv_out, p);
else else
fprintf(stderr, "fatsv: output too large (max %d, overran by %d)\n", TSV_MAX_PACKET_SIZE, (int) (p - end)); fprintf(stderr, "fatsv: output too large (max %d, overran by %d)\n", TSV_MAX_PACKET_SIZE, (int) (p - end));
@ -1924,6 +1922,7 @@ static void writeFATSVEventMessage(struct modesMessage *mm, const char *datafiel
char *end = p + TSV_MAX_PACKET_SIZE; char *end = p + TSV_MAX_PACKET_SIZE;
p = appendFATSV(p, end, "_v", "%s", TSV_VERSION);
p = appendFATSV(p, end, "clock", "%" PRIu64, messageNow() / 1000); p = appendFATSV(p, end, "clock", "%" PRIu64, messageNow() / 1000);
p = appendFATSV(p, end, (mm->addr & MODES_NON_ICAO_ADDRESS) ? "otherid" : "hexid", "%06X", mm->addr & 0xFFFFFF); p = appendFATSV(p, end, (mm->addr & MODES_NON_ICAO_ADDRESS) ? "otherid" : "hexid", "%06X", mm->addr & 0xFFFFFF);
if (mm->addrtype != ADDR_ADSB_ICAO) { if (mm->addrtype != ADDR_ADSB_ICAO) {
@ -1936,7 +1935,7 @@ static void writeFATSVEventMessage(struct modesMessage *mm, const char *datafiel
} }
p = safe_snprintf(p, end, "\n"); p = safe_snprintf(p, end, "\n");
if (p <= end) if (p < end)
completeWrite(&Modes.fatsv_out, p); completeWrite(&Modes.fatsv_out, p);
else else
fprintf(stderr, "fatsv: output too large (max %d, overran by %d)\n", TSV_MAX_PACKET_SIZE, (int) (p - end)); fprintf(stderr, "fatsv: output too large (max %d, overran by %d)\n", TSV_MAX_PACKET_SIZE, (int) (p - end));
@ -2136,7 +2135,9 @@ static void writeFATSV()
(trackDataValid(&a->mach_valid) && fabs(a->mach - a->fatsv_emitted_mach) >= 0.02); (trackDataValid(&a->mach_valid) && fabs(a->mach - a->fatsv_emitted_mach) >= 0.02);
int immediate = int immediate =
(trackDataValid(&a->nav_altitude_valid) && unsigned_difference(a->nav_altitude, a->fatsv_emitted_nav_altitude) > 50) || (trackDataValid(&a->nav_altitude_mcp_valid) && unsigned_difference(a->nav_altitude_mcp, a->fatsv_emitted_nav_altitude_mcp) > 50) ||
(trackDataValid(&a->nav_altitude_fms_valid) && unsigned_difference(a->nav_altitude_fms, a->fatsv_emitted_nav_altitude_fms) > 50) ||
(trackDataValid(&a->nav_altitude_src_valid) && a->nav_altitude_src != a->fatsv_emitted_nav_altitude_src) ||
(trackDataValid(&a->nav_heading_valid) && heading_difference(a->nav_heading, a->fatsv_emitted_nav_heading) > 2) || (trackDataValid(&a->nav_heading_valid) && heading_difference(a->nav_heading, a->fatsv_emitted_nav_heading) > 2) ||
(trackDataValid(&a->nav_modes_valid) && a->nav_modes != a->fatsv_emitted_nav_modes) || (trackDataValid(&a->nav_modes_valid) && a->nav_modes != a->fatsv_emitted_nav_modes) ||
(trackDataValid(&a->nav_qnh_valid) && fabs(a->nav_qnh - a->fatsv_emitted_nav_qnh) > 0.8) || // 0.8 is the ES message resolution (trackDataValid(&a->nav_qnh_valid) && fabs(a->nav_qnh - a->fatsv_emitted_nav_qnh) > 0.8) || // 0.8 is the ES message resolution
@ -2174,6 +2175,7 @@ static void writeFATSV()
return; return;
char *end = p + TSV_MAX_PACKET_SIZE; char *end = p + TSV_MAX_PACKET_SIZE;
p = appendFATSV(p, end, "_v", "%s", TSV_VERSION);
p = appendFATSV(p, end, "clock", "%" PRIu64, messageNow() / 1000); p = appendFATSV(p, end, "clock", "%" PRIu64, messageNow() / 1000);
p = appendFATSV(p, end, (a->addr & MODES_NON_ICAO_ADDRESS) ? "otherid" : "hexid", "%06X", a->addr & 0xFFFFFF); p = appendFATSV(p, end, (a->addr & MODES_NON_ICAO_ADDRESS) ? "otherid" : "hexid", "%06X", a->addr & 0xFFFFFF);
@ -2236,8 +2238,10 @@ static void writeFATSV()
p = appendFATSVMeta(p, end, "track_rate", a, &a->track_rate_valid, "%.2f", a->track_rate); p = appendFATSVMeta(p, end, "track_rate", a, &a->track_rate_valid, "%.2f", a->track_rate);
p = appendFATSVMeta(p, end, "roll", a, &a->roll_valid, "%.1f", a->roll); p = appendFATSVMeta(p, end, "roll", a, &a->roll_valid, "%.1f", a->roll);
p = appendFATSVMeta(p, end, "heading_magnetic", a, &a->mag_heading_valid, "%.1f", a->mag_heading); p = appendFATSVMeta(p, end, "heading_magnetic", a, &a->mag_heading_valid, "%.1f", a->mag_heading);
p = appendFATSVMeta(p, end, "heading_true", a, &a->true_heading_valid, "%.1f", a->true_heading); p = appendFATSVMeta(p, end, "heading_true", a, &a->true_heading_valid, "%.1f", a->true_heading);
p = appendFATSVMeta(p, end, "nav_alt", a, &a->nav_altitude_valid, "%u", a->nav_altitude); p = appendFATSVMeta(p, end, "nav_alt_mcp", a, &a->nav_altitude_mcp_valid, "%u", a->nav_altitude_mcp);
p = appendFATSVMeta(p, end, "nav_alt_fms", a, &a->nav_altitude_fms_valid, "%u", a->nav_altitude_fms);
p = appendFATSVMeta(p, end, "nav_alt_src", a, &a->nav_altitude_src_valid, "%s", nav_altitude_source_enum_string(a->nav_altitude_src));
p = appendFATSVMeta(p, end, "nav_heading", a, &a->nav_heading_valid, "%.1f", a->nav_heading); p = appendFATSVMeta(p, end, "nav_heading", a, &a->nav_heading_valid, "%.1f", a->nav_heading);
p = appendFATSVMeta(p, end, "nav_modes", a, &a->nav_modes_valid, "{%s}", nav_modes_flags_string(a->nav_modes)); p = appendFATSVMeta(p, end, "nav_modes", a, &a->nav_modes_valid, "{%s}", nav_modes_flags_string(a->nav_modes));
p = appendFATSVMeta(p, end, "nav_qnh", a, &a->nav_qnh_valid, "%.1f", a->nav_qnh); p = appendFATSVMeta(p, end, "nav_qnh", a, &a->nav_qnh_valid, "%.1f", a->nav_qnh);
@ -2252,7 +2256,7 @@ static void writeFATSV()
--p; // remove last tab --p; // remove last tab
p = safe_snprintf(p, end, "\n"); p = safe_snprintf(p, end, "\n");
if (p <= end) if (p < end)
completeWrite(&Modes.fatsv_out, p); completeWrite(&Modes.fatsv_out, p);
else else
fprintf(stderr, "fatsv: output too large (max %d, overran by %d)\n", TSV_MAX_PACKET_SIZE, (int) (p - end)); fprintf(stderr, "fatsv: output too large (max %d, overran by %d)\n", TSV_MAX_PACKET_SIZE, (int) (p - end));
@ -2271,7 +2275,9 @@ static void writeFATSV()
a->fatsv_emitted_mag_heading = a->mag_heading; a->fatsv_emitted_mag_heading = a->mag_heading;
a->fatsv_emitted_true_heading = a->true_heading; a->fatsv_emitted_true_heading = a->true_heading;
a->fatsv_emitted_airground = a->airground; a->fatsv_emitted_airground = a->airground;
a->fatsv_emitted_nav_altitude = a->nav_altitude; a->fatsv_emitted_nav_altitude_mcp = a->nav_altitude_mcp;
a->fatsv_emitted_nav_altitude_fms = a->nav_altitude_fms;
a->fatsv_emitted_nav_altitude_src = a->nav_altitude_src;
a->fatsv_emitted_nav_heading = a->nav_heading; a->fatsv_emitted_nav_heading = a->nav_heading;
a->fatsv_emitted_nav_modes = a->nav_modes; a->fatsv_emitted_nav_modes = a->nav_modes;
a->fatsv_emitted_nav_qnh = a->nav_qnh; a->fatsv_emitted_nav_qnh = a->nav_qnh;

View file

@ -87,8 +87,6 @@ void modesInitNet(void);
void modesQueueOutput(struct modesMessage *mm, struct aircraft *a); void modesQueueOutput(struct modesMessage *mm, struct aircraft *a);
void modesNetPeriodicWork(void); void modesNetPeriodicWork(void);
void writeFATSVHeader();
// TODO: move these somewhere else // TODO: move these somewhere else
char *generateAircraftJson(const char *url_path, int *len); char *generateAircraftJson(const char *url_path, int *len);
char *generateStatsJson(const char *url_path, int *len); char *generateStatsJson(const char *url_path, int *len);

View file

@ -11,8 +11,8 @@ then
exit 1 exit 1
fi fi
export DEBFULLNAME=${DEBFULLNAME:-FlightAware build automation} export DEBFULLNAME="${DEBFULLNAME:-FlightAware build automation}"
export DEBEMAIL=${DEBEMAIL:-adsb-devs@flightaware.com} export DEBEMAIL="${DEBEMAIL:-adsb-devs@flightaware.com}"
TOP=`dirname $0` TOP=`dirname $0`
DIST=$1 DIST=$1

View file

@ -384,7 +384,16 @@ PlaneObject.prototype.updateIcon = function() {
var outline = (this.position_from_mlat ? OutlineMlatColor : OutlineADSBColor); var outline = (this.position_from_mlat ? OutlineMlatColor : OutlineADSBColor);
var add_stroke = (this.selected && !SelectedAllPlanes) ? ' stroke="black" stroke-width="1px"' : ''; var add_stroke = (this.selected && !SelectedAllPlanes) ? ' stroke="black" stroke-width="1px"' : '';
var baseMarker = getBaseMarker(this.category, this.icaotype, this.typeDescription, this.wtc); var baseMarker = getBaseMarker(this.category, this.icaotype, this.typeDescription, this.wtc);
var rotation = (this.track === null ? 0 : this.track); var rotation = this.track;
if (rotation === null) {
rotation = this.true_heading;
}
if (rotation === null) {
rotation = this.mag_heading;
}
if (rotation === null) {
rotation = 0;
}
//var transparentBorderWidth = (32 / baseMarker.scale / scaleFactor).toFixed(1); //var transparentBorderWidth = (32 / baseMarker.scale / scaleFactor).toFixed(1);
var svgKey = col + '!' + outline + '!' + baseMarker.svg + '!' + add_stroke + "!" + scaleFactor; var svgKey = col + '!' + outline + '!' + baseMarker.svg + '!' + add_stroke + "!" + scaleFactor;
@ -445,7 +454,7 @@ PlaneObject.prototype.updateData = function(receiver_timestamp, data) {
var fields = ["alt_baro", "alt_geom", "gs", "ias", "tas", "track", var fields = ["alt_baro", "alt_geom", "gs", "ias", "tas", "track",
"track_rate", "mag_heading", "true_heading", "mach", "track_rate", "mag_heading", "true_heading", "mach",
"roll", "nav_altitude", "nav_heading", "nav_modes", "roll", "nav_heading", "nav_modes",
"nac_p", "nac_v", "nic_baro", "sil_type", "sil", "nac_p", "nac_v", "nic_baro", "sil_type", "sil",
"nav_qnh", "baro_rate", "geom_rate", "rc", "nav_qnh", "baro_rate", "geom_rate", "rc",
"squawk", "category", "version"]; "squawk", "category", "version"];
@ -498,6 +507,15 @@ PlaneObject.prototype.updateData = function(receiver_timestamp, data) {
this.altitude = null; this.altitude = null;
} }
// Pick a selected altitude
if ('nav_altitude_fms' in data) {
this.nav_altitude = data.nav_altitude_fms;
} else if ('nav_altitude_mcp' in data) {
this.nav_altitude = data.nav_altitude_mcp;
} else {
this.nav_altitude = null;
}
// Pick vertical rate from either baro or geom rate // Pick vertical rate from either baro or geom rate
// geometric rate is generally more reliable (smoothed etc) // geometric rate is generally more reliable (smoothed etc)
if ('geom_rate' in data) { if ('geom_rate' in data) {

View file

@ -389,6 +389,9 @@ function start_load_history() {
for (var i = 0; i < PositionHistorySize; i++) { for (var i = 0; i < PositionHistorySize; i++) {
load_history_item(i); load_history_item(i);
} }
} else {
// Nothing to load
end_load_history();
} }
} }

View file

@ -23,6 +23,11 @@
#include <libbladeRF.h> #include <libbladeRF.h>
#include <inttypes.h> #include <inttypes.h>
// Polyfill for the older bladerf API
#if defined(LIBBLADERF_API_VERSION) && (LIBBLADERF_API_VERSION < 0x02000000)
typedef unsigned int bladerf_frequency;
#endif
static struct { static struct {
const char *device_str; const char *device_str;
const char *fpga_path; const char *fpga_path;
@ -102,7 +107,7 @@ static void show_config()
int status; int status;
unsigned rate; unsigned rate;
unsigned freq; bladerf_frequency freq;
bladerf_lpf_mode lpf_mode; bladerf_lpf_mode lpf_mode;
unsigned lpf_bw; unsigned lpf_bw;
bladerf_lna_gain lna_gain; bladerf_lna_gain lna_gain;

View file

@ -362,10 +362,11 @@ void rtlsdrRun()
start_cpu_timing(&rtlsdr_thread_cpu); start_cpu_timing(&rtlsdr_thread_cpu);
while (!Modes.exit) { rtlsdr_read_async(RTLSDR.dev, rtlsdrCallback, NULL,
rtlsdr_read_async(RTLSDR.dev, rtlsdrCallback, NULL, /* MODES_RTL_BUFFERS */ 4,
/* MODES_RTL_BUFFERS */ 4, MODES_RTL_BUF_SIZE);
MODES_RTL_BUF_SIZE); if (!Modes.exit) {
fprintf(stderr, "rtlsdr: rtlsdr_read_async returned unexpectedly, probably lost the USB device, bailing out\n");
} }
} }

148
track.c
View file

@ -116,7 +116,9 @@ struct aircraft *trackCreateAircraft(struct modesMessage *mm) {
F(squawk, 15, 70); // ADS-B or Mode S F(squawk, 15, 70); // ADS-B or Mode S
F(airground, 15, 70); // ADS-B or Mode S F(airground, 15, 70); // ADS-B or Mode S
F(nav_qnh, 60, 70); // Comm-B only F(nav_qnh, 60, 70); // Comm-B only
F(nav_altitude, 60, 70); // ADS-B or Comm-B F(nav_altitude_mcp, 60, 70); // ADS-B or Comm-B
F(nav_altitude_fms, 60, 70); // ADS-B or Comm-B
F(nav_altitude_src, 60, 70); // ADS-B or Comm-B
F(nav_heading, 60, 70); // ADS-B or Comm-B F(nav_heading, 60, 70); // ADS-B or Comm-B
F(nav_modes, 60, 70); // ADS-B or Comm-B F(nav_modes, 60, 70); // ADS-B or Comm-B
F(cpr_odd, 60, 70); // ADS-B only F(cpr_odd, 60, 70); // ADS-B only
@ -302,6 +304,18 @@ static int speed_check(struct aircraft *a, double lat, double lon, int surface)
return inrange; return inrange;
} }
// return 1 if left_rc is worse (less accurate) than right_rc
static int rcIsWorse(int left_rc, int right_rc)
{
if (left_rc == 0 && right_rc == 0) // both unknown
return 0;
if (left_rc == 0)
return 1; // left unknown < right known
if (right_rc == 0)
return 0; // left known > right unknown
return (left_rc > right_rc);
}
static int doGlobalCPR(struct aircraft *a, struct modesMessage *mm, double *lat, double *lon, unsigned *nic, unsigned *rc) static int doGlobalCPR(struct aircraft *a, struct modesMessage *mm, double *lat, double *lon, unsigned *nic, unsigned *rc)
{ {
int result; int result;
@ -309,9 +323,9 @@ static int doGlobalCPR(struct aircraft *a, struct modesMessage *mm, double *lat,
int surface = (mm->cpr_type == CPR_SURFACE); int surface = (mm->cpr_type == CPR_SURFACE);
// derive NIC, Rc from the worse of the two position // derive NIC, Rc from the worse of the two position
// smaller NIC is worse; larger Rc is worse // smaller NIC is worse
*nic = (a->cpr_even_nic < a->cpr_odd_nic ? a->cpr_even_nic : a->cpr_odd_nic); *nic = (a->cpr_even_nic < a->cpr_odd_nic ? a->cpr_even_nic : a->cpr_odd_nic);
*rc = (a->cpr_even_rc > a->cpr_odd_rc ? a->cpr_even_rc : a->cpr_odd_rc); *rc = (rcIsWorse(a->cpr_even_rc, a->cpr_odd_rc) ? a->cpr_even_rc : a->cpr_odd_rc);
if (surface) { if (surface) {
// surface global CPR // surface global CPR
@ -372,7 +386,7 @@ static int doGlobalCPR(struct aircraft *a, struct modesMessage *mm, double *lat,
return result; return result;
// check speed limit // check speed limit
if (trackDataValid(&a->position_valid) && a->pos_nic >= *nic && a->pos_rc <= *rc && !speed_check(a, *lat, *lon, surface)) { if (trackDataValid(&a->position_valid) && a->pos_nic >= *nic && !rcIsWorse(a->pos_rc, *rc) && !speed_check(a, *lat, *lon, surface)) {
Modes.stats_current.cpr_global_speed_checks++; Modes.stats_current.cpr_global_speed_checks++;
return -2; return -2;
} }
@ -404,7 +418,7 @@ static int doLocalCPR(struct aircraft *a, struct modesMessage *mm, double *lat,
if (a->pos_nic < *nic) if (a->pos_nic < *nic)
*nic = a->pos_nic; *nic = a->pos_nic;
if (a->pos_rc < *rc) if (rcIsWorse(a->pos_rc, *rc))
*rc = a->pos_rc; *rc = a->pos_rc;
range_limit = 50e3; range_limit = 50e3;
@ -454,7 +468,7 @@ static int doLocalCPR(struct aircraft *a, struct modesMessage *mm, double *lat,
} }
// check speed limit // check speed limit
if (trackDataValid(&a->position_valid) && a->pos_nic >= *nic && a->pos_rc <= *rc && !speed_check(a, *lat, *lon, surface)) { if (trackDataValid(&a->position_valid) && a->pos_nic >= *nic && !rcIsWorse(a->pos_rc, *rc) && !speed_check(a, *lat, *lon, surface)) {
#ifdef DEBUG_CPR_CHECKS #ifdef DEBUG_CPR_CHECKS
fprintf(stderr, "Speed check for %06X with local decoding failed\n", a->addr); fprintf(stderr, "Speed check for %06X with local decoding failed\n", a->addr);
#endif #endif
@ -661,6 +675,8 @@ static unsigned compute_nic(unsigned metype, unsigned version, unsigned nic_a, u
static unsigned compute_rc(unsigned metype, unsigned version, unsigned nic_a, unsigned nic_b, unsigned nic_c) static unsigned compute_rc(unsigned metype, unsigned version, unsigned nic_a, unsigned nic_b, unsigned nic_c)
{ {
// ED-102 Table 2-14, Table N-4, Table N-11
switch (metype) { switch (metype) {
case 5: // surface case 5: // surface
case 9: // airborne case 9: // airborne
@ -696,7 +712,7 @@ static unsigned compute_rc(unsigned metype, unsigned version, unsigned nic_a, un
} else if (nic_a && !nic_c) { } else if (nic_a && !nic_c) {
return 556; // 555.6m, 0.3NM return 556; // 555.6m, 0.3NM
} else if (!nic_a && nic_c) { } else if (!nic_a && nic_c) {
return 926; // 926m, 0.5NM return 1111; // 1111m, 0.6NM
} else { } else {
return RC_UNKNOWN; return RC_UNKNOWN;
} }
@ -709,16 +725,16 @@ static unsigned compute_rc(unsigned metype, unsigned version, unsigned nic_a, un
if (nic_a && nic_b) { if (nic_a && nic_b) {
return 75; return 75;
} else { } else {
return 186; // 370.4m, 0.2NM return 186; // 185.2m, 0.1NM
} }
} else if (version == 1) { } else if (version == 1) {
if (nic_a) { if (nic_a) {
return 75; return 75;
} else { } else {
return 186; // 370.4m, 0.2NM return 186; // 185.2m, 0.1NM
} }
} else { } else {
return 186; // 370.4m, 0.2NM return 186; // 185.2m, 0.1NM
} }
case 12: // airborne case 12: // airborne
@ -776,6 +792,81 @@ static unsigned compute_rc(unsigned metype, unsigned version, unsigned nic_a, un
} }
} }
// Map ADS-B v0 position message type to NACp value
// returned computed NACp, or -1 if not a suitable message type
static int compute_v0_nacp(struct modesMessage *mm)
{
if (mm->msgtype != 17 && mm->msgtype != 18) {
return -1;
}
// ED-102A Table N-7
switch (mm->metype) {
case 0: return 0;
case 5: return 11;
case 6: return 10;
case 7: return 8;
case 8: return 0;
case 9: return 11;
case 10: return 10;
case 11: return 8;
case 12: return 7;
case 13: return 6;
case 14: return 5;
case 15: return 4;
case 16: return 1;
case 17: return 1;
case 18: return 0;
case 20: return 11;
case 21: return 10;
case 22: return 0;
default: return -1;
}
}
// Map ADS-B v0 position message type to SIL value
// returned computed SIL, or -1 if not a suitable message type
static int compute_v0_sil(struct modesMessage *mm)
{
if (mm->msgtype != 17 && mm->msgtype != 18) {
return -1;
}
// ED-102A Table N-8
switch (mm->metype) {
case 0:
return 0;
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
return 2;
case 18:
return 0;
case 20:
case 21:
return 2;
case 22:
return 0;
default:
return -1;
}
}
static void compute_nic_rc_from_message(struct modesMessage *mm, struct aircraft *a, unsigned *nic, unsigned *rc) static void compute_nic_rc_from_message(struct modesMessage *mm, struct aircraft *a, unsigned *nic, unsigned *rc)
{ {
int nic_a = (trackDataValid(&a->nic_a_valid) && a->nic_a); int nic_a = (trackDataValid(&a->nic_a_valid) && a->nic_a);
@ -861,6 +952,23 @@ struct aircraft *trackUpdateFromMessage(struct modesMessage *mm)
} }
} }
// fill in ADS-B v0 NACp, SIL from position message type
if (a->adsb_version == 0 && !mm->accuracy.nac_p_valid) {
int computed_nacp = compute_v0_nacp(mm);
if (computed_nacp != -1) {
mm->accuracy.nac_p_valid = 1;
mm->accuracy.nac_p = computed_nacp;
}
}
if (a->adsb_version == 0 && mm->accuracy.sil_type == SIL_INVALID) {
int computed_sil = compute_v0_sil(mm);
if (computed_sil != -1) {
mm->accuracy.sil_type = SIL_UNKNOWN;
mm->accuracy.sil = computed_sil;
}
}
if (mm->altitude_baro_valid && accept_data(&a->altitude_baro_valid, mm->source)) { if (mm->altitude_baro_valid && accept_data(&a->altitude_baro_valid, mm->source)) {
int alt = altitude_to_feet(mm->altitude_baro, mm->altitude_baro_unit); int alt = altitude_to_feet(mm->altitude_baro, mm->altitude_baro_unit);
if (a->modeC_hit) { if (a->modeC_hit) {
@ -985,12 +1093,16 @@ struct aircraft *trackUpdateFromMessage(struct modesMessage *mm)
memcpy(a->callsign, mm->callsign, sizeof(a->callsign)); memcpy(a->callsign, mm->callsign, sizeof(a->callsign));
} }
// prefer MCP over FMS if (mm->nav.mcp_altitude_valid && accept_data(&a->nav_altitude_mcp_valid, mm->source)) {
// unless the source says otherwise a->nav_altitude_mcp = mm->nav.mcp_altitude;
if (mm->nav.mcp_altitude_valid && mm->nav.altitude_source != NAV_ALT_FMS && accept_data(&a->nav_altitude_valid, mm->source)) { }
a->nav_altitude = mm->nav.mcp_altitude;
} else if (mm->nav.fms_altitude_valid && accept_data(&a->nav_altitude_valid, mm->source)) { if (mm->nav.fms_altitude_valid && accept_data(&a->nav_altitude_fms_valid, mm->source)) {
a->nav_altitude = mm->nav.fms_altitude; a->nav_altitude_fms = mm->nav.fms_altitude;
}
if (mm->nav.altitude_source != NAV_ALT_INVALID && accept_data(&a->nav_altitude_src_valid, mm->source)) {
a->nav_altitude_src = mm->nav.altitude_source;
} }
if (mm->nav.heading_valid && accept_data(&a->nav_heading_valid, mm->source)) { if (mm->nav.heading_valid && accept_data(&a->nav_heading_valid, mm->source)) {
@ -1205,7 +1317,9 @@ static void trackRemoveStaleAircraft(uint64_t now)
EXPIRE(squawk); EXPIRE(squawk);
EXPIRE(airground); EXPIRE(airground);
EXPIRE(nav_qnh); EXPIRE(nav_qnh);
EXPIRE(nav_altitude); EXPIRE(nav_altitude_mcp);
EXPIRE(nav_altitude_fms);
EXPIRE(nav_altitude_src);
EXPIRE(nav_heading); EXPIRE(nav_heading);
EXPIRE(nav_modes); EXPIRE(nav_modes);
EXPIRE(cpr_odd); EXPIRE(cpr_odd);

14
track.h
View file

@ -151,8 +151,14 @@ struct aircraft {
data_validity nav_qnh_valid; data_validity nav_qnh_valid;
float nav_qnh; // Altimeter setting (QNH/QFE), millibars float nav_qnh; // Altimeter setting (QNH/QFE), millibars
data_validity nav_altitude_valid; data_validity nav_altitude_mcp_valid;
unsigned nav_altitude; // FMS or FCU selected altitude unsigned nav_altitude_mcp; // FCU/MCP selected altitude
data_validity nav_altitude_fms_valid;
unsigned nav_altitude_fms; // FMS selected altitude
data_validity nav_altitude_src_valid;
nav_altitude_source_t nav_altitude_src; // source of altitude used by automation
data_validity nav_heading_valid; data_validity nav_heading_valid;
float nav_heading; // target heading, degrees (0-359) float nav_heading; // target heading, degrees (0-359)
@ -220,7 +226,9 @@ struct aircraft {
unsigned fatsv_emitted_tas; // -"- TAS unsigned fatsv_emitted_tas; // -"- TAS
float fatsv_emitted_mach; // -"- Mach number float fatsv_emitted_mach; // -"- Mach number
airground_t fatsv_emitted_airground; // -"- air/ground state airground_t fatsv_emitted_airground; // -"- air/ground state
unsigned fatsv_emitted_nav_altitude; // -"- target altitude unsigned fatsv_emitted_nav_altitude_mcp; // -"- MCP altitude
unsigned fatsv_emitted_nav_altitude_fms; // -"- FMS altitude
unsigned fatsv_emitted_nav_altitude_src; // -"- automation altitude source
float fatsv_emitted_nav_heading; // -"- target heading float fatsv_emitted_nav_heading; // -"- target heading
nav_modes_t fatsv_emitted_nav_modes; // -"- enabled navigation modes nav_modes_t fatsv_emitted_nav_modes; // -"- enabled navigation modes
float fatsv_emitted_nav_qnh; // -"- altimeter setting float fatsv_emitted_nav_qnh; // -"- altimeter setting