Skip to content

Commit

Permalink
Merge PR antirez#61 (Stratux output format support) plus fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mutability committed Sep 8, 2020
2 parents ee552eb + 303dcc9 commit 418e13e
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 0 deletions.
5 changes: 5 additions & 0 deletions dump1090.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ static void showHelp(void)
"--net-sbs-port <ports> TCP BaseStation output listen ports (default: 30003)\n"
"--net-bi-port <ports> TCP Beast input listen ports (default: 30004,30104)\n"
"--net-bo-port <ports> TCP Beast output listen ports (default: 30005)\n"
"--net-stratux-port <ports> TCP Stratux output listen ports (default: disabled)\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"
Expand Down Expand Up @@ -548,6 +549,10 @@ int main(int argc, char **argv) {
Modes.net = 1;
free(Modes.net_output_sbs_ports);
Modes.net_output_sbs_ports = strdup(argv[++j]);
} else if (!strcmp(argv[j],"--net-stratux-port") && more) {
Modes.net = 1;
free(Modes.net_output_stratux_ports);
Modes.net_output_stratux_ports = strdup(argv[++j]);
} else if (!strcmp(argv[j],"--net-buffer") && more) {
Modes.net_sndbuf_size = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-verbatim")) {
Expand Down
2 changes: 2 additions & 0 deletions dump1090.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ struct _Modes { // Internal state
struct net_writer beast_verbatim_out; // Beast-format output, verbatim mode
struct net_writer beast_cooked_out; // Beast-format output, "cooked" mode
struct net_writer sbs_out; // SBS-format output
struct net_writer stratux_out; // Stratux-format output
struct net_writer fatsv_out; // FATSV-format output

#ifdef _WIN32
Expand All @@ -324,6 +325,7 @@ struct _Modes { // Internal state
char *net_output_raw_ports; // List of raw output TCP ports
char *net_input_raw_ports; // List of raw input TCP ports
char *net_output_sbs_ports; // List of SBS output TCP ports
char *net_output_stratux_ports; // List of Stratux output TCP ports
char *net_input_beast_ports; // List of Beast input TCP ports
char *net_output_beast_ports; // List of Beast output TCP ports
char *net_bind_address; // Bind address
Expand Down
211 changes: 211 additions & 0 deletions net_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ static void moveNetClient(struct client *c, struct net_service *new_service);
static void send_raw_heartbeat(struct net_service *service);
static void send_beast_heartbeat(struct net_service *service);
static void send_sbs_heartbeat(struct net_service *service);
static void send_stratux_heartbeat(struct net_service *service);

static void writeBeastMessage(struct net_writer *writer, uint64_t timestamp, double signalLevel, unsigned char *msg, int msgLen);

Expand All @@ -85,6 +86,11 @@ static void writeFATSVPositionUpdate(float lat, float lon, float alt);

static void autoset_modeac();

__attribute__ ((format (printf,3,0))) static char *safe_vsnprintf(char *p, char *end, const char *format, va_list ap);
__attribute__ ((format (printf,3,4))) static char *safe_snprintf(char *p, char *end, const char *format, ...);

static const char *jsonEscapeString(const char *str);

//
//=========================================================================
//
Expand Down Expand Up @@ -268,6 +274,9 @@ void modesInitNet(void) {
s = serviceInit("Basestation TCP output", &Modes.sbs_out, send_sbs_heartbeat, READ_MODE_IGNORE, NULL, NULL);
serviceListen(s, Modes.net_bind_address, Modes.net_output_sbs_ports);

s = serviceInit("Stratux TCP output", &Modes.stratux_out, send_stratux_heartbeat, READ_MODE_IGNORE, NULL, NULL);
serviceListen(s, Modes.net_bind_address, Modes.net_output_stratux_ports);

s = serviceInit("Raw TCP input", NULL, NULL, READ_MODE_ASCII, "\n", decodeHexMessage);
serviceListen(s, Modes.net_bind_address, Modes.net_input_raw_ports);

Expand Down Expand Up @@ -776,13 +785,215 @@ static void send_sbs_heartbeat(struct net_service *service)
completeWrite(service->writer, data + len);
}

//
//=========================================================================
//
// Write Stratux output to TCP clients
//

#define STRATUX_MAX_PACKET_SIZE 1000
static void modesSendStratuxOutput(struct modesMessage *mm, struct aircraft *a) {
char *p;

// We require a tracked aircraft for Stratux output
if (!a)
return;

// Don't ever forward 2-bit-corrected messages via Stratux output.
if (mm->correctedbits >= 2)
return;

// Don't ever forward mlat messages via Stratux output.
if (mm->source == SOURCE_MLAT)
return;

// Don't ever send unreliable messages via Stratux output
if (!mm->reliable && !a->reliable)
return;

p = prepareWrite(&Modes.stratux_out, STRATUX_MAX_PACKET_SIZE); // larger buffer size needed vs SBS
if (!p)
return;

char *end = p + STRATUX_MAX_PACKET_SIZE;

// Begin populating the traffic.go fields.
// ICAO address, Mode S message types, and signal level

int cacf = 0; // overload the JSON "CA" field to report CA (DF11 or DF17), CF (DF18), or zero (all other DF types)
if ((mm->msgtype == 11) || (mm->msgtype == 17)) {
cacf = mm->CA;
} else if (mm->msgtype == 18) {
cacf = mm->CF;
}

p = safe_snprintf(p, end,
"{\"Icao_addr\":%d,"
"\"DF\":%d,\"CA\":%d,"
"\"TypeCode\":%d,"
"\"SubtypeCode\":%d,"
"\"SignalLevel\":%f,",
mm->addr,
mm->msgtype, cacf,
mm->metype,
mm->mesub,
mm->signalLevel); // what precision and range is needed for RSSI?

//// callsign
if (mm->callsign_valid)
p = safe_snprintf(p, end, "\"Tail\":\"%s\",", jsonEscapeString(mm->callsign));
else
p = safe_snprintf(p, end, "\"Tail\":null,");

//// altitude & gnss
bool alt_is_geom;
if (mm->altitude_baro_valid) {
p = safe_snprintf(p, end, "\"Alt\":%d,",mm->altitude_baro);
alt_is_geom = false;
} else if (mm->altitude_geom_valid) {
p = safe_snprintf(p, end, "\"Alt\":%d,",mm->altitude_geom);
alt_is_geom = true;
} else {
p = safe_snprintf(p, end, "\"Alt\":null,");
alt_is_geom = false;
}

// altitude source
if (alt_is_geom)
p = safe_snprintf(p, end, "\"AltIsGNSS\":true,");
else
p = safe_snprintf(p, end, "\"AltIsGNSS\":false,");

// GNSS alt. delta From baro alt.
if (trackDataValid(&a->geom_delta_valid))
p = safe_snprintf(p, end, "\"GnssDiffFromBaroAlt\":%d,",a->geom_delta);
else
p = safe_snprintf(p, end, "\"GnssDiffFromBaroAlt\":null,");
////

//// ground speed and track
if (mm->gs_valid)
p = safe_snprintf(p, end, "\"Speed_valid\":true,\"Speed\":%.0f,", mm->gs.selected);
else
p = safe_snprintf(p, end, "\"Speed_valid\":false,\"Speed\":null,");

//// ground heading
if (mm->heading_valid && mm->heading_type == HEADING_GROUND_TRACK)
p = safe_snprintf(p, end, "\"Track\":%.0f,", mm->heading);
else
p = safe_snprintf(p, end, "\"Track\":null,");

//// position
if (mm->cpr_decoded)
p = safe_snprintf(p, end, "\"Lat\":%.6f,\"Lng\":%.6f,\"Position_valid\":true,",
mm->decoded_lat, mm->decoded_lon);
else
p = safe_snprintf(p, end, "\"Lat\":null,\"Lng\":null,\"Position_valid\":false,");

//// vrate (use barometric if possible)
if (mm->baro_rate_valid)
p = safe_snprintf(p, end, "\"Vvel\":%d,", mm->baro_rate);
else if (mm->geom_rate_valid)
p = safe_snprintf(p, end, "\"Vvel\":%d,", mm->geom_rate);
else
p = safe_snprintf(p, end, "\"Vvel\":null,");

//// squawk
if (mm->squawk_valid)
p = safe_snprintf(p, end, "\"Squawk\":%x,", mm->squawk);
else
p = safe_snprintf(p, end, "\"Squawk\":null,");

// TODO: squawk changing alert support in stratux?
// TODO: squawk emergency flag?
// TODO: squawk ident flag?

// airground
switch (mm->airground) {
case AG_GROUND:
p = safe_snprintf(p, end, "\"OnGround\":true,");
break;
case AG_AIRBORNE:
p = safe_snprintf(p, end, "\"OnGround\":false,");
break;
default:
p = safe_snprintf(p, end, "\"OnGround\":null,");
}

// navigation accuracy category - position
if (mm->accuracy.nac_p_valid) {
p = safe_snprintf(p, end, "\"NACp\":%d,", mm->accuracy.nac_p);
} else {
p = safe_snprintf(p, end, "\"NACp\":null,");
}

// emitter type
int emitter = -1;
if ((mm->msgtype == 17) || (mm->msgtype == 18)) {
switch (mm->metype) {
case 1:
emitter = ((mm->mesub) | 0x18);
break;
case 2:
emitter = ((mm->mesub) | 0x10);
break;
case 3:
emitter = ((mm->mesub) | 0x08);
break;
case 4:
emitter = (mm->mesub);
break;
}
}

if (emitter >= 0)
p = safe_snprintf(p, end, "\"Emitter_category\":%d,", emitter);
else
p = safe_snprintf(p, end, "\"Emitter_category\":null,");

// Time message received (based on system clock). Format is 2016-02-20T06:35:43.155Z
struct tm stTime_receive;
time_t received = (time_t) (mm->sysTimestampMsg / 1000);
gmtime_r(&received, &stTime_receive);
p = safe_snprintf(p, end, "\"Timestamp\":\"%04d-%02d-%02dT%02d:%02d:%02d.%03dZ\"",
(stTime_receive.tm_year+1900),(stTime_receive.tm_mon+1),
stTime_receive.tm_mday, stTime_receive.tm_hour,
stTime_receive.tm_min, stTime_receive.tm_sec,
(unsigned)(mm->sysTimestampMsg % 1000));

p = safe_snprintf(p, end, "}\r\n");

if (p < end)
completeWrite(&Modes.stratux_out, p);
else
fprintf(stderr, "stratux: output too large (max %d, overran by %d)\n", STRATUX_MAX_PACKET_SIZE, (int) (p - end));
}

static void send_stratux_heartbeat(struct net_service *service)
{
static char *heartbeat_message = "{\"Icao_addr\":134217727}\r\n"; // 0x07FFFFFF. Overflows 24-bit ICAO to signal invalic #, need to validate that this won't cause problems with traffic.go
char *data;
int len = strlen(heartbeat_message);

if (!service->writer)
return;

data = prepareWrite(service->writer, len);
if (!data)
return;

memcpy(data, heartbeat_message, len);
completeWrite(service->writer, data + len);
}

//
//=========================================================================
//
void modesQueueOutput(struct modesMessage *mm, struct aircraft *a) {

// Delegate to the format-specific outputs, each of which makes its own decision about filtering messages
modesSendSBSOutput(mm, a);
modesSendStratuxOutput(mm, a);
modesSendRawOutput(mm, a);
modesSendBeastVerbatimOutput(mm, a);
modesSendBeastCookedOutput(mm, a);
Expand Down

0 comments on commit 418e13e

Please sign in to comment.