mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2024-12-14 12:08:40 +00:00
Merge pull request #129 from jwetzell/add-heading-to-geomap
Add heading to geomap
This commit is contained in:
commit
4b02a1c410
@ -240,7 +240,7 @@ AISRecentEntryDetailView::AISRecentEntryDetailView(NavigationView& nav) {
|
||||
|
||||
void AISRecentEntryDetailView::update_position() {
|
||||
if (send_updates)
|
||||
geomap_view->update_position(ais::format::latlon_float(entry_.last_position.latitude.normalized()), ais::format::latlon_float(entry_.last_position.longitude.normalized()));
|
||||
geomap_view->update_position(ais::format::latlon_float(entry_.last_position.latitude.normalized()), ais::format::latlon_float(entry_.last_position.longitude.normalized()), (float)entry_.last_position.true_heading);
|
||||
}
|
||||
|
||||
void AISRecentEntryDetailView::focus() {
|
||||
|
@ -92,12 +92,16 @@ void ADSBRxDetailsView::update(const AircraftRecentEntry& entry) {
|
||||
text_last_seen.set(to_string_dec_uint(age / 60) + " minutes ago");
|
||||
|
||||
text_infos.set(entry_copy.info_string);
|
||||
|
||||
if(entry_copy.velo.heading < 360 && entry_copy.velo.speed >=0){ //I don't like this but...
|
||||
text_info2.set("Hdg:" + to_string_dec_uint(entry_copy.velo.heading) + " Spd:" + to_string_dec_int(entry_copy.velo.speed));
|
||||
}else{
|
||||
text_info2.set("");
|
||||
}
|
||||
text_frame_pos_even.set(to_string_hex_array(entry_copy.frame_pos_even.get_raw_data(), 14));
|
||||
text_frame_pos_odd.set(to_string_hex_array(entry_copy.frame_pos_odd.get_raw_data(), 14));
|
||||
|
||||
if (send_updates)
|
||||
geomap_view->update_position(entry_copy.pos.latitude, entry_copy.pos.longitude);
|
||||
geomap_view->update_position(entry_copy.pos.latitude, entry_copy.pos.longitude, entry_copy.velo.heading);
|
||||
}
|
||||
|
||||
ADSBRxDetailsView::~ADSBRxDetailsView() {
|
||||
@ -123,6 +127,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
||||
&text_airline,
|
||||
&text_country,
|
||||
&text_infos,
|
||||
&text_info2,
|
||||
&text_frame_pos_even,
|
||||
&text_frame_pos_odd,
|
||||
&button_see_map
|
||||
@ -172,7 +177,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
||||
GeoPos::alt_unit::FEET,
|
||||
entry_copy.pos.latitude,
|
||||
entry_copy.pos.longitude,
|
||||
0,
|
||||
entry_copy.velo.heading,
|
||||
[this]() {
|
||||
send_updates = false;
|
||||
});
|
||||
@ -199,7 +204,7 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||
|
||||
auto frame = message->frame;
|
||||
uint32_t ICAO_address = frame.get_ICAO_address();
|
||||
|
||||
|
||||
if (frame.check_CRC() && frame.get_ICAO_address()) {
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
auto& entry = ::on_packet(recent, ICAO_address);
|
||||
@ -214,6 +219,7 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||
|
||||
if (frame.get_DF() == DF_ADSB) {
|
||||
uint8_t msg_type = frame.get_msg_type();
|
||||
uint8_t msg_sub = frame.get_msg_sub();
|
||||
uint8_t * raw_data = frame.get_raw_data();
|
||||
|
||||
if ((msg_type >= 1) && (msg_type <= 4)) {
|
||||
@ -224,10 +230,10 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||
entry.set_frame_pos(frame, raw_data[6] & 4);
|
||||
|
||||
if (entry.pos.valid) {
|
||||
str_info = "Alt:" + to_string_dec_uint(entry.pos.altitude) +
|
||||
" Lat" + to_string_dec_int(entry.pos.latitude) +
|
||||
str_info = "Alt:" + to_string_dec_int(entry.pos.altitude) +
|
||||
" Lat:" + to_string_dec_int(entry.pos.latitude) +
|
||||
"." + to_string_dec_int((int)abs(entry.pos.latitude * 1000) % 100, 2, '0') +
|
||||
" Lon" + to_string_dec_int(entry.pos.longitude) +
|
||||
" Lon:" + to_string_dec_int(entry.pos.longitude) +
|
||||
"." + to_string_dec_int((int)abs(entry.pos.longitude * 1000) % 100, 2, '0');
|
||||
|
||||
entry.set_info_string(str_info);
|
||||
@ -236,6 +242,13 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||
if (send_updates)
|
||||
details_view->update(entry);
|
||||
}
|
||||
} else if(msg_type == 19 && msg_sub >= 1 && msg_sub <= 4){
|
||||
entry.set_frame_velo(frame);
|
||||
logentry += "Type:" + to_string_dec_uint(msg_sub) +
|
||||
" Hdg:" + to_string_dec_uint(entry.velo.heading) +
|
||||
" Spd: "+ to_string_dec_int(entry.velo.speed);
|
||||
if (send_updates)
|
||||
details_view->update(entry);
|
||||
}
|
||||
}
|
||||
recent_entries_view.set_dirty();
|
||||
|
@ -49,7 +49,7 @@ struct AircraftRecentEntry {
|
||||
uint16_t hits { 0 };
|
||||
uint32_t age { 0 };
|
||||
adsb_pos pos { false, 0, 0, 0 };
|
||||
|
||||
adsb_vel velo { false, 0, 999 };
|
||||
ADSBFrame frame_pos_even { };
|
||||
ADSBFrame frame_pos_odd { };
|
||||
|
||||
@ -86,6 +86,10 @@ struct AircraftRecentEntry {
|
||||
pos = decode_frame_pos(frame_pos_even, frame_pos_odd);
|
||||
}
|
||||
}
|
||||
|
||||
void set_frame_velo(ADSBFrame& frame){
|
||||
velo = decode_frame_velo(frame);
|
||||
}
|
||||
|
||||
void set_info_string(std::string& new_info_string) {
|
||||
info_string = new_info_string;
|
||||
@ -146,8 +150,8 @@ private:
|
||||
{ { 0 * 8, 2 * 16 }, "Last seen:", Color::light_grey() },
|
||||
{ { 0 * 8, 3 * 16 }, "Airline:", Color::light_grey() },
|
||||
{ { 0 * 8, 5 * 16 }, "Country:", Color::light_grey() },
|
||||
{ { 0 * 8, 12 * 16 }, "Even position frame:", Color::light_grey() },
|
||||
{ { 0 * 8, 14 * 16 }, "Odd position frame:", Color::light_grey() }
|
||||
{ { 0 * 8, 13 * 16 }, "Even position frame:", Color::light_grey() },
|
||||
{ { 0 * 8, 15 * 16 }, "Odd position frame:", Color::light_grey() }
|
||||
};
|
||||
|
||||
Text text_callsign {
|
||||
@ -174,17 +178,23 @@ private:
|
||||
{ 0 * 8, 6 * 16, 30 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_info2 {
|
||||
{0*8, 7*16, 30*8, 16},
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_frame_pos_even {
|
||||
{ 0 * 8, 13 * 16, 30 * 8, 16 },
|
||||
{ 0 * 8, 14 * 16, 30 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
Text text_frame_pos_odd {
|
||||
{ 0 * 8, 15 * 16, 30 * 8, 16 },
|
||||
{ 0 * 8, 16 * 16, 30 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Button button_see_map {
|
||||
{ 8 * 8, 8 * 16, 14 * 8, 3 * 16 },
|
||||
{ 8 * 8, 9 * 16, 14 * 8, 3 * 16 },
|
||||
"See on map"
|
||||
};
|
||||
};
|
||||
|
@ -59,7 +59,7 @@ GeoPos::GeoPos(
|
||||
set_altitude(0);
|
||||
set_lat(0);
|
||||
set_lon(0);
|
||||
|
||||
|
||||
const auto changed_fn = [this](int32_t) {
|
||||
float lat_value = lat();
|
||||
float lon_value = lon();
|
||||
@ -163,15 +163,22 @@ void GeoMap::paint(Painter& painter) {
|
||||
prev_x_pos = x_pos;
|
||||
prev_y_pos = y_pos;
|
||||
}
|
||||
|
||||
//center tag above point
|
||||
if(tag_.find_first_not_of(' ') != tag_.npos){ //only draw tag if we have something other than spaces
|
||||
painter.draw_string(r.center() - Point(((int)tag_.length() * 8 / 2), 2 * 16), style(), tag_);
|
||||
}
|
||||
if (mode_ == PROMPT) {
|
||||
// Cross
|
||||
display.fill_rectangle({ r.center() - Point(16, 1), { 32, 2 } }, Color::red());
|
||||
display.fill_rectangle({ r.center() - Point(1, 16), { 2, 32 } }, Color::red());
|
||||
} else {
|
||||
} else if (angle_ < 360){
|
||||
//if we have a valid angle draw bearing
|
||||
draw_bearing(r.center(), angle_, 10, Color::red());
|
||||
//center tag above bearing
|
||||
painter.draw_string(r.center() - Point(((int)tag_.length() * 8 / 2), 2 * 16), style(), tag_);
|
||||
}
|
||||
else {
|
||||
//draw a small cross
|
||||
display.fill_rectangle({ r.center() - Point(8, 1), { 16, 2 } }, Color::red());
|
||||
display.fill_rectangle({ r.center() - Point(1, 8), { 2, 16 } }, Color::red());
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,7 +238,7 @@ void GeoMap::set_mode(GeoMapMode mode) {
|
||||
mode_ = mode;
|
||||
}
|
||||
|
||||
void GeoMap::draw_bearing(const Point origin, const uint32_t angle, uint32_t size, const Color color) {
|
||||
void GeoMap::draw_bearing(const Point origin, const uint16_t angle, uint32_t size, const Color color) {
|
||||
Point arrow_a, arrow_b, arrow_c;
|
||||
|
||||
for (size_t thickness = 0; thickness < 3; thickness++) {
|
||||
@ -254,11 +261,12 @@ void GeoMapView::focus() {
|
||||
nav_.display_modal("No map", "No world_map.bin file in\n/ADSB/ directory", ABORT, nullptr);
|
||||
}
|
||||
|
||||
void GeoMapView::update_position(float lat, float lon) {
|
||||
void GeoMapView::update_position(float lat, float lon, uint16_t angle) {
|
||||
lat_ = lat;
|
||||
lon_ = lon;
|
||||
geopos.set_lat(lat_);
|
||||
geopos.set_lon(lon_);
|
||||
geomap.set_angle(angle);
|
||||
geomap.move(lon_, lat_);
|
||||
geomap.set_dirty();
|
||||
}
|
||||
@ -269,7 +277,7 @@ void GeoMapView::setup() {
|
||||
geopos.set_altitude(altitude_);
|
||||
geopos.set_lat(lat_);
|
||||
geopos.set_lon(lon_);
|
||||
|
||||
|
||||
geopos.on_change = [this](int32_t altitude, float lat, float lon) {
|
||||
altitude_ = altitude;
|
||||
lat_ = lat;
|
||||
@ -307,7 +315,7 @@ GeoMapView::GeoMapView(
|
||||
GeoPos::alt_unit altitude_unit,
|
||||
float lat,
|
||||
float lon,
|
||||
float angle,
|
||||
uint16_t angle,
|
||||
const std::function<void(void)> on_close
|
||||
) : nav_ (nav),
|
||||
altitude_ (altitude),
|
||||
@ -328,6 +336,7 @@ GeoMapView::GeoMapView(
|
||||
|
||||
geomap.set_mode(mode_);
|
||||
geomap.set_tag(tag);
|
||||
geomap.set_angle(angle);
|
||||
geomap.move(lon_, lat_);
|
||||
|
||||
geopos.set_read_only(true);
|
||||
|
@ -129,8 +129,12 @@ public:
|
||||
tag_ = new_tag;
|
||||
}
|
||||
|
||||
void set_angle(uint16_t new_angle){
|
||||
angle_ = new_angle;
|
||||
}
|
||||
|
||||
private:
|
||||
void draw_bearing(const Point origin, const uint32_t angle, uint32_t size, const Color color);
|
||||
void draw_bearing(const Point origin, const uint16_t angle, uint32_t size, const Color color);
|
||||
|
||||
GeoMapMode mode_ { };
|
||||
File map_file { };
|
||||
@ -141,7 +145,7 @@ private:
|
||||
int32_t prev_x_pos { 0xFFFF }, prev_y_pos { 0xFFFF };
|
||||
float lat_ { };
|
||||
float lon_ { };
|
||||
float angle_ { };
|
||||
uint16_t angle_ { };
|
||||
std::string tag_ { };
|
||||
};
|
||||
|
||||
@ -154,7 +158,7 @@ public:
|
||||
GeoPos::alt_unit altitude_unit,
|
||||
float lat,
|
||||
float lon,
|
||||
float angle,
|
||||
uint16_t angle,
|
||||
const std::function<void(void)> on_close = nullptr
|
||||
);
|
||||
GeoMapView(NavigationView& nav,
|
||||
@ -173,7 +177,7 @@ public:
|
||||
|
||||
void focus() override;
|
||||
|
||||
void update_position(float lat, float lon);
|
||||
void update_position(float lat, float lon, uint16_t angle);
|
||||
|
||||
std::string title() const override { return "Map view"; };
|
||||
|
||||
@ -190,7 +194,7 @@ private:
|
||||
GeoPos::alt_unit altitude_unit_ { };
|
||||
float lat_ { };
|
||||
float lon_ { };
|
||||
float angle_ { };
|
||||
uint16_t angle_ { };
|
||||
std::function<void(void)> on_close_ { nullptr };
|
||||
|
||||
bool map_opened { };
|
||||
|
@ -300,8 +300,8 @@ void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint
|
||||
|
||||
v_rate_coded = (v_rate / 64) + 1;
|
||||
|
||||
velo_ew_abs = abs(velo_ew);
|
||||
velo_ns_abs = abs(velo_ns);
|
||||
velo_ew_abs = abs(velo_ew) + 1;
|
||||
velo_ns_abs = abs(velo_ns) + 1;
|
||||
v_rate_coded_abs = abs(v_rate_coded);
|
||||
|
||||
make_frame_adsb(frame, ICAO_address);
|
||||
@ -317,4 +317,52 @@ void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint
|
||||
frame.make_CRC();
|
||||
}
|
||||
|
||||
// Decoding method from dump1090
|
||||
adsb_vel decode_frame_velo(ADSBFrame& frame){
|
||||
adsb_vel velo {false, 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;
|
||||
|
||||
if((frame_data[8] & 0x8) >> 3) 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(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 = sqrt(velo_ns*velo_ns + velo_ew*velo_ew);
|
||||
|
||||
if(velo.speed){
|
||||
//calculate heading in degrees from ew/ns velocities
|
||||
int16_t heading_temp = (int16_t)(atan2(velo_ew,velo_ns) * 180.0 / pi);
|
||||
// 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;
|
||||
}
|
||||
|
||||
return velo;
|
||||
|
||||
}
|
||||
|
||||
} /* namespace adsb */
|
||||
|
@ -56,6 +56,13 @@ struct adsb_pos {
|
||||
int32_t altitude;
|
||||
};
|
||||
|
||||
struct adsb_vel {
|
||||
bool valid;
|
||||
int32_t speed; //knot
|
||||
uint16_t heading; //degree
|
||||
int32_t v_rate; //ft/min
|
||||
};
|
||||
|
||||
const float CPR_MAX_VALUE = 131072.0;
|
||||
|
||||
const float adsb_lat_lut[58] = {
|
||||
@ -89,6 +96,8 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd);
|
||||
void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed,
|
||||
const float angle, const int32_t v_rate);
|
||||
|
||||
adsb_vel decode_frame_velo(ADSBFrame& frame);
|
||||
|
||||
//void encode_frame_emergency(ADSBFrame& frame, const uint32_t ICAO_address, const uint8_t code);
|
||||
|
||||
void encode_frame_squawk(ADSBFrame& frame, const uint32_t squawk);
|
||||
|
@ -41,6 +41,10 @@ public:
|
||||
return (raw_data[4] >> 3);
|
||||
}
|
||||
|
||||
uint8_t get_msg_sub() {
|
||||
return (raw_data[4] & 7);
|
||||
}
|
||||
|
||||
uint32_t get_ICAO_address() {
|
||||
return (raw_data[1] << 16) + (raw_data[2] << 8) + raw_data[3];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user