diff --git a/net_io.c b/net_io.c index 4d88cd1..10e7166 100644 --- a/net_io.c +++ b/net_io.c @@ -77,6 +77,8 @@ 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 writeFATSVEvent(struct modesMessage *mm, struct aircraft *a); + // //========================================================================= // @@ -725,6 +727,10 @@ void modesQueueOutput(struct modesMessage *mm, struct aircraft *a) { // Forward mlat messages via beast output only if --forward-mlat is set modesSendBeastOutput(mm); } + + if (!is_mlat) { + writeFATSVEvent(mm, a); + } } // //========================================================================= @@ -1652,6 +1658,82 @@ static void modesReadFromClient(struct client *c) { #define TSV_MAX_PACKET_SIZE 180 +static void writeFATSVEventMessage(struct modesMessage *mm, const char *datafield, unsigned char *data, size_t len) +{ + char *p = prepareWrite(&Modes.fatsv_out, TSV_MAX_PACKET_SIZE); + if (!p) + return; + + char *end = p + TSV_MAX_PACKET_SIZE; +# define bufsize(_p,_e) ((_p) >= (_e) ? (size_t)0 : (size_t)((_e) - (_p))) + + p += snprintf(p, bufsize(p, end), "clock\t%" PRIu64 "\thexid\t%06X\t%s\t", mstime() / 1000, mm->addr, datafield); + + for (size_t i = 0; i < len; ++i) { + p += snprintf(p, bufsize(p, end), "%02X", data[i]); + } + + p += snprintf(p, bufsize(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)); +# undef bufsize +} + +static void writeFATSVEvent(struct modesMessage *mm, struct aircraft *a) +{ + // Write event records for a couple of message types. + + if (!Modes.fatsv_out.service || !Modes.fatsv_out.service->connections) { + return; // not enabled or no active connections + } + + // skip non-ICAO + if (mm->addr & MODES_NON_ICAO_ADDRESS) + return; + + if (a->messages < 2) // basic filter for bad decodes + return; + + switch (mm->msgtype) { + case 20: + case 21: + if (mm->correctedbits > 0) + break; // only messages we trust a little more + + // DF 20/21: Comm-B: emit if they've changed since we last sent them + // + // BDS 1,0: data link capability report + // BDS 3,0: ACAS RA report + if (mm->MB[0] == 0x10 && memcmp(mm->MB, a->fatsv_emitted_bds_10, 7) != 0) { + memcpy(a->fatsv_emitted_bds_10, mm->MB, 7); + writeFATSVEventMessage(mm, "datalink_caps", mm->MB, 7); + } + + else if (mm->MB[0] == 0x30 && memcmp(mm->MB, a->fatsv_emitted_bds_30, 7) != 0) { + memcpy(a->fatsv_emitted_bds_30, mm->MB, 7); + writeFATSVEventMessage(mm, "acas_ra", mm->MB, 7); + } + + break; + + case 17: + // DF 17: extended squitter + // type 28 subtype 2: ACAS RA report + // first byte has the type/subtype, remaining bytes match the BDS 3,0 format + if (mm->metype == 28 && mm->mesub == 2 && memcmp(&mm->ME[1], &a->fatsv_emitted_bds_30[1], 6) != 0) { + memcpy(a->fatsv_emitted_bds_30, &mm->ME[1], 6); + writeFATSVEventMessage(mm, "acas_ra", mm->ME, 7); + } else if (mm->metype == 31 && (mm->mesub == 0 || mm->mesub == 1) && memcmp(mm->ME, a->fatsv_emitted_es_status, 7) != 0) { + memcpy(a->fatsv_emitted_es_status, mm->ME, 7); + writeFATSVEventMessage(mm, "es_op_status", mm->ME, 7); + } + break; + } +} + static void writeFATSV() { struct aircraft *a; diff --git a/track.c b/track.c index d8f832b..02fd026 100644 --- a/track.c +++ b/track.c @@ -70,6 +70,9 @@ struct aircraft *trackCreateAircraft(struct modesMessage *mm) { a->signalLevel[i] = 1e-5; a->signalNext = 0; + // start off with the "last emitted" ACAS RA being blank (just the BDS 3,0 code) + a->fatsv_emitted_bds_30[0] = 0x30; + // mm->msgtype 32 is used to represent Mode A/C. These values can never change, so // set them once here during initialisation, and don't bother to set them every // time this ModeA/C is received again in the future diff --git a/track.h b/track.h index 1e0ef23..0e27fc1 100644 --- a/track.h +++ b/track.h @@ -145,6 +145,9 @@ struct aircraft { int fatsv_emitted_speed_ias; // -"- IAS int fatsv_emitted_speed_tas; // -"- TAS airground_t fatsv_emitted_airground; // -"- air/ground state + unsigned char fatsv_emitted_bds_10[7]; // -"- BDS 1,0 message + unsigned char fatsv_emitted_bds_30[7]; // -"- BDS 3,0 message + unsigned char fatsv_emitted_es_status[7]; // -"- ES operational status message uint64_t fatsv_last_emitted; // time (millis) aircraft was last FA emitted