diff --git a/firmware/application/apps/ui_adsb_rx.cpp b/firmware/application/apps/ui_adsb_rx.cpp index 1ae332ee8..c2b8669d0 100644 --- a/firmware/application/apps/ui_adsb_rx.cpp +++ b/firmware/application/apps/ui_adsb_rx.cpp @@ -46,10 +46,10 @@ void RecentEntriesTable::draw( auto entry_age = entry.age; // Color decay for flights not being updated anymore - if (entry_age < ADSB_DECAY_A) { + if (entry_age < ADSB_CURRENT) { aged_color = 0x10; target_color = Color::green(); - } else if (entry_age < ADSB_DECAY_B) { + } else if (entry_age < ADSB_RECENT) { aged_color = 0x07; target_color = Color::light_grey(); } else { @@ -59,21 +59,13 @@ void RecentEntriesTable::draw( std::string entry_string = "\x1B"; entry_string += aged_color; -#if false - entry_string += to_string_hex(entry.ICAO_address, 6) + " " + - entry.callsign + " " + - (entry.hits <= 999 ? to_string_dec_uint(entry.hits, 4) : "999+") + " " + - entry.time_string; -#else - // SBT entry_string += - (entry.callsign[0]!=' ' ? entry.callsign + " " : to_string_hex(entry.ICAO_address, 6) + " ") + - to_string_dec_uint((unsigned int)((entry.pos.altitude+50)/100),4) + + (entry.callsign[0]!=' ' ? entry.callsign + " " : entry.icaoStr + " ") + + to_string_dec_uint((unsigned int)(entry.pos.altitude/100),4) + to_string_dec_uint((unsigned int)entry.velo.speed,4) + to_string_dec_uint((unsigned int)(entry.amp>>9),4) + " " + (entry.hits <= 999 ? to_string_dec_uint(entry.hits, 3) + " " : "1k+ ") + to_string_dec_uint(entry.age, 4); -#endif painter.draw_string( target_rect.location(), @@ -124,8 +116,6 @@ ADSBRxAircraftDetailsView::ADSBRxAircraftDetailsView( }); std::unique_ptr logger { }; - //update(entry_copy); - icao_code = to_string_hex(entry_copy.ICAO_address, 6); text_icao_address.set(to_string_hex(entry_copy.ICAO_address, 6)); @@ -225,7 +215,10 @@ void ADSBRxDetailsView::update(const AircraftRecentEntry& entry) { text_frame_pos_odd.set(to_string_hex_array(entry_copy.frame_pos_odd.get_raw_data(), 14)); if (send_updates) + { + geomap_view->update_tag(trimr(entry.callsign[0]!=' ' ? entry.callsign : to_string_hex(entry.ICAO_address, 6))); geomap_view->update_position(entry_copy.pos.latitude, entry_copy.pos.longitude, entry_copy.velo.heading, entry_copy.pos.altitude); + } } ADSBRxDetailsView::~ADSBRxDetailsView() { @@ -277,19 +270,14 @@ ADSBRxDetailsView::ADSBRxDetailsView( text_icao_address.set(to_string_hex(entry_copy.ICAO_address, 6)); button_aircraft_details.on_select = [this, &nav](Button&) { - //detailed_entry_key = entry.key(); - aircraft_details_view = nav.push( - entry_copy, - [this]() { - send_updates = false; - }); + aircraft_details_view = nav.push(entry_copy, [this]() { send_updates = false;}); send_updates = false; }; button_see_map.on_select = [this, &nav](Button&) { if (!send_updates) { // Prevent recursively launching the map geomap_view = nav.push( - entry_copy.callsign, + trimr(entry_copy.callsign[0]!=' ' ? entry_copy.callsign : entry_copy.icaoStr), entry_copy.pos.altitude, GeoPos::alt_unit::FEET, entry_copy.pos.latitude, @@ -309,6 +297,7 @@ void ADSBRxView::focus() { } ADSBRxView::~ADSBRxView() { + receiver_model.set_tuning_frequency(prevFreq); // Restore previous frequency on exit // save app settings settings.save("rx_adsb", &app_settings); @@ -326,8 +315,6 @@ AircraftRecentEntry ADSBRxView::find_or_create_entry(uint32_t ICAO_address) { // If not found if (it == std::end(recent)){ recent.emplace_front(ICAO_address); // Add it - truncate_entries(recent); // Truncate the list - sort_entries_by_state(); it = find(recent, ICAO_address); // Find it again } return *it; @@ -342,6 +329,21 @@ void ADSBRxView::replace_entry(AircraftRecentEntry & entry) entry); } +void ADSBRxView::remove_old_entries() +{ + auto it = recent.rbegin(); + auto end = recent.rend(); + while (it != end) + { + if (it->age_state>=4) { + std::advance(it, 1); + recent.erase( it.base() ); + } else { + break; // stop looking because the list is sorted + } + } +} + void ADSBRxView::sort_entries_by_state() { // Sorting List pn age_state using lambda function as comparator @@ -349,8 +351,8 @@ void ADSBRxView::sort_entries_by_state() } void ADSBRxView::on_frame(const ADSBFrameMessage * message) { + logger = std::make_unique(); rtc::RTC datetime; - std::string str_timestamp; std::string callsign; std::string str_info; std::string logentry; @@ -365,16 +367,16 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) { entry.reset_age(); if (entry.hits==0) { - entry.amp = message->amp; + entry.amp = message->amp; // Store amplitude on first hit } else { - entry.amp = ((entry.amp*15)+message->amp)>>4; + entry.amp = ((entry.amp*15)+message->amp)>>4; // Update smoothed amplitude on updates } - str_timestamp = to_string_datetime(datetime, HMS); - entry.set_time_string(str_timestamp); entry.inc_hit(); - logentry += to_string_hex_array(frame.get_raw_data(), 14) + " "; - logentry += "ICAO:" + to_string_hex(ICAO_address, 6) + " "; + if (logger) { + logentry += to_string_hex_array(frame.get_raw_data(), 14) + " "; + logentry += "ICAO:" + entry.icaoStr + " "; + } if (frame.get_DF() == DF_ADSB) { uint8_t msg_type = frame.get_msg_type(); @@ -385,7 +387,9 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) { if ((msg_type >= AIRCRAFT_ID_L) && (msg_type <= AIRCRAFT_ID_H)) { callsign = decode_frame_id(frame); entry.set_callsign(callsign); - logentry+=callsign+" "; + if (logger) { + logentry+=callsign+" "; + } } // 9: // 18: { // Extended squitter/non-transponder @@ -400,30 +404,33 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) { " Lat:" + to_string_decimal(entry.pos.latitude, 2) + " Lon:" + to_string_decimal(entry.pos.longitude, 2); - // printing the coordinates in the log file with more - // resolution, as we are not constrained by screen - // real estate there: - - std::string log_info = "Alt:" + to_string_dec_int(entry.pos.altitude) + - " Lat:" + to_string_decimal(entry.pos.latitude, 7) + - " Lon:" + to_string_decimal(entry.pos.longitude, 7); entry.set_info_string(str_info); - logentry+=log_info + " "; + + if (logger) { + // printing the coordinates in the log file with more + // resolution, as we are not constrained by screen + // real estate there: + + std::string log_info = "Alt:" + to_string_dec_int(entry.pos.altitude) + + " Lat:" + to_string_decimal(entry.pos.latitude, 7) + + " Lon:" + to_string_decimal(entry.pos.longitude, 7); + logentry+=log_info + " "; + } } } else if(msg_type == AIRBORNE_VEL && msg_sub >= VEL_GND_SUBSONIC && msg_sub <= VEL_AIR_SUPERSONIC){ 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 (logger) { + logentry += "Type:" + to_string_dec_uint(msg_sub) + + " Hdg:" + to_string_dec_uint(entry.velo.heading) + + " Spd: "+ to_string_dec_int(entry.velo.speed); + } } - } + replace_entry(entry); + } // frame.get_DF() == DF_ADSB - replace_entry(entry); - - logger = std::make_unique(); if (logger) { logger->append(u"adsb.txt"); // will log each frame in format: @@ -433,20 +440,69 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) { } } -void ADSBRxView::on_tick_second() { - // Decay and refresh if needed - for (auto& entry : recent) { - entry.inc_age(); - - if (details_view) { - if (send_updates && (entry.key() == detailed_entry_key)) // Check if the ICAO address match - details_view->update(entry); +void ADSBRxView::on_tick_second() { + if (recent.size() <= 16){ // Not many entries update everything (16 is one screen full) + updateDetailsAndMap(1); + updateRecentEntries(); + } else if (updateState==0) { // Even second + updateState = 1; + updateDetailsAndMap(2); + } else { // Odd second only performed when there are many entries + updateState = 0; + updateRecentEntries(); + } +} + +void ADSBRxView::updateDetailsAndMap(int ageStep) { + ui::GeoMarker marker; + bool storeNewMarkers = false; + + // Sort and truncate the entries, grouped, newest group first + sort_entries_by_state(); + truncate_entries(recent); + remove_old_entries(); + + // Calculate if it is time to update markers + if (send_updates && details_view && details_view->geomap_view) { + ticksSinceMarkerRefresh += ageStep; + if (ticksSinceMarkerRefresh >= MARKER_UPDATE_SECONDS) { // Update other aircraft every few seconds + storeNewMarkers = true; + ticksSinceMarkerRefresh=0; } + } else { + ticksSinceMarkerRefresh = MARKER_UPDATE_SECONDS; // Send the markers as soon as the geoview exists } - // Sort the list if it is being displayed - if (!send_updates) { - sort_entries_by_state(); + // Increment age, and pass updates to the details and map + const bool otherMarkersCanBeSent = send_updates && storeNewMarkers && details_view && details_view->geomap_view; // Save retesting all of this + MapMarkerStored markerStored = MARKER_NOT_STORED; + if (otherMarkersCanBeSent) {details_view->geomap_view->clear_markers();} + // Loop through all entries + for (auto& entry : recent) { + entry.inc_age(ageStep); + + // Only if there is a details view + if (send_updates && details_view) { + if (entry.key() == detailed_entry_key) // Check if the ICAO address match + { + details_view->update(entry); + } + // Store if the view is present and the list isn't full + else if (otherMarkersCanBeSent && (markerStored != MARKER_LIST_FULL) && (entry.age_state==0)) + { + marker.lon = entry.pos.longitude; + marker.lat = entry.pos.latitude; + marker.angle = entry.velo.heading; + marker.tag = trimr(entry.callsign[0]!=' ' ? entry.callsign : entry.icaoStr); + markerStored = details_view->geomap_view->store_marker(marker); + } + } + } // Loop through all entries, if only to update the age +} + +void ADSBRxView::updateRecentEntries() { + // Redraw the list of aircraft + if (!send_updates){ recent_entries_view.set_dirty(); } } @@ -492,7 +548,7 @@ ADSBRxView::ADSBRxView(NavigationView& nav) { on_tick_second(); }; - prevFreq = receiver_model.tuning_frequency(); + prevFreq = receiver_model.tuning_frequency(); // Store previous frequency on creation baseband::set_adsb(); diff --git a/firmware/application/apps/ui_adsb_rx.hpp b/firmware/application/apps/ui_adsb_rx.hpp index e882b8db5..4764d7b9d 100644 --- a/firmware/application/apps/ui_adsb_rx.hpp +++ b/firmware/application/apps/ui_adsb_rx.hpp @@ -25,6 +25,7 @@ #include "ui_receiver.hpp" #include "ui_geomap.hpp" #include "ui_font_fixed_8x16.hpp" +#include "string_format.hpp" #include "file.hpp" #include "database.hpp" @@ -39,9 +40,9 @@ using namespace adsb; namespace ui { -#define ADSB_DECAY_A 10 // In seconds -#define ADSB_DECAY_B 30 -#define ADSB_DECAY_C 60 // Can be used for removing old entries, RecentEntries already caps to 64 +#define ADSB_CURRENT 10 // Seconds +#define ADSB_RECENT 30 // Seconds +#define ADSB_REMOVE 300 // Used for removing old entries #define AIRCRAFT_ID_L 1 // aircraft ID message type (lowest type id) #define AIRCRAFT_ID_H 4 // aircraft ID message type (highest type id) @@ -83,14 +84,15 @@ struct AircraftRecentEntry { ADSBFrame frame_pos_even { }; ADSBFrame frame_pos_odd { }; + std::string icaoStr {" "}; std::string callsign { " " }; - std::string time_string { "" }; std::string info_string { "" }; AircraftRecentEntry( const uint32_t ICAO_address ) : ICAO_address { ICAO_address } { + this->icaoStr = to_string_hex(ICAO_address, 6); } Key key() const { @@ -125,23 +127,20 @@ struct AircraftRecentEntry { info_string = new_info_string; } - void set_time_string(std::string& new_time_string) { - time_string = new_time_string; - } - void reset_age() { age = 0; } - void inc_age() { - age++; - if (age < ADSB_DECAY_A) - { + void inc_age(int delta) { + age+=delta; + if (age < ADSB_CURRENT){ age_state = pos.valid ? 0 : 1; - } - else - { - age_state = (age < ADSB_DECAY_B) ? 2 : 3; + } else if(age < ADSB_RECENT){ + age_state = 2; + } else if(age < ADSB_REMOVE){ + age_state = 3; + } else{ + age_state = 4; } } }; @@ -276,7 +275,6 @@ public: private: AircraftRecentEntry entry_copy { 0 }; std::function on_close_ { }; - GeoMapView* geomap_view { nullptr }; ADSBRxAircraftDetailsView* aircraft_details_view { nullptr }; bool send_updates { false }; std::database db = { }; @@ -364,6 +362,7 @@ public: std::string title() const override { return "ADS-B RX"; }; void replace_entry(AircraftRecentEntry & entry); + void remove_old_entries(); AircraftRecentEntry find_or_create_entry(uint32_t ICAO_address); void sort_entries_by_state(); @@ -372,24 +371,23 @@ private: std::unique_ptr logger { }; void on_frame(const ADSBFrameMessage * message); void on_tick_second(); + int updateState = { 0 }; + void updateRecentEntries(); + void updateDetailsAndMap(int ageStep); + + #define MARKER_UPDATE_SECONDS (5) + int ticksSinceMarkerRefresh { MARKER_UPDATE_SECONDS-1 }; // app save settings std::app_settings settings { }; std::app_settings::AppSettings app_settings { }; const RecentEntriesColumns columns { { -#if false - { "ICAO", 6 }, - { "Callsign", 9 }, - { "Hits", 4 }, - { "Time", 8 } -#else { "ICAO/Call", 9 }, { "Lvl", 3 }, { "Spd", 3 }, { "Amp", 3 }, { "Hit", 3 }, { "Age", 4 } -#endif } }; AircraftRecentEntries recent { }; RecentEntriesView> recent_entries_view { columns, recent }; diff --git a/firmware/baseband/proc_adsbrx.cpp b/firmware/baseband/proc_adsbrx.cpp index 4520f1c9b..f52d51013 100644 --- a/firmware/baseband/proc_adsbrx.cpp +++ b/firmware/baseband/proc_adsbrx.cpp @@ -45,8 +45,8 @@ void ADSBRXProcessor::execute(const buffer_c8_t& buffer) { for (size_t i = 0; i < buffer.count; i++) { // Compute sample's magnitude - re = (int32_t)buffer.p[i].real(); // make re float and scale it - im = (int32_t)buffer.p[i].imag(); // make re float and scale it + re = (int32_t)buffer.p[i].real(); + im = (int32_t)buffer.p[i].imag(); mag = ((uint32_t)(re*re) + (uint32_t)(im*im)); if (decoding) { @@ -63,7 +63,6 @@ void ADSBRXProcessor::execute(const buffer_c8_t& buffer) { } else { - //confidence = true; bit = (prev_mag > mag) ? 1 : 0; } @@ -94,7 +93,7 @@ void ADSBRXProcessor::execute(const buffer_c8_t& buffer) { } // Continue looking for preamble even if in a packet - // switch is new preamble id higher magnitude + // switch if new preamble is higher magnitude // Shift the preamble for (c = 0; c < (ADSB_PREAMBLE_LENGTH ); c++) { shifter[c] = shifter[c + 1]; } diff --git a/firmware/common/adsb.cpp b/firmware/common/adsb.cpp index c209cdf8a..5560745cc 100644 --- a/firmware/common/adsb.cpp +++ b/firmware/common/adsb.cpp @@ -22,6 +22,7 @@ #include "adsb.hpp" #include "sine_table.hpp" +#include "utility.hpp" #include @@ -369,11 +370,11 @@ adsb_vel decode_frame_velo(ADSBFrame& frame){ 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); + 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)(atan2(velo_ew,velo_ns) * 180.0 / pi); + 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;