Add direct support for FATSV-format output.
This is adapted from the FlightAware fork, with some cleanup and modifications needed to work with the net-cleanup changes. Inclusion of "verbatim" TSV data read from an AVR-format input connection is not supported.
This commit is contained in:
parent
66849e1096
commit
2dcc8e3524
2
debian/changelog
vendored
2
debian/changelog
vendored
|
@ -1,6 +1,8 @@
|
|||
dump1090-mutability (1.08.2302.14+1mu-2) UNRELEASED; urgency=medium
|
||||
|
||||
* Fix a memory leak from use of realpath() in HTTP request processing.
|
||||
* Add direct support for FATSV-format output, adapted from the FlightAware
|
||||
fork.
|
||||
|
||||
-- Oliver Jowett <oliver@mutability.co.uk> Sun, 07 Dec 2014 14:14:25 +0000
|
||||
|
||||
|
|
3
debian/dump1090-mutability.default
vendored
3
debian/dump1090-mutability.default
vendored
|
@ -81,6 +81,9 @@ DUMP1090_USER="dump1090"
|
|||
# Port to listen on for Beast-format output connections. 0 disables.
|
||||
#BEAST_OUTPUT_PORT=30005
|
||||
|
||||
# Port to listen on for FATSV-format output connections. 0 disables.
|
||||
#FATSV_OUTPUT_PORT=10001
|
||||
|
||||
# TCP heartbeat interval in seconds. 0 disables.
|
||||
#NET_HEARTBEAT=60
|
||||
|
||||
|
|
2
debian/dump1090-mutability.init
vendored
2
debian/dump1090-mutability.init
vendored
|
@ -44,6 +44,7 @@ RAW_OUTPUT_PORT=30002
|
|||
SBS_OUTPUT_PORT=30003
|
||||
BEAST_INPUT_PORT=30004
|
||||
BEAST_OUTPUT_PORT=30005
|
||||
FATSV_OUTPUT_PORT=10001
|
||||
NET_HEARTBEAT=60
|
||||
NET_OUTPUT_SIZE=500
|
||||
NET_OUTPUT_INTERVAL=1
|
||||
|
@ -87,6 +88,7 @@ if [ "x$RAW_OUTPUT_PORT" != "x30002" ]; then ARGS="$ARGS --net-ro-port $RAW_OUTP
|
|||
if [ "x$SBS_OUTPUT_PORT" != "x30003" ]; then ARGS="$ARGS --net-sbs-port $SBS_OUTPUT_PORT"; fi
|
||||
if [ "x$BEAST_INPUT_PORT" != "x30004" ]; then ARGS="$ARGS --net-bi-port $BEAST_INPUT_PORT"; fi
|
||||
if [ "x$BEAST_OUTPUT_PORT" != "x30005" ]; then ARGS="$ARGS --net-bo-port $BEAST_OUTPUT_PORT"; fi
|
||||
if [ "x$FATSV_OUTPUT_PORT" != "x10001" ]; then ARGS="$ARGS --net-fatsv-port $FATSV_OUTPUT_PORT"; fi
|
||||
if [ "x$NET_HEARTBEAT" != "x60" ]; then ARGS="$ARGS --net-heartbeat $NET_HEARTBEAT"; fi
|
||||
if [ "x$NET_OUTPUT_SIZE" != "x0" ]; then ARGS="$ARGS --net-ro-size $NET_OUTPUT_SIZE"; fi
|
||||
if [ "x$NET_OUTPUT_INTERVAL" != "x0" ]; then ARGS="$ARGS --net-ro-interval $NET_OUTPUT_INTERVAL"; fi
|
||||
|
|
|
@ -77,6 +77,7 @@ void modesInitConfig(void) {
|
|||
Modes.net_output_beast_port = MODES_NET_OUTPUT_BEAST_PORT;
|
||||
Modes.net_input_beast_port = MODES_NET_INPUT_BEAST_PORT;
|
||||
Modes.net_http_port = MODES_NET_HTTP_PORT;
|
||||
Modes.net_fatsv_port = MODES_NET_OUTPUT_FA_TSV_PORT;
|
||||
Modes.interactive_rows = getTermRows();
|
||||
Modes.interactive_delete_ttl = MODES_INTERACTIVE_DELETE_TTL;
|
||||
Modes.interactive_display_ttl = MODES_INTERACTIVE_DISPLAY_TTL;
|
||||
|
@ -424,6 +425,7 @@ void showHelp(void) {
|
|||
"--net-sbs-port <port> TCP BaseStation output listen port (default: 30003)\n"
|
||||
"--net-bi-port <port> TCP Beast input listen port (default: 30004)\n"
|
||||
"--net-bo-port <port> TCP Beast output listen port (default: 30005)\n"
|
||||
"--net-fatsv-port <port> FlightAware TSV output port (default: 10001)\n"
|
||||
"--net-ro-size <size> TCP output minimum size (default: 0)\n"
|
||||
"--net-ro-interval <rate> TCP output memory flush rate in seconds (default: 0)\n"
|
||||
"--net-heartbeat <rate> TCP heartbeat rate in seconds (default: 60 sec; 0 to disable)\n"
|
||||
|
@ -767,6 +769,8 @@ int main(int argc, char **argv) {
|
|||
Modes.net_bind_address = strdup(argv[++j]);
|
||||
} else if (!strcmp(argv[j],"--net-http-port") && more) {
|
||||
Modes.net_http_port = atoi(argv[++j]);
|
||||
} else if (!strcmp(argv[j],"--net-fatsv-port") && more) {
|
||||
Modes.net_fatsv_port = atoi(argv[++j]);
|
||||
} else if (!strcmp(argv[j],"--net-sbs-port") && more) {
|
||||
Modes.net_output_sbs_port = atoi(argv[++j]);
|
||||
} else if (!strcmp(argv[j],"--net-buffer") && more) {
|
||||
|
|
|
@ -179,13 +179,14 @@
|
|||
|
||||
#define MODES_NET_HEARTBEAT_INTERVAL 60 // seconds
|
||||
|
||||
#define MODES_NET_SERVICES_NUM 6
|
||||
#define MODES_NET_SERVICES_NUM 7
|
||||
#define MODES_NET_INPUT_RAW_PORT 30001
|
||||
#define MODES_NET_OUTPUT_RAW_PORT 30002
|
||||
#define MODES_NET_OUTPUT_SBS_PORT 30003
|
||||
#define MODES_NET_INPUT_BEAST_PORT 30004
|
||||
#define MODES_NET_OUTPUT_BEAST_PORT 30005
|
||||
#define MODES_NET_HTTP_PORT 8080
|
||||
#define MODES_NET_OUTPUT_FA_TSV_PORT 10001
|
||||
#define MODES_CLIENT_BUF_SIZE 1024
|
||||
#define MODES_NET_SNDBUF_SIZE (1024*64)
|
||||
#define MODES_NET_SNDBUF_MAX (7)
|
||||
|
@ -227,6 +228,10 @@ struct aircraft {
|
|||
long modeCcount; // Mode C Altitude hit Count
|
||||
int modeACflags; // Flags for mode A/C recognition
|
||||
|
||||
int fatsv_emitted_altitude; // last FA emitted altitude
|
||||
int fatsv_emitted_track; // last FA emitted angle of flight
|
||||
time_t fatsv_last_emitted; // time aircraft was last FA emitted
|
||||
|
||||
// Encoded latitude and longitude as extracted by odd and even CPR encoded messages
|
||||
int odd_cprlat;
|
||||
int odd_cprlon;
|
||||
|
@ -317,6 +322,7 @@ struct { // Internal state
|
|||
struct net_writer raw_out; // Raw output
|
||||
struct net_writer beast_out; // Beast-format output
|
||||
struct net_writer sbs_out; // SBS-format output
|
||||
struct net_writer fatsv_out; // FATSV-format output
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData; // Windows socket initialisation
|
||||
|
@ -344,6 +350,7 @@ struct { // Internal state
|
|||
int net_input_beast_port; // Beast input TCP port
|
||||
char *net_bind_address; // Bind address
|
||||
int net_http_port; // HTTP port
|
||||
int net_fatsv_port; // FlightAware TSV port
|
||||
int net_sndbuf_size; // TCP output buffer size (64Kb * 2^n)
|
||||
int quiet; // Suppress stdout
|
||||
int interactive; // Interactive mode
|
||||
|
|
156
net_io.c
156
net_io.c
|
@ -65,7 +65,8 @@ void modesInitNet(void) {
|
|||
{"Beast TCP output", &Modes.beast_out.socket, &Modes.beast_out, Modes.net_output_beast_port, 1},
|
||||
{"Beast TCP input", &Modes.bis, NULL, Modes.net_input_beast_port, 1},
|
||||
{"HTTP server", &Modes.https, NULL, Modes.net_http_port, 1},
|
||||
{"Basestation TCP output", &Modes.sbs_out.socket, &Modes.sbs_out, Modes.net_output_sbs_port, 1}
|
||||
{"Basestation TCP output", &Modes.sbs_out.socket, &Modes.sbs_out, Modes.net_output_sbs_port, 1},
|
||||
{"FlightAware TSV output", &Modes.fatsv_out.socket, &Modes.fatsv_out, Modes.net_fatsv_port, 1}
|
||||
};
|
||||
|
||||
memcpy(&services, &svc, sizeof(svc));//services = svc;
|
||||
|
@ -217,7 +218,7 @@ static void *prepareWrite(struct net_writer *writer, int len) {
|
|||
!writer->data)
|
||||
return NULL;
|
||||
|
||||
if (len >= MODES_OUT_BUF_SIZE)
|
||||
if (len > MODES_OUT_BUF_SIZE)
|
||||
return NULL;
|
||||
|
||||
if (writer->dataUsed + len >= MODES_OUT_BUF_SIZE) {
|
||||
|
@ -1053,6 +1054,154 @@ void modesReadFromClient(struct client *c, char *sep,
|
|||
}
|
||||
}
|
||||
|
||||
#define TSV_MAX_PACKET_SIZE 160
|
||||
|
||||
static void writeFATSV() {
|
||||
struct aircraft *a;
|
||||
time_t now;
|
||||
static time_t lastTime = 0;
|
||||
|
||||
if (!Modes.fatsv_out.connections) {
|
||||
return; // no active connections
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
if (now <= lastTime) {
|
||||
// scan once a second at most
|
||||
return;
|
||||
}
|
||||
|
||||
lastTime = now;
|
||||
|
||||
for (a = Modes.aircrafts; a; a = a->next) {
|
||||
int altValid = 0;
|
||||
int alt = 0;
|
||||
int groundValid = 0;
|
||||
int ground = 0;
|
||||
int latlonValid = 0;
|
||||
int useful = 0;
|
||||
int emittedSecondsAgo;
|
||||
char *p;
|
||||
|
||||
// don't emit if it hasn't updated since last time
|
||||
if (a->seen < a->fatsv_last_emitted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
emittedSecondsAgo = (int)(now - a->fatsv_last_emitted);
|
||||
|
||||
// don't emit more than once every five seconds
|
||||
if (emittedSecondsAgo < 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (a->bFlags & MODES_ACFLAGS_ALTITUDE_VALID) {
|
||||
altValid = 1;
|
||||
alt = a->altitude;
|
||||
}
|
||||
|
||||
if (a->bFlags & MODES_ACFLAGS_AOG_VALID) {
|
||||
groundValid = 1;
|
||||
|
||||
if (a->bFlags & MODES_ACFLAGS_AOG) {
|
||||
alt = 0;
|
||||
ground = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (a->bFlags & MODES_ACFLAGS_LATLON_VALID) {
|
||||
latlonValid = 1;
|
||||
}
|
||||
|
||||
// if it's over 10,000 feet, don't emit more than once every 10 seconds
|
||||
if (alt > 10000 && emittedSecondsAgo < 10) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// disable if you want only ads-b
|
||||
// also don't send mode S very often
|
||||
if (!latlonValid) {
|
||||
if (emittedSecondsAgo < 30) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// if it hasn't changed altitude very much and it hasn't changed
|
||||
// heading very much, don't update real often
|
||||
if (abs(a->track - a->fatsv_emitted_track) < 2 && abs(alt - a->fatsv_emitted_altitude) < 50) {
|
||||
if (alt < 10000) {
|
||||
// it hasn't changed much but we're below 10,000 feet
|
||||
// so update more frequently
|
||||
if (emittedSecondsAgo < 10) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// above 10,000 feet, don't update so often when it
|
||||
// hasn't changed much
|
||||
if (emittedSecondsAgo < 30) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p = prepareWrite(&Modes.fatsv_out, MODES_OUT_BUF_SIZE);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
p += sprintf(p, "clock\t%ld\thexid\t%06X", a->seen, a->addr);
|
||||
|
||||
if (*a->flight != '\0') {
|
||||
p += sprintf(p, "\tident\t%s", a->flight);
|
||||
}
|
||||
|
||||
if (a->bFlags & MODES_ACFLAGS_SQUAWK_VALID) {
|
||||
p += sprintf(p, "\tsquawk\t%04x", a->modeA);
|
||||
}
|
||||
|
||||
if (altValid) {
|
||||
p += sprintf(p, "\talt\t%d", alt);
|
||||
useful = 1;
|
||||
}
|
||||
|
||||
if (a->bFlags & MODES_ACFLAGS_SPEED_VALID) {
|
||||
p += sprintf(p, "\tspeed\t%d", a->speed);
|
||||
useful = 1;
|
||||
}
|
||||
|
||||
if (groundValid) {
|
||||
if (ground) {
|
||||
p += sprintf(p, "\tairGround\tG");
|
||||
} else {
|
||||
p += sprintf(p, "\tairGround\tA");
|
||||
}
|
||||
}
|
||||
|
||||
if (latlonValid) {
|
||||
p += sprintf(p, "\tlat\t%.5f\tlon\t%.5f", a->lat, a->lon);
|
||||
useful = 1;
|
||||
}
|
||||
|
||||
if (a->bFlags & MODES_ACFLAGS_HEADING_VALID) {
|
||||
p += sprintf(p, "\theading\t%d", a->track);
|
||||
useful = 1;
|
||||
}
|
||||
|
||||
// if we didn't get at least an alt or a speed or a latlon or
|
||||
// a heading, bail out. We don't need to do anything special
|
||||
// to unwind prepareWrite().
|
||||
if (!useful) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p += sprintf(p, "\n");
|
||||
completeWrite(&Modes.fatsv_out, p);
|
||||
|
||||
a->fatsv_last_emitted = now;
|
||||
a->fatsv_emitted_altitude = alt;
|
||||
a->fatsv_emitted_track = a->track;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Perform periodic network work
|
||||
//
|
||||
|
@ -1076,6 +1225,9 @@ void modesNetPeriodicWork(void) {
|
|||
}
|
||||
}
|
||||
|
||||
// Generate FATSV output
|
||||
writeFATSV();
|
||||
|
||||
// If we have generated no messages for a while, generate
|
||||
// a dummy heartbeat message.
|
||||
if (Modes.net_heartbeat_interval) {
|
||||
|
|
Loading…
Reference in a new issue