WIP on decoding operational status & target state messages.
This commit is contained in:
parent
08887642ea
commit
3e08de91ed
65
dump1090.h
65
dump1090.h
|
@ -177,6 +177,10 @@ typedef enum {
|
||||||
HEADING_MAGNETIC
|
HEADING_MAGNETIC
|
||||||
} heading_source_t;
|
} heading_source_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SIL_PER_SAMPLE, SIL_PER_HOUR
|
||||||
|
} sil_type_t;
|
||||||
|
|
||||||
#define MODES_NON_ICAO_ADDRESS (1<<24) // Set on addresses to indicate they are not ICAO addresses
|
#define MODES_NON_ICAO_ADDRESS (1<<24) // Set on addresses to indicate they are not ICAO addresses
|
||||||
|
|
||||||
#define MODES_DEBUG_DEMOD (1<<0)
|
#define MODES_DEBUG_DEMOD (1<<0)
|
||||||
|
@ -448,6 +452,67 @@ struct modesMessage {
|
||||||
// valid if cpr_decoded:
|
// valid if cpr_decoded:
|
||||||
double decoded_lat;
|
double decoded_lat;
|
||||||
double decoded_lon;
|
double decoded_lon;
|
||||||
|
|
||||||
|
// Operational Status
|
||||||
|
struct {
|
||||||
|
unsigned valid : 1;
|
||||||
|
unsigned version : 3;
|
||||||
|
|
||||||
|
unsigned om_acas_ra : 1;
|
||||||
|
unsigned om_ident : 1;
|
||||||
|
unsigned om_atc : 1;
|
||||||
|
unsigned om_saf : 1;
|
||||||
|
unsigned om_sda : 2;
|
||||||
|
|
||||||
|
unsigned cc_acas : 1;
|
||||||
|
unsigned cc_cdti : 1;
|
||||||
|
unsigned cc_1090_in : 1;
|
||||||
|
unsigned cc_arv : 1;
|
||||||
|
unsigned cc_ts : 1;
|
||||||
|
unsigned cc_tc : 2;
|
||||||
|
unsigned cc_uat_in : 1;
|
||||||
|
unsigned cc_poa : 1;
|
||||||
|
unsigned cc_b2_low : 1;
|
||||||
|
unsigned cc_nac_v : 3;
|
||||||
|
unsigned cc_nic_supp_c : 1;
|
||||||
|
unsigned cc_lw_valid : 1;
|
||||||
|
|
||||||
|
unsigned nic_supp_a : 1;
|
||||||
|
unsigned nac_p : 4;
|
||||||
|
unsigned gva : 2;
|
||||||
|
unsigned sil : 2;
|
||||||
|
unsigned nic_baro : 1;
|
||||||
|
|
||||||
|
sil_type_t sil_type;
|
||||||
|
enum { ANGLE_HEADING, ANGLE_TRACK } track_angle;
|
||||||
|
heading_source_t hrd;
|
||||||
|
|
||||||
|
unsigned cc_lw;
|
||||||
|
unsigned cc_antenna_offset;
|
||||||
|
} opstatus;
|
||||||
|
|
||||||
|
// Target State & Status (ADS-B V2 only)
|
||||||
|
struct {
|
||||||
|
unsigned valid : 1;
|
||||||
|
unsigned altitude_valid : 1;
|
||||||
|
unsigned baro_valid : 1;
|
||||||
|
unsigned heading_valid : 1;
|
||||||
|
unsigned mode_valid : 1;
|
||||||
|
unsigned mode_autopilot : 1;
|
||||||
|
unsigned mode_vnav : 1;
|
||||||
|
unsigned mode_alt_hold : 1;
|
||||||
|
unsigned mode_approach : 1;
|
||||||
|
unsigned acas_operational : 1;
|
||||||
|
unsigned nac_p : 4;
|
||||||
|
unsigned nic_baro : 1;
|
||||||
|
unsigned sil : 2;
|
||||||
|
|
||||||
|
sil_type_t sil_type;
|
||||||
|
enum { TSS_ALTITUDE_MCP, TSS_ALTITUDE_FMS } altitude_type;
|
||||||
|
unsigned altitude;
|
||||||
|
float baro;
|
||||||
|
unsigned heading;
|
||||||
|
} tss;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This one needs modesMessage:
|
// This one needs modesMessage:
|
||||||
|
|
192
mode_s.c
192
mode_s.c
|
@ -702,6 +702,7 @@ static void decodeBDS20(struct modesMessage *mm)
|
||||||
static void decodeExtendedSquitter(struct modesMessage *mm)
|
static void decodeExtendedSquitter(struct modesMessage *mm)
|
||||||
{
|
{
|
||||||
unsigned char *msg = mm->msg;
|
unsigned char *msg = mm->msg;
|
||||||
|
unsigned char *me = mm->ME;
|
||||||
int metype = mm->metype = msg[4] >> 3; // Extended squitter message type
|
int metype = mm->metype = msg[4] >> 3; // Extended squitter message type
|
||||||
int mesub = mm->mesub = (metype == 29 ? ((msg[4]&6)>>1) : (msg[4] & 7)); // Extended squitter message subtype
|
int mesub = mm->mesub = (metype == 29 ? ((msg[4]&6)>>1) : (msg[4] & 7)); // Extended squitter message subtype
|
||||||
|
|
||||||
|
@ -956,6 +957,48 @@ static void decodeExtendedSquitter(struct modesMessage *mm)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 29: // Aircraft Trajectory Intent
|
case 29: // Aircraft Trajectory Intent
|
||||||
|
if (mesub == 1) { // Target state and status, V2
|
||||||
|
mm->tss.valid = 1;
|
||||||
|
mm->tss.sil_type = (me[0] & 0x01) ? SIL_PER_SAMPLE : SIL_PER_HOUR;
|
||||||
|
mm->tss.altitude_type = (me[1] & 0x80) ? TSS_ALTITUDE_FMS : TSS_ALTITUDE_MCP;
|
||||||
|
|
||||||
|
unsigned alt_bits = ((me[1] << 4) | (me[2] >> 4)) & 0x7FF;
|
||||||
|
if (alt_bits == 0) {
|
||||||
|
mm->tss.altitude_valid = 0;
|
||||||
|
} else {
|
||||||
|
mm->tss.altitude_valid = 1;
|
||||||
|
mm->tss.altitude = (alt_bits - 1) * 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned baro_bits = ((me[2] << 5) | (me[3] >> 3)) & 0x1FF;
|
||||||
|
if (baro_bits == 0) {
|
||||||
|
mm->tss.baro_valid = 0;
|
||||||
|
} else {
|
||||||
|
mm->tss.baro_valid = 1;
|
||||||
|
mm->tss.baro = 800.0 + (baro_bits - 1) * 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm->tss.heading_valid = (me[3] & 0x04) != 0;
|
||||||
|
if (mm->tss.heading_valid) {
|
||||||
|
// two's complement -180..+180, which is conveniently
|
||||||
|
// also the same as unsigned 0..360
|
||||||
|
unsigned heading_bits = ((me[3] << 7) | (me[4] >> 1)) & 0x1ff;
|
||||||
|
mm->tss.heading = heading_bits * 180 / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm->tss.nac_p = ((me[4] << 3) | (me[5] >> 5)) & 0x0f;
|
||||||
|
mm->tss.nic_baro = (me[5] & 0x10) ? 1 : 0;
|
||||||
|
mm->tss.sil = (me[5] >> 2) & 0x03;
|
||||||
|
mm->tss.mode_valid = (me[5] & 0x02) ? 1 : 0;
|
||||||
|
if (mm->tss.mode_valid) {
|
||||||
|
mm->tss.mode_autopilot = (me[5] & 0x01) != 0;
|
||||||
|
mm->tss.mode_vnav = (me[6] & 0x80) != 0;
|
||||||
|
mm->tss.mode_alt_hold = (me[6] & 0x40) != 0;
|
||||||
|
mm->tss.mode_approach = (me[6] & 0x10) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm->tss.acas_operational = (me[6] & 0x08) != 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 30: // Aircraft Operational Coordination
|
case 30: // Aircraft Operational Coordination
|
||||||
|
@ -964,6 +1007,94 @@ static void decodeExtendedSquitter(struct modesMessage *mm)
|
||||||
case 31: // Aircraft Operational Status
|
case 31: // Aircraft Operational Status
|
||||||
if (check_imf && (msg[10] & 0x01))
|
if (check_imf && (msg[10] & 0x01))
|
||||||
mm->addr |= MODES_NON_ICAO_ADDRESS;
|
mm->addr |= MODES_NON_ICAO_ADDRESS;
|
||||||
|
|
||||||
|
if (mm->mesub == 0 || mm->mesub == 1) {
|
||||||
|
mm->opstatus.valid = 1;
|
||||||
|
mm->opstatus.version = (me[5] >> 5) & 0x07;
|
||||||
|
|
||||||
|
switch (mm->opstatus.version) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
if ((me[3] & 0xC0) == 0) {
|
||||||
|
mm->opstatus.om_acas_ra = (me[3] & 0x20) != 0;
|
||||||
|
mm->opstatus.om_ident = (me[3] & 0x10) != 0;
|
||||||
|
mm->opstatus.om_atc = (me[3] & 0x08) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mm->mesub == 0 && (me[1] & 0xCC) == 0) {
|
||||||
|
// airborne
|
||||||
|
mm->opstatus.cc_acas = (me[1] & 0x20) == 0;
|
||||||
|
mm->opstatus.cc_cdti = (me[1] & 0x10) != 0;
|
||||||
|
mm->opstatus.cc_arv = (me[1] & 0x02) != 0;
|
||||||
|
mm->opstatus.cc_ts = (me[1] & 0x01) != 0;
|
||||||
|
mm->opstatus.cc_tc = (me[2] >> 6) & 0x03;
|
||||||
|
} else if (mm->mesub == 1 && (me[1] & 0xCC) == 0) {
|
||||||
|
// surface
|
||||||
|
mm->opstatus.cc_poa = (me[1] & 0x20) != 0;
|
||||||
|
mm->opstatus.cc_cdti = (me[1] & 0x10) != 0;
|
||||||
|
mm->opstatus.cc_b2_low = (me[1] & 0x02) != 0;
|
||||||
|
mm->opstatus.cc_lw_valid = 1;
|
||||||
|
mm->opstatus.cc_lw = me[2] & 0x0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm->opstatus.nic_supp_a = (me[5] & 0x10) ? 1 : 0;
|
||||||
|
mm->opstatus.nac_p = me[5] & 0x0F;
|
||||||
|
mm->opstatus.sil = (me[6] >> 4) & 0x03;
|
||||||
|
if (mm->mesub == 0) {
|
||||||
|
mm->opstatus.nic_baro = (me[6] & 0x08) ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
mm->opstatus.track_angle = (me[6] & 0x08) ? ANGLE_TRACK : ANGLE_HEADING;
|
||||||
|
}
|
||||||
|
mm->opstatus.hrd = (me[6] & 0x04) ? HEADING_MAGNETIC : HEADING_TRUE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
default:
|
||||||
|
if ((me[3] & 0xC0) == 0) {
|
||||||
|
mm->opstatus.om_acas_ra = (me[3] & 0x20) != 0;
|
||||||
|
mm->opstatus.om_ident = (me[3] & 0x10) != 0;
|
||||||
|
mm->opstatus.om_atc = (me[3] & 0x08) != 0;
|
||||||
|
mm->opstatus.om_saf = (me[3] & 0x04) != 0;
|
||||||
|
mm->opstatus.om_sda = (me[3] & 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mm->mesub == 0 && (me[1] & 0xCC) == 0) {
|
||||||
|
// airborne
|
||||||
|
mm->opstatus.cc_acas = (me[1] & 0x20) != 0;
|
||||||
|
mm->opstatus.cc_1090_in = (me[1] & 0x10) != 0;
|
||||||
|
mm->opstatus.cc_arv = (me[1] & 0x02) != 0;
|
||||||
|
mm->opstatus.cc_ts = (me[1] & 0x01) != 0;
|
||||||
|
mm->opstatus.cc_tc = (me[2] >> 6) & 0x03;
|
||||||
|
mm->opstatus.cc_uat_in = (me[2] & 0x20) != 0;
|
||||||
|
} else if (mm->mesub == 1 && (me[1] & 0xCC) == 0) {
|
||||||
|
// surface
|
||||||
|
mm->opstatus.cc_poa = (me[1] & 0x20) != 0;
|
||||||
|
mm->opstatus.cc_1090_in = (me[1] & 0x10) != 0;
|
||||||
|
mm->opstatus.cc_b2_low = (me[1] & 0x02) != 0;
|
||||||
|
mm->opstatus.cc_uat_in = (me[1] & 0x01) != 0;
|
||||||
|
mm->opstatus.cc_nac_v = (me[2] >> 5) & 0x07;
|
||||||
|
mm->opstatus.cc_nic_supp_c = (me[2] & 0x10) ? 1 : 0;
|
||||||
|
mm->opstatus.cc_lw_valid = 1;
|
||||||
|
mm->opstatus.cc_lw = me[2] & 0x0F;
|
||||||
|
mm->opstatus.cc_antenna_offset = me[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
mm->opstatus.nic_supp_a = (me[5] & 0x10) ? 1 : 0;
|
||||||
|
mm->opstatus.nac_p = me[5] & 0x0F;
|
||||||
|
mm->opstatus.sil = (me[6] >> 4) & 0x03;
|
||||||
|
if (mm->mesub == 0) {
|
||||||
|
mm->opstatus.gva = (me[6] >> 6) & 0x03;
|
||||||
|
mm->opstatus.nic_baro = (me[6] & 0x08) ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
mm->opstatus.track_angle = (me[6] & 0x08) ? ANGLE_TRACK : ANGLE_HEADING;
|
||||||
|
}
|
||||||
|
mm->opstatus.hrd = (me[6] & 0x04) ? HEADING_MAGNETIC : HEADING_TRUE;
|
||||||
|
mm->opstatus.sil_type = (me[6] & 0x02) ? SIL_PER_SAMPLE : SIL_PER_HOUR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1387,6 +1518,67 @@ void displayModesMessage(struct modesMessage *mm) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mm->opstatus.valid) {
|
||||||
|
printf(" Aircraft Operational Status:\n");
|
||||||
|
printf(" Version: %d\n", mm->opstatus.version);
|
||||||
|
|
||||||
|
printf(" Capability classes: ");
|
||||||
|
if (mm->opstatus.cc_acas) printf("ACAS ");
|
||||||
|
if (mm->opstatus.cc_cdti) printf("CDTI ");
|
||||||
|
if (mm->opstatus.cc_1090_in) printf("1090IN ");
|
||||||
|
if (mm->opstatus.cc_arv) printf("ARV ");
|
||||||
|
if (mm->opstatus.cc_ts) printf("TS ");
|
||||||
|
if (mm->opstatus.cc_tc) printf("TC=%d ", mm->opstatus.cc_tc);
|
||||||
|
if (mm->opstatus.cc_uat_in) printf("UATIN ");
|
||||||
|
if (mm->opstatus.cc_poa) printf("POA ");
|
||||||
|
if (mm->opstatus.cc_b2_low) printf("B2-LOW ");
|
||||||
|
if (mm->opstatus.cc_nac_v) printf("NACv=%d ", mm->opstatus.cc_nac_v);
|
||||||
|
if (mm->opstatus.cc_nic_supp_c) printf("NIC-C=1 ");
|
||||||
|
if (mm->opstatus.cc_lw_valid) printf("L/W=%d ", mm->opstatus.cc_lw);
|
||||||
|
if (mm->opstatus.cc_antenna_offset) printf("GPS-OFFSET=%d ", mm->opstatus.cc_antenna_offset);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf(" Operational modes: ");
|
||||||
|
if (mm->opstatus.om_acas_ra) printf("ACASRA ");
|
||||||
|
if (mm->opstatus.om_ident) printf("IDENT ");
|
||||||
|
if (mm->opstatus.om_atc) printf("ATC ");
|
||||||
|
if (mm->opstatus.om_saf) printf("SAF ");
|
||||||
|
if (mm->opstatus.om_sda) printf("SDA=%d ", mm->opstatus.om_sda);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
if (mm->opstatus.nic_supp_a) printf(" NIC-A: %d\n", mm->opstatus.nic_supp_a);
|
||||||
|
if (mm->opstatus.nac_p) printf(" NACp: %d\n", mm->opstatus.nac_p);
|
||||||
|
if (mm->opstatus.gva) printf(" GVA: %d\n", mm->opstatus.gva);
|
||||||
|
if (mm->opstatus.sil) printf(" SIL: %d (%s)\n", mm->opstatus.sil, (mm->opstatus.sil_type == SIL_PER_HOUR ? "per hour" : "per sample"));
|
||||||
|
if (mm->opstatus.nic_baro) printf(" NICbaro: %d\n", mm->opstatus.nic_baro);
|
||||||
|
|
||||||
|
if (mm->mesub == 1)
|
||||||
|
printf(" Heading type: %s\n", (mm->opstatus.track_angle == ANGLE_HEADING ? "heading" : "track angle"));
|
||||||
|
printf(" Heading reference: %s\n", (mm->opstatus.hrd == HEADING_TRUE ? "true north" : "magnetic north"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mm->tss.valid) {
|
||||||
|
printf(" Target State and Status:\n");
|
||||||
|
if (mm->tss.altitude_valid)
|
||||||
|
printf(" Target altitude: %s, %d ft\n", (mm->tss.altitude_type == TSS_ALTITUDE_MCP ? "MCP" : "FMS"), mm->tss.altitude);
|
||||||
|
if (mm->tss.baro_valid)
|
||||||
|
printf(" Altimeter setting: %.1f millibars\n", mm->tss.baro);
|
||||||
|
if (mm->tss.heading_valid)
|
||||||
|
printf(" Target heading: %d\n", mm->tss.heading);
|
||||||
|
if (mm->tss.mode_valid) {
|
||||||
|
printf(" Active modes: ");
|
||||||
|
if (mm->tss.mode_autopilot) printf("autopilot ");
|
||||||
|
if (mm->tss.mode_vnav) printf("VNAV ");
|
||||||
|
if (mm->tss.mode_alt_hold) printf("altitude-hold ");
|
||||||
|
if (mm->tss.mode_approach) printf("approach ");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
printf(" ACAS: %s\n", mm->tss.acas_operational ? "operational" : "NOT operational");
|
||||||
|
printf(" NACp: %d\n", mm->tss.nac_p);
|
||||||
|
printf(" NICbaro: %d\n", mm->tss.nic_baro);
|
||||||
|
printf(" SIL: %d (%s)\n", mm->tss.sil, (mm->opstatus.sil_type == SIL_PER_HOUR ? "per hour" : "per sample"));
|
||||||
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue