diff --git a/firmware/application/pocsag_app.cpp b/firmware/application/pocsag_app.cpp index 6aace1bc..97c15d9b 100644 --- a/firmware/application/pocsag_app.cpp +++ b/firmware/application/pocsag_app.cpp @@ -144,7 +144,7 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage * message) { std::string alphanum_text = ""; if (message->packet.flag() != NORMAL) - console.writeln("\n\x1B\x01RX ERROR: " + pocsag::flag_str(message->packet.flag())); + console.writeln("\n\x1B\x0CRX ERROR: " + pocsag::flag_str(message->packet.flag())); else { pocsag_decode_batch(message->packet, &pocsag_state); diff --git a/firmware/application/ui_adsb_rx.cpp b/firmware/application/ui_adsb_rx.cpp index d134c4de..872c5474 100644 --- a/firmware/application/ui_adsb_rx.cpp +++ b/firmware/application/ui_adsb_rx.cpp @@ -24,6 +24,7 @@ #include "ui_alphanum.hpp" #include "ui_geomap.hpp" +#include "rtc_time.hpp" #include "string_format.hpp" #include "portapack.hpp" #include "baseband_api.hpp" @@ -43,18 +44,35 @@ void RecentEntriesTable::draw( Painter& painter, const Style& style ) { + char aged_color; + Color target_color; + + if (entry.age < 10) { + aged_color = 0x10; + target_color = Color::green(); + } else if ((entry.age >= 10) && (entry.age < 30)) { + aged_color = 0x07; + target_color = Color::light_grey(); + } else { + aged_color = 0x08; + target_color = Color::dark_grey(); + } + + std::string string = "\x1B"; + string += aged_color; + string += to_string_hex(entry.ICAO_address, 6) + " " + + entry.callsign + " " + + (entry.hits <= 999 ? to_string_dec_uint(entry.hits, 4) : "999+") + " " + + entry.time_string; + painter.draw_string( target_rect.location(), style, - to_string_hex(entry.ICAO_address, 6) + - (entry.pos.valid ? " \x1B\x02" : " ") + - entry.callsign + " \x1B\x00" + - (entry.hits <= 999 ? to_string_dec_uint(entry.hits, 4) : "999+") + " " + - entry.time_string + string ); if (entry.pos.valid) - painter.draw_bitmap(target_rect.location() + Point(15 * 8, 0), bitmap_target, style.foreground, style.background); + painter.draw_bitmap(target_rect.location() + Point(15 * 8, 0), bitmap_target, target_color, style.background); } void ADSBRxView::focus() { @@ -62,6 +80,7 @@ void ADSBRxView::focus() { } ADSBRxView::~ADSBRxView() { + rtc_time::signal_tick_second -= signal_token_tick_second; receiver_model.disable(); baseband::shutdown(); } @@ -70,18 +89,17 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) { rtc::RTC datetime; std::string str_timestamp; std::string callsign; + std::string str_info; auto frame = message->frame; - uint32_t ICAO_address = frame.get_ICAO_address(); - if (frame.check_CRC() && frame.get_ICAO_address()) { - frame.set_rx_timestamp(datetime.minute() * 60 + datetime.second()); - + rtcGetTime(&RTCD1, &datetime); auto& entry = ::on_packet(recent, ICAO_address); - rtcGetTime(&RTCD1, &datetime); + frame.set_rx_timestamp(datetime.minute() * 60 + datetime.second()); + entry.reset_age(); str_timestamp = to_string_datetime(datetime, HMS); entry.set_time_string(str_timestamp); @@ -98,13 +116,13 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) { entry.set_frame_pos(frame, raw_data[6] & 4); if (entry.pos.valid) { - callsign = "Alt:" + to_string_dec_uint(entry.pos.altitude) + + str_info = "Alt:" + to_string_dec_uint(entry.pos.altitude) + " Lat" + to_string_dec_int(entry.pos.latitude) + "." + to_string_dec_int((int)(entry.pos.latitude * 1000) % 100) + " Lon" + to_string_dec_int(entry.pos.longitude) + "." + to_string_dec_int((int)(entry.pos.longitude * 1000) % 100); - entry.set_pos_string(callsign); + entry.set_info_string(str_info); } } } @@ -113,6 +131,14 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) { } } +void ADSBRxView::on_tick_second() { + for (auto& entry : recent) { + entry.inc_age(); + if ((entry.age == 10) || (entry.age == 30)) + recent_entries_view.set_dirty(); + } +} + ADSBRxView::ADSBRxView(NavigationView&) { baseband::run_image(portapack::spi_flash::image_tag_adsb_rx); @@ -129,11 +155,15 @@ ADSBRxView::ADSBRxView(NavigationView&) { recent_entries_view.set_parent_rect({ 0, 64, 240, 224 }); recent_entries_view.on_select = [this](const AircraftRecentEntry& entry) { - text_debug_a.set(entry.pos_string); + text_debug_a.set(entry.info_string); text_debug_b.set(to_string_hex_array(entry.frame_pos_even.get_raw_data(), 14)); text_debug_c.set(to_string_hex_array(entry.frame_pos_odd.get_raw_data(), 14)); }; + signal_token_tick_second = rtc_time::signal_tick_second += [this]() { + on_tick_second(); + }; + baseband::set_adsb(); receiver_model.set_tuning_frequency(1090000000); diff --git a/firmware/application/ui_adsb_rx.hpp b/firmware/application/ui_adsb_rx.hpp index 6ec035ef..9fd754df 100644 --- a/firmware/application/ui_adsb_rx.hpp +++ b/firmware/application/ui_adsb_rx.hpp @@ -40,6 +40,7 @@ struct AircraftRecentEntry { uint32_t ICAO_address { }; uint16_t hits { 0 }; + uint32_t age { 0 }; adsb_pos pos { false, 0, 0, 0 }; ADSBFrame frame_pos_even { }; @@ -47,7 +48,7 @@ struct AircraftRecentEntry { std::string callsign { " " }; std::string time_string { "" }; - std::string pos_string { "" }; + std::string info_string { "" }; AircraftRecentEntry( const uint32_t ICAO_address @@ -79,13 +80,21 @@ struct AircraftRecentEntry { } } - void set_pos_string(std::string& new_pos_string) { - pos_string = new_pos_string; + void set_info_string(std::string& new_info_string) { + 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++; + } }; using AircraftRecentEntries = RecentEntries; @@ -101,6 +110,7 @@ public: private: void on_frame(const ADSBFrameMessage * message); + void on_tick_second(); const RecentEntriesColumns columns { { { "ICAO", 6 }, @@ -111,6 +121,8 @@ private: AircraftRecentEntries recent { }; RecentEntriesView> recent_entries_view { columns, recent }; + SignalToken signal_token_tick_second { }; + RSSI rssi { { 19 * 8, 4, 10 * 8, 8 }, }; diff --git a/firmware/common/ui.cpp b/firmware/common/ui.cpp index c5482e73..c257d1fa 100644 --- a/firmware/common/ui.cpp +++ b/firmware/common/ui.cpp @@ -26,14 +26,23 @@ namespace ui { -Color term_colors[8] = { +// CGA palette +Color term_colors[16] = { Color::black(), - Color::red(), - Color::green(), - Color::yellow(), + Color::dark_blue(), + Color::dark_green(), + Color::dark_cyan(), + Color::dark_red(), + Color::dark_magenta(), + Color::dark_yellow(), + Color::light_grey(), + Color::dark_grey(), Color::blue(), - Color::magenta(), + Color::green(), Color::cyan(), + Color::red(), + Color::magenta(), + Color::yellow(), Color::white() }; diff --git a/firmware/common/ui.hpp b/firmware/common/ui.hpp index a6625417..81333cc1 100644 --- a/firmware/common/ui.hpp +++ b/firmware/common/ui.hpp @@ -104,10 +104,16 @@ struct Color { static constexpr Color cyan() { return { 0, 255, 255 }; } + static constexpr Color dark_cyan() { + return { 0, 127, 127 }; + } static constexpr Color magenta() { return { 255, 0, 255 }; } + static constexpr Color dark_magenta() { + return { 127, 0, 127 }; + } static constexpr Color white() { return { 255, 255, 255 }; @@ -128,7 +134,7 @@ struct Color { } }; -extern Color term_colors[8]; +extern Color term_colors[16]; struct ColorRGB888 { uint8_t r; diff --git a/firmware/common/ui_painter.cpp b/firmware/common/ui_painter.cpp index cfa7ad0a..90f22bbb 100644 --- a/firmware/common/ui_painter.cpp +++ b/firmware/common/ui_painter.cpp @@ -51,8 +51,10 @@ int Painter::draw_string(Point p, const Font& font, const Color foreground, for(const auto c : text) { if (escape) { - pen = term_colors[c & 7]; - if (!c) pen = foreground; + if (c <= 15) + pen = term_colors[c & 15]; + else + pen = foreground; escape = false; } else { if (c == '\x1B') { diff --git a/firmware/graphics/target.png b/firmware/graphics/target.png new file mode 100644 index 00000000..81c50f7c Binary files /dev/null and b/firmware/graphics/target.png differ