WIP on MRAR decoding

This commit is contained in:
Oliver Jowett 2021-07-29 19:04:49 +08:00
parent 6b8cac3922
commit e3a8e00412
3 changed files with 245 additions and 5 deletions

174
comm_b.c
View File

@ -29,6 +29,7 @@ static int decodeBDS17(struct modesMessage *mm, bool store);
static int decodeBDS20(struct modesMessage *mm, bool store);
static int decodeBDS30(struct modesMessage *mm, bool store);
static int decodeBDS40(struct modesMessage *mm, bool store);
static int decodeBDS44(struct modesMessage *mm, bool store);
static int decodeBDS50(struct modesMessage *mm, bool store);
static int decodeBDS60(struct modesMessage *mm, bool store);
@ -40,7 +41,8 @@ static CommBDecoderFn comm_b_decoders[] = {
&decodeBDS17,
&decodeBDS40,
&decodeBDS50,
&decodeBDS60
&decodeBDS60,
&decodeBDS44
};
void decodeCommB(struct modesMessage *mm)
@ -148,10 +150,10 @@ static int decodeBDS17(struct modesMessage *mm, bool store)
score -= 2;
}
if (getbit(msg, 13)) { // 4,4 meterological routine report
score -= 2;
score -= 1;
}
if (getbit(msg, 14)) { // 4,4 meterological hazard report
score -= 2;
score -= 1;
}
if (getbit(msg, 20)) { // 5,4 waypoint 1
score -= 2;
@ -173,8 +175,11 @@ static int decodeBDS17(struct modesMessage *mm, bool store)
} else if (!getbit(msg, 1) && !getbit(msg, 2) && !getbit(msg, 3) && !getbit(msg, 4) && !getbit(msg, 5) && !getbit(msg, 6)) {
// not ES capable
score += 1;
} else if (!getbit(msg, 1) && !getbit(msg, 2) && getbit(msg, 3) && getbit(msg, 4) && getbit(msg, 5)) {
// ES with no position data
score += 3;
} else {
// partial ES support, unlikely
// other combinations, unlikely
score -= 12;
}
@ -740,3 +745,164 @@ static int decodeBDS60(struct modesMessage *mm, bool store)
return score;
}
// BDS4,4 Meterological 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 windspeed_raw = getbits(msg, 6, 14);
unsigned winddir_raw = getbits(msg, 15, 23);
// ICAO 9871 is inconsistent, it claims:
// bit 24 sign
// bits 25..34 static air temperature, MSB = 64C, LSB=0.25C, range -128C..+128C
//
// .. but this does not actually work, there is one too many bits in the bitfield
// for the claimed values.
//
// Based on observed data, the most plausible actual layout is:
//
// bit 24 status
// bit 25 sign
// bits 26..34 static air temperature, MSB=64C, LSB=0.25C, range -128C..+128C
unsigned sat_valid = getbit(msg, 24);
unsigned sat_sign = getbit(msg, 25);
unsigned sat_raw = getbits(msg, 26, 34);
unsigned asp_valid = getbit(msg, 35);
unsigned asp_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 (source == MRAR_SOURCE_INVALID || source > 5)
return 0; // invalid or reserved source
if (!wind_valid || !sat_valid)
return 0; // all valid messages seen in the wild have at least temp + wind
if (!asp_valid && asp_raw != 0)
return 0; // ASP not valid, but non-zero values in the ASP field
if (!turbulence_valid && turbulence_raw != 0)
return 0; // turbulence not valid, but non-zero values in the turbulence field
if (!humidity_valid && humidity_raw != 0)
return 0; // humidity not valid, but non-zero values in the humidity field
int score = 0;
float wind_speed = 0;
float wind_dir = 0;
if (wind_valid) {
wind_dir = winddir_raw * (180.0 / 256.0);
wind_speed = windspeed_raw;
if (windspeed_raw == 0) // possible but uncommon
score += 2;
else if (wind_speed <= 250)
score += 19;
else
return 0;
} else {
score += 1;
}
float sat = 0;
if (sat_valid) {
sat = sat_raw * 0.25;
if (sat_sign)
sat -= 128;
if (sat == 0) // possible but uncommon
score += 2;
else if (sat >= -80 && sat <= 60)
score += 11;
else
return 0;
} else {
score += 1;
}
float asp = 0;
if (asp_valid) {
asp = asp_raw;
if (asp >= 25 && asp <= 1100)
score += 12;
else
return 0;
} else {
score += 1;
}
hazard_t turbulence = HAZARD_NIL;
if (turbulence_valid) {
turbulence = (hazard_t) turbulence_raw;
score += 3;
} else {
score += 1;
}
float humidity = 0;
if (humidity_valid) {
humidity = humidity_raw * (100.0 / 64.0);
score += 7;
} else {
score += 1;
}
if (source == MRAR_SOURCE_DMEDME && wind_valid && sat_valid && score > 0) {
// Some GICB messages can be easily mistaken for a MRAR:
//
// GICB bit 1: BDS 0,5 ES airborne position = 0 ]
// GICB bit 2: BDS 0,6 ES surface position = 0 ]
// GICB bit 3: BDS 0,7 ES status = 1 ]
// GICB bit 4: BDS 0,8 ES type & identification = 1 ] -> MRAR source = 3
// GICB bit 5: BDS 0,9 ES airborne velocity = 1 -> MRAR wind valid bit
// GICB bit 24: BDS 6,0 heading and speed report = 1 -> MRAR temp valid bit
// most trailing bits = 0
//
// so only treat this as MRAR as a last resort
score = 1;
}
if (store) {
mm->commb_format = COMMB_MRAR;
mm->mrar_source = (mrar_source_t) source;
if (wind_valid) {
mm->wind_valid = 1;
mm->wind_speed = wind_speed;
mm->wind_dir = wind_dir;
}
if (sat_valid) {
mm->temperature_valid = 1;
mm->temperature = sat;
}
if (asp_valid) {
mm->pressure_valid = 1;
mm->pressure = asp;
}
if (turbulence_valid) {
mm->turbulence_valid = 1;
mm->turbulence = turbulence;
}
if (humidity_valid) {
mm->humidity_valid = 1;
mm->humidity = humidity;
}
}
return score;
}

View File

@ -209,7 +209,8 @@ typedef enum {
COMMB_ACAS_RA,
COMMB_VERTICAL_INTENT,
COMMB_TRACK_TURN,
COMMB_HEADING_SPEED
COMMB_HEADING_SPEED,
COMMB_MRAR
} commb_format_t;
typedef enum {
@ -237,6 +238,23 @@ typedef enum {
NAV_ALT_INVALID, NAV_ALT_UNKNOWN, NAV_ALT_AIRCRAFT, NAV_ALT_MCP, NAV_ALT_FMS
} nav_altitude_source_t;
// BDS4,4 MRAR - FOM/Source values
typedef enum {
MRAR_SOURCE_INVALID = 0,
MRAR_SOURCE_INS = 1,
MRAR_SOURCE_GNSS = 2,
MRAR_SOURCE_DMEDME = 3,
MRAR_SOURCE_VORDME = 4
} mrar_source_t;
// BDS4,4 and BDS4,5 hazard reports
typedef enum {
HAZARD_NIL = 0,
HAZARD_LIGHT = 1,
HAZARD_MODERATE = 2,
HAZARD_SEVERE = 3
} hazard_t;
#define MODES_NON_ICAO_ADDRESS (1<<24) // Set on addresses to indicate they are not ICAO addresses
#define MODES_INTERACTIVE_REFRESH_TIME 250 // Milliseconds
@ -611,6 +629,22 @@ struct modesMessage {
nav_modes_t modes;
} nav;
// BDS 4,4 MRAR
unsigned mrar_source_valid : 1;
unsigned wind_valid : 1;
unsigned temperature_valid : 1;
unsigned pressure_valid : 1;
unsigned turbulence_valid : 1;
unsigned humidity_valid : 1;
mrar_source_t mrar_source;
float wind_speed; // kts
float wind_dir; // degrees
float temperature; // degrees C
float pressure; // hPa
hazard_t turbulence; // NIL/LIGHT/MODERATE/SEVERE
float humidity; // 0-100 %
};
// This one needs modesMessage:

View File

@ -1695,6 +1695,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_MRAR:
return "BDS4,4 Meterological routine air report";
default:
return "unknown format";
}
@ -1748,6 +1750,29 @@ static const char *emergency_to_string(emergency_t emergency)
}
}
static const char *mrar_source_to_string(mrar_source_t source)
{
switch (source) {
case MRAR_SOURCE_INVALID: return "invalid";
case MRAR_SOURCE_INS: return "INS";
case MRAR_SOURCE_GNSS: return "GNSS";
case MRAR_SOURCE_DMEDME: return "DME/DME";
case MRAR_SOURCE_VORDME: return "VOR/DME";
default: return "reserved";
}
}
static const char *hazard_to_string(hazard_t hazard)
{
switch (hazard) {
case HAZARD_NIL: return "nil";
case HAZARD_LIGHT: return "light";
case HAZARD_MODERATE: return "moderate";
case HAZARD_SEVERE: return "severe";
default: return "invalid hazard severity";
}
}
static void print_hex_bytes(unsigned char *data, size_t len) {
size_t i;
for (i = 0; i < len; ++i) {
@ -2213,6 +2238,21 @@ void displayModesMessage(struct modesMessage *mm) {
printf(" Emergency/priority: %s\n", emergency_to_string(mm->emergency));
}
if (mm->mrar_source_valid)
printf(" MRAR FOM/Source: %s\n", mrar_source_to_string(mm->mrar_source));
if (mm->wind_valid) {
printf(" Wind speed: %.0f kt\n", mm->wind_speed);
printf(" Wind direction: %.1f degrees\n", mm->wind_dir);
}
if (mm->temperature_valid)
printf(" Air temperature: %.1f degrees C\n", mm->temperature);
if (mm->pressure_valid)
printf(" Static pressure: %.0f hPa\n", mm->pressure);
if (mm->turbulence_valid)
printf(" Turbulence: %s\n", hazard_to_string(mm->turbulence));
if (mm->humidity_valid)
printf(" Humidity: %.0f%%\n", mm->humidity);
printf("\n");
fflush(stdout);
}