mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-13 14:55:29 +00:00
slightly improved ads-b receiver module (#2649)
* slightly improved ads-b receiver module: * fix Heading, Speed and Vrate decoders * decode more ModeS messages * log all ModeS messages (except DF11) * fix formatting (clang-style); advice on data alignment taken into account * ADS-B module: convert Indicated AirSpeed to True AirSpeed if altitute is known * ADS-B rx module: replacing floating point with integer arithmetic
This commit is contained in:
@@ -282,7 +282,7 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
|
||||
uint32_t latcprE, latcprO, loncprE, loncprO;
|
||||
float latE, latO, m, Dlon, cpr_lon_odd, cpr_lon_even, cpr_lat_odd, cpr_lat_even;
|
||||
int ni;
|
||||
adsb_pos position{false, 0, 0, 0};
|
||||
adsb_pos position{false, false, 0, 0, 0};
|
||||
|
||||
uint32_t time_even = frame_even.get_rx_timestamp();
|
||||
uint32_t time_odd = frame_odd.get_rx_timestamp();
|
||||
@@ -296,8 +296,10 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
|
||||
raw_data = frame_data_odd;
|
||||
|
||||
// Q-bit must be present
|
||||
if (raw_data[5] & 1)
|
||||
if (raw_data[5] & 1) {
|
||||
position.altitude = ((((raw_data[5] & 0xFE) << 3) | ((raw_data[6] & 0xF0) >> 4)) * 25) - 1000;
|
||||
position.alt_valid = true;
|
||||
}
|
||||
|
||||
// Position
|
||||
latcprE = ((frame_data_even[6] & 3) << 15) | (frame_data_even[7] << 7) | (frame_data_even[8] >> 1);
|
||||
@@ -350,7 +352,7 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
|
||||
|
||||
if (position.longitude >= 180) position.longitude -= 360;
|
||||
|
||||
position.valid = true;
|
||||
position.pos_valid = true;
|
||||
|
||||
return position;
|
||||
}
|
||||
@@ -396,46 +398,59 @@ void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint
|
||||
|
||||
// Decoding method from dump1090
|
||||
adsb_vel decode_frame_velo(ADSBFrame& frame) {
|
||||
adsb_vel velo{false, 0, 0, 0};
|
||||
adsb_vel velo{false, SPD_GND, 0, 0, 0};
|
||||
|
||||
uint8_t* frame_data = frame.get_raw_data();
|
||||
uint8_t velo_type = frame.get_msg_sub();
|
||||
|
||||
if (velo_type >= 1 && velo_type <= 4) { // vertical rate is always present
|
||||
|
||||
velo.v_rate = (((frame_data[8] & 0x07) << 6) | ((frame_data[9] >> 2) - 1)) * 64;
|
||||
velo.v_rate = ((((frame_data[8] & 0x07) << 6) | (frame_data[9] >> 2)) - 1) * 64;
|
||||
|
||||
if ((frame_data[8] & 0x8) >> 3) velo.v_rate *= -1; // check v_rate sign
|
||||
if (frame_data[8] & 0x8) velo.v_rate *= -1; // check v_rate sign
|
||||
}
|
||||
|
||||
if (velo_type == 1 || velo_type == 2) { // Ground Speed
|
||||
int32_t raw_ew = ((frame_data[5] & 0x03) << 8) | frame_data[6];
|
||||
int32_t velo_ew = raw_ew - 1; // velocities are all offset by one (this is part of the spec)
|
||||
|
||||
int32_t raw_ns = ((frame_data[7] & 0x7f) << 3) | (frame_data[8] >> 5);
|
||||
int32_t velo_ns = raw_ns - 1;
|
||||
|
||||
if (velo_type == 2) { // supersonic indicator so multiply by 4
|
||||
velo_ew = velo_ew << 2;
|
||||
velo_ns = velo_ns << 2;
|
||||
if (raw_ew && raw_ns) { // check data available
|
||||
int32_t velo_ew = raw_ew - 1; // velocities are all offset by one (this is part of the spec)
|
||||
int32_t velo_ns = raw_ns - 1;
|
||||
|
||||
if (velo_type == 2) { // supersonic indicator so multiply by 4
|
||||
velo_ew = velo_ew << 2;
|
||||
velo_ns = velo_ns << 2;
|
||||
}
|
||||
|
||||
if (frame_data[5] & 0x04) velo_ew *= -1; // check ew direction sign
|
||||
if (frame_data[7] & 0x80) velo_ns *= -1; // check ns direction sign
|
||||
|
||||
velo.speed = fast_int_magnitude(velo_ns, velo_ew);
|
||||
|
||||
if (velo.speed) {
|
||||
// calculate heading in degrees from ew/ns velocities
|
||||
int16_t heading_temp = (int16_t)(int_atan2(velo_ew, velo_ns)); // Nearest degree
|
||||
// We don't want negative values but a 0-360 scale.
|
||||
if (heading_temp < 0) heading_temp += 360.0;
|
||||
velo.heading = (uint16_t)heading_temp;
|
||||
|
||||
velo.valid = true;
|
||||
velo.type = SPD_GND;
|
||||
}
|
||||
}
|
||||
|
||||
if (frame_data[5] & 0x04) velo_ew *= -1; // check ew direction sign
|
||||
if (frame_data[7] & 0x80) velo_ns *= -1; // check ns direction sign
|
||||
|
||||
velo.speed = fast_int_magnitude(velo_ns, velo_ew);
|
||||
|
||||
if (velo.speed) {
|
||||
// calculate heading in degrees from ew/ns velocities
|
||||
int16_t heading_temp = (int16_t)(int_atan2(velo_ew, velo_ns)); // Nearest degree
|
||||
// We don't want negative values but a 0-360 scale.
|
||||
if (heading_temp < 0) heading_temp += 360.0;
|
||||
velo.heading = (uint16_t)heading_temp;
|
||||
}
|
||||
|
||||
} else if (velo_type == 3 || velo_type == 4) { // Airspeed
|
||||
velo.valid = frame_data[5] & (1 << 2);
|
||||
velo.heading = ((((frame_data[5] & 0x03) << 8) | frame_data[6]) * 45) << 7;
|
||||
velo.heading = ((((frame_data[5] & 0x03) << 8) | frame_data[6]) * 45) >> 7;
|
||||
|
||||
int32_t raw = ((frame_data[7] & 0x7F) << 3) | (frame_data[8] >> 5);
|
||||
if (raw) { // check speed available
|
||||
velo.speed = raw - 1;
|
||||
velo.type = (frame_data[7] & 0x80) ? SPD_TAS : SPD_IAS; // set AirSpeed type
|
||||
|
||||
// supersonic indicator so multiply by 4
|
||||
if (velo_type == 4) velo.speed *= 4;
|
||||
}
|
||||
}
|
||||
|
||||
return velo;
|
||||
|
@@ -50,8 +50,15 @@ enum data_selector {
|
||||
BDS_HEADING = 0x60
|
||||
};
|
||||
|
||||
enum speed_type {
|
||||
SPD_GND = 0, // Ground Speed
|
||||
SPD_IAS = 1, // Indicated AirSpeed
|
||||
SPD_TAS = 2 // True AirSpeed
|
||||
};
|
||||
|
||||
struct adsb_pos {
|
||||
bool valid;
|
||||
bool pos_valid;
|
||||
bool alt_valid;
|
||||
float latitude;
|
||||
float longitude;
|
||||
int32_t altitude;
|
||||
@@ -59,6 +66,7 @@ struct adsb_pos {
|
||||
|
||||
struct adsb_vel {
|
||||
bool valid;
|
||||
speed_type type; // ground speed, IAS or TAS
|
||||
int32_t speed; // knot
|
||||
uint16_t heading; // degree
|
||||
int32_t v_rate; // ft/min
|
||||
|
@@ -80,20 +80,24 @@ class ADSBFrame {
|
||||
void make_CRC() {
|
||||
uint32_t computed_CRC = compute_CRC();
|
||||
|
||||
uint8_t crc_pos = (raw_data[0] & 0x80) ? 11 : 4;
|
||||
|
||||
// Insert CRC in frame
|
||||
raw_data[11] = (computed_CRC >> 16) & 0xFF;
|
||||
raw_data[12] = (computed_CRC >> 8) & 0xFF;
|
||||
raw_data[13] = computed_CRC & 0xFF;
|
||||
raw_data[crc_pos] = (computed_CRC >> 16) & 0xFF;
|
||||
raw_data[crc_pos + 1] = (computed_CRC >> 8) & 0xFF;
|
||||
raw_data[crc_pos + 2] = computed_CRC & 0xFF;
|
||||
}
|
||||
|
||||
bool check_CRC() {
|
||||
uint32_t check_CRC() {
|
||||
uint32_t computed_CRC = compute_CRC();
|
||||
|
||||
if ((raw_data[11] != ((computed_CRC >> 16) & 0xFF)) ||
|
||||
(raw_data[12] != ((computed_CRC >> 8) & 0xFF)) ||
|
||||
(raw_data[13] != (computed_CRC & 0xFF))) return false;
|
||||
uint8_t crc_pos = (raw_data[0] & 0x80) ? 11 : 4;
|
||||
|
||||
return true;
|
||||
uint32_t received_CRC = (raw_data[crc_pos] << 16) |
|
||||
(raw_data[crc_pos + 1] << 8) |
|
||||
raw_data[crc_pos + 2];
|
||||
|
||||
return (received_CRC ^ computed_CRC) & 0xFFFFFF;
|
||||
}
|
||||
|
||||
bool empty() {
|
||||
@@ -111,12 +115,13 @@ class ADSBFrame {
|
||||
uint8_t adsb_crc[14] = {0}; // Temp buffer
|
||||
uint8_t b, c, s, bitn;
|
||||
const uint32_t crc_poly = 0x1205FFF;
|
||||
uint8_t data_len = (raw_data[0] & 0x80) ? 11 : 4;
|
||||
|
||||
// Copy frame data
|
||||
memcpy(adsb_crc, raw_data, 11);
|
||||
memcpy(adsb_crc, raw_data, data_len);
|
||||
|
||||
// Compute CRC
|
||||
for (c = 0; c < 11; c++) {
|
||||
for (c = 0; c < data_len; c++) {
|
||||
for (b = 0; b < 8; b++) {
|
||||
if ((adsb_crc[c] << b) & 0x80) {
|
||||
for (s = 0; s < 25; s++) {
|
||||
@@ -127,7 +132,7 @@ class ADSBFrame {
|
||||
}
|
||||
}
|
||||
|
||||
return (adsb_crc[11] << 16) + (adsb_crc[12] << 8) + adsb_crc[13];
|
||||
return (adsb_crc[data_len] << 16) + (adsb_crc[data_len + 1] << 8) + adsb_crc[data_len + 2];
|
||||
}
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user