From db8fd370e96deefcec913ef8bcd0814df203739b Mon Sep 17 00:00:00 2001 From: Dennis Date: Wed, 29 Mar 2023 13:16:57 -0400 Subject: [PATCH 01/32] first attempt at asterix output --- net_io.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ readsb.h | 1 + 2 files changed, 266 insertions(+) diff --git a/net_io.c b/net_io.c index cc9d044c..f6d087ee 100644 --- a/net_io.c +++ b/net_io.c @@ -60,6 +60,7 @@ #include #include #include +#include "ais_charset.c" #include "uat2esnt/uat2esnt.h" @@ -831,6 +832,7 @@ void modesInitNet(void) { struct net_service *sbs_out_mlat; struct net_service *sbs_out_jaero; struct net_service *sbs_out_prio; + struct net_service *asterix_out; struct net_service *sbs_in; struct net_service *sbs_in_mlat; struct net_service *sbs_in_jaero; @@ -872,6 +874,9 @@ void modesInitNet(void) { serviceListen(sbs_out_jaero, Modes.net_bind_address, Modes.net_output_jaero_ports, Modes.net_epfd); + asterix_out = serviceInit(&Modes.services_out, "ASTERIX CAT021 output", &Modes.asterix_out, no_heartbeat, no_heartbeat, READ_MODE_IGNORE, NULL, NULL); + serviceListen(asterix_out, Modes.net_bind_address, Modes.net_output_asterix_ports, Modes.net_epfd); + int sbs_port_len = strlen(Modes.net_output_sbs_ports); int pos = sbs_port_len - 1; if (sbs_port_len <= 5 && Modes.net_output_sbs_ports[pos] == '5') { @@ -988,6 +993,8 @@ void modesInitNet(void) { con->service = feedmap_out; else if (strcmp(con->protocol, "sbs_out") == 0) con->service = sbs_out; + else if (strcmp(con->protocol, "asterix_out") == 0) + con->service = asterix_out; else if (strcmp(con->protocol, "sbs_in") == 0) con->service = sbs_in; else if (strcmp(con->protocol, "sbs_in_mlat") == 0) @@ -1744,6 +1751,264 @@ static void modesSendRawOutput(struct modesMessage *mm) { completeWrite(&Modes.raw_out, p); } +// +//========================================================================= +// +// Write raw output to TCP clients +// +static void modesSendAsterixOutput(struct modesMessage *mm) { + int msgLen = 1; + uint8_t category; + if (mm->from_mlat) // CAT 20 + return; + if (mm->from_tisb) + return; + else { // CAT 21 + category = 21; + bool item_010; + bool item_040; + bool item_130; + bool item_131; + bool item_150; + bool item_151; + bool item_080; + bool item_073; + bool item_075; + bool item_140; + bool item_090; + bool item_210; + bool item_070; + bool item_145; + bool item_152; + bool item_200; + bool item_155; + bool item_157; + bool item_160; + bool item_077; + bool item_170; + bool item_020; + bool item_008; + + item_010 = true; + msgLen +=2; + uint8_t sac = 000; + uint8_t sic = 001; + + item_040 = true; + msgLen++; + uint item_040_primary; + if (mm->addrtype <= 3 ) + item_040_primary = 0; + else + item_040_primary = 3; + item_040_primary *= 32; + if (mm->alt_q_bit == 0) + item_040_primary += 8; + uint item_040_ext1 = 0; + if (mm->airground == AG_GROUND) + item_040_ext1 += 64; + if (mm->opstatus.valid == 0) + item_040_ext1 +=2; + if (item_040_ext1){ + msgLen++; + item_040_primary += 1; + } + item_130 = false; + item_131 = false; + int32_t lat; + int32_t lon; + uint64_t item_131_value; + if(mm->cpr_decoded){ + item_131 = true; + item_073 = true; + msgLen += 11; + lat = mm->decoded_lat / (180 / pow(2,30)); + lon = mm->decoded_lon / (180 / pow(2,30)); + item_131_value = (lat << 32) + lon; + } + uint16_t item_150_value; + if(mm->ias_valid || mm->mach_valid){ + item_150 = true; + msgLen +=2; + if (mm->mach_valid){ + item_150_value = (1 << 15); + item_150_value += mm->mach * 1000; + } + else{ + item_150_value = ((mm->ias) / 3600) * pow(2,14); + } + } + uint16_t item_151_value; + if(mm->tas_valid){ + item_151 = true; + msgLen += 2; + item_151_value = mm->tas; + } + item_080 = true; + msgLen += 3; + + int item_073_value; + if (item_073){ + time_t midnight = (time / 86400) * 86400000; + item_073_value = (mm->timestamp) - midnight; + if (item_073_value < 0) + item_073_value += 86400 + item_073_value = (int)(item_073_value * 0.128); + } + + item_075 = false; + + int item_140_value; + if (mm->geom_alt_valid){ + item_140 = true; + msgLen +=2; + if(mm->geom_alt_unit == UNIT_FEET) + item_140_value = mm->geom_alt / 6.25; + else + item_140_value = mm->geom_alt / 20.5053; + } + + item_090 = true; + msgLen++; + int item_080_primary = 0; + if (mm->accuracy.nac_v_valid) + item_080_primary += mm->accuracy.nac_v << 5; + if (mm->cpr_decoded) + item_080_primary += mm->cpr_nucp << 1; + int item_080_ext1 = 0; + if (mm->accuracy.nic_baro_valid) + item_080_ext1 += mm->accuracy.nic_baro << 7; + if (mm->accuracy.sil_type != SIL_INVALID) + item_080_ext1 += mm->accuracy.sil << 5; + if (mm->accuracy.nac_p_valid) + item_080_ext1 += mm->accuracy.nac_p << 1; + if (item_080_ext1){ + msgLen++; + item_080_primary++; + } + int item_080_ext2 = 0; + if (mm->accuracy.sil_type == SIL_PER_SAMPLE) + item_080_ext2 += 1 << 5; + if (mm->accuracy.sda_valid) + item_080_ext2 += mm->accuracy.sda << 3; + if (mm->accuracy.gva_valid) + item_080_ext2 += mm->accuracy.gva << 1; + if (item_080_ext2){ + msgLen++; + item_080_ext1++; + } + + item_210 = false; + + uint16_t item_070_value; + if(mm->squawk_valid){ + msgLen +=2; + item_070 = true; + item_070_value = mm->squawk; + } + + int16_t item_145_value; + if(mm->baro_alt_valid){ + msgLen +=2; + item_145 = true; + item_145_value = mm->baro_alt * 4; + if (mm->baro_alt_unit == UNIT_METERS) + item_145_value = (int)(mm-> baro_alt * 3.2808) + } + + uint16_t item_152_value; + if(mm->heading_valid && mm->heading_type == HEADING_MAGNETIC){ + item_152 = true; + msgLen +=2; + item_152_value = mm->heading * (pow(2,16) / 360); + } + + uint8_t item_200_value = 0; + if (mm->nav.modes_valid){ + if (mm->nav.modes && 0b00000010) + item_200_value += 1 << 6; + } + if (mm->emergency_valid) + item_200_value += (mm->emergency << 2); + if (mm->alert_valid) + item_200_value += (mm->alert); + else if (mm->spi_valid && mm->spi) + item_200_value +=3; + if (item_200_value){ + item_200 = true; + msgLen++; + } + + uint16_t item_155_value = 0; + if (mm->baro_rate_valid){ + item_155 = true; + msgLen += 2; + double adj_baro_rate = mm->baro_rate * 3.125; + item_155_value = (adj_baro_rate >> 1); + } + + uint16_t item_157_value = 0; + if (mm->geom_rate_valid){ + item_157 = true; + msgLen += 2; + double adj_geom_rate = mm->geom_rate * 3.125; + item_157_value = (adj_geom_rate >> 1); + } + + uint32_t item_160_value = 0; + if (mm->gs_valid && mm->track_valid && mm->calculated_track != -1){ + item_160 = true; + msgLen += 4; + double adj_gs = mm->gs.v0 * 4.5511; + item_160_value += ((int)adj_gs << 16); + double adj_trk = mm->track * 182.0444; + item_160_value += ((uint16_t)adj_trk); + } + + item_077 = true; + msgLen += 3; + int midnight = (time / 86400) * 86400; + int item_077_value = time - midnight; + + uint64_t item_170_value = 0; + if(mm->callsign_valid){ + item_170 = true; + msgLen += 6; + for (int i = 0; i < 7; i++) + { + char *letter = strchr(ais_charset, mm->callsign[i]); + if (letter){ + item_170_value = item_170_value << 6; + item_170_value += (letter - ais_charset); + } + } + } + uint8_t item_020_value; + if (mm->category_valid){ + item_020 = true; + msgLen += 1; + item_020_value = mm->category; + } + + uint8_t item_008_value = 0; + if (mm->opstatus.valid){ + item_008 = true; + msgLen += 1; + item_008_value += (mm->opstatus.om_acas_ra << 7); + item_008_value += (mm->opstatus.cc_tc << 5); + item_008_value += (mm->opstatus.cc_ts << 4); + item_008_value += (mm->opstatus.cc_arv << 3); + item_008_value += (mm->opstatus.cc_cdti << 2); + } + + char *p = prepareWrite(&Modes.asterix_out, msgLen * 2); + memset(p, &category, 1); + p += 1; + memcpy(p, &msgLen, 2); + p += 1; + completeWrite(&Modes.asterix_out, p); + } +} // //========================================================================= // diff --git a/readsb.h b/readsb.h index 4bb64f82..2ad49af3 100644 --- a/readsb.h +++ b/readsb.h @@ -584,6 +584,7 @@ struct _Modes struct net_writer sbs_out_jaero; // SBS-format output struct net_writer sbs_out_prio; // SBS-format output struct net_writer json_out; // SBS-format output + struct net_writer asterix_out; // Asterix CAT021 output struct net_writer feedmap_out; // SBS-format output struct net_writer vrs_out; // SBS-format output struct net_writer fatsv_out; // FATSV-format output From e8500ad8cbad3442baa1ab858389f2e5f3b43eb9 Mon Sep 17 00:00:00 2001 From: Dennis Date: Wed, 29 Mar 2023 13:20:48 -0400 Subject: [PATCH 02/32] add send asterix output successfully made plausible ASTERIX packets with position, time, altitude, vertical rates, address, and aircraft identification --- help.h | 1 + net_io.c | 389 ++++++++++++++++++++++++++++++++++++------------------- readsb.c | 4 + readsb.h | 3 + 4 files changed, 264 insertions(+), 133 deletions(-) diff --git a/help.h b/help.h index 5f193b17..ce2bc03e 100644 --- a/help.h +++ b/help.h @@ -119,6 +119,7 @@ static struct argp_option optionsReadsb[] = { {"net-only", OptNetOnly, 0, 0, "Enable just networking, no RTL device or file used", 2}, {"net-bind-address", OptNetBindAddr, "", 0, "IP address to bind to (default: Any; Use 127.0.0.1 for private)", 2}, {"net-bo-port", OptNetBoPorts, "", 0, "TCP Beast output listen ports (default: 0)", 2}, + {"net-ao-port", OptNetAsteriskOutPorts, "", 0, "TCP Asterisk output listen ports (default: 0)", 2}, {"net-ri-port", OptNetRiPorts, "", 0, "TCP raw input listen ports (default: 0)", 2}, {"net-ro-port", OptNetRoPorts, "", 0, "TCP raw output listen ports (default: 0)", 2}, {"net-sbs-port", OptNetSbsPorts, "", 0, "TCP BaseStation output listen ports (default: 0)", 2}, diff --git a/net_io.c b/net_io.c index f6d087ee..ed387040 100644 --- a/net_io.c +++ b/net_io.c @@ -60,7 +60,6 @@ #include #include #include -#include "ais_charset.c" #include "uat2esnt/uat2esnt.h" @@ -193,6 +192,19 @@ static struct net_service *serviceInit(struct net_service_group *group, const ch return service; } +static char *ais_charset = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?"; +static uint8_t char_to_ais(int ch) +{ + char *match; + if (!ch) + return 32; + + match = strchr(ais_charset, ch); + if (match) + return (uint8_t)(match - ais_charset); + else + return 32; +} static int sendFiveHeartbeats(struct client *c, int64_t now) { // send 5 heartbeats to signal that we are a client that can accomodate feedback .... some counterparts crash if they get stuff they don't understand @@ -679,9 +691,9 @@ void serviceListen(struct net_service *service, char *bind_addr, char *bind_port int newfds[16]; int nfds, i; - int unix = 0; + int unixSocket = 0; if (strncmp(p, "unix:", 5) == 0) { - unix = 1; + unixSocket = 1; p += 5; } @@ -699,7 +711,7 @@ void serviceListen(struct net_service *service, char *bind_addr, char *bind_port buf[len] = 0; p = end + 1; } - if (unix) { + if (unixSocket) { if (service->unixSocket) { fprintf(stderr, "Multiple unix sockets per service are not supported! %s (%s): %s\n", buf, service->descr, Modes.aneterr); @@ -1757,7 +1769,6 @@ static void modesSendRawOutput(struct modesMessage *mm) { // Write raw output to TCP clients // static void modesSendAsterixOutput(struct modesMessage *mm) { - int msgLen = 1; uint8_t category; if (mm->from_mlat) // CAT 20 return; @@ -1765,37 +1776,18 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { return; else { // CAT 21 category = 21; - bool item_010; - bool item_040; - bool item_130; - bool item_131; - bool item_150; - bool item_151; - bool item_080; - bool item_073; - bool item_075; - bool item_140; - bool item_090; - bool item_210; - bool item_070; - bool item_145; - bool item_152; - bool item_200; - bool item_155; - bool item_157; - bool item_160; - bool item_077; - bool item_170; - bool item_020; - bool item_008; - - item_010 = true; - msgLen +=2; + uint8_t fspec[7]; + for (size_t i = 0; i < 7; i++) + { + fspec[i] = 0; + } + fspec[0] |= 1UL << 7; uint8_t sac = 000; uint8_t sic = 001; + uint16_t item_010_value = (sac << 8) + sic; + + fspec[0] |= 1UL << 6; - item_040 = true; - msgLen++; uint item_040_primary; if (mm->addrtype <= 3 ) item_040_primary = 0; @@ -1807,29 +1799,27 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { uint item_040_ext1 = 0; if (mm->airground == AG_GROUND) item_040_ext1 += 64; + /* if (mm->opstatus.valid == 0) item_040_ext1 +=2; + */ if (item_040_ext1){ - msgLen++; item_040_primary += 1; } - item_130 = false; - item_131 = false; - int32_t lat; - int32_t lon; - uint64_t item_131_value; + uint64_t item_131_value = 0; if(mm->cpr_decoded){ - item_131 = true; - item_073 = true; - msgLen += 11; + fspec[0] |= 1UL << 1; + fspec[1] |= 1UL << 3; + int32_t lat; + int32_t lon; lat = mm->decoded_lat / (180 / pow(2,30)); lon = mm->decoded_lon / (180 / pow(2,30)); - item_131_value = (lat << 32) + lon; + item_131_value = ((unsigned long long)lat << 32) + lon; } - uint16_t item_150_value; + + uint16_t item_150_value = 0x69; if(mm->ias_valid || mm->mach_valid){ - item_150 = true; - msgLen +=2; + fspec[1] |= 1UL << 6;; if (mm->mach_valid){ item_150_value = (1 << 15); item_150_value += mm->mach * 1000; @@ -1838,94 +1828,85 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { item_150_value = ((mm->ias) / 3600) * pow(2,14); } } - uint16_t item_151_value; + uint16_t item_151_value = 0x42; if(mm->tas_valid){ - item_151 = true; - msgLen += 2; + fspec[1] |= 1UL << 5; item_151_value = mm->tas; } - item_080 = true; - msgLen += 3; - - int item_073_value; - if (item_073){ - time_t midnight = (time / 86400) * 86400000; - item_073_value = (mm->timestamp) - midnight; + fspec[1] |= 1UL << 4; + uint item_080_value = mm->addr; + int item_073_value = 0; + if (fspec[1] & 0b1000){ + long midnight = (long)(time(NULL) / 86400) * 86400000; + item_073_value = (mm->sysTimestamp) - midnight; if (item_073_value < 0) - item_073_value += 86400 + item_073_value += 86400; item_073_value = (int)(item_073_value * 0.128); } - item_075 = false; + //fspec[1] |= 1UL << 1; - int item_140_value; + int16_t item_140_value = 0; if (mm->geom_alt_valid){ - item_140 = true; - msgLen +=2; + fspec[2] |= 1UL << 6; if(mm->geom_alt_unit == UNIT_FEET) item_140_value = mm->geom_alt / 6.25; else item_140_value = mm->geom_alt / 20.5053; } - item_090 = true; - msgLen++; - int item_080_primary = 0; + fspec[2] |= 1UL << 5; + + uint8_t item_090_primary = 0; if (mm->accuracy.nac_v_valid) - item_080_primary += mm->accuracy.nac_v << 5; + item_090_primary += mm->accuracy.nac_v << 5; if (mm->cpr_decoded) - item_080_primary += mm->cpr_nucp << 1; - int item_080_ext1 = 0; + item_090_primary += mm->cpr_nucp << 1; + uint8_t item_090_ext1 = 0; if (mm->accuracy.nic_baro_valid) - item_080_ext1 += mm->accuracy.nic_baro << 7; + item_090_ext1 += mm->accuracy.nic_baro << 7; if (mm->accuracy.sil_type != SIL_INVALID) - item_080_ext1 += mm->accuracy.sil << 5; + item_090_ext1 += mm->accuracy.sil << 5; if (mm->accuracy.nac_p_valid) - item_080_ext1 += mm->accuracy.nac_p << 1; - if (item_080_ext1){ - msgLen++; - item_080_primary++; + item_090_ext1 += mm->accuracy.nac_p << 1; + if (item_090_ext1){ + item_090_primary++; } - int item_080_ext2 = 0; + uint8_t item_090_ext2 = 0; if (mm->accuracy.sil_type == SIL_PER_SAMPLE) - item_080_ext2 += 1 << 5; + item_090_ext2 += 1 << 5; if (mm->accuracy.sda_valid) - item_080_ext2 += mm->accuracy.sda << 3; + item_090_ext2 += mm->accuracy.sda << 3; if (mm->accuracy.gva_valid) - item_080_ext2 += mm->accuracy.gva << 1; - if (item_080_ext2){ - msgLen++; - item_080_ext1++; + item_090_ext2 += mm->accuracy.gva << 1; + if (item_090_ext2){ + item_090_ext1++; } + //fspec[2] |= 1UL << 4; - item_210 = false; - - uint16_t item_070_value; + uint16_t item_070_value = 0; if(mm->squawk_valid){ - msgLen +=2; - item_070 = true; + fspec[2] |= 1UL << 3; item_070_value = mm->squawk; } - int16_t item_145_value; + int16_t item_145_value = 0; if(mm->baro_alt_valid){ - msgLen +=2; - item_145 = true; - item_145_value = mm->baro_alt * 4; + fspec[2] |= 1UL << 1; + item_145_value = mm->baro_alt / 25; if (mm->baro_alt_unit == UNIT_METERS) - item_145_value = (int)(mm-> baro_alt * 3.2808) + item_145_value = (int)(mm-> baro_alt * 3.2808); } - uint16_t item_152_value; + uint16_t item_152_value = 0; if(mm->heading_valid && mm->heading_type == HEADING_MAGNETIC){ - item_152 = true; - msgLen +=2; + fspec[3] |= 1UL << 7; item_152_value = mm->heading * (pow(2,16) / 360); } uint8_t item_200_value = 0; if (mm->nav.modes_valid){ - if (mm->nav.modes && 0b00000010) + if (mm->nav.modes & 0b00000010) item_200_value += 1 << 6; } if (mm->emergency_valid) @@ -1934,66 +1915,53 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { item_200_value += (mm->alert); else if (mm->spi_valid && mm->spi) item_200_value +=3; - if (item_200_value){ - item_200 = true; - msgLen++; + if (mm->spi_valid || mm->alert_valid || mm->emergency_valid || mm->nav.modes_valid){ + fspec[3] |= 1UL << 6; } uint16_t item_155_value = 0; if (mm->baro_rate_valid){ - item_155 = true; - msgLen += 2; - double adj_baro_rate = mm->baro_rate * 3.125; - item_155_value = (adj_baro_rate >> 1); + fspec[3] |= 1UL << 5; + item_155_value = ((int16_t)(mm->baro_rate / 3.125)) >> 1; } uint16_t item_157_value = 0; if (mm->geom_rate_valid){ - item_157 = true; - msgLen += 2; - double adj_geom_rate = mm->geom_rate * 3.125; - item_157_value = (adj_geom_rate >> 1); + fspec[3] |= 1UL << 4; + item_157_value = ((int16_t)(mm->geom_rate / 3.125)) >> 1; } uint32_t item_160_value = 0; - if (mm->gs_valid && mm->track_valid && mm->calculated_track != -1){ - item_160 = true; - msgLen += 4; + if (mm->gs_valid && mm->track_valid && mm->calculated_track != -1 && mm->heading_type == HEADING_GROUND_TRACK){ + fspec[3] |= 1UL << 3; double adj_gs = mm->gs.v0 * 4.5511; item_160_value += ((int)adj_gs << 16); - double adj_trk = mm->track * 182.0444; + double adj_trk = mm->heading * 182.0444; item_160_value += ((uint16_t)adj_trk); } - - item_077 = true; - msgLen += 3; - int midnight = (time / 86400) * 86400; +/* + fspec[3] |= 1UL << 1; + long midnight = ((long)time / 86400L) * 86400000L; int item_077_value = time - midnight; - +*/ uint64_t item_170_value = 0; if(mm->callsign_valid){ - item_170 = true; - msgLen += 6; + fspec[4] |= 1UL << 7; for (int i = 0; i < 7; i++) { - char *letter = strchr(ais_charset, mm->callsign[i]); - if (letter){ - item_170_value = item_170_value << 6; - item_170_value += (letter - ais_charset); - } + uint8_t ch = char_to_ais(mm->callsign[i]); + item_170_value = (item_170_value << 6) + (ch & 0x3F); } } - uint8_t item_020_value; + uint8_t item_020_value = 0; if (mm->category_valid){ - item_020 = true; - msgLen += 1; + fspec[4] |= 1UL << 6; item_020_value = mm->category; } uint8_t item_008_value = 0; if (mm->opstatus.valid){ - item_008 = true; - msgLen += 1; + fspec[5] |= 1UL << 7; item_008_value += (mm->opstatus.om_acas_ra << 7); item_008_value += (mm->opstatus.cc_tc << 5); item_008_value += (mm->opstatus.cc_ts << 4); @@ -2001,14 +1969,166 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { item_008_value += (mm->opstatus.cc_cdti << 2); } - char *p = prepareWrite(&Modes.asterix_out, msgLen * 2); - memset(p, &category, 1); - p += 1; - memcpy(p, &msgLen, 2); - p += 1; - completeWrite(&Modes.asterix_out, p); + for (int i = 5; i >= 0; i--) + { + if (fspec[i + 1]){ + fspec[i] |= 1; + } + } + unsigned char bytes[Modes.net_output_flush_size]; + for (int i = 0; i < Modes.net_output_flush_size; i++){ + bytes[i] = 0; + } + int p = 4; + for (size_t i = 1; i < 7; i++) + { + if (fspec[i]){ + bytes[p] = fspec[i]; + p++; + //printf("%u", p); printf("%s", "/"); printf("%u", msgLen);printf("%s", " fp"); printf("%lu", i); printf("%s", " "); + } + } + bytes[0] = category; + bytes[3] = fspec[0]; + if (fspec[0] & 0b10000000){ + bytes[p] = (item_010_value >> 8) & 0xFF; + bytes[p + 1] = (item_010_value) & 0xFF; + p += 2; + // diag + } + if (fspec[0] & 0b01000000){ + bytes[p] = item_040_primary; + p++; + // diag + if(item_040_primary & 0x1){ + bytes[p] = item_040_ext1; + p++; + // diag + } + } + if (fspec[0] & 0b00000010){ + bytes[p] = (item_131_value >> 56) & 0xFF; + bytes[p + 1] = (item_131_value >> 48) & 0xFF; + bytes[p + 2] = (item_131_value >> 40) & 0xFF; + bytes[p + 3] = (item_131_value >> 32) & 0xFF; + bytes[p + 4] = (item_131_value >> 24) & 0xFF; + bytes[p + 5] = (item_131_value >> 16) & 0xFF; + bytes[p + 6] = (item_131_value >> 8) & 0xFF; + bytes[p + 7] = (item_131_value) & 0xFF; + p += 8; + // diag + } + if (fspec[1] & 0b01000000){ + bytes[p] = (item_150_value >> 8) & 0xFF; + bytes[p + 1] = (item_150_value) & 0xFF; + p += 2; + // diag + } + if (fspec[1] & 0b00100000){ + bytes[p] = (item_151_value >> 8) & 0xFF; + bytes[p + 1] = (item_151_value) & 0xFF; + p += 2; + // diag + } + if (fspec[1] & 0b00010000){ + bytes[p] = (item_080_value >> 16) & 0xFF; + bytes[p + 1] = (item_080_value >> 8) & 0xFF; + bytes[p + 2] = (item_080_value) & 0xFF; + p += 3; + // diag + } + if (fspec[1] & 0b00001000){ + bytes[p] = (item_073_value >> 16) & 0xFF; + bytes[p + 1] = (item_073_value >> 8) & 0xFF; + bytes[p + 2] = (item_073_value) & 0xFF; + p += 3; + } + if (fspec[2] & 0b01000000){ + bytes[p] = (item_140_value >> 8) & 0xFF; + bytes[p + 1] = (item_140_value) & 0xFF; + p += 2; + } + if (fspec[2] & 0b00100000){ + bytes[p] = item_090_primary; + p++; + if(item_090_ext1){ + bytes[p] = item_090_ext1; + p++; + if(item_090_ext2){ + bytes[p] = item_090_ext2; + p++; + } + } + } + if (fspec[2] & 0b00001000){ + bytes[p] = (item_070_value >> 8) & 0xFF; + bytes[p + 1] = (item_070_value) & 0xFF; + p += 2; + } + if (fspec[2] & 0b00000010){ + bytes[p] = (item_145_value >> 8) & 0xFF; + bytes[p + 1] = (item_145_value) & 0xFF; + p += 2; + } + if (fspec[3] & 0b10000000){ + bytes[p] = (item_152_value >> 8) & 0xFF; + bytes[p + 1] = (item_152_value) & 0xFF; + p += 2; + } + if (fspec[3] & 0b01000000){ + bytes[p] = item_200_value; + p ++; + } + if (fspec[3] & 0b00100000){ + bytes[p] = (item_155_value >> 8) & 0xFF; + bytes[p + 1] = (item_155_value) & 0xFF; + p += 2; + } + if (fspec[3] & 0b00010000){ + bytes[p] = (item_157_value >> 8) & 0xFF; + bytes[p + 1] = (item_157_value) & 0xFF; + p += 2; + } + if (fspec[3] & 0b00001000){ + bytes[p] = (item_160_value >> 24) & 0xFF; + bytes[p + 1] = (item_160_value >> 16) & 0xFF; + bytes[p + 2] = (item_160_value >> 8) & 0xFF; + bytes[p + 3] = (item_160_value) & 0xFF; + p += 4; + }/* + if (fspec[3] && 0b00000010){ + memcpy(p, &item_077_value, 3); + p += 3; + }*/ + if (fspec[4] & 0b10000000){ + bytes[p] = (uint8_t)((item_170_value >> 40) & 0xFF); + bytes[p + 1] = (uint8_t)((item_170_value >> 32) & 0xFF); + bytes[p + 2] = (uint8_t)((item_170_value >> 24) & 0xFF); + bytes[p + 3] = (uint8_t)((item_170_value >> 16) & 0xFF); + bytes[p + 4] = (uint8_t)((item_170_value >> 8) & 0xFF); + bytes[p + 5] = (uint8_t)((item_170_value) & 0xFF); + p += 6; + } + if (fspec[4] & 0b01000000){ + bytes[p] = item_020_value; + p++; + } + if (fspec[5] & 0b10000000){ + bytes[p] = item_008_value; + p++; + } + + uint16_t msgLen = p; + bytes[1] = (msgLen >> 8) & 0xFF; + bytes[2] = msgLen & 0xFF; + char *w = prepareWrite(&Modes.asterix_out, msgLen); + memcpy(w, &bytes, msgLen); + w += msgLen; + completeWrite(&Modes.asterix_out, w); + } } + // //========================================================================= // @@ -2810,7 +2930,7 @@ static int handleBeastCommand(struct client *c, char *p, int remote, int64_t now // // to save a couple cycles we remove the escapes in the calling function and expect nonescaped messages here static int decodeBinMessage(struct client *c, char *p, int remote, int64_t now, struct messageBuffer *mb) { - int msgLen = 0; + uint16_t msgLen = 0; int j; unsigned char ch; struct modesMessage *mm = netGetMM(mb); @@ -4558,6 +4678,9 @@ static void outputMessage(struct modesMessage *mm) { if (Modes.dump_fw && (!Modes.dump_reduce || mm->reduce_forward)) { modesDumpBeastData(mm); } + if (Modes.asterix_out.connections){ + modesSendAsterixOutput(mm); + } } // In non-interactive non-quiet mode, display messages on standard output diff --git a/readsb.c b/readsb.c index 4c61690c..30aa5689 100644 --- a/readsb.c +++ b/readsb.c @@ -1597,6 +1597,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { sfree(Modes.net_input_beast_ports); Modes.net_input_beast_ports = strdup(arg); break; + case OptNetAsteriskOutPorts: + sfree(Modes.net_output_asterix_ports); + Modes.net_output_asterix_ports = strdup(arg); + break; case OptNetBeastReducePorts: sfree(Modes.net_output_beast_reduce_ports); Modes.net_output_beast_reduce_ports = strdup(arg); diff --git a/readsb.h b/readsb.h index 2ad49af3..2b4f70fa 100644 --- a/readsb.h +++ b/readsb.h @@ -738,6 +738,7 @@ struct _Modes char *net_input_beast_ports; // List of Beast input TCP ports char *net_output_beast_ports; // List of Beast output TCP ports char *net_output_beast_reduce_ports; // List of Beast output TCP ports + char *net_output_asterix_ports; // List of Asterix output TCP ports char *net_output_json_ports; char *net_output_api_ports; char *garbage_ports; @@ -1156,6 +1157,8 @@ enum { OptNetJaeroInPorts, OptNetBiPorts, OptNetBoPorts, + OptNetAsteriskInPorts, + OptNetAsteriskOutPorts, OptNetBeastReducePorts, OptNetBeastReduceInterval, OptNetBeastReduceFilterAlt, From 23c37ad89c18ff00d2df7ff8b8a75dabadd16093 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Mon, 3 Apr 2023 20:08:20 -0400 Subject: [PATCH 03/32] fix squawk, add MOPS --- net_io.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/net_io.c b/net_io.c index ed387040..4cc922a9 100644 --- a/net_io.c +++ b/net_io.c @@ -1883,11 +1883,25 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { item_090_ext1++; } //fspec[2] |= 1UL << 4; + uint8_t item_210_value = 0; + if (mm->opstatus.valid == 0){ + fspec[2] |= 1UL << 4; + item_210_value += mm->opstatus.version << 3; + if (mm->opstatus.cc_uat_in) + item_210_value += 1; + else if (mm->opstatus.cc_1090_in) + item_210_value += 2; + } + uint16_t item_070_value = 0; if(mm->squawk_valid){ fspec[2] |= 1UL << 3; - item_070_value = mm->squawk; + int squawk = mm->squawk; + item_070_value += (squawk & 0x7000) >> 3; + item_070_value += (squawk & 0x700) >> 2; + item_070_value += (squawk & 0x70) >> 1; + item_070_value += (squawk & 0x7); } int16_t item_145_value = 0; @@ -2060,6 +2074,10 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { } } } + if (fspec[2] & 0b00010000){ + bytes[p] = (item_210_value); + p += 1; + } if (fspec[2] & 0b00001000){ bytes[p] = (item_070_value >> 8) & 0xFF; bytes[p + 1] = (item_070_value) & 0xFF; From 35a854d44db7a45024297f9278bb62bcf99d29fc Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Tue, 4 Apr 2023 08:25:42 -0400 Subject: [PATCH 04/32] WIP redoing how the bytes are written --- net_io.c | 158 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 81 insertions(+), 77 deletions(-) diff --git a/net_io.c b/net_io.c index 1b6ea611..d2ee4431 100644 --- a/net_io.c +++ b/net_io.c @@ -1770,43 +1770,42 @@ static void modesSendRawOutput(struct modesMessage *mm) { // static void modesSendAsterixOutput(struct modesMessage *mm) { uint8_t category; + unsigned char bytes[Modes.net_output_flush_size * 2]; + for (int i = 0; i < Modes.net_output_flush_size * 2; i++){ + bytes[i] = 0; + } + int p = 0; if (mm->from_mlat) // CAT 20 return; if (mm->from_tisb) return; else { // CAT 21 - category = 21; + bytes[0] = 21; uint8_t fspec[7]; for (size_t i = 0; i < 7; i++) { fspec[i] = 0; } fspec[0] |= 1UL << 7; - uint8_t sac = 000; - uint8_t sic = 001; - uint16_t item_010_value = (sac << 8) + sic; + bytes[p++] = 000; //SAC + bytes[p++] = 001; //SIC fspec[0] |= 1UL << 6; - uint item_040_primary; - if (mm->addrtype <= 3 ) - item_040_primary = 0; - else - item_040_primary = 3; - item_040_primary *= 32; + if (mm->addrtype >= 3 ) + bytes[p] |= (3 << 5); + if (mm->alt_q_bit == 0) - item_040_primary += 8; - uint item_040_ext1 = 0; + bytes[p] |= 3; + if (mm->airground == AG_GROUND) - item_040_ext1 += 64; - /* - if (mm->opstatus.valid == 0) - item_040_ext1 +=2; - */ - if (item_040_ext1){ - item_040_primary += 1; - } - uint64_t item_131_value = 0; + bytes[p + 1] |= 1 << 6; + if (bytes[p + 1]){ + bytes[p] |= 1; + p++ + } + p++; + if(mm->cpr_decoded){ fspec[0] |= 1UL << 1; fspec[1] |= 1UL << 3; @@ -1814,108 +1813,117 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { int32_t lon; lat = mm->decoded_lat / (180 / pow(2,30)); lon = mm->decoded_lon / (180 / pow(2,30)); - item_131_value = ((unsigned long long)lat << 32) + lon; + bytes[p++] = (lat & 0xFF000000) >> 24; + bytes[p++] = (lat & 0xFF0000) >> 16; + bytes[p++] = (lat & 0xFF00) >> 8; + bytes[p++] = (lat & 0xFF); + bytes[p++] = (lon & 0xFF000000) >> 24; + bytes[p++] = (lon & 0xFF0000) >> 16; + bytes[p++] = (lon & 0xFF00) >> 8; + bytes[p++] = (lon & 0xFF); } - uint16_t item_150_value = 0x69; if(mm->ias_valid || mm->mach_valid){ - fspec[1] |= 1UL << 6;; + fspec[1] |= 1UL << 6; + uint16_t speedval; if (mm->mach_valid){ - item_150_value = (1 << 15); - item_150_value += mm->mach * 1000; + bytes[p] = (1 << 15); + speedval = mm->mach * 1000; } else{ - item_150_value = ((mm->ias) / 3600) * pow(2,14); + speedval = (mm->ias / 3600) * pow(2,14); } + bytes[p++] |= (speedval & 0x7f00) >> 8; + bytes[p++] = (speedval & 0xff); } - uint16_t item_151_value = 0x42; if(mm->tas_valid){ fspec[1] |= 1UL << 5; - item_151_value = mm->tas; + bytes[p++] = (mm->tas & 0x7f00) >> 8; + bytes[p++] = (mm->tas & 0xff); } fspec[1] |= 1UL << 4; - uint item_080_value = mm->addr; - int item_073_value = 0; + bytes[p++] = (mm->addr & 0xff0000) >> 16; + bytes[p++] = (mm->addr & 0xff00) >> 16; + bytes[p++] = (mm->addr & 0xff); if (fspec[1] & 0b1000){ long midnight = (long)(time(NULL) / 86400) * 86400000; - item_073_value = (mm->sysTimestamp) - midnight; - if (item_073_value < 0) - item_073_value += 86400; - item_073_value = (int)(item_073_value * 0.128); + int tsm = (mm->sysTimestamp) - midnight; + if (tsm < 0) + tsm += 86400; + tsm = (int)(tsm * 0.128); + bytes[p++] = (tsm & 0xff00) >> 8; + bytes[p++] = tsm & 0xff; } //fspec[1] |= 1UL << 1; - int16_t item_140_value = 0; if (mm->geom_alt_valid){ fspec[2] |= 1UL << 6; + int16_t alt; if(mm->geom_alt_unit == UNIT_FEET) - item_140_value = mm->geom_alt / 6.25; + alt = mm->geom_alt / 6.25; else - item_140_value = mm->geom_alt / 20.5053; + alt = mm->geom_alt / 20.5053; + bytes[p++] = (alt & 0xff00) >> 8; + bytes[p++] = alt & 0xff; } fspec[2] |= 1UL << 5; - uint8_t item_090_primary = 0; if (mm->accuracy.nac_v_valid) - item_090_primary += mm->accuracy.nac_v << 5; + bytes[p] += mm->accuracy.nac_v << 5; if (mm->cpr_decoded) - item_090_primary += mm->cpr_nucp << 1; - uint8_t item_090_ext1 = 0; + bytes[p] |= mm->cpr_nucp << 1; if (mm->accuracy.nic_baro_valid) - item_090_ext1 += mm->accuracy.nic_baro << 7; + bytes[p + 1] |= mm->accuracy.nic_baro << 7; if (mm->accuracy.sil_type != SIL_INVALID) - item_090_ext1 += mm->accuracy.sil << 5; + bytes[p + 1] |= mm->accuracy.sil << 5; if (mm->accuracy.nac_p_valid) - item_090_ext1 += mm->accuracy.nac_p << 1; - if (item_090_ext1){ - item_090_primary++; + bytes[p + 1] |= mm->accuracy.nac_p << 1; + if (bytes[p + 1]){ + bytes[p] |= 1; + p++; } uint8_t item_090_ext2 = 0; if (mm->accuracy.sil_type == SIL_PER_SAMPLE) - item_090_ext2 += 1 << 5; + bytes[p + 1] |= 1 << 5; if (mm->accuracy.sda_valid) - item_090_ext2 += mm->accuracy.sda << 3; + bytes[p + 1] |= mm->accuracy.sda << 3; if (mm->accuracy.gva_valid) - item_090_ext2 += mm->accuracy.gva << 1; - if (item_090_ext2){ - item_090_ext1++; + bytes[p + 1] |= mm->accuracy.gva << 1; + if (bytes[p + 1]){ + bytes[p] |= 1; + p++; } //fspec[2] |= 1UL << 4; - uint8_t item_210_value = 0; if (mm->opstatus.valid == 0){ fspec[2] |= 1UL << 4; - item_210_value += mm->opstatus.version << 3; - if (mm->opstatus.cc_uat_in) - item_210_value += 1; - else if (mm->opstatus.cc_1090_in) - item_210_value += 2; + bytes[p++] += mm->opstatus.version << 3; } - - - uint16_t item_070_value = 0; if(mm->squawk_valid){ fspec[2] |= 1UL << 3; int squawk = mm->squawk; - item_070_value += (squawk & 0x7000) >> 3; - item_070_value += (squawk & 0x700) >> 2; - item_070_value += (squawk & 0x70) >> 1; - item_070_value += (squawk & 0x7); + bytes[p] |= (squawk & 0x700) >> 3; + bytes[p++] |= (squawk & 0x400) >> 2; + bytes[p] |= (squawk & 0x300) >> 2; + bytes[p] |= (squawk & 0x70) >> 1; + bytes[p++] |= (squawk & 0x7); } - int16_t item_145_value = 0; if(mm->baro_alt_valid){ fspec[2] |= 1UL << 1; - item_145_value = mm->baro_alt / 25; + int16_t value = mm->baro_alt / 25; if (mm->baro_alt_unit == UNIT_METERS) - item_145_value = (int)(mm-> baro_alt * 3.2808); + value = (int)(mm-> baro_alt * 3.2808); + bytes[p++] = (value & 0xff00) >> 8; + bytes[p++] = value & 0xff; } - uint16_t item_152_value = 0; if(mm->heading_valid && mm->heading_type == HEADING_MAGNETIC){ fspec[3] |= 1UL << 7; - item_152_value = mm->heading * (pow(2,16) / 360); + uint16_t value = mm->heading * (pow(2,16) / 360); + bytes[p++] = (value & 0xff00) >> 8; + bytes[p++] = value & 0xff; } uint8_t item_200_value = 0; @@ -1989,11 +1997,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { fspec[i] |= 1; } } - unsigned char bytes[Modes.net_output_flush_size]; - for (int i = 0; i < Modes.net_output_flush_size; i++){ - bytes[i] = 0; - } - int p = 4; + for (size_t i = 1; i < 7; i++) { if (fspec[i]){ @@ -2002,8 +2006,8 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { //printf("%u", p); printf("%s", "/"); printf("%u", msgLen);printf("%s", " fp"); printf("%lu", i); printf("%s", " "); } } - bytes[0] = category; - bytes[3] = fspec[0]; + //bytes[0] = category; + //bytes[3] = fspec[0]; if (fspec[0] & 0b10000000){ bytes[p] = (item_010_value >> 8) & 0xFF; bytes[p + 1] = (item_010_value) & 0xFF; From bfc3ad8a9e00a6d3f43294898e60689d47e9a715 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Tue, 4 Apr 2023 20:07:29 -0400 Subject: [PATCH 05/32] Asterix CAT021 mostly working --- net_io.c | 376 +++++++++++++++++++++++-------------------------------- 1 file changed, 156 insertions(+), 220 deletions(-) diff --git a/net_io.c b/net_io.c index d2ee4431..90096f4f 100644 --- a/net_io.c +++ b/net_io.c @@ -1766,7 +1766,7 @@ static void modesSendRawOutput(struct modesMessage *mm) { // //========================================================================= // -// Write raw output to TCP clients +// Write ASTERIX output to TCP clients // static void modesSendAsterixOutput(struct modesMessage *mm) { uint8_t category; @@ -1780,35 +1780,36 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { if (mm->from_tisb) return; else { // CAT 21 - bytes[0] = 21; + category = 21; uint8_t fspec[7]; for (size_t i = 0; i < 7; i++) { fspec[i] = 0; } - fspec[0] |= 1UL << 7; + // I021/010 Data Source Identification + fspec[0] |= 1 << 7; bytes[p++] = 000; //SAC bytes[p++] = 001; //SIC - fspec[0] |= 1UL << 6; - + // I021/040 Target Report Descriptor + fspec[0] |= 1 << 6; if (mm->addrtype >= 3 ) bytes[p] |= (3 << 5); if (mm->alt_q_bit == 0) - bytes[p] |= 3; + bytes[p] |= (1 << 3); if (mm->airground == AG_GROUND) bytes[p + 1] |= 1 << 6; if (bytes[p + 1]){ bytes[p] |= 1; - p++ + p++; } p++; + // I021/131 Position in WGS-84 co-ordinates, high res. if(mm->cpr_decoded){ - fspec[0] |= 1UL << 1; - fspec[1] |= 1UL << 3; + fspec[0] |= 1 << 1; int32_t lat; int32_t lon; lat = mm->decoded_lat / (180 / pow(2,30)); @@ -1822,12 +1823,12 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { bytes[p++] = (lon & 0xFF00) >> 8; bytes[p++] = (lon & 0xFF); } - + // I021/150 Air Speed if(mm->ias_valid || mm->mach_valid){ - fspec[1] |= 1UL << 6; + fspec[1] |= 1 << 6; uint16_t speedval; if (mm->mach_valid){ - bytes[p] = (1 << 15); + bytes[p] = (1 << 7); speedval = mm->mach * 1000; } else{ @@ -1836,29 +1837,49 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { bytes[p++] |= (speedval & 0x7f00) >> 8; bytes[p++] = (speedval & 0xff); } + + // I021/151 True Air Speed if(mm->tas_valid){ - fspec[1] |= 1UL << 5; + fspec[1] |= 1 << 5; bytes[p++] = (mm->tas & 0x7f00) >> 8; bytes[p++] = (mm->tas & 0xff); } - fspec[1] |= 1UL << 4; + + // I021/080 Target Address + fspec[1] |= 1 << 4; bytes[p++] = (mm->addr & 0xff0000) >> 16; - bytes[p++] = (mm->addr & 0xff00) >> 16; + bytes[p++] = (mm->addr & 0xff00) >> 8; bytes[p++] = (mm->addr & 0xff); - if (fspec[1] & 0b1000){ + + // I021/073 Time of Message Reception of Position + if (fspec[0] & 0b10){ + fspec[1] |= 1 << 3; long midnight = (long)(time(NULL) / 86400) * 86400000; int tsm = (mm->sysTimestamp) - midnight; if (tsm < 0) - tsm += 86400; + tsm += 86400000; tsm = (int)(tsm * 0.128); + bytes[p++] = (tsm & 0xff0000) >> 16; bytes[p++] = (tsm & 0xff00) >> 8; bytes[p++] = tsm & 0xff; } - //fspec[1] |= 1UL << 1; + // I021/075 Time of Message Reception of Velocity + if (mm->gs_valid && mm->heading_valid && mm->heading_type == HEADING_GROUND_TRACK){ + fspec[1] |= 1 << 1; + long midnight = (long)(time(NULL) / 86400) * 86400000; + int tsm = (mm->sysTimestamp) - midnight; + if (tsm < 0) + tsm += 86400000; + tsm = (int)(tsm * 0.128); + bytes[p++] = (tsm & 0xff0000) >> 16; + bytes[p++] = (tsm & 0xff00) >> 8; + bytes[p++] = tsm & 0xff; + } + // I021/140 Geometric Height if (mm->geom_alt_valid){ - fspec[2] |= 1UL << 6; + fspec[2] |= 1 << 6; int16_t alt; if(mm->geom_alt_unit == UNIT_FEET) alt = mm->geom_alt / 6.25; @@ -1868,8 +1889,8 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { bytes[p++] = alt & 0xff; } - fspec[2] |= 1UL << 5; - + // I021/090 Quality Indicators + fspec[2] |= 1 << 5; if (mm->accuracy.nac_v_valid) bytes[p] += mm->accuracy.nac_v << 5; if (mm->cpr_decoded) @@ -1884,7 +1905,6 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { bytes[p] |= 1; p++; } - uint8_t item_090_ext2 = 0; if (mm->accuracy.sil_type == SIL_PER_SAMPLE) bytes[p + 1] |= 1 << 5; if (mm->accuracy.sda_valid) @@ -1895,23 +1915,36 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { bytes[p] |= 1; p++; } - //fspec[2] |= 1UL << 4; - if (mm->opstatus.valid == 0){ - fspec[2] |= 1UL << 4; - bytes[p++] += mm->opstatus.version << 3; + p++; + + // I021/210 MOPS Version + if (mm->opstatus.valid){ + fspec[2] |= 1 << 4; + bytes[p++] += (mm->opstatus.version) << 3; } + + // I021/070 Mode 3/A Code if(mm->squawk_valid){ - fspec[2] |= 1UL << 3; - int squawk = mm->squawk; - bytes[p] |= (squawk & 0x700) >> 3; - bytes[p++] |= (squawk & 0x400) >> 2; - bytes[p] |= (squawk & 0x300) >> 2; - bytes[p] |= (squawk & 0x70) >> 1; - bytes[p++] |= (squawk & 0x7); + fspec[2] |= 1 << 3; + uint16_t squawk = mm->squawk; + bytes[p] |= ((squawk & 0x7000)) >> 11; + bytes[p++] |= ((squawk & 0x0400)) >> 10; + bytes[p] |= ((squawk & 0x0300)) >> 2; + bytes[p] |= ((squawk & 0x0070)) >> 1; + bytes[p++] |= ((squawk & 0x0007)); + } + + // I021/230 Roll Angle + if(mm->roll_valid){ + fspec[2] |= 1 << 2; + int16_t roll = mm->roll * 100; + bytes[p++] = (roll & 0xFF00) >> 8; + bytes[p++] = (roll & 0xFF); } + // I021/145 Flight Level if(mm->baro_alt_valid){ - fspec[2] |= 1UL << 1; + fspec[2] |= 1 << 1; int16_t value = mm->baro_alt / 25; if (mm->baro_alt_unit == UNIT_METERS) value = (int)(mm-> baro_alt * 3.2808); @@ -1919,85 +1952,115 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { bytes[p++] = value & 0xff; } + // I021/152 Magnetic Heading if(mm->heading_valid && mm->heading_type == HEADING_MAGNETIC){ - fspec[3] |= 1UL << 7; - uint16_t value = mm->heading * (pow(2,16) / 360); - bytes[p++] = (value & 0xff00) >> 8; - bytes[p++] = value & 0xff; + fspec[3] |= 1 << 7; + double adj_trk = mm->heading * 182.0444; + uint16_t trk = (int)adj_trk; + bytes[p++] = (trk & 0xff00) >> 8; + bytes[p++] = trk & 0xff; } - uint8_t item_200_value = 0; - if (mm->nav.modes_valid){ - if (mm->nav.modes & 0b00000010) - item_200_value += 1 << 6; - } - if (mm->emergency_valid) - item_200_value += (mm->emergency << 2); - if (mm->alert_valid) - item_200_value += (mm->alert); - else if (mm->spi_valid && mm->spi) - item_200_value +=3; + // I021/200 Target Status if (mm->spi_valid || mm->alert_valid || mm->emergency_valid || mm->nav.modes_valid){ - fspec[3] |= 1UL << 6; + fspec[3] |= 1 << 6; + if (mm->nav.modes_valid){ + if (mm->nav.modes & 0b00000010) + bytes[p] |= 1 << 6; + } + if (mm->emergency_valid) + bytes[p] |= (mm->emergency << 2); + if (mm->alert_valid) + bytes[p] |= (mm->alert); + else if (mm->spi_valid && mm->spi) + bytes[p] |=3; + p++; } - uint16_t item_155_value = 0; + // I021/155 Barometric Vertical Rate if (mm->baro_rate_valid){ - fspec[3] |= 1UL << 5; - item_155_value = ((int16_t)(mm->baro_rate / 3.125)) >> 1; + fspec[3] |= 1 << 5; + int value = ((int16_t)(mm->baro_rate / 3.125)) >> 1; + bytes[p++] = (value & 0xff00) >> 8; + bytes[p++] = value & 0xff; } - uint16_t item_157_value = 0; + // I021/157 Geometric Vertical Rate if (mm->geom_rate_valid){ - fspec[3] |= 1UL << 4; - item_157_value = ((int16_t)(mm->geom_rate / 3.125)) >> 1; + fspec[3] |= 1 << 4; + int value = ((int16_t)(mm->geom_rate / 3.125)) >> 1; + bytes[p++] = (value & 0xff00) >> 8; + bytes[p++] = value & 0xff; } - uint32_t item_160_value = 0; - if (mm->gs_valid && mm->track_valid && mm->calculated_track != -1 && mm->heading_type == HEADING_GROUND_TRACK){ - fspec[3] |= 1UL << 3; + // I021/160 Airborne Ground Vector + if (mm->gs_valid && mm->heading_valid && mm->heading_type == HEADING_GROUND_TRACK){ + fspec[3] |= 1 << 3; double adj_gs = mm->gs.v0 * 4.5511; - item_160_value += ((int)adj_gs << 16); + bytes[p++] = ((int)adj_gs & 0xff00) >> 8; + bytes[p++] = (int)adj_gs & 0xff; double adj_trk = mm->heading * 182.0444; - item_160_value += ((uint16_t)adj_trk); + uint16_t trk = (int)adj_trk; + bytes[p++] = (trk & 0xff00) >> 8; + bytes[p++] = trk & 0xff; } -/* - fspec[3] |= 1UL << 1; - long midnight = ((long)time / 86400L) * 86400000L; - int item_077_value = time - midnight; -*/ - uint64_t item_170_value = 0; + + // I021/077 Time of Report Transmission + { + fspec[3] |= 1 << 1; + long midnight = (long)(time(NULL) / 86400) * 86400000; + int tsm = mstime() - midnight; + if (tsm < 0) + tsm += 86400000; + tsm = (int)(tsm * 0.128); + bytes[p++] = (tsm & 0xff0000) >> 16; + bytes[p++] = (tsm & 0xff00) >> 8; + bytes[p++] = tsm & 0xff; + } + + // I021/170 Target Identification if(mm->callsign_valid){ - fspec[4] |= 1UL << 7; - for (int i = 0; i < 7; i++) + fspec[4] |= 1 << 7; + uint64_t enc_callsign = 0; + for (int i = 0; i <= 7; i++) { uint8_t ch = char_to_ais(mm->callsign[i]); - item_170_value = (item_170_value << 6) + (ch & 0x3F); + enc_callsign = (enc_callsign << 6) + (ch & 0x3F); } + bytes[p++] = (enc_callsign & 0xff0000000000) >> 40; + bytes[p++] = (enc_callsign & 0xff00000000) >> 32; + bytes[p++] = (enc_callsign & 0xff000000) >> 24; + bytes[p++] = (enc_callsign & 0xff0000) >> 16; + bytes[p++] = (enc_callsign & 0xff00) >> 8; + bytes[p++] = (enc_callsign & 0xff); } - uint8_t item_020_value = 0; + + // I021/020 Emitter Category if (mm->category_valid){ - fspec[4] |= 1UL << 6; - item_020_value = mm->category; + fspec[4] |= 1 << 6; + bytes[p++] = mm->category; } - uint8_t item_008_value = 0; + // I021/008 Aircraft Operational Status if (mm->opstatus.valid){ - fspec[5] |= 1UL << 7; - item_008_value += (mm->opstatus.om_acas_ra << 7); - item_008_value += (mm->opstatus.cc_tc << 5); - item_008_value += (mm->opstatus.cc_ts << 4); - item_008_value += (mm->opstatus.cc_arv << 3); - item_008_value += (mm->opstatus.cc_cdti << 2); + fspec[5] |= 1 << 7; + bytes[p] |= (mm->opstatus.om_acas_ra << 7); + bytes[p] |= (mm->opstatus.cc_tc << 5); + bytes[p] |= (mm->opstatus.cc_ts << 4); + bytes[p] |= (mm->opstatus.cc_arv << 3); + bytes[p] |= (mm->opstatus.cc_cdti << 2); + p++; } + int fspec_len = 1; for (int i = 5; i >= 0; i--) { if (fspec[i + 1]){ fspec[i] |= 1; + fspec_len++; } } - + /* for (size_t i = 1; i < 7; i++) { if (fspec[i]){ @@ -2005,147 +2068,20 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { p++; //printf("%u", p); printf("%s", "/"); printf("%u", msgLen);printf("%s", " fp"); printf("%lu", i); printf("%s", " "); } - } - //bytes[0] = category; - //bytes[3] = fspec[0]; - if (fspec[0] & 0b10000000){ - bytes[p] = (item_010_value >> 8) & 0xFF; - bytes[p + 1] = (item_010_value) & 0xFF; - p += 2; - // diag - } - if (fspec[0] & 0b01000000){ - bytes[p] = item_040_primary; - p++; - // diag - if(item_040_primary & 0x1){ - bytes[p] = item_040_ext1; - p++; - // diag - } - } - if (fspec[0] & 0b00000010){ - bytes[p] = (item_131_value >> 56) & 0xFF; - bytes[p + 1] = (item_131_value >> 48) & 0xFF; - bytes[p + 2] = (item_131_value >> 40) & 0xFF; - bytes[p + 3] = (item_131_value >> 32) & 0xFF; - bytes[p + 4] = (item_131_value >> 24) & 0xFF; - bytes[p + 5] = (item_131_value >> 16) & 0xFF; - bytes[p + 6] = (item_131_value >> 8) & 0xFF; - bytes[p + 7] = (item_131_value) & 0xFF; - p += 8; - // diag - } - if (fspec[1] & 0b01000000){ - bytes[p] = (item_150_value >> 8) & 0xFF; - bytes[p + 1] = (item_150_value) & 0xFF; - p += 2; - // diag - } - if (fspec[1] & 0b00100000){ - bytes[p] = (item_151_value >> 8) & 0xFF; - bytes[p + 1] = (item_151_value) & 0xFF; - p += 2; - // diag - } - if (fspec[1] & 0b00010000){ - bytes[p] = (item_080_value >> 16) & 0xFF; - bytes[p + 1] = (item_080_value >> 8) & 0xFF; - bytes[p + 2] = (item_080_value) & 0xFF; - p += 3; - // diag - } - if (fspec[1] & 0b00001000){ - bytes[p] = (item_073_value >> 16) & 0xFF; - bytes[p + 1] = (item_073_value >> 8) & 0xFF; - bytes[p + 2] = (item_073_value) & 0xFF; - p += 3; - } - if (fspec[2] & 0b01000000){ - bytes[p] = (item_140_value >> 8) & 0xFF; - bytes[p + 1] = (item_140_value) & 0xFF; - p += 2; - } - if (fspec[2] & 0b00100000){ - bytes[p] = item_090_primary; - p++; - if(item_090_ext1){ - bytes[p] = item_090_ext1; - p++; - if(item_090_ext2){ - bytes[p] = item_090_ext2; - p++; - } - } - } - if (fspec[2] & 0b00010000){ - bytes[p] = (item_210_value); - p += 1; - } - if (fspec[2] & 0b00001000){ - bytes[p] = (item_070_value >> 8) & 0xFF; - bytes[p + 1] = (item_070_value) & 0xFF; - p += 2; - } - if (fspec[2] & 0b00000010){ - bytes[p] = (item_145_value >> 8) & 0xFF; - bytes[p + 1] = (item_145_value) & 0xFF; - p += 2; - } - if (fspec[3] & 0b10000000){ - bytes[p] = (item_152_value >> 8) & 0xFF; - bytes[p + 1] = (item_152_value) & 0xFF; - p += 2; - } - if (fspec[3] & 0b01000000){ - bytes[p] = item_200_value; - p ++; - } - if (fspec[3] & 0b00100000){ - bytes[p] = (item_155_value >> 8) & 0xFF; - bytes[p + 1] = (item_155_value) & 0xFF; - p += 2; - } - if (fspec[3] & 0b00010000){ - bytes[p] = (item_157_value >> 8) & 0xFF; - bytes[p + 1] = (item_157_value) & 0xFF; - p += 2; - } - if (fspec[3] & 0b00001000){ - bytes[p] = (item_160_value >> 24) & 0xFF; - bytes[p + 1] = (item_160_value >> 16) & 0xFF; - bytes[p + 2] = (item_160_value >> 8) & 0xFF; - bytes[p + 3] = (item_160_value) & 0xFF; - p += 4; - }/* - if (fspec[3] && 0b00000010){ - memcpy(p, &item_077_value, 3); - p += 3; }*/ - if (fspec[4] & 0b10000000){ - bytes[p] = (uint8_t)((item_170_value >> 40) & 0xFF); - bytes[p + 1] = (uint8_t)((item_170_value >> 32) & 0xFF); - bytes[p + 2] = (uint8_t)((item_170_value >> 24) & 0xFF); - bytes[p + 3] = (uint8_t)((item_170_value >> 16) & 0xFF); - bytes[p + 4] = (uint8_t)((item_170_value >> 8) & 0xFF); - bytes[p + 5] = (uint8_t)((item_170_value) & 0xFF); - p += 6; - } - if (fspec[4] & 0b01000000){ - bytes[p] = item_020_value; - p++; - } - if (fspec[5] & 0b10000000){ - bytes[p] = item_008_value; - p++; - } - - uint16_t msgLen = p; - bytes[1] = (msgLen >> 8) & 0xFF; - bytes[2] = msgLen & 0xFF; + uint16_t msgLen = p + 3 + fspec_len; + uint8_t msgLenA = (msgLen & 0xFF00) >> 8; + uint8_t msgLenB = msgLen & 0xFF; char *w = prepareWrite(&Modes.asterix_out, msgLen); - memcpy(w, &bytes, msgLen); - w += msgLen; + memcpy(w, &category, 1); + w++; + memcpy(w, &msgLenA, 1); + memcpy(w + 1, &msgLenB, 1); + w+=2; + memcpy(w, &fspec, fspec_len); + w += fspec_len; + memcpy(w, &bytes, p); + w += p; completeWrite(&Modes.asterix_out, w); } From ebface6a93332af7404c6e3f5cd8ea69650ab41e Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Thu, 6 Apr 2023 07:42:19 -0400 Subject: [PATCH 06/32] Add met status, add asterix_reduce_out, prepare options for asterix_in --- help.h | 4 +++- net_io.c | 60 +++++++++++++++++++++++++++++++++++++++++++++----------- readsb.c | 6 +++++- readsb.h | 9 ++++++--- 4 files changed, 63 insertions(+), 16 deletions(-) diff --git a/help.h b/help.h index 53545819..a3029eed 100644 --- a/help.h +++ b/help.h @@ -120,7 +120,9 @@ static struct argp_option optionsReadsb[] = { {"net-only", OptNetOnly, 0, 0, "Enable just networking, no RTL device or file used", 2}, {"net-bind-address", OptNetBindAddr, "", 0, "IP address to bind to (default: Any; Use 127.0.0.1 for private)", 2}, {"net-bo-port", OptNetBoPorts, "", 0, "TCP Beast output listen ports (default: 0)", 2}, - {"net-ao-port", OptNetAsteriskOutPorts, "", 0, "TCP Asterisk output listen ports (default: 0)", 2}, + {"net-ao-port", OptNetAsterixOutPorts, "", 0, "TCP Asterix output listen ports (default: 0)", 2}, + {"net-ai-port", OptNetAsterixInPorts, "", 0, "TCP Asterix input listen ports (default: 0)", 2}, + {"net-asterix-reduce-out-port", OptNetAsterixReducePorts, "", 0, "TCP AsterixReduce output listen ports (default: 0)", 2}, {"net-ri-port", OptNetRiPorts, "", 0, "TCP raw input listen ports (default: 0)", 2}, {"net-ro-port", OptNetRoPorts, "", 0, "TCP raw output listen ports (default: 0)", 2}, {"net-sbs-port", OptNetSbsPorts, "", 0, "TCP BaseStation output listen ports (default: 0)", 2}, diff --git a/net_io.c b/net_io.c index 90096f4f..59a80c2e 100644 --- a/net_io.c +++ b/net_io.c @@ -845,6 +845,7 @@ void modesInitNet(void) { struct net_service *sbs_out_jaero; struct net_service *sbs_out_prio; struct net_service *asterix_out; + struct net_service *asterix_reduce_out; struct net_service *sbs_in; struct net_service *sbs_in_mlat; struct net_service *sbs_in_jaero; @@ -886,8 +887,10 @@ void modesInitNet(void) { serviceListen(sbs_out_jaero, Modes.net_bind_address, Modes.net_output_jaero_ports, Modes.net_epfd); - asterix_out = serviceInit(&Modes.services_out, "ASTERIX CAT021 output", &Modes.asterix_out, no_heartbeat, no_heartbeat, READ_MODE_IGNORE, NULL, NULL); + asterix_out = serviceInit(&Modes.services_out, "ASTERIX output", &Modes.asterix_out, no_heartbeat, no_heartbeat, READ_MODE_IGNORE, NULL, NULL); serviceListen(asterix_out, Modes.net_bind_address, Modes.net_output_asterix_ports, Modes.net_epfd); + asterix_reduce_out = serviceInit(&Modes.services_out, "ASTERIX output", &Modes.asterix_reduce_out, no_heartbeat, no_heartbeat, READ_MODE_IGNORE, NULL, NULL); + serviceListen(asterix_reduce_out, Modes.net_bind_address, Modes.net_output_asterix_reduce_ports, Modes.net_epfd); int sbs_port_len = strlen(Modes.net_output_sbs_ports); int pos = sbs_port_len - 1; @@ -1768,12 +1771,19 @@ static void modesSendRawOutput(struct modesMessage *mm) { // // Write ASTERIX output to TCP clients // -static void modesSendAsterixOutput(struct modesMessage *mm) { +static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *writer) { + struct aircraft *ac = mm->aircraft; + int64_t now = mstime(); uint8_t category; unsigned char bytes[Modes.net_output_flush_size * 2]; for (int i = 0; i < Modes.net_output_flush_size * 2; i++){ bytes[i] = 0; } + uint8_t fspec[7]; + for (size_t i = 0; i < 7; i++) + { + fspec[i] = 0; + } int p = 0; if (mm->from_mlat) // CAT 20 return; @@ -1781,11 +1791,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { return; else { // CAT 21 category = 21; - uint8_t fspec[7]; - for (size_t i = 0; i < 7; i++) - { - fspec[i] = 0; - } + // I021/010 Data Source Identification fspec[0] |= 1 << 7; bytes[p++] = 000; //SAC @@ -2009,7 +2015,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { { fspec[3] |= 1 << 1; long midnight = (long)(time(NULL) / 86400) * 86400000; - int tsm = mstime() - midnight; + int tsm = now - midnight; if (tsm < 0) tsm += 86400000; tsm = (int)(tsm * 0.128); @@ -2041,6 +2047,35 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { bytes[p++] = mm->category; } + // I021/220 Met Information + if (ac && ((now < ac->oat_updated + TRACK_EXPIRE) || (now < ac->wind_updated + TRACK_EXPIRE && abs(ac->wind_altitude - ac->baro_alt) < 500))){ + fspec[4] |= 1 << 5; + bool wind = false; + bool temp = false; + if (now < ac->wind_updated + TRACK_EXPIRE && abs(ac->wind_altitude - ac->baro_alt) < 500){ + bytes[p] |= 0xC0; + wind = true; + } + if (now < ac->oat_updated + TRACK_EXPIRE){ + bytes[p] |= 0x20; + temp = true; + } + p++; + if (wind){ + uint16_t ws = (int)(ac->wind_speed); + uint16_t wd = (int)(ac->wind_direction); + bytes[p++] = (ws & 0xFF00) >> 8; + bytes[p++] = ws & 0xFF; + bytes[p++] = (wd & 0xFF00) >> 8; + bytes[p++] = wd & 0xFF; + } + if (temp){ + int16_t oat = (int16_t)((ac->oat) * 4); + bytes[p++] = (oat & 0xFF00) >> 8; + bytes[p++] = oat & 0xFF; + } + } + // I021/008 Aircraft Operational Status if (mm->opstatus.valid){ fspec[5] |= 1 << 7; @@ -2072,7 +2107,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { uint16_t msgLen = p + 3 + fspec_len; uint8_t msgLenA = (msgLen & 0xFF00) >> 8; uint8_t msgLenB = msgLen & 0xFF; - char *w = prepareWrite(&Modes.asterix_out, msgLen); + char *w = prepareWrite(writer, msgLen); memcpy(w, &category, 1); w++; memcpy(w, &msgLenA, 1); @@ -2082,7 +2117,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm) { w += fspec_len; memcpy(w, &bytes, p); w += p; - completeWrite(&Modes.asterix_out, w); + completeWrite(writer, w); } } @@ -4637,7 +4672,10 @@ static void outputMessage(struct modesMessage *mm) { modesDumpBeastData(mm); } if (Modes.asterix_out.connections){ - modesSendAsterixOutput(mm); + modesSendAsterixOutput(mm, &Modes.asterix_out); + } + if (mm->reduce_forward && Modes.asterix_reduce_out.connections) { + modesSendAsterixOutput(mm, &Modes.asterix_reduce_out); } } diff --git a/readsb.c b/readsb.c index c30457e8..8b934e92 100644 --- a/readsb.c +++ b/readsb.c @@ -1600,10 +1600,14 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { sfree(Modes.net_input_beast_ports); Modes.net_input_beast_ports = strdup(arg); break; - case OptNetAsteriskOutPorts: + case OptNetAsterixOutPorts: sfree(Modes.net_output_asterix_ports); Modes.net_output_asterix_ports = strdup(arg); break; + case OptNetAsterixReducePorts: + sfree(Modes.net_output_asterix_reduce_ports); + Modes.net_output_asterix_reduce_ports = strdup(arg); + break; case OptNetBeastReducePorts: sfree(Modes.net_output_beast_reduce_ports); Modes.net_output_beast_reduce_ports = strdup(arg); diff --git a/readsb.h b/readsb.h index 6125abc2..eef3d813 100644 --- a/readsb.h +++ b/readsb.h @@ -584,7 +584,8 @@ struct _Modes struct net_writer sbs_out_jaero; // SBS-format output struct net_writer sbs_out_prio; // SBS-format output struct net_writer json_out; // SBS-format output - struct net_writer asterix_out; // Asterix CAT021 output + struct net_writer asterix_out; // Asterix output + struct net_writer asterix_reduce_out; // Asterix output struct net_writer feedmap_out; // SBS-format output struct net_writer vrs_out; // SBS-format output struct net_writer fatsv_out; // FATSV-format output @@ -740,6 +741,7 @@ struct _Modes char *net_output_beast_ports; // List of Beast output TCP ports char *net_output_beast_reduce_ports; // List of Beast output TCP ports char *net_output_asterix_ports; // List of Asterix output TCP ports + char *net_output_asterix_reduce_ports; // List of Asterix output TCP ports char *net_output_json_ports; char *net_output_api_ports; char *garbage_ports; @@ -1159,8 +1161,9 @@ enum { OptNetJaeroInPorts, OptNetBiPorts, OptNetBoPorts, - OptNetAsteriskInPorts, - OptNetAsteriskOutPorts, + OptNetAsterixInPorts, + OptNetAsterixOutPorts, + OptNetAsterixReducePorts, OptNetBeastReducePorts, OptNetBeastReduceInterval, OptNetBeastReduceFilterAlt, From c996e05d89c106571df874f3c251bc735f619b8f Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Thu, 6 Apr 2023 07:55:31 -0400 Subject: [PATCH 07/32] change asterix_reduce_out to be more like --net-sbs-reduce option --- README.md | 3 +++ help.h | 2 +- net_io.c | 8 +------- readsb.c | 5 ++--- readsb.h | 5 ++--- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 37dc0dae..38a42070 100644 --- a/README.md +++ b/README.md @@ -319,6 +319,9 @@ TCP json position output: include aircraft without --net-sbs-port= TCP BaseStation output listen ports (default: 0) --net-sbs-reduce Apply beast reduce logic and interval to SBS outputs + --net-ao-port= TCP ASTERIX output listen ports (default: 0) + --net-asterix-reduce Apply beast reduce logic and interval to ASTERIX + outputs --net-verbatim Forward messages unchanged --net-vrs-interval= TCP VRS json output interval (default: 5.0) diff --git a/help.h b/help.h index a3029eed..980d62f9 100644 --- a/help.h +++ b/help.h @@ -122,7 +122,7 @@ static struct argp_option optionsReadsb[] = { {"net-bo-port", OptNetBoPorts, "", 0, "TCP Beast output listen ports (default: 0)", 2}, {"net-ao-port", OptNetAsterixOutPorts, "", 0, "TCP Asterix output listen ports (default: 0)", 2}, {"net-ai-port", OptNetAsterixInPorts, "", 0, "TCP Asterix input listen ports (default: 0)", 2}, - {"net-asterix-reduce-out-port", OptNetAsterixReducePorts, "", 0, "TCP AsterixReduce output listen ports (default: 0)", 2}, + {"net-asterix-reduce", OptNetAsterixReduce, 0, 0, "Apply beast reduce logic and interval to ASTERIX outputs", 2}, {"net-ri-port", OptNetRiPorts, "", 0, "TCP raw input listen ports (default: 0)", 2}, {"net-ro-port", OptNetRoPorts, "", 0, "TCP raw output listen ports (default: 0)", 2}, {"net-sbs-port", OptNetSbsPorts, "", 0, "TCP BaseStation output listen ports (default: 0)", 2}, diff --git a/net_io.c b/net_io.c index 59a80c2e..c8d5dbe5 100644 --- a/net_io.c +++ b/net_io.c @@ -845,7 +845,6 @@ void modesInitNet(void) { struct net_service *sbs_out_jaero; struct net_service *sbs_out_prio; struct net_service *asterix_out; - struct net_service *asterix_reduce_out; struct net_service *sbs_in; struct net_service *sbs_in_mlat; struct net_service *sbs_in_jaero; @@ -889,8 +888,6 @@ void modesInitNet(void) { asterix_out = serviceInit(&Modes.services_out, "ASTERIX output", &Modes.asterix_out, no_heartbeat, no_heartbeat, READ_MODE_IGNORE, NULL, NULL); serviceListen(asterix_out, Modes.net_bind_address, Modes.net_output_asterix_ports, Modes.net_epfd); - asterix_reduce_out = serviceInit(&Modes.services_out, "ASTERIX output", &Modes.asterix_reduce_out, no_heartbeat, no_heartbeat, READ_MODE_IGNORE, NULL, NULL); - serviceListen(asterix_reduce_out, Modes.net_bind_address, Modes.net_output_asterix_reduce_ports, Modes.net_epfd); int sbs_port_len = strlen(Modes.net_output_sbs_ports); int pos = sbs_port_len - 1; @@ -4671,12 +4668,9 @@ static void outputMessage(struct modesMessage *mm) { if (Modes.dump_fw && (!Modes.dump_reduce || mm->reduce_forward)) { modesDumpBeastData(mm); } - if (Modes.asterix_out.connections){ + if (Modes.asterix_out.connections && (!Modes.asterixReduce || mm->reduce_forward)){ modesSendAsterixOutput(mm, &Modes.asterix_out); } - if (mm->reduce_forward && Modes.asterix_reduce_out.connections) { - modesSendAsterixOutput(mm, &Modes.asterix_reduce_out); - } } // In non-interactive non-quiet mode, display messages on standard output diff --git a/readsb.c b/readsb.c index 8b934e92..b2e54b2a 100644 --- a/readsb.c +++ b/readsb.c @@ -1604,9 +1604,8 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { sfree(Modes.net_output_asterix_ports); Modes.net_output_asterix_ports = strdup(arg); break; - case OptNetAsterixReducePorts: - sfree(Modes.net_output_asterix_reduce_ports); - Modes.net_output_asterix_reduce_ports = strdup(arg); + case OptNetAsterixReduce: + Modes.asterixReduce = 1; break; case OptNetBeastReducePorts: sfree(Modes.net_output_beast_reduce_ports); diff --git a/readsb.h b/readsb.h index eef3d813..0eee64c6 100644 --- a/readsb.h +++ b/readsb.h @@ -585,7 +585,6 @@ struct _Modes struct net_writer sbs_out_prio; // SBS-format output struct net_writer json_out; // SBS-format output struct net_writer asterix_out; // Asterix output - struct net_writer asterix_reduce_out; // Asterix output struct net_writer feedmap_out; // SBS-format output struct net_writer vrs_out; // SBS-format output struct net_writer fatsv_out; // FATSV-format output @@ -690,6 +689,7 @@ struct _Modes int8_t jsonLongtype; int8_t viewadsb; int8_t sbsReduce; // apply beast reduce logic to SBS messages + int8_t asterixReduce; // apply beast reduce logic to SBS messages int position_persistence; // Maximum number of consecutive implausible positions from global CPR to invalidate a known position int json_reliable; @@ -741,7 +741,6 @@ struct _Modes char *net_output_beast_ports; // List of Beast output TCP ports char *net_output_beast_reduce_ports; // List of Beast output TCP ports char *net_output_asterix_ports; // List of Asterix output TCP ports - char *net_output_asterix_reduce_ports; // List of Asterix output TCP ports char *net_output_json_ports; char *net_output_api_ports; char *garbage_ports; @@ -1163,7 +1162,7 @@ enum { OptNetBoPorts, OptNetAsterixInPorts, OptNetAsterixOutPorts, - OptNetAsterixReducePorts, + OptNetAsterixReduce, OptNetBeastReducePorts, OptNetBeastReduceInterval, OptNetBeastReduceFilterAlt, From eb75da07258864bd13225d5f99663b04b4f229ae Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sat, 8 Apr 2023 07:26:55 -0400 Subject: [PATCH 08/32] Decode BDS4,4 Meteorological routine air report --- comm_b.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- mode_s.c | 2 + net_io.c | 55 +++++++++++++++------- readsb.h | 18 ++++++- track.c | 18 ++++++- track.h | 1 + 6 files changed, 215 insertions(+), 20 deletions(-) diff --git a/comm_b.c b/comm_b.c index 27ac4962..24785549 100644 --- a/comm_b.c +++ b/comm_b.c @@ -35,6 +35,7 @@ static int decodeBDS30(struct modesMessage *mm, bool store); static int decodeBDS40(struct modesMessage *mm, bool store); static int decodeBDS50(struct modesMessage *mm, bool store); static int decodeBDS60(struct modesMessage *mm, bool store); +static int decodeBDS44(struct modesMessage *mm, bool store); static CommBDecoderFn comm_b_decoders[] = { &decodeEmptyResponse, @@ -44,7 +45,8 @@ static CommBDecoderFn comm_b_decoders[] = { &decodeBDS17, &decodeBDS40, &decodeBDS50, - &decodeBDS60 + &decodeBDS60, + &decodeBDS44 }; void decodeCommB(struct modesMessage *mm) { @@ -820,3 +822,140 @@ static int decodeBDS60(struct modesMessage *mm, bool store) { return score; } + +// BDS 4,4 Meteorological routine air report + +static int decodeBDS44(struct modesMessage *mm, bool store) { + unsigned char *msg = mm->MB; + + unsigned source = getbits(msg, 1, 4); + + unsigned wind_valid = getbit(msg, 5); + unsigned wind_speed_raw = getbits(msg, 6, 14); + unsigned wind_direction_raw = getbits(msg, 15, 23); + + unsigned temperature_sign = getbit(msg, 24); + unsigned static_air_temperature_raw = getbits(msg, 25, 34); + + unsigned pressure_valid = getbit(msg, 35); + unsigned static_pressure_raw = getbits(msg, 36, 46); + + unsigned turbulence_valid = getbit(msg, 47); + unsigned turbulence_raw = getbits(msg, 48, 49); + + unsigned humidity_valid = getbit(msg, 50); + unsigned humidity_raw = getbits(msg, 51, 56); + +/* + if (!wind_valid || !temperature_valid || !pressure_valid || !turbulence_valid && !humidity_valid){ + return 0; + } +*/ + int met_source = source; + int score = 0; + int wind_speed = 0; + float wind_direction = 0; + float temperature = 0; + int static_pressure = 0; + int turbulence = 0; + float humidity = 0; + if (met_source >= 0 && met_source <= 6) { + score += 4; + } + else { + return 0; + } + if (wind_valid){ + wind_speed = (int)wind_speed_raw; + if (wind_speed <= 511 && wind_speed >= 0){ + score += 9; + } + else { + return 0; + } + wind_direction = wind_direction_raw * (180 / 256); + if (wind_direction >= 0 && wind_direction <= 360){ + score += 9; + } + else { + return 0; + } + } + else if (wind_speed == 0) { + score += 2; + } + if (temperature_sign){ + temperature = (static_air_temperature_raw - pow(2, 10)) * 0.25; + } + else { + temperature = static_air_temperature_raw * 0.25; + } + if (temperature >= -128 && temperature <= 128){ + score += 10; + } + else { + return 0; + } + if (pressure_valid){ + static_pressure = (int)static_pressure_raw; + if (static_pressure >= 0 && static_pressure <= 2048){ + score += 11; + return 0; + } + else { + } + } + else if (static_pressure == 0) { + score += 1; + } + if (turbulence_valid){ + turbulence = (int)turbulence_raw; + if (turbulence >= 0 && turbulence <= 3) { + score += 2; + } + else { + return 0; + } + } + else if (turbulence == 0) { + score += 1; + } + if (humidity_valid) { + humidity = humidity_raw * (100.0f / 64); + if (humidity >= 0 && humidity <= 100){ + score += 6; + } + else { + return 0; + } + } + else if (humidity == 0) { + score += 1; + } + if (store) { + mm->commb_format = COMMB_METEOROLOGICAL_ROUTINE; + mm->met_source_valid = 1; + mm->met_source = met_source; + if (wind_valid) { + mm->wind_valid = 1; + mm->wind_speed = wind_speed; + mm->wind_direction = wind_direction; + } + mm->oat_valid = 1; + mm->oat = temperature; + if (pressure_valid) { + mm->static_pressure_valid = 1; + mm->static_pressure = static_pressure; + } + if (turbulence_valid) { + mm->turbulence_valid = 1; + mm->turbulence = turbulence; + } + if (humidity_valid) { + mm->humidity_valid = 1; + mm->humidity = humidity; + } + } + return score; +} + diff --git a/mode_s.c b/mode_s.c index a75c2652..bbd8ce24 100644 --- a/mode_s.c +++ b/mode_s.c @@ -1645,6 +1645,8 @@ static const char *commb_format_to_string(commb_format_t format) { return "BDS5,0 Track and turn report"; case COMMB_HEADING_SPEED: return "BDS6,0 Heading and speed report"; + case COMMB_METEOROLOGICAL_ROUTINE: + return "BDS4,4 Meteorological routine air report"; default: return "unknown format"; } diff --git a/net_io.c b/net_io.c index c8d5dbe5..bf683773 100644 --- a/net_io.c +++ b/net_io.c @@ -1769,7 +1769,6 @@ static void modesSendRawOutput(struct modesMessage *mm) { // Write ASTERIX output to TCP clients // static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *writer) { - struct aircraft *ac = mm->aircraft; int64_t now = mstime(); uint8_t category; unsigned char bytes[Modes.net_output_flush_size * 2]; @@ -2045,29 +2044,32 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w } // I021/220 Met Information - if (ac && ((now < ac->oat_updated + TRACK_EXPIRE) || (now < ac->wind_updated + TRACK_EXPIRE && abs(ac->wind_altitude - ac->baro_alt) < 500))){ + //if (ac && ((now < ac->oat_updated + TRACK_EXPIRE) || (now < ac->wind_updated + TRACK_EXPIRE && abs(ac->wind_altitude - ac->baro_alt) < 500))){ + if (mm->wind_valid || mm->oat_valid || mm->turbulence_valid || mm->static_pressure_valid || mm->humidity_valid) { fspec[4] |= 1 << 5; bool wind = false; bool temp = false; - if (now < ac->wind_updated + TRACK_EXPIRE && abs(ac->wind_altitude - ac->baro_alt) < 500){ + //if (now < ac->wind_updated + TRACK_EXPIRE && abs(ac->wind_altitude - ac->baro_alt) < 500){ + if (mm->wind_valid) { bytes[p] |= 0xC0; wind = true; } - if (now < ac->oat_updated + TRACK_EXPIRE){ + //if (now < ac->oat_updated + TRACK_EXPIRE){ + if (mm->oat_valid) { bytes[p] |= 0x20; temp = true; } p++; if (wind){ - uint16_t ws = (int)(ac->wind_speed); - uint16_t wd = (int)(ac->wind_direction); + uint16_t ws = (int)(mm->wind_speed); + uint16_t wd = (int)(mm->wind_direction); bytes[p++] = (ws & 0xFF00) >> 8; bytes[p++] = ws & 0xFF; bytes[p++] = (wd & 0xFF00) >> 8; bytes[p++] = wd & 0xFF; } if (temp){ - int16_t oat = (int16_t)((ac->oat) * 4); + int16_t oat = (int16_t)((mm->oat) * 4); bytes[p++] = (oat & 0xFF00) >> 8; bytes[p++] = oat & 0xFF; } @@ -2084,6 +2086,35 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w p++; } + // I021/295 Data Ages + /* + if (fspec[4] == 0b100000){ + fspec[5] |= 1 << 1; + bytes[p++] |= 1; + bytes[p++] |= 1; + bytes[p++] |= 1 << 2; + if((now < ac->wind_updated + TRACK_EXPIRE && abs(ac->wind_altitude - ac->baro_alt) < 500) && + (now < ac->oat_updated + TRACK_EXPIRE)) { + uint64_t wind_age = now - ac->wind_updated; + uint64_t oat_age = now - ac->oat_updated; + if (wind_age > oat_age){ + bytes[p++] = (int)(wind_age / 100); + } + else { + bytes[p++] = (int)(oat_age / 100); + } + } + else if (now < ac->wind_updated + TRACK_EXPIRE && abs(ac->wind_altitude - ac->baro_alt) < 500){ + uint64_t wind_age = now - ac->wind_updated; + bytes[p++] = (int)(wind_age / 100); + } + else if (now < ac->oat_updated + TRACK_EXPIRE){ + uint64_t oat_age = now - ac->oat_updated; + bytes[p++] = (int)(oat_age / 100); + } + } + */ + int fspec_len = 1; for (int i = 5; i >= 0; i--) { @@ -2092,15 +2123,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w fspec_len++; } } - /* - for (size_t i = 1; i < 7; i++) - { - if (fspec[i]){ - bytes[p] = fspec[i]; - p++; - //printf("%u", p); printf("%s", "/"); printf("%u", msgLen);printf("%s", " fp"); printf("%lu", i); printf("%s", " "); - } - }*/ + uint16_t msgLen = p + 3 + fspec_len; uint8_t msgLenA = (msgLen & 0xFF00) >> 8; uint8_t msgLenB = msgLen & 0xFF; diff --git a/readsb.h b/readsb.h index 0eee64c6..968c991d 100644 --- a/readsb.h +++ b/readsb.h @@ -256,7 +256,8 @@ typedef enum { COMMB_ACAS_RA, COMMB_VERTICAL_INTENT, COMMB_TRACK_TURN, - COMMB_HEADING_SPEED + COMMB_HEADING_SPEED, + COMMB_METEOROLOGICAL_ROUTINE } commb_format_t; typedef enum @@ -941,6 +942,12 @@ struct modesMessage bool alt_q_bit; bool acas_ra_valid; bool geom_alt_derived; + bool wind_valid; + bool oat_valid; + bool static_pressure_valid; + bool turbulence_valid; + bool humidity_valid; + bool met_source_valid; bool squawk_emergency_valid; bool squawk_emergency; @@ -997,6 +1004,15 @@ struct modesMessage double receiver_distance; // distance to receiver float calculated_track; // set in speed_check, -1 is invalid + // meteorological + int wind_speed; + float wind_direction; + float oat; + int static_pressure; + int turbulence; + float humidity; + int met_source; + commb_format_t commb_format; // Inferred format of a comm-b message // various integrity/accuracy things diff --git a/track.c b/track.c index c4d7347d..c330a692 100644 --- a/track.c +++ b/track.c @@ -2211,6 +2211,18 @@ struct aircraft *trackUpdateFromMessage(struct modesMessage *mm) { a->spi = mm->spi; } + if (mm->wind_valid) { + a->wind_speed = a->wind_speed; + a->wind_direction = a->wind_direction; + a->wind_updated = now; + a->wind_altitude = a->baro_alt; + } + + if (mm->oat_valid) { + a->oat = mm->oat; + a->oat_updated = now; + } + // CPR, even if (mm->cpr_valid && !mm->cpr_odd && accept_data(&a->cpr_even_valid, mm->source, mm, a, REDUCE_OFTEN)) { a->cpr_even_type = mm->cpr_type; @@ -3179,8 +3191,10 @@ void to_state_all(struct aircraft *a, struct state_all *new, int64_t now) { } if (now < a->oat_updated + TRACK_EXPIRE) { new->oat = (int) nearbyint(a->oat); - new->tat = (int) nearbyint(a->tat); - new->temp_valid = 1; + if (now < a->tat_updated + TRACK_EXPIRE) { + new->temp_valid = 1; + new->tat = (int) nearbyint(a->tat); + } } if (a->adsb_version < 0) diff --git a/track.h b/track.h index 11dd4909..93f2e8e2 100644 --- a/track.h +++ b/track.h @@ -387,6 +387,7 @@ struct aircraft float oat; int64_t wind_updated; int64_t oat_updated; + int64_t tat_updated; // ---- From 2830073165397833396dfed970d30966d432cfd8 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sat, 22 Apr 2023 09:37:00 -0400 Subject: [PATCH 09/32] Beginnings of working ASTERIX in. Stuff is still broken, but it does read in --- net_io.c | 415 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- net_io.h | 4 +- readsb.c | 4 + readsb.h | 1 + 4 files changed, 413 insertions(+), 11 deletions(-) diff --git a/net_io.c b/net_io.c index 4ba2a234..163116e5 100644 --- a/net_io.c +++ b/net_io.c @@ -75,6 +75,7 @@ static int decodeBinMessage(struct client *c, char *p, int remote, int64_t now, static int processHexMessage(struct client *c, char *hex, int remote, int64_t now, struct messageBuffer *mb); static int decodeUatMessage(struct client *c, char *msg, int remote, int64_t now, struct messageBuffer *mb); static int decodeSbsLine(struct client *c, char *line, int remote, int64_t now, struct messageBuffer *mb); +static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t now, struct messageBuffer *mb); static int decodeSbsLineMlat(struct client *c, char *line, int remote, int64_t now, struct messageBuffer *mb) { MODES_NOTUSED(remote); return decodeSbsLine(c, line, 64 + SOURCE_MLAT, now, mb); @@ -845,6 +846,7 @@ void modesInitNet(void) { struct net_service *sbs_out_jaero; struct net_service *sbs_out_prio; struct net_service *asterix_out; + struct net_service *asterix_in; struct net_service *sbs_in; struct net_service *sbs_in_mlat; struct net_service *sbs_in_jaero; @@ -886,8 +888,6 @@ void modesInitNet(void) { serviceListen(sbs_out_jaero, Modes.net_bind_address, Modes.net_output_jaero_ports, Modes.net_epfd); - asterix_out = serviceInit(&Modes.services_out, "ASTERIX output", &Modes.asterix_out, no_heartbeat, no_heartbeat, READ_MODE_IGNORE, NULL, NULL); - serviceListen(asterix_out, Modes.net_bind_address, Modes.net_output_asterix_ports, Modes.net_epfd); int sbs_port_len = strlen(Modes.net_output_sbs_ports); int pos = sbs_port_len - 1; @@ -947,6 +947,12 @@ void modesInitNet(void) { sfree(jaero); } + asterix_out = serviceInit(&Modes.services_out, "ASTERIX output", &Modes.asterix_out, no_heartbeat, no_heartbeat, READ_MODE_IGNORE, NULL, NULL); + serviceListen(asterix_out, Modes.net_bind_address, Modes.net_output_asterix_ports, Modes.net_epfd); + + asterix_in = serviceInit(&Modes.services_in, "ASTERIX TCP input", NULL, no_heartbeat, no_heartbeat, READ_MODE_ASTERIX, NULL, decodeAsterixMessage); + serviceListen(asterix_in, Modes.net_bind_address, Modes.net_input_asterix_ports, Modes.net_epfd); + gpsd_in = serviceInit(&Modes.services_in, "GPSD TCP input", &Modes.gpsd_in, no_heartbeat, no_heartbeat, READ_MODE_ASCII, "\n", handle_gpsd); if (Modes.json_dir && Modes.json_globe_index && Modes.globe_history_dir) { @@ -1762,6 +1768,368 @@ static void modesSendRawOutput(struct modesMessage *mm) { completeWrite(&Modes.raw_out, p); } +// +// Read Asterix FSPEC +// +static uint8_t * readFspec(char **p){ + uint8_t* fspec = malloc(24*sizeof(uint8_t*)); + for (int i = 1; i < 24; i++) { + fspec[i] = 0; + } + fspec[0] = **p; + (*p)++; + for (int i = 1; *(*p - 1) & 0x1; i++){ + fspec[i] = *(*p); + (*p)++; + } + return fspec; +} + +// +// Read Asterix Time +// +static uint64_t readAsterixTime(char **p) { + int rawtime = ((*(*p) & 0xff) << 16) + ((*(*p + 1) & 0xff) << 8) + (*(*p + 2) & 0xff); + int mssm = (int)(rawtime / .128); + long midnight = (long)(mstime() / 86400000) * 86400000; + int diff = (int)(midnight + mssm - mstime()); + (*p) += 3; + if (abs(diff) > 43200000){ + return midnight - 86400000 + mssm; + } + return midnight + mssm; +} + +// +// Read Asterix High Precision Time +// +static void readAsterixHighPrecisionTime(uint64_t *timeStamp, char **p) { + uint8_t fsi = (**p & 0xc0) >> 6; + double offset = ((**p & 0x3f) << 24) + ((*(*p + 1) & 0xff) << 16) + ((*(*p + 2) & 0xff) << 8) + (*(*p + 3) & 0xff); + (*p) += 4; + offset = offset * pow(2, -27); + uint64_t wholesecond = (int)(*timeStamp / 1000) * 1000; + switch(fsi) + { + case 1: + wholesecond += 1; + break; + case 2: + wholesecond -= 1; + break; + } + *timeStamp = wholesecond + offset; +} + +// +//========================================================================= +// +// Read ASTERIX input from TCP clients +// +static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t now, struct messageBuffer *mb) { + //uint16_t msgLen = (*(p + 1) << 8) + *(p + 2); + //int j; + unsigned char category; + + struct modesMessage *mm = netGetMM(mb); + mm->client = c; + MODES_NOTUSED(c); + if (remote >= 64) + mm->source = remote - 64; + else + mm->source = SOURCE_SBS; + mm->remote = 1; + mm->sbs_in = 1; + mm->signalLevel = 0; + category = *p; // Get the category + p += 3; + uint8_t *fspec = readFspec(&p); + mm->receiverId = c->receiverId; + if (unlikely(Modes.incrementId)) { + mm->receiverId += now / (10 * MINUTES); + } + mm->sysTimestamp = -1; + switch(category){ + case 21: // ADS-B Message + ; + if(!(fspec[1] & 0x10)){ // no address. this is useless to us + free(fspec); + return -1; + } + if (fspec[0] & 0x80){ // ID021/010 Data Source Identification + p += 2; + } + if (fspec[0] & 0x40){ // ID021/040 Target Report Descriptor + uint8_t *trd = readFspec(&p); + if (trd[1] & 0x40){ + mm->airground = AG_GROUND; + } + else { + mm->airground = AG_AIRBORNE; + } + free(trd); + } + if (fspec[0] & 0x20){ // I021/161 Track Number + p += 2; + } + if (fspec[0] & 0x10){ // I021/015 Service Identification + p += 1; + } + if (fspec[0] & 0x8){ // I021/071 Time of Applicability for Position 3 + mm->sysTimestamp = readAsterixTime(&p); + } + if (fspec[0] & 0x4){ // I021/130 Position in WGS-84 co-ordinates + int lat = (*p & 0xff) << 16; + lat += (*(p + 1) & 0xff) << 8; + lat += (*(p + 2) & 0xff); + p += 3; + int lon = (*p & 0xff) << 16; + lon += (*(p + 1) & 0xff) << 8; + lon += (*(p + 2) & 0xff); + p += 3; + if (lat >= 0x800000){ + lat -= 0x1000000; + } + if (lon >= 0x800000){ + lon -= 0x1000000; + } + double latitude = lat * (180 / pow(2, 23)); + double longitude = lon * (180 / pow(2, 23)); + if (latitude <= 90 && latitude >= -90 && longitude >= -180 && longitude <= 180){ + mm->cpr_decoded = true; + mm->decoded_lat = latitude; + mm->decoded_lon = longitude; + } + } + if (fspec[0] & 0x2){ // I021/131 Position in WGS-84 co-ordinates, high res. + int lat = (*p & 0xff) << 24; + lat += (*(p + 1) & 0xff) << 16; + lat += (*(p + 2) & 0xff) << 8; + lat += (*(p + 3) & 0xff); + p += 4; + int lon = *p << 24; + lon += (*(p + 1) & 0xff) << 16; + lon += (*(p + 2) & 0xff) << 8; + lon += (*(p + 3) & 0xff); + p += 4; + double latitude = lat * (180 / pow(2, 30)); + double longitude = lon * (180 / pow(2, 30)); + if (latitude <= 90 && latitude >= -90 && longitude >= -180 && longitude <= 180){ + mm->sbs_pos_valid = true; + mm->decoded_lat = latitude; + mm->decoded_lon = longitude; + } + } + if (fspec[1] & 0x80){ // I021/072 Time of Applicability for Velocity + if (mm->sysTimestamp == -1){ + mm->sysTimestamp = readAsterixTime(&p); + } + else { + p += 3; + } + } + if (fspec[1] & 0x40){ // I021/150 Air Speed + uint16_t raw_speed = (*p & 0x7f) << 8; + raw_speed += *(p + 1) & 0xff; + if (*p & 0x80){ //Mach + mm->mach = raw_speed * 0.001; + mm->mach_valid = true; + } + else{ // IAS + mm->ias = (raw_speed * pow(2, -14)) * 3600; + mm->ias_valid = true; + } + p += 2; + } + if (fspec[1] & 0x20){ // I021/151 True Airspeed + uint16_t raw_speed = (*p & 0x7f) << 8; + raw_speed += *(p + 1) & 0xff; + if (!(*p & 0x80)){ + mm->tas_valid = true; + mm->tas = raw_speed; + } + p += 2; + } // I021/080 Target Address + mm->addr = (((*p & 0xff) << 16) + ((*(p + 1) & 0xff) << 8) + (*(p + 2) & 0xff)) & 0xffffff; + p += 3; + //printf("Addr: %x ", mm->addr); + if (fspec[1] & 0x8){ // I021/073 Time of Message Reception of Position + if (mm->cpr_decoded){ + uint64_t ts = readAsterixTime(&p); + if (fspec[1] & 0x4){ // I021/074 Time of Message Reception of Position=High Precision + readAsterixHighPrecisionTime(&ts, &p); + } + if (mm->sysTimestamp == -1){ + mm->sysTimestamp = ts; + } + } + else if (fspec[1] & 0x4) { + p += 7; + } + else { + p += 3; + } + } + if (fspec[1] & 0x2){ // I021/075 Time of Message Reception of Velocity + if (mm->ias_valid || mm->mach_valid || mm->gs_valid){ + uint64_t ts = readAsterixTime(&p); + if (fspec[2] & 0x80){ // I021/074 Time of Message Reception of Velocity=High Precision + readAsterixHighPrecisionTime(&ts, &p); + } + if (mm->sysTimestamp == -1){ + mm->sysTimestamp = ts; + } + } + else if (fspec[2] & 0x80) { + p += 7; + } + else { + p += 3; + } + } + if (fspec[2] & 0x40){ // I021/140 Geometric Height + int16_t raw_alt = (((*p & 0xff) << 8) + (*(p + 1) & 0xff)); + double alt = raw_alt * 6.25; + if (alt >= -1500 && alt <= 150000){ + mm->geom_alt_valid = true; + mm->geom_alt_unit = UNIT_FEET; + mm->geom_alt = alt; + } + p += 2; + } + if (fspec[2] & 0x20){ // I021/090 Quality Indicators + uint8_t *qi = readFspec(&p); + free(qi); + } + if (fspec[2] & 0x10){ // I021/210 MOPS Version + mm->opstatus.version = ((*p) & 0x38) >> 3; + p++; + //uint8_t ltt = ((*p) & 0x7); + } + if (fspec[2] & 0x8){ // I021/070 Mode 3/A Code + mm->squawk += (((*p & 0xe) << 11) + ((*p & 0x1) << 10) + ((*(p + 1) & 0xC0) << 2) + ((*(p + 1) & 0x38) << 1) + ((*(p + 1) & 0x7))) ; + mm->squawk_valid = true; + p += 2; + } + if (fspec[2] & 0x4){ // I021/230 Roll Angle + int16_t roll = ((*p & 0xff) << 8) + (*(p + 1) & 0xff); + mm->roll = roll * 0.01; + mm->roll_valid = true; + p += 2; + } + if (fspec[2] & 0x2){ // I021/045 Flight Level + int16_t alt = ((*p & 0xff) << 8) + (*(p + 1) & 0xff); + mm->baro_alt_valid = true; + mm->baro_alt = alt * 25; + mm->baro_alt_unit = UNIT_FEET; + p += 2; + } + if (fspec[3] & 0x80){ // I021/152 Magnetic Heading + mm->heading_valid = true; + mm->heading_type = HEADING_MAGNETIC; + uint16_t heading = ((*p & 0xff) << 8) + (*(p + 1) & 0xff); + mm->heading = heading * (360 / pow(2, 16)); + p += 2; + } + if (fspec[3] & 0x40){ // I021/200 Target Status + mm->spi_valid = true; + mm->alert_valid = true; + mm->emergency_valid = true; + mm->nav.modes_valid = true; + mm->nav.modes |= (*p & 0b01000000) >> 4; + mm->emergency = (*p & 0b00011100) >> 2; + mm->alert = (*p & 0b11); + mm->spi = (*p & 0b11) == 3; + p++; + } + if (fspec[3] & 0x20){ // ID021/155 Barometric Vertical Rate + if (*p & 0x80){ //range exceeded + p += 2; + } + else{ + int16_t vr = ((*p & 0x7f) << 9) + ((*(p + 1) & 0xff) << 1); + mm->baro_rate_valid = true; + mm->baro_rate = vr * 3.125; + p += 2; + } + } + if (fspec[3] & 0x10){ // ID021/157 Geometric Vertical Rate + if (*p & 0x80){ //range exceeded + p += 2; + } + else{ + int16_t vr = ((*p & 0x7f) << 9) + ((*(p + 1) & 0xff) << 1); + mm->geom_rate_valid = true; + mm->geom_rate = vr * 3.125; + p += 2; + } + } + if (fspec[3] & 0x8){ // ID021/160 Airborne Ground Vector + if (*p & 0x80){ //range exceeded + p += 4; + } + else{ + uint16_t gs = ((*p & 0x7f) << 8) + ((*(p + 1) & 0xff) << 1); + p += 2; + uint16_t ta = ((*p & 0xff) << 8) + ((*(p + 1) & 0xff) << 1); + p += 2; + mm->gs_valid = true; + mm->heading_valid = true; + mm->heading_type = HEADING_GROUND_TRACK; + mm->gs.v0 = gs * pow(2, -14) * 3600; + mm->heading = ta * (360 / pow(2, 16)); + } + } + if (fspec[3] & 0x4){ // ID021/165 Track Angle Rate + p += 2; + } + if (fspec[3] & 0x2){ // ID021/077 Time of Report Transmission + uint64_t tt = readAsterixTime(&p); + if (mm->sysTimestamp == -1){ + mm->sysTimestamp = tt; + } + } + if (fspec[4] & 0x80){ // ID021/170 Target Identification + uint64_t cs = ((uint64_t)(*p & 0xff) << 40) + ((uint64_t)(*(p + 1) & 0xff) << 32) + ((uint64_t)(*(p + 2) & 0xff) << 24) + ((uint64_t)(*(p + 3) & 0xff) << 16) + ((uint64_t)(*(p + 4) & 0xff) << 8) + (uint64_t)(*(p + 5) & 0xff); + char *callsign = mm->callsign; + callsign[0] = ais_charset[((cs & 0xFC0000000000) >> 42)]; + callsign[1] = ais_charset[((cs & 0x3F000000000) >> 36)]; + callsign[2] = ais_charset[((cs & 0xFC0000000) >> 30)]; + callsign[3] = ais_charset[((cs & 0x3F000000) >> 24)]; + callsign[4] = ais_charset[((cs & 0xFC0000) >> 18)]; + callsign[5] = ais_charset[((cs & 0x3F000) >> 12)]; + callsign[6] = ais_charset[((cs & 0xFC0) >> 6)]; + callsign[7] = ais_charset[(cs & 0x3F)]; + callsign[8] = 0; + mm->callsign_valid = 1; + for (int i = 0; i < 8; ++i) { + if ( + (callsign[i] >= 'A' && callsign[i] <= 'Z') + // -./0123456789 + || (callsign[i] >= '-' && callsign[i] <= '9') + || callsign[i] == ' ' + || callsign[i] == '@' + ) { + // valid chars + } else { + mm->callsign_valid = 0; + } + } + p += 6; + } + + } + if (mm->sysTimestamp == -1){ + mm->sysTimestamp = mstime(); + } + free(fspec); + mm->decoded_nic = 0; + mm->decoded_rc = RC_UNKNOWN; + netUseMessage(mm); + return 0; +} + + // //========================================================================= @@ -1834,7 +2202,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w speedval = mm->mach * 1000; } else{ - speedval = (mm->ias / 3600) * pow(2,14); + speedval = (mm->ias / 3600.0) * pow(2,14); } bytes[p++] |= (speedval & 0x7f00) >> 8; bytes[p++] = (speedval & 0xff); @@ -1890,7 +2258,12 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w bytes[p++] = (alt & 0xff00) >> 8; bytes[p++] = alt & 0xff; } - + else if (mm->geom_delta_valid){ + fspec[2] |= 1 << 6; + int16_t alt = (int)((mm->baro_alt + mm->geom_delta) / 6.25); + bytes[p++] = (alt & 0xff00) >> 8; + bytes[p++] = alt & 0xff; + } // I021/090 Quality Indicators fspec[2] |= 1 << 5; if (mm->accuracy.nac_v_valid) @@ -1983,7 +2356,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w if (mm->baro_rate_valid){ fspec[3] |= 1 << 5; int value = ((int16_t)(mm->baro_rate / 3.125)) >> 1; - bytes[p++] = (value & 0xff00) >> 8; + bytes[p++] = (value & 0x7f00) >> 8; bytes[p++] = value & 0xff; } @@ -1991,17 +2364,17 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w if (mm->geom_rate_valid){ fspec[3] |= 1 << 4; int value = ((int16_t)(mm->geom_rate / 3.125)) >> 1; - bytes[p++] = (value & 0xff00) >> 8; + bytes[p++] = (value & 0x7f00) >> 8; bytes[p++] = value & 0xff; } // I021/160 Airborne Ground Vector if (mm->gs_valid && mm->heading_valid && mm->heading_type == HEADING_GROUND_TRACK){ fspec[3] |= 1 << 3; - double adj_gs = mm->gs.v0 * 4.5511; - bytes[p++] = ((int)adj_gs & 0xff00) >> 8; + double adj_gs = (mm->gs.v0 / 3600.0) / pow(2, -14); + bytes[p++] = ((int)adj_gs & 0x7f00) >> 8; bytes[p++] = (int)adj_gs & 0xff; - double adj_trk = mm->heading * 182.0444; + double adj_trk = mm->heading * (pow(2,16) / 360.0); uint16_t trk = (int)adj_trk; bytes[p++] = (trk & 0xff00) >> 8; bytes[p++] = trk & 0xff; @@ -2598,6 +2971,7 @@ static void modesSendSBSOutput(struct modesMessage *mm, struct aircraft *a, stru completeWrite(writer, p); } + void jsonPositionOutput(struct modesMessage *mm, struct aircraft *a) { MODES_NOTUSED(mm); char *p; @@ -3607,6 +3981,24 @@ static int readAscii(struct client *c, int64_t now, struct messageBuffer *mb) { return 0; } +static int readAsterix(struct client *c, int64_t now, struct messageBuffer *mb) { + + while (c->som < c->eod) { + char *p = c->som; + uint16_t msgLen = (*(p + 1) << 8) + *(p + 2); + char *end = c->som + msgLen; + c->som = end; + if (c->service->read_handler(c, p, c->remote, now, mb)) { + if (Modes.debug_net) { + fprintf(stderr, "%s: Closing connection from %s port %s\n", c->service->descr, c->host, c->port); + } + modesCloseClient(c); + return -1; + } + } + return 0; +} + static int readBeast(struct client *c, int64_t now, struct messageBuffer *mb) { // This is the Beast Binary scanning case. // If there is a complete message still in the buffer, there must be the separator 'sep' @@ -3994,6 +4386,11 @@ static int processClient(struct client *c, int64_t now, struct messageBuffer *mb if (res != 0) { return res; } + } else if (read_mode == READ_MODE_ASTERIX) { + int res = readAsterix(c, now, mb); + if (res != 0) { + return res; + } } if (!c->receiverIdLocked && (c->bytesReceived > 512 || now > c->connectedSince + 10000)) { diff --git a/net_io.h b/net_io.h index cee3b9cd..c766a083 100644 --- a/net_io.h +++ b/net_io.h @@ -42,7 +42,8 @@ typedef enum READ_MODE_IGNORE, READ_MODE_BEAST, READ_MODE_BEAST_COMMAND, - READ_MODE_ASCII + READ_MODE_ASCII, + READ_MODE_ASTERIX } read_mode_t; typedef struct { @@ -226,5 +227,4 @@ void netUseMessage(struct modesMessage *mm); void netDrainMessageBuffers(); struct modesMessage *netGetMM(); - #endif diff --git a/readsb.c b/readsb.c index 54ea0f90..88fb4612 100644 --- a/readsb.c +++ b/readsb.c @@ -1617,6 +1617,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { sfree(Modes.net_output_asterix_ports); Modes.net_output_asterix_ports = strdup(arg); break; + case OptNetAsterixInPorts: + sfree(Modes.net_input_asterix_ports); + Modes.net_input_asterix_ports = strdup(arg); + break; case OptNetAsterixReduce: Modes.asterixReduce = 1; break; diff --git a/readsb.h b/readsb.h index 6d4d1860..2b301e2e 100644 --- a/readsb.h +++ b/readsb.h @@ -746,6 +746,7 @@ struct _Modes char *net_output_beast_ports; // List of Beast output TCP ports char *net_output_beast_reduce_ports; // List of Beast output TCP ports char *net_output_asterix_ports; // List of Asterix output TCP ports + char *net_input_asterix_ports; // List of Asterix input TCP ports char *net_output_json_ports; char *net_output_api_ports; char *garbage_ports; From 541ecdc2ddd730b3a6cb896cfbb2a88d0609368f Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sat, 22 Apr 2023 09:41:45 -0400 Subject: [PATCH 10/32] Check for valid baro alt --- net_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net_io.c b/net_io.c index 163116e5..cb9ea8a9 100644 --- a/net_io.c +++ b/net_io.c @@ -2258,7 +2258,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w bytes[p++] = (alt & 0xff00) >> 8; bytes[p++] = alt & 0xff; } - else if (mm->geom_delta_valid){ + else if (mm->geom_delta_valid && mm->baro_alt_valid){ fspec[2] |= 1 << 6; int16_t alt = (int)((mm->baro_alt + mm->geom_delta) / 6.25); bytes[p++] = (alt & 0xff00) >> 8; From b4b067ada56e49fd808030aa4d248af50a0ee8e3 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sat, 22 Apr 2023 10:27:08 -0400 Subject: [PATCH 11/32] try to send geom data using offset --- net_io.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net_io.c b/net_io.c index cb9ea8a9..827098fb 100644 --- a/net_io.c +++ b/net_io.c @@ -2220,7 +2220,11 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w bytes[p++] = (mm->addr & 0xff0000) >> 16; bytes[p++] = (mm->addr & 0xff00) >> 8; bytes[p++] = (mm->addr & 0xff); - + struct aircraft *a = aircraftGet(mm->addr); + if (!a) { // If it's a currently unknown aircraft.... + a = aircraftCreate(mm->addr); // ., create a new record for it, + } + // I021/073 Time of Message Reception of Position if (fspec[0] & 0b10){ fspec[1] |= 1 << 3; @@ -2258,12 +2262,12 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w bytes[p++] = (alt & 0xff00) >> 8; bytes[p++] = alt & 0xff; } - else if (mm->geom_delta_valid && mm->baro_alt_valid){ - fspec[2] |= 1 << 6; - int16_t alt = (int)((mm->baro_alt + mm->geom_delta) / 6.25); - bytes[p++] = (alt & 0xff00) >> 8; - bytes[p++] = alt & 0xff; - } + else if (mm->geom_delta_valid){ + fspec[2] |= 1 << 6; + int16_t alt = (int)((a->baro_alt + mm->geom_delta) / 6.25); + bytes[p++] = (alt & 0xff00) >> 8; + bytes[p++] = alt & 0xff; + } // I021/090 Quality Indicators fspec[2] |= 1 << 5; if (mm->accuracy.nac_v_valid) From 0204c7b0ce8570a0a4185bdf733261d75129931c Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sat, 22 Apr 2023 11:15:37 -0400 Subject: [PATCH 12/32] fix error in decoding groundspeed --- net_io.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/net_io.c b/net_io.c index 827098fb..ae0d6d0b 100644 --- a/net_io.c +++ b/net_io.c @@ -2066,19 +2066,19 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n } if (fspec[3] & 0x8){ // ID021/160 Airborne Ground Vector if (*p & 0x80){ //range exceeded - p += 4; - } - else{ - uint16_t gs = ((*p & 0x7f) << 8) + ((*(p + 1) & 0xff) << 1); - p += 2; - uint16_t ta = ((*p & 0xff) << 8) + ((*(p + 1) & 0xff) << 1); - p += 2; - mm->gs_valid = true; - mm->heading_valid = true; - mm->heading_type = HEADING_GROUND_TRACK; - mm->gs.v0 = gs * pow(2, -14) * 3600; - mm->heading = ta * (360 / pow(2, 16)); - } + p += 4; + } + else{ + uint16_t gs = ((*p & 0x7f) << 8) + ((*(p + 1) & 0xff)); + p += 2; + uint16_t ta = ((*p & 0xff) << 8) + ((*(p + 1) & 0xff)); + p += 2; + mm->gs_valid = true; + mm->heading_valid = true; + mm->heading_type = HEADING_GROUND_TRACK; + mm->gs.v0 = gs * pow(2, -14) * 3600; + mm->heading = ta * (360 / pow(2, 16)); + } } if (fspec[3] & 0x4){ // ID021/165 Track Angle Rate p += 2; @@ -2375,7 +2375,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w // I021/160 Airborne Ground Vector if (mm->gs_valid && mm->heading_valid && mm->heading_type == HEADING_GROUND_TRACK){ fspec[3] |= 1 << 3; - double adj_gs = (mm->gs.v0 / 3600.0) / pow(2, -14); + double adj_gs = mm->gs.v0 * 4.5511; bytes[p++] = ((int)adj_gs & 0x7f00) >> 8; bytes[p++] = (int)adj_gs & 0xff; double adj_trk = mm->heading * (pow(2,16) / 360.0); From ddbd6aadd6e35513547bf38022bd2f8ddee73e16 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sat, 22 Apr 2023 13:18:10 -0400 Subject: [PATCH 13/32] fix indenting --- net_io.c | 519 +++++++++++++++++++++++++++---------------------------- 1 file changed, 259 insertions(+), 260 deletions(-) diff --git a/net_io.c b/net_io.c index 80489924..7e0f4af8 100644 --- a/net_io.c +++ b/net_io.c @@ -1850,273 +1850,272 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n mm->sysTimestamp = -1; switch(category){ case 21: // ADS-B Message - ; - if(!(fspec[1] & 0x10)){ // no address. this is useless to us - free(fspec); - return -1; - } - if (fspec[0] & 0x80){ // ID021/010 Data Source Identification - p += 2; - } - if (fspec[0] & 0x40){ // ID021/040 Target Report Descriptor - uint8_t *trd = readFspec(&p); - if (trd[1] & 0x40){ - mm->airground = AG_GROUND; - } - else { - mm->airground = AG_AIRBORNE; - } - free(trd); - } - if (fspec[0] & 0x20){ // I021/161 Track Number - p += 2; - } - if (fspec[0] & 0x10){ // I021/015 Service Identification - p += 1; + if(!(fspec[1] & 0x10)){ // no address. this is useless to us + free(fspec); + return -1; + } + if (fspec[0] & 0x80){ // ID021/010 Data Source Identification + p += 2; + } + if (fspec[0] & 0x40){ // ID021/040 Target Report Descriptor + uint8_t *trd = readFspec(&p); + if (trd[1] & 0x40){ + mm->airground = AG_GROUND; + } + else { + mm->airground = AG_AIRBORNE; + } + free(trd); + } + if (fspec[0] & 0x20){ // I021/161 Track Number + p += 2; + } + if (fspec[0] & 0x10){ // I021/015 Service Identification + p += 1; } if (fspec[0] & 0x8){ // I021/071 Time of Applicability for Position 3 - mm->sysTimestamp = readAsterixTime(&p); - } - if (fspec[0] & 0x4){ // I021/130 Position in WGS-84 co-ordinates - int lat = (*p & 0xff) << 16; - lat += (*(p + 1) & 0xff) << 8; - lat += (*(p + 2) & 0xff); - p += 3; - int lon = (*p & 0xff) << 16; - lon += (*(p + 1) & 0xff) << 8; - lon += (*(p + 2) & 0xff); - p += 3; - if (lat >= 0x800000){ - lat -= 0x1000000; - } - if (lon >= 0x800000){ - lon -= 0x1000000; - } - double latitude = lat * (180 / pow(2, 23)); - double longitude = lon * (180 / pow(2, 23)); - if (latitude <= 90 && latitude >= -90 && longitude >= -180 && longitude <= 180){ - mm->cpr_decoded = true; - mm->decoded_lat = latitude; - mm->decoded_lon = longitude; - } - } - if (fspec[0] & 0x2){ // I021/131 Position in WGS-84 co-ordinates, high res. - int lat = (*p & 0xff) << 24; - lat += (*(p + 1) & 0xff) << 16; - lat += (*(p + 2) & 0xff) << 8; - lat += (*(p + 3) & 0xff); - p += 4; - int lon = *p << 24; - lon += (*(p + 1) & 0xff) << 16; - lon += (*(p + 2) & 0xff) << 8; - lon += (*(p + 3) & 0xff); - p += 4; - double latitude = lat * (180 / pow(2, 30)); - double longitude = lon * (180 / pow(2, 30)); - if (latitude <= 90 && latitude >= -90 && longitude >= -180 && longitude <= 180){ - mm->sbs_pos_valid = true; - mm->decoded_lat = latitude; - mm->decoded_lon = longitude; - } - } - if (fspec[1] & 0x80){ // I021/072 Time of Applicability for Velocity - if (mm->sysTimestamp == -1){ - mm->sysTimestamp = readAsterixTime(&p); - } - else { - p += 3; - } - } - if (fspec[1] & 0x40){ // I021/150 Air Speed - uint16_t raw_speed = (*p & 0x7f) << 8; - raw_speed += *(p + 1) & 0xff; - if (*p & 0x80){ //Mach - mm->mach = raw_speed * 0.001; - mm->mach_valid = true; - } - else{ // IAS - mm->ias = (raw_speed * pow(2, -14)) * 3600; - mm->ias_valid = true; - } - p += 2; - } - if (fspec[1] & 0x20){ // I021/151 True Airspeed - uint16_t raw_speed = (*p & 0x7f) << 8; - raw_speed += *(p + 1) & 0xff; - if (!(*p & 0x80)){ - mm->tas_valid = true; - mm->tas = raw_speed; - } - p += 2; - } // I021/080 Target Address - mm->addr = (((*p & 0xff) << 16) + ((*(p + 1) & 0xff) << 8) + (*(p + 2) & 0xff)) & 0xffffff; - p += 3; - //printf("Addr: %x ", mm->addr); - if (fspec[1] & 0x8){ // I021/073 Time of Message Reception of Position - if (mm->cpr_decoded){ - uint64_t ts = readAsterixTime(&p); - if (fspec[1] & 0x4){ // I021/074 Time of Message Reception of Position=High Precision - readAsterixHighPrecisionTime(&ts, &p); - } - if (mm->sysTimestamp == -1){ - mm->sysTimestamp = ts; - } - } - else if (fspec[1] & 0x4) { - p += 7; - } - else { - p += 3; - } - } - if (fspec[1] & 0x2){ // I021/075 Time of Message Reception of Velocity - if (mm->ias_valid || mm->mach_valid || mm->gs_valid){ - uint64_t ts = readAsterixTime(&p); - if (fspec[2] & 0x80){ // I021/074 Time of Message Reception of Velocity=High Precision - readAsterixHighPrecisionTime(&ts, &p); - } - if (mm->sysTimestamp == -1){ - mm->sysTimestamp = ts; - } - } - else if (fspec[2] & 0x80) { - p += 7; - } - else { - p += 3; - } - } - if (fspec[2] & 0x40){ // I021/140 Geometric Height - int16_t raw_alt = (((*p & 0xff) << 8) + (*(p + 1) & 0xff)); - double alt = raw_alt * 6.25; - if (alt >= -1500 && alt <= 150000){ - mm->geom_alt_valid = true; - mm->geom_alt_unit = UNIT_FEET; - mm->geom_alt = alt; - } - p += 2; - } - if (fspec[2] & 0x20){ // I021/090 Quality Indicators - uint8_t *qi = readFspec(&p); - free(qi); - } - if (fspec[2] & 0x10){ // I021/210 MOPS Version - mm->opstatus.version = ((*p) & 0x38) >> 3; - p++; - //uint8_t ltt = ((*p) & 0x7); - } - if (fspec[2] & 0x8){ // I021/070 Mode 3/A Code - mm->squawk += (((*p & 0xe) << 11) + ((*p & 0x1) << 10) + ((*(p + 1) & 0xC0) << 2) + ((*(p + 1) & 0x38) << 1) + ((*(p + 1) & 0x7))) ; - mm->squawk_valid = true; - p += 2; - } - if (fspec[2] & 0x4){ // I021/230 Roll Angle - int16_t roll = ((*p & 0xff) << 8) + (*(p + 1) & 0xff); - mm->roll = roll * 0.01; - mm->roll_valid = true; - p += 2; - } - if (fspec[2] & 0x2){ // I021/045 Flight Level - int16_t alt = ((*p & 0xff) << 8) + (*(p + 1) & 0xff); - mm->baro_alt_valid = true; - mm->baro_alt = alt * 25; - mm->baro_alt_unit = UNIT_FEET; - p += 2; - } - if (fspec[3] & 0x80){ // I021/152 Magnetic Heading - mm->heading_valid = true; - mm->heading_type = HEADING_MAGNETIC; - uint16_t heading = ((*p & 0xff) << 8) + (*(p + 1) & 0xff); - mm->heading = heading * (360 / pow(2, 16)); - p += 2; - } - if (fspec[3] & 0x40){ // I021/200 Target Status - mm->spi_valid = true; - mm->alert_valid = true; - mm->emergency_valid = true; - mm->nav.modes_valid = true; - mm->nav.modes |= (*p & 0b01000000) >> 4; - mm->emergency = (*p & 0b00011100) >> 2; - mm->alert = (*p & 0b11); - mm->spi = (*p & 0b11) == 3; - p++; - } - if (fspec[3] & 0x20){ // ID021/155 Barometric Vertical Rate - if (*p & 0x80){ //range exceeded - p += 2; - } - else{ - int16_t vr = ((*p & 0x7f) << 9) + ((*(p + 1) & 0xff) << 1); - mm->baro_rate_valid = true; - mm->baro_rate = vr * 3.125; - p += 2; - } - } - if (fspec[3] & 0x10){ // ID021/157 Geometric Vertical Rate - if (*p & 0x80){ //range exceeded - p += 2; - } - else{ - int16_t vr = ((*p & 0x7f) << 9) + ((*(p + 1) & 0xff) << 1); - mm->geom_rate_valid = true; - mm->geom_rate = vr * 3.125; - p += 2; - } - } - if (fspec[3] & 0x8){ // ID021/160 Airborne Ground Vector - if (*p & 0x80){ //range exceeded - p += 4; + mm->sysTimestamp = readAsterixTime(&p); } - else{ - uint16_t gs = ((*p & 0x7f) << 8) + ((*(p + 1) & 0xff)); + if (fspec[0] & 0x4){ // I021/130 Position in WGS-84 co-ordinates + int lat = (*p & 0xff) << 16; + lat += (*(p + 1) & 0xff) << 8; + lat += (*(p + 2) & 0xff); + p += 3; + int lon = (*p & 0xff) << 16; + lon += (*(p + 1) & 0xff) << 8; + lon += (*(p + 2) & 0xff); + p += 3; + if (lat >= 0x800000){ + lat -= 0x1000000; + } + if (lon >= 0x800000){ + lon -= 0x1000000; + } + double latitude = lat * (180 / pow(2, 23)); + double longitude = lon * (180 / pow(2, 23)); + if (latitude <= 90 && latitude >= -90 && longitude >= -180 && longitude <= 180){ + mm->cpr_decoded = true; + mm->decoded_lat = latitude; + mm->decoded_lon = longitude; + } + } + if (fspec[0] & 0x2){ // I021/131 Position in WGS-84 co-ordinates, high res. + int lat = (*p & 0xff) << 24; + lat += (*(p + 1) & 0xff) << 16; + lat += (*(p + 2) & 0xff) << 8; + lat += (*(p + 3) & 0xff); + p += 4; + int lon = *p << 24; + lon += (*(p + 1) & 0xff) << 16; + lon += (*(p + 2) & 0xff) << 8; + lon += (*(p + 3) & 0xff); + p += 4; + double latitude = lat * (180 / pow(2, 30)); + double longitude = lon * (180 / pow(2, 30)); + if (latitude <= 90 && latitude >= -90 && longitude >= -180 && longitude <= 180){ + mm->sbs_pos_valid = true; + mm->decoded_lat = latitude; + mm->decoded_lon = longitude; + } + } + if (fspec[1] & 0x80){ // I021/072 Time of Applicability for Velocity + if (mm->sysTimestamp == -1){ + mm->sysTimestamp = readAsterixTime(&p); + } + else { + p += 3; + } + } + if (fspec[1] & 0x40){ // I021/150 Air Speed + uint16_t raw_speed = (*p & 0x7f) << 8; + raw_speed += *(p + 1) & 0xff; + if (*p & 0x80){ //Mach + mm->mach = raw_speed * 0.001; + mm->mach_valid = true; + } + else{ // IAS + mm->ias = (raw_speed * pow(2, -14)) * 3600; + mm->ias_valid = true; + } + p += 2; + } + if (fspec[1] & 0x20){ // I021/151 True Airspeed + uint16_t raw_speed = (*p & 0x7f) << 8; + raw_speed += *(p + 1) & 0xff; + if (!(*p & 0x80)){ + mm->tas_valid = true; + mm->tas = raw_speed; + } + p += 2; + } + // I021/080 Target Address + mm->addr = (((*p & 0xff) << 16) + ((*(p + 1) & 0xff) << 8) + (*(p + 2) & 0xff)) & 0xffffff; + p += 3; + if (fspec[1] & 0x8){ // I021/073 Time of Message Reception of Position + if (mm->cpr_decoded){ + uint64_t ts = readAsterixTime(&p); + if (fspec[1] & 0x4){ // I021/074 Time of Message Reception of Position=High Precision + readAsterixHighPrecisionTime(&ts, &p); + } + if (mm->sysTimestamp == -1){ + mm->sysTimestamp = ts; + } + } + else if (fspec[1] & 0x4) { + p += 7; + } + else { + p += 3; + } + } + if (fspec[1] & 0x2){ // I021/075 Time of Message Reception of Velocity + if (mm->ias_valid || mm->mach_valid || mm->gs_valid){ + uint64_t ts = readAsterixTime(&p); + if (fspec[2] & 0x80){ // I021/074 Time of Message Reception of Velocity=High Precision + readAsterixHighPrecisionTime(&ts, &p); + } + if (mm->sysTimestamp == -1){ + mm->sysTimestamp = ts; + } + } + else if (fspec[2] & 0x80) { + p += 7; + } + else { + p += 3; + } + } + if (fspec[2] & 0x40){ // I021/140 Geometric Height + int16_t raw_alt = (((*p & 0xff) << 8) + (*(p + 1) & 0xff)); + double alt = raw_alt * 6.25; + if (alt >= -1500 && alt <= 150000){ + mm->geom_alt_valid = true; + mm->geom_alt_unit = UNIT_FEET; + mm->geom_alt = alt; + } + p += 2; + } + if (fspec[2] & 0x20){ // I021/090 Quality Indicators + uint8_t *qi = readFspec(&p); + free(qi); + } + if (fspec[2] & 0x10){ // I021/210 MOPS Version + mm->opstatus.version = ((*p) & 0x38) >> 3; + p++; + //uint8_t ltt = ((*p) & 0x7); + } + if (fspec[2] & 0x8){ // I021/070 Mode 3/A Code + mm->squawk += (((*p & 0xe) << 11) + ((*p & 0x1) << 10) + ((*(p + 1) & 0xC0) << 2) + ((*(p + 1) & 0x38) << 1) + ((*(p + 1) & 0x7))) ; + mm->squawk_valid = true; p += 2; - uint16_t ta = ((*p & 0xff) << 8) + ((*(p + 1) & 0xff)); + } + if (fspec[2] & 0x4){ // I021/230 Roll Angle + int16_t roll = ((*p & 0xff) << 8) + (*(p + 1) & 0xff); + mm->roll = roll * 0.01; + mm->roll_valid = true; + p += 2; + } + if (fspec[2] & 0x2){ // I021/045 Flight Level + int16_t alt = ((*p & 0xff) << 8) + (*(p + 1) & 0xff); + mm->baro_alt_valid = true; + mm->baro_alt = alt * 25; + mm->baro_alt_unit = UNIT_FEET; p += 2; - mm->gs_valid = true; + } + if (fspec[3] & 0x80){ // I021/152 Magnetic Heading mm->heading_valid = true; - mm->heading_type = HEADING_GROUND_TRACK; - mm->gs.v0 = gs * pow(2, -14) * 3600; - mm->heading = ta * (360 / pow(2, 16)); + mm->heading_type = HEADING_MAGNETIC; + uint16_t heading = ((*p & 0xff) << 8) + (*(p + 1) & 0xff); + mm->heading = heading * (360 / pow(2, 16)); + p += 2; } - } - if (fspec[3] & 0x4){ // ID021/165 Track Angle Rate - p += 2; - } - if (fspec[3] & 0x2){ // ID021/077 Time of Report Transmission - uint64_t tt = readAsterixTime(&p); - if (mm->sysTimestamp == -1){ - mm->sysTimestamp = tt; - } - } - if (fspec[4] & 0x80){ // ID021/170 Target Identification - uint64_t cs = ((uint64_t)(*p & 0xff) << 40) + ((uint64_t)(*(p + 1) & 0xff) << 32) + ((uint64_t)(*(p + 2) & 0xff) << 24) + ((uint64_t)(*(p + 3) & 0xff) << 16) + ((uint64_t)(*(p + 4) & 0xff) << 8) + (uint64_t)(*(p + 5) & 0xff); - char *callsign = mm->callsign; - callsign[0] = ais_charset[((cs & 0xFC0000000000) >> 42)]; - callsign[1] = ais_charset[((cs & 0x3F000000000) >> 36)]; - callsign[2] = ais_charset[((cs & 0xFC0000000) >> 30)]; - callsign[3] = ais_charset[((cs & 0x3F000000) >> 24)]; - callsign[4] = ais_charset[((cs & 0xFC0000) >> 18)]; - callsign[5] = ais_charset[((cs & 0x3F000) >> 12)]; - callsign[6] = ais_charset[((cs & 0xFC0) >> 6)]; - callsign[7] = ais_charset[(cs & 0x3F)]; - callsign[8] = 0; - mm->callsign_valid = 1; - for (int i = 0; i < 8; ++i) { - if ( - (callsign[i] >= 'A' && callsign[i] <= 'Z') - // -./0123456789 - || (callsign[i] >= '-' && callsign[i] <= '9') - || callsign[i] == ' ' - || callsign[i] == '@' - ) { - // valid chars - } else { - mm->callsign_valid = 0; - } - } - p += 6; - } - + if (fspec[3] & 0x40){ // I021/200 Target Status + mm->spi_valid = true; + mm->alert_valid = true; + mm->emergency_valid = true; + mm->nav.modes_valid = true; + mm->nav.modes |= (*p & 0b01000000) >> 4; + mm->emergency = (*p & 0b00011100) >> 2; + mm->alert = (*p & 0b11); + mm->spi = (*p & 0b11) == 3; + p++; + } + if (fspec[3] & 0x20){ // ID021/155 Barometric Vertical Rate + if (*p & 0x80){ //range exceeded + p += 2; + } + else{ + int16_t vr = ((*p & 0x7f) << 9) + ((*(p + 1) & 0xff) << 1); + mm->baro_rate_valid = true; + mm->baro_rate = vr * 3.125; + p += 2; + } + } + if (fspec[3] & 0x10){ // ID021/157 Geometric Vertical Rate + if (*p & 0x80){ //range exceeded + p += 2; + } + else{ + int16_t vr = ((*p & 0x7f) << 9) + ((*(p + 1) & 0xff) << 1); + mm->geom_rate_valid = true; + mm->geom_rate = vr * 3.125; + p += 2; + } + } + if (fspec[3] & 0x8){ // ID021/160 Airborne Ground Vector + if (*p & 0x80){ //range exceeded + p += 4; + } + else{ + uint16_t gs = ((*p & 0x7f) << 8) + ((*(p + 1) & 0xff)); + p += 2; + uint16_t ta = ((*p & 0xff) << 8) + ((*(p + 1) & 0xff)); + p += 2; + mm->gs_valid = true; + mm->heading_valid = true; + mm->heading_type = HEADING_GROUND_TRACK; + mm->gs.v0 = gs * pow(2, -14) * 3600; + mm->heading = ta * (360 / pow(2, 16)); + } + } + if (fspec[3] & 0x4){ // ID021/165 Track Angle Rate + p += 2; + } + if (fspec[3] & 0x2){ // ID021/077 Time of Report Transmission + uint64_t tt = readAsterixTime(&p); + if (mm->sysTimestamp == -1){ + mm->sysTimestamp = tt; + } + } + if (fspec[4] & 0x80){ // ID021/170 Target Identification + uint64_t cs = ((uint64_t)(*p & 0xff) << 40) + ((uint64_t)(*(p + 1) & 0xff) << 32) + ((uint64_t)(*(p + 2) & 0xff) << 24) + ((uint64_t)(*(p + 3) & 0xff) << 16) + ((uint64_t)(*(p + 4) & 0xff) << 8) + (uint64_t)(*(p + 5) & 0xff); + char *callsign = mm->callsign; + callsign[0] = ais_charset[((cs & 0xFC0000000000) >> 42)]; + callsign[1] = ais_charset[((cs & 0x3F000000000) >> 36)]; + callsign[2] = ais_charset[((cs & 0xFC0000000) >> 30)]; + callsign[3] = ais_charset[((cs & 0x3F000000) >> 24)]; + callsign[4] = ais_charset[((cs & 0xFC0000) >> 18)]; + callsign[5] = ais_charset[((cs & 0x3F000) >> 12)]; + callsign[6] = ais_charset[((cs & 0xFC0) >> 6)]; + callsign[7] = ais_charset[(cs & 0x3F)]; + callsign[8] = 0; + mm->callsign_valid = 1; + for (int i = 0; i < 8; ++i) { + if ( + (callsign[i] >= 'A' && callsign[i] <= 'Z') + // -./0123456789 + || (callsign[i] >= '-' && callsign[i] <= '9') + || callsign[i] == ' ' + || callsign[i] == '@' + ) { + // valid chars + } else { + mm->callsign_valid = 0; + } + } + p += 6; + } + break; } if (mm->sysTimestamp == -1){ mm->sysTimestamp = mstime(); From 1d8ea75e2ece83a8da6844165c4422800193457d Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sat, 22 Apr 2023 18:30:25 -0400 Subject: [PATCH 14/32] possibly properly interperet quality indicators --- net_io.c | 100 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/net_io.c b/net_io.c index 7e0f4af8..f11f3157 100644 --- a/net_io.c +++ b/net_io.c @@ -1987,22 +1987,77 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n } if (fspec[2] & 0x40){ // I021/140 Geometric Height int16_t raw_alt = (((*p & 0xff) << 8) + (*(p + 1) & 0xff)); - double alt = raw_alt * 6.25; - if (alt >= -1500 && alt <= 150000){ - mm->geom_alt_valid = true; - mm->geom_alt_unit = UNIT_FEET; - mm->geom_alt = alt; - } - p += 2; + double alt = raw_alt * 6.25; + if (alt >= -1500 && alt <= 150000){ + mm->geom_alt_valid = true; + mm->geom_alt_unit = UNIT_FEET; + mm->geom_alt = alt; + } + p += 2; } + uint8_t *qi; + //uint8_t nucp_or_nic; + uint8_t nucr_or_nacv; + uint8_t nicbaro; + uint8_t sil; + uint8_t nacp; + uint8_t sils; + uint8_t sda; + uint8_t gva; + //uint8_t pic; if (fspec[2] & 0x20){ // I021/090 Quality Indicators - uint8_t *qi = readFspec(&p); - free(qi); + qi = readFspec(&p); + //nucp_or_nic = (qi[0] & 0x1e) >> 1; + nucr_or_nacv = (qi[0] & 0xe0) >> 5; + mm->accuracy.nac_v_valid = true; + mm->accuracy.nac_v = nucr_or_nacv; + if (qi[0] & 0x1){ + nicbaro = (qi[1] & 0x80) >> 7; + sil = (qi[1] & 0x60) >> 5; + mm->accuracy.sil = sil; + nacp = (qi[1] & 0x1e) >> 1; + if (qi[1] & 0x1){ + sils = (qi[2] & 0x20) >> 5; + if (sils){ + mm->accuracy.sil_type = SIL_PER_SAMPLE; + } + else{ + mm->accuracy.sil_type = SIL_PER_HOUR; + } + sda = (qi[2] & 0x18) >> 3; + gva = (qi[2] & 0x6) >> 1; + //pic = (qi[3] & 0xf0) >> 4; + } + else{ + mm->accuracy.sil_type = SIL_UNKNOWN; + } + } + free(qi); } if (fspec[2] & 0x10){ // I021/210 MOPS Version + mm->opstatus.valid = true; mm->opstatus.version = ((*p) & 0x38) >> 3; - p++; - //uint8_t ltt = ((*p) & 0x7); + p++; + switch(mm->opstatus.version){ + case 1: + mm->accuracy.nac_p_valid = true; + mm->accuracy.nac_p = nacp; + mm->accuracy.nic_baro_valid = true; + mm->accuracy.nic_baro = nicbaro; + mm->accuracy.sil_type = SIL_UNKNOWN; + break; + case 2: + mm->accuracy.nac_p_valid = true; + mm->accuracy.nac_p = nacp; + mm->accuracy.gva_valid = true; + mm->accuracy.gva = gva; + mm->accuracy.sda_valid = true; + mm->accuracy.sda = sda; + mm->accuracy.nic_baro_valid = true; + mm->accuracy.nic_baro_valid = true; + mm->accuracy.nic_baro = nicbaro; + break; + } } if (fspec[2] & 0x8){ // I021/070 Mode 3/A Code mm->squawk += (((*p & 0xe) << 11) + ((*p & 0x1) << 10) + ((*(p + 1) & 0xC0) << 2) + ((*(p + 1) & 0x38) << 1) + ((*(p + 1) & 0x7))) ; @@ -2121,8 +2176,8 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n mm->sysTimestamp = mstime(); } free(fspec); - mm->decoded_nic = 0; - mm->decoded_rc = RC_UNKNOWN; + //mm->decoded_nic = 0; + //mm->decoded_rc = RC_UNKNOWN; netUseMessage(mm); return 0; } @@ -2452,13 +2507,18 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w // I021/008 Aircraft Operational Status if (mm->opstatus.valid){ - fspec[5] |= 1 << 7; - bytes[p] |= (mm->opstatus.om_acas_ra << 7); - bytes[p] |= (mm->opstatus.cc_tc << 5); - bytes[p] |= (mm->opstatus.cc_ts << 4); - bytes[p] |= (mm->opstatus.cc_arv << 3); - bytes[p] |= (mm->opstatus.cc_cdti << 2); - p++; + if (mm->opstatus.om_acas_ra || mm->opstatus.cc_tc || + mm->opstatus.cc_ts || mm->opstatus.cc_arv || mm->opstatus.cc_cdti + || !(mm->opstatus.cc_acas)){ + fspec[5] |= 1 << 7; + bytes[p] |= (mm->opstatus.om_acas_ra & 0x1) << 7; + bytes[p] |= (mm->opstatus.cc_tc & 0x3) << 5; + bytes[p] |= (mm->opstatus.cc_ts & 0x1) << 4; + bytes[p] |= (mm->opstatus.cc_arv & 0x1) << 3; + bytes[p] |= (mm->opstatus.cc_cdti & 0x1) << 2; + bytes[p] |= (!(mm->opstatus.cc_acas) & 0x1) << 1; + p++; + } } // I021/295 Data Ages From 840ca97bbe0226beba2dfbefc640f22b06a1665c Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 07:46:02 -0400 Subject: [PATCH 15/32] assign values --- net_io.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net_io.c b/net_io.c index f11f3157..307d82dd 100644 --- a/net_io.c +++ b/net_io.c @@ -1998,12 +1998,12 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n uint8_t *qi; //uint8_t nucp_or_nic; uint8_t nucr_or_nacv; - uint8_t nicbaro; + uint8_t nicbaro = 0; uint8_t sil; - uint8_t nacp; + uint8_t nacp = 0; uint8_t sils; - uint8_t sda; - uint8_t gva; + uint8_t sda = 0; + uint8_t gva = 0; //uint8_t pic; if (fspec[2] & 0x20){ // I021/090 Quality Indicators qi = readFspec(&p); @@ -2054,7 +2054,6 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n mm->accuracy.sda_valid = true; mm->accuracy.sda = sda; mm->accuracy.nic_baro_valid = true; - mm->accuracy.nic_baro_valid = true; mm->accuracy.nic_baro = nicbaro; break; } From bd7b82a2b5d59b4671878fc7a1d47abbdeddb9ab Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 08:50:33 -0400 Subject: [PATCH 16/32] Add receiver ID --- net_io.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net_io.c b/net_io.c index 307d82dd..a4020fea 100644 --- a/net_io.c +++ b/net_io.c @@ -2520,6 +2520,12 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w } } + // I021/400 Receiver ID + if (mm->receiverId){ + fspec[5] |= 1 << 2; + bytes[p++] = (mm->receiverId) & 0xFF; + } + // I021/295 Data Ages /* if (fspec[4] == 0b100000){ From 7460ae497a19a0710cec0b0719d785a6f1e69e43 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 09:09:59 -0400 Subject: [PATCH 17/32] switch to using 24-bit position --- net_io.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/net_io.c b/net_io.c index a4020fea..ecf87fa5 100644 --- a/net_io.c +++ b/net_io.c @@ -1894,7 +1894,7 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n double latitude = lat * (180 / pow(2, 23)); double longitude = lon * (180 / pow(2, 23)); if (latitude <= 90 && latitude >= -90 && longitude >= -180 && longitude <= 180){ - mm->cpr_decoded = true; + mm->sbs_pos_valid = true; mm->decoded_lat = latitude; mm->decoded_lon = longitude; } @@ -2229,7 +2229,29 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w } p++; + // I021/130 Position in WGS-84 co-ordinates + if(mm->cpr_decoded){ + fspec[0] |= 1 << 2; + int32_t lat; + int32_t lon; + lat = mm->decoded_lat / (180 / pow(2,23)); + lon = mm->decoded_lon / (180 / pow(2,23)); + if (lat < 0){ + lat += 0x1000000; + } + if (lon < 0){ + lon += 0x1000000; + } + bytes[p++] = (lat & 0xFF0000) >> 16; + bytes[p++] = (lat & 0xFF00) >> 8; + bytes[p++] = (lat & 0xFF); + bytes[p++] = (lon & 0xFF0000) >> 16; + bytes[p++] = (lon & 0xFF00) >> 8; + bytes[p++] = (lon & 0xFF); + } + // I021/131 Position in WGS-84 co-ordinates, high res. + /* if(mm->cpr_decoded){ fspec[0] |= 1 << 1; int32_t lat; @@ -2245,6 +2267,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w bytes[p++] = (lon & 0xFF00) >> 8; bytes[p++] = (lon & 0xFF); } + */ // I021/150 Air Speed if(mm->ias_valid || mm->mach_valid){ fspec[1] |= 1 << 6; From bb126465460b787883b3dbafa0eb697499517230 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 09:11:40 -0400 Subject: [PATCH 18/32] fix indenting --- net_io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net_io.c b/net_io.c index ecf87fa5..d1a1cbc9 100644 --- a/net_io.c +++ b/net_io.c @@ -1918,8 +1918,8 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n mm->decoded_lon = longitude; } } - if (fspec[1] & 0x80){ // I021/072 Time of Applicability for Velocity - if (mm->sysTimestamp == -1){ + if (fspec[1] & 0x80){ // I021/072 Time of Applicability for Velocity + if (mm->sysTimestamp == -1){ mm->sysTimestamp = readAsterixTime(&p); } else { From 92c145bfdb2310a722cf8c241a8f351949894971 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 09:30:48 -0400 Subject: [PATCH 19/32] send time when using 24-bit position also --- net_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net_io.c b/net_io.c index d1a1cbc9..8eaa0a5f 100644 --- a/net_io.c +++ b/net_io.c @@ -2301,7 +2301,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w } // I021/073 Time of Message Reception of Position - if (fspec[0] & 0b10){ + if (fspec[0] & 0b110){ fspec[1] |= 1 << 3; long midnight = (long)(time(NULL) / 86400) * 86400000; int tsm = (mm->sysTimestamp) - midnight; From 05296e9b1b6fd4fbb902b6545ef8add184e88be0 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 09:48:31 -0400 Subject: [PATCH 20/32] Fix indenting --- net_io.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/net_io.c b/net_io.c index d1a1cbc9..d43caac9 100644 --- a/net_io.c +++ b/net_io.c @@ -2096,25 +2096,25 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n } if (fspec[3] & 0x20){ // ID021/155 Barometric Vertical Rate if (*p & 0x80){ //range exceeded - p += 2; - } - else{ - int16_t vr = ((*p & 0x7f) << 9) + ((*(p + 1) & 0xff) << 1); - mm->baro_rate_valid = true; - mm->baro_rate = vr * 3.125; - p += 2; - } + p += 2; + } + else{ + int16_t vr = ((*p & 0x7f) << 9) + ((*(p + 1) & 0xff) << 1); + mm->baro_rate_valid = true; + mm->baro_rate = vr * 3.125; + p += 2; + } } if (fspec[3] & 0x10){ // ID021/157 Geometric Vertical Rate if (*p & 0x80){ //range exceeded - p += 2; - } - else{ - int16_t vr = ((*p & 0x7f) << 9) + ((*(p + 1) & 0xff) << 1); - mm->geom_rate_valid = true; - mm->geom_rate = vr * 3.125; - p += 2; - } + p += 2; + } + else{ + int16_t vr = ((*p & 0x7f) << 9) + ((*(p + 1) & 0xff) << 1); + mm->geom_rate_valid = true; + mm->geom_rate = vr * 3.125; + p += 2; + } } if (fspec[3] & 0x8){ // ID021/160 Airborne Ground Vector if (*p & 0x80){ //range exceeded @@ -2136,10 +2136,10 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n p += 2; } if (fspec[3] & 0x2){ // ID021/077 Time of Report Transmission - uint64_t tt = readAsterixTime(&p); - if (mm->sysTimestamp == -1){ - mm->sysTimestamp = tt; - } + uint64_t tt = readAsterixTime(&p); + if (mm->sysTimestamp == -1){ + mm->sysTimestamp = tt; + } } if (fspec[4] & 0x80){ // ID021/170 Target Identification uint64_t cs = ((uint64_t)(*p & 0xff) << 40) + ((uint64_t)(*(p + 1) & 0xff) << 32) + ((uint64_t)(*(p + 2) & 0xff) << 24) + ((uint64_t)(*(p + 3) & 0xff) << 16) + ((uint64_t)(*(p + 4) & 0xff) << 8) + (uint64_t)(*(p + 5) & 0xff); From f9c01bdd27bf9bea01e9e46afd9946402eb9773f Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 11:20:43 -0400 Subject: [PATCH 21/32] send ASTERIX position from SBS data, too --- net_io.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net_io.c b/net_io.c index a0e348f9..e80a8526 100644 --- a/net_io.c +++ b/net_io.c @@ -1952,7 +1952,7 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n mm->addr = (((*p & 0xff) << 16) + ((*(p + 1) & 0xff) << 8) + (*(p + 2) & 0xff)) & 0xffffff; p += 3; if (fspec[1] & 0x8){ // I021/073 Time of Message Reception of Position - if (mm->cpr_decoded){ + if (mm->cpr_decoded || mm->sbs_pos_valid){ uint64_t ts = readAsterixTime(&p); if (fspec[1] & 0x4){ // I021/074 Time of Message Reception of Position=High Precision readAsterixHighPrecisionTime(&ts, &p); @@ -2230,7 +2230,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w p++; // I021/130 Position in WGS-84 co-ordinates - if(mm->cpr_decoded){ + if (mm->cpr_decoded || mm->sbs_pos_valid){ fspec[0] |= 1 << 2; int32_t lat; int32_t lon; @@ -2252,7 +2252,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w // I021/131 Position in WGS-84 co-ordinates, high res. /* - if(mm->cpr_decoded){ + if (mm->cpr_decoded || mm->sbs_pos_valid){ fspec[0] |= 1 << 1; int32_t lat; int32_t lon; From 02bd08af279636601c3b978ca3f469a9d6499355 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 11:42:46 -0400 Subject: [PATCH 22/32] add asterix_in to net_connectors --- net_io.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net_io.c b/net_io.c index e80a8526..59c43f44 100644 --- a/net_io.c +++ b/net_io.c @@ -1013,6 +1013,8 @@ void modesInitNet(void) { con->service = sbs_out; else if (strcmp(con->protocol, "asterix_out") == 0) con->service = asterix_out; + else if (strcmp(con->protocol, "asterix_in") == 0) + con->service = asterix_in; else if (strcmp(con->protocol, "sbs_in") == 0) con->service = sbs_in; else if (strcmp(con->protocol, "sbs_in_mlat") == 0) From a50a1e45ba7db7f2a7f9ac758b23218920662d13 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 11:46:40 -0400 Subject: [PATCH 23/32] add asterix_in and asterix_out to net_connector args --- readsb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readsb.c b/readsb.c index 9fe215a5..860f5c35 100644 --- a/readsb.c +++ b/readsb.c @@ -1345,6 +1345,8 @@ static int make_net_connector(char *arg) { && strcmp(con->protocol, "sbs_out_mlat") != 0 && strcmp(con->protocol, "sbs_out_jaero") != 0 && strcmp(con->protocol, "sbs_out_prio") != 0 + && strcmp(con->protocol, "asterix_out") != 0 + && strcmp(con->protocol, "asterix_in") != 0 && strcmp(con->protocol, "json_out") != 0 && strcmp(con->protocol, "feedmap_out") != 0 && strcmp(con->protocol, "gpsd_in") != 0 @@ -1354,6 +1356,7 @@ static int make_net_connector(char *arg) { fprintf(stderr, "Supported protocols: beast_out, beast_in, beast_reduce_out, beast_reduce_plus_out, raw_out, raw_in, \n" "sbs_out, sbs_out_replay, sbs_out_mlat, sbs_out_jaero, \n" "sbs_in, sbs_in_mlat, sbs_in_jaero, \n" + "sbs_out_prio, asterix_out, asterix_in, \n" "vrs_out, json_out, gpsd_in, uat_in\n"); return 1; } From b2b4aa97c323c974e0549fd1fdcde21aabb2d161 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 12:02:04 -0400 Subject: [PATCH 24/32] add asterix options to README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 38a42070..0679e2a6 100644 --- a/README.md +++ b/README.md @@ -275,9 +275,9 @@ Don't write recent(1), full(2), either(3) traces Establish connection, can be specified multiple times (e.g. 127.0.0.1,23004,beast_out) Protocols: beast_out, beast_in, raw_out, raw_in, sbs_in, - sbs_in_jaero, sbs_out, sbs_out_jaero, vrs_out, - json_out, gpsd_in (one failover ip/address,port - can be specified: + sbs_in_jaero, sbs_out, sbs_out_jaero, sbs_out_prio + vrs_out, asterix_out, asterx_in, gpsd_in (one failover + ip/address,port can be specified: primary-address,primary-port,protocol,failover-address,failover-port) --net-connector-delay= Outbound re-connection delay (default: 30) @@ -320,6 +320,7 @@ TCP json position output: include aircraft without --net-sbs-reduce Apply beast reduce logic and interval to SBS outputs --net-ao-port= TCP ASTERIX output listen ports (default: 0) + --net-ai-port= TCP ASTERIX input listen ports (default: 0) --net-asterix-reduce Apply beast reduce logic and interval to ASTERIX outputs --net-verbatim Forward messages unchanged From df9a948d6e22ca7fc5abf691f014396c45192e83 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 13:21:36 -0400 Subject: [PATCH 25/32] correct item numbers --- net_io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net_io.c b/net_io.c index e80a8526..68a80541 100644 --- a/net_io.c +++ b/net_io.c @@ -1971,7 +1971,7 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n if (fspec[1] & 0x2){ // I021/075 Time of Message Reception of Velocity if (mm->ias_valid || mm->mach_valid || mm->gs_valid){ uint64_t ts = readAsterixTime(&p); - if (fspec[2] & 0x80){ // I021/074 Time of Message Reception of Velocity=High Precision + if (fspec[2] & 0x80){ // I021/076 Time of Message Reception of Velocity=High Precision readAsterixHighPrecisionTime(&ts, &p); } if (mm->sysTimestamp == -1){ @@ -2069,7 +2069,7 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n mm->roll_valid = true; p += 2; } - if (fspec[2] & 0x2){ // I021/045 Flight Level + if (fspec[2] & 0x2){ // I021/145 Flight Level int16_t alt = ((*p & 0xff) << 8) + (*(p + 1) & 0xff); mm->baro_alt_valid = true; mm->baro_alt = alt * 25; From fcf9e72294c03af828f7e505c97c0c619da6cebe Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 23 Apr 2023 13:49:27 -0400 Subject: [PATCH 26/32] accidentally deleted json_out, and misspelled asterix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0679e2a6..cf5a1a35 100644 --- a/README.md +++ b/README.md @@ -276,8 +276,8 @@ Don't write recent(1), full(2), either(3) traces times (e.g. 127.0.0.1,23004,beast_out) Protocols: beast_out, beast_in, raw_out, raw_in, sbs_in, sbs_in_jaero, sbs_out, sbs_out_jaero, sbs_out_prio - vrs_out, asterix_out, asterx_in, gpsd_in (one failover - ip/address,port can be specified: + vrs_out, json_out, asterix_out, asterix_in, + gpsd_in (one failover ip/address,port can be specified: primary-address,primary-port,protocol,failover-address,failover-port) --net-connector-delay= Outbound re-connection delay (default: 30) From 2440482dd1d7c62de6bab1a9d27d52c3bf2b9bc8 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Tue, 25 Apr 2023 08:04:42 -0400 Subject: [PATCH 27/32] Correctly input/output Emitter Category --- net_io.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/net_io.c b/net_io.c index e8fafb96..c0b2b346 100644 --- a/net_io.c +++ b/net_io.c @@ -2171,6 +2171,72 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n } p += 6; } + if (fspec[4] & 0x40){ // ID021/020 Emitter Category + int tc = 0; + int ca = 0; + uint8_t ecat = *p++ & 0xFF; + switch (ecat) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + tc = 4; + ca = ecat; + break; + case 10: + tc = 4; + ca = 7; + break; + case 11: + tc = 3; + ca = 1; + break; + case 12: + tc = 3; + ca = 2; + break; + case 13: + tc = 3; + ca = 6; + break; + case 14: + tc = 3; + ca = 7; + break; + case 15: + tc = 3; + ca = 4; + break; + case 16: + tc = 3; + ca = 3; + break; + case 20: + tc = 2; + ca = 1; + break; + case 21: + tc = 2; + ca = 3; + break; + case 22: + tc = 2; + ca = 4; + break; + case 23: + tc = 2; + ca = 5; + break; + case 24: + tc = 2; + ca = 6; + break; + } + mm->category = ((0x0E - tc) << 4) | ca; + mm->category_valid = 1; + } break; } if (mm->sysTimestamp == -1){ @@ -2494,7 +2560,68 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w // I021/020 Emitter Category if (mm->category_valid){ fspec[4] |= 1 << 6; - bytes[p++] = mm->category; + int tc = 0x0e - ((mm->category & 0x1F0) >> 4); + int ca = mm->category & 7; + if (ca){ + switch (tc) { + case 1: + break; + case 2: + switch (ca){ + case 1: + bytes[p++] = 20; + break; + case 3: + bytes[p++] = 21; + break; + case 4: + case 5: + case 6: + case 7: + bytes[p++] = 22; + break; + } + break; + case 3: + switch (ca){ + case 1: + bytes[p++] = 11; + break; + case 2: + bytes[p++] = 12; + break; + case 3: + bytes[p++] = 16; + break; + case 4: + bytes[p++] = 15; + break; + case 6: + bytes[p++] = 13; + break; + case 7: + bytes[p++] = 14; + break; + } + break; + case 4: + switch (ca){ + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + bytes[p++] = ca; + break; + case 7: + bytes[p++] = 10; + } + break; + } + } else { + bytes[p++] = 0; + } } // I021/220 Met Information From 534c302cdd4b74d0ad0cb855d32166ec5255903b Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Wed, 26 Apr 2023 06:33:45 -0400 Subject: [PATCH 28/32] input address type --- net_io.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net_io.c b/net_io.c index c0b2b346..f588b2c1 100644 --- a/net_io.c +++ b/net_io.c @@ -1861,13 +1861,17 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n } if (fspec[0] & 0x40){ // ID021/040 Target Report Descriptor uint8_t *trd = readFspec(&p); + mm->addrtype = (trd[1] & 0xE0) >> 5; + if (!(trd[0] & 0x18)){ + mm->alt_q_bit = 1; + } if (trd[1] & 0x40){ - mm->airground = AG_GROUND; - } - else { - mm->airground = AG_AIRBORNE; - } - free(trd); + mm->airground = AG_GROUND; + } + else { + mm->airground = AG_AIRBORNE; + } + free(trd); } if (fspec[0] & 0x20){ // I021/161 Track Number p += 2; @@ -2283,7 +2287,7 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w // I021/040 Target Report Descriptor fspec[0] |= 1 << 6; - if (mm->addrtype >= 3 ) + if (mm->addrtype > 0) bytes[p] |= (3 << 5); if (mm->alt_q_bit == 0) From 0c0162022690051761943527aacaea70451372b7 Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Wed, 26 Apr 2023 06:42:32 -0400 Subject: [PATCH 29/32] don't try to use invalid asterix message --- net_io.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net_io.c b/net_io.c index f588b2c1..65a773a1 100644 --- a/net_io.c +++ b/net_io.c @@ -1831,7 +1831,7 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n //uint16_t msgLen = (*(p + 1) << 8) + *(p + 2); //int j; unsigned char category; - + bool mmvalid = false; struct modesMessage *mm = netGetMM(mb); mm->client = c; MODES_NOTUSED(c); @@ -2241,15 +2241,21 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n mm->category = ((0x0E - tc) << 4) | ca; mm->category_valid = 1; } + mmvalid = true; break; } + free(fspec); if (mm->sysTimestamp == -1){ mm->sysTimestamp = mstime(); } - free(fspec); + if (mmvalid){ + netUseMessage(mm); + } + else { + free(mm); + } //mm->decoded_nic = 0; //mm->decoded_rc = RC_UNKNOWN; - netUseMessage(mm); return 0; } From 4aa7790b5fd902baa75a04ae5e89d65225ac020c Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Wed, 26 Apr 2023 07:33:39 -0400 Subject: [PATCH 30/32] input/output I021/146, Selected Altitude --- net_io.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/net_io.c b/net_io.c index 65a773a1..e68a0b03 100644 --- a/net_io.c +++ b/net_io.c @@ -2241,6 +2241,30 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n mm->category = ((0x0E - tc) << 4) | ca; mm->category_valid = 1; } + + if (fspec[4] & 0x20) { // I021/220 Met Information + uint8_t *met = readFspec(&p); + free(met); + } + + if (fspec[4] & 0x10) { // I021/146 Selected Altitude + if (*p & 0x80 && *p & 0x60) { + int16_t alt = (*p & 0x1F) << 8; + alt += *(p + 1) & 0xFF; + if (alt < 0x1000){ + if ((*p & 0x60) == 0x40) { // MCP + mm->nav.mcp_altitude_valid = 1; + mm->nav.mcp_altitude = alt * 25; + } + else if ((*p & 0x60) == 0x60) { //FMS + mm->nav.fms_altitude_valid = 1; + mm->nav.fms_altitude = alt * 25; + } + } + } + p += 2; + } + mmvalid = true; break; } @@ -2666,6 +2690,23 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w } } + // I021/146 Selected Altitude + if (mm->nav.fms_altitude_valid || mm->nav.mcp_altitude_valid){ + fspec[4] |= 1 << 4; + int alt = 0; + if (mm->nav.mcp_altitude_valid){ + alt = mm->nav.mcp_altitude; + bytes[p] |= 0xC0; + } + else if (mm->nav.fms_altitude_valid){ + alt = mm->nav.fms_altitude; + bytes[p] |= 0xE0; + } + alt /= 25; + bytes[p++] |= (alt & 0x1F00) >> 8; + bytes[p++] = (alt & 0xFF); + } + // I021/008 Aircraft Operational Status if (mm->opstatus.valid){ if (mm->opstatus.om_acas_ra || mm->opstatus.cc_tc || From 6cfeeec35b25f4233c6cfe8e843eaab973c3ed4c Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Fri, 28 Apr 2023 07:59:12 -0400 Subject: [PATCH 31/32] undo free mm if invalid. seems to be incorrect --- net_io.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/net_io.c b/net_io.c index e68a0b03..55327bef 100644 --- a/net_io.c +++ b/net_io.c @@ -1831,7 +1831,6 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n //uint16_t msgLen = (*(p + 1) << 8) + *(p + 2); //int j; unsigned char category; - bool mmvalid = false; struct modesMessage *mm = netGetMM(mb); mm->client = c; MODES_NOTUSED(c); @@ -2264,20 +2263,13 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n } p += 2; } - - mmvalid = true; + netUseMessage(mm); break; } free(fspec); if (mm->sysTimestamp == -1){ mm->sysTimestamp = mstime(); } - if (mmvalid){ - netUseMessage(mm); - } - else { - free(mm); - } //mm->decoded_nic = 0; //mm->decoded_rc = RC_UNKNOWN; return 0; From 01d2f33d8ed8300fc98d752cdded9ff026afc20a Mon Sep 17 00:00:00 2001 From: Dennis Graiani Date: Sun, 30 Apr 2023 12:19:24 -0400 Subject: [PATCH 32/32] try to get address types working right --- net_io.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 7 deletions(-) diff --git a/net_io.c b/net_io.c index 55327bef..3f97ee6d 100644 --- a/net_io.c +++ b/net_io.c @@ -1837,7 +1837,7 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n if (remote >= 64) mm->source = remote - 64; else - mm->source = SOURCE_SBS; + mm->source = SOURCE_INDIRECT; mm->remote = 1; mm->sbs_in = 1; mm->signalLevel = 0; @@ -1858,9 +1858,10 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n if (fspec[0] & 0x80){ // ID021/010 Data Source Identification p += 2; } + uint8_t addrtype = 3; if (fspec[0] & 0x40){ // ID021/040 Target Report Descriptor uint8_t *trd = readFspec(&p); - mm->addrtype = (trd[1] & 0xE0) >> 5; + addrtype = (trd[0] & 0xE0) >> 5; if (!(trd[0] & 0x18)){ mm->alt_q_bit = 1; } @@ -1955,6 +1956,9 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n } // I021/080 Target Address mm->addr = (((*p & 0xff) << 16) + ((*(p + 1) & 0xff) << 8) + (*(p + 2) & 0xff)) & 0xffffff; + if (addrtype == 3){ + mm->addr |= MODES_NON_ICAO_ADDRESS; + } p += 3; if (fspec[1] & 0x8){ // I021/073 Time of Message Reception of Position if (mm->cpr_decoded || mm->sbs_pos_valid){ @@ -2042,6 +2046,7 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n if (fspec[2] & 0x10){ // I021/210 MOPS Version mm->opstatus.valid = true; mm->opstatus.version = ((*p) & 0x38) >> 3; + uint8_t ltt = (*p) & 0x7; p++; switch(mm->opstatus.version){ case 1: @@ -2062,6 +2067,35 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n mm->accuracy.nic_baro = nicbaro; break; } + switch (ltt) { + case 0: + if (!addrtype){ + mm->addrtype = ADDR_TISB_ICAO; + } + else{ + mm->addrtype = ADDR_TISB_OTHER; + } + break; + case 1: + if (!addrtype){ + mm->addrtype = ADDR_ADSR_ICAO; + } + else{ + mm->addrtype = ADDR_ADSR_OTHER; + } + break; + case 2: + if (!addrtype){ + mm->addrtype = ADDR_ADSB_ICAO; + } + else{ + mm->addrtype = ADDR_ADSB_OTHER; + } + break; + default: + mm->addrtype = ADDR_UNKNOWN; + break; + } } if (fspec[2] & 0x8){ // I021/070 Mode 3/A Code mm->squawk += (((*p & 0xe) << 11) + ((*p & 0x1) << 10) + ((*(p + 1) & 0xC0) << 2) + ((*(p + 1) & 0x38) << 1) + ((*(p + 1) & 0x7))) ; @@ -2179,6 +2213,10 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n int ca = 0; uint8_t ecat = *p++ & 0xFF; switch (ecat) { + case 0: + tc = 0x0e; + ca = 0; + break; case 1: case 2: case 3: @@ -2263,7 +2301,7 @@ static int decodeAsterixMessage(struct client *c, char *p, int remote, int64_t n } p += 2; } - netUseMessage(mm); + netUseMessage(mm); break; } free(fspec); @@ -2309,9 +2347,13 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w // I021/040 Target Report Descriptor fspec[0] |= 1 << 6; - if (mm->addrtype > 0) + if (mm->addr & MODES_NON_ICAO_ADDRESS){ bytes[p] |= (3 << 5); - + } + else if (mm->addrtype == ADDR_ADSB_OTHER || mm->addrtype == ADDR_TISB_OTHER || mm->addrtype == ADDR_ADSR_OTHER){ + bytes[p] |= (2 << 5); + } + if (mm->alt_q_bit == 0) bytes[p] |= (1 << 3); @@ -2468,7 +2510,36 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w // I021/210 MOPS Version if (mm->opstatus.valid){ fspec[2] |= 1 << 4; - bytes[p++] += (mm->opstatus.version) << 3; + + if (mm->remote) { + switch (mm->addrtype){ + case ADDR_ADSB_ICAO: + case ADDR_ADSB_OTHER: + bytes[p] = 2; + break; + case ADDR_ADSR_ICAO: + case ADDR_ADSR_OTHER: + bytes[p] = 1; + break; + default: + bytes[p] = 0; + break; + } + } + else { + switch (mm->source){ + case SOURCE_ADSB: + bytes[p] = 2; + break; + case SOURCE_ADSR: + bytes[p] = 1; + break; + default: + bytes[p] = 0; + break; + } + } + bytes[p++] |= (mm->opstatus.version) << 3; } // I021/070 Mode 3/A Code @@ -2649,7 +2720,10 @@ static void modesSendAsterixOutput(struct modesMessage *mm, struct net_writer *w bytes[p++] = 0; } } - + else if (!(a->category)){ + fspec[4] |= 1 << 6; + bytes[p++] = 0; + } // I021/220 Met Information //if (ac && ((now < ac->oat_updated + TRACK_EXPIRE) || (now < ac->wind_updated + TRACK_EXPIRE && abs(ac->wind_altitude - ac->baro_alt) < 500))){ if (mm->wind_valid || mm->oat_valid || mm->turbulence_valid || mm->static_pressure_valid || mm->humidity_valid) {