From c53adfc7657fed92917864e46ee898e584b9591a Mon Sep 17 00:00:00 2001 From: RocketGod <57732082+RocketGod-git@users.noreply.github.com> Date: Sun, 14 Dec 2025 10:08:39 -0800 Subject: [PATCH] Refactor FLEX RX UI to use console for messages (#2890) --- firmware/application/external/flex/main.cpp | 84 ----------- .../external/flex_rx/ui_flex_rx.cpp | 130 +++++++----------- .../external/flex_rx/ui_flex_rx.hpp | 41 ++---- 3 files changed, 57 insertions(+), 198 deletions(-) delete mode 100644 firmware/application/external/flex/main.cpp diff --git a/firmware/application/external/flex/main.cpp b/firmware/application/external/flex/main.cpp deleted file mode 100644 index 64ed2a07b..000000000 --- a/firmware/application/external/flex/main.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2025 timelf123 - * with barely any help from RocketGod but I exist. - * - * This file is part of PortaPack. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "ui.hpp" -#include "ui_flex_rx.hpp" -#include "ui_navigation.hpp" -#include "external_app.hpp" - -namespace ui::external_app::flex_rx { -void initialize_app(ui::NavigationView& nav) { - nav.push(); -} -} // namespace ui::external_app::flex_rx - -extern "C" { - -__attribute__((section(".external_app.app_flex_rx.application_information"), used)) application_information_t _application_information_flex_rx = { - /*.memory_location = */ (uint8_t*)0x00000000, - /*.externalAppEntry = */ ui::external_app::flex_rx::initialize_app, - /*.header_version = */ CURRENT_HEADER_VERSION, - /*.app_version = */ VERSION_MD5, - - /*.app_name = */ "FLEX RX", - /*.bitmap_data = */ { - 0x00, - 0x00, - 0xFE, - 0x7F, - 0x02, - 0x40, - 0xFA, - 0x5F, - 0x02, - 0x40, - 0xF2, - 0x4F, - 0x02, - 0x40, - 0xE2, - 0x47, - 0x02, - 0x40, - 0xC2, - 0x43, - 0x02, - 0x40, - 0x82, - 0x41, - 0x02, - 0x40, - 0xFE, - 0x7F, - 0x00, - 0x00, - 0x00, - 0x00, - }, - /*.icon_color = */ ui::Color::cyan().v, - /*.menu_location = */ app_location_t::RX, - /*.desired_menu_position = */ -1, - - /*.m4_app_tag = portapack::spi_flash::image_tag_flex */ {'P', 'F', 'L', 'X'}, - /*.m4_app_offset = */ 0x00000000, // will be filled at compile time -}; -} \ No newline at end of file diff --git a/firmware/application/external/flex_rx/ui_flex_rx.cpp b/firmware/application/external/flex_rx/ui_flex_rx.cpp index e04a688df..ccc7410d5 100644 --- a/firmware/application/external/flex_rx/ui_flex_rx.cpp +++ b/firmware/application/external/flex_rx/ui_flex_rx.cpp @@ -18,9 +18,8 @@ FlexAppView::FlexAppView(NavigationView& nav) &field_rf_amp, &field_lna, &field_vga, - &button_color, &rssi, - &menu_view}); + &console}); // Restore saved frequency field_frequency.set_value(frequency_value); @@ -31,11 +30,6 @@ FlexAppView::FlexAppView(NavigationView& nav) update_freq(f); }; - // Color button cycles through available colors - button_color.on_select = [this](Button&) { - cycle_color(); - }; - // Configure receiver receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000); @@ -45,7 +39,7 @@ FlexAppView::FlexAppView(NavigationView& nav) // Initialize FLEX baseband baseband::set_flex_config(); - log_message("FLEX RX Ready"); + console.writeln("Ready"); } FlexAppView::~FlexAppView() { @@ -57,79 +51,53 @@ void FlexAppView::focus() { field_frequency.focus(); } -// Cycle to next text color and refresh display -void FlexAppView::cycle_color() { - current_color_index = (current_color_index + 1) % text_colors.size(); - rebuild_menu(); -} - -// Rebuild entire menu with current color -void FlexAppView::rebuild_menu() { - menu_view.clear(); - Color current_color = text_colors[current_color_index]; - for (const auto& msg : log_messages) { - menu_view.add_item({msg, - current_color, - nullptr, - [](KeyEvent) {}}); - } - if (menu_view.item_count() > 0) { - menu_view.set_highlighted(menu_view.item_count() - 1); +// Redraw all messages to console +void FlexAppView::redraw_console() { + console.clear(true); + bool first = true; + for (const auto& msg : messages) { + if (!first) { + console.writeln(""); // Blank line between messages + } + first = false; + console.writeln(msg); } } // Add message to log with automatic line wrapping void FlexAppView::log_message(const std::string& message) { - // Calculate characters per line based on screen width (8 pixels per char) const size_t chars_per_line = screen_width / 8; - Color current_color = text_colors[current_color_index]; + // Console height accounts for status bar and controls row + const size_t console_lines = (screen_height - 2 * 16) / 16; - std::string remaining = message; - bool first_line = true; - bool needs_rebuild = false; - size_t lines_added = 0; + messages.push_back(message); - // Split message into screen-width chunks - while (!remaining.empty()) { - std::string line; - if (remaining.length() <= chars_per_line) { - line = remaining; - remaining.clear(); - } else { - line = remaining.substr(0, chars_per_line); - remaining = remaining.substr(chars_per_line); - } - - // Indent continuation lines - if (!first_line) { - line = " " + line; - } - first_line = false; - - // Remove oldest line if at limit - if (log_messages.size() >= MAX_LOG_LINES) { - log_messages.erase(log_messages.begin()); - needs_rebuild = true; - } - - log_messages.push_back(line); - lines_added++; + // Calculate total lines used (messages + blank lines between them) + size_t total_lines = 0; + for (size_t i = 0; i < messages.size(); i++) { + if (i > 0) total_lines++; // Count blank line separator + size_t msg_lines = (messages[i].length() + chars_per_line - 1) / chars_per_line; + if (msg_lines == 0) msg_lines = 1; + total_lines += msg_lines; } - // Either rebuild all or just add new lines - if (needs_rebuild) { - rebuild_menu(); + // If console would overflow, remove oldest messages and redraw + if (total_lines > console_lines) { + while (total_lines > console_lines && !messages.empty()) { + const auto& oldest = messages.front(); + size_t oldest_lines = (oldest.length() + chars_per_line - 1) / chars_per_line; + if (oldest_lines == 0) oldest_lines = 1; + total_lines -= oldest_lines; + if (messages.size() > 1) total_lines--; // Remove separator line too + messages.erase(messages.begin()); + } + redraw_console(); } else { - size_t start_idx = log_messages.size() - lines_added; - for (size_t i = start_idx; i < log_messages.size(); i++) { - menu_view.add_item({log_messages[i], - current_color, - nullptr, - [](KeyEvent) {}}); - } - if (menu_view.item_count() > 0) { - menu_view.set_highlighted(menu_view.item_count() - 1); + // Just append new message + if (messages.size() > 1) { + console.writeln(""); // Blank line before new message } + console.writeln(message); } } @@ -141,27 +109,21 @@ void FlexAppView::update_freq(rf::Frequency f) { // Handle decoded FLEX packet from baseband void FlexAppView::on_packet(const FlexPacketMessage* message) { - std::string text = "FLEX "; - text += to_string_dec_uint(message->packet.bitrate); - text += " "; - text += to_string_dec_uint(message->packet.capcode); - text += ": "; - text += message->packet.message; - - log_message(text); + log_message(message->packet.message); } // Handle stats message (currently unused) -void FlexAppView::on_stats(const FlexStatsMessage* /* message */) { +void FlexAppView::on_stats(const FlexStatsMessage*) { } -// Handle debug message from baseband +// Debug handler - uncomment to see baseband debug messages void FlexAppView::on_debug(const FlexDebugMessage* message) { - std::string text = "DBG: "; - text += message->text; - text += " " + to_string_hex(message->val1, 8); - text += " " + to_string_hex(message->val2, 8); - log_message(text); + (void)message; // Suppress unused parameter warning + // std::string text = "DBG: "; + // text += message->text; + // text += " " + to_string_hex(message->val1, 8); + // text += " " + to_string_hex(message->val2, 8); + // log_message(text); } } // namespace ui::external_app::flex_rx \ No newline at end of file diff --git a/firmware/application/external/flex_rx/ui_flex_rx.hpp b/firmware/application/external/flex_rx/ui_flex_rx.hpp index 034633487..7f182878a 100644 --- a/firmware/application/external/flex_rx/ui_flex_rx.hpp +++ b/firmware/application/external/flex_rx/ui_flex_rx.hpp @@ -11,7 +11,6 @@ #include #include -#include namespace ui::external_app::flex_rx { @@ -28,28 +27,17 @@ class FlexAppView : public View { // Saved settings rf::Frequency frequency_value{931740000}; // Default FLEX frequency - uint32_t current_color_index{0}; // Current text color selection - - // Available text colors for message display - static constexpr std::array text_colors = {{Color::green(), - Color::white(), - Color::cyan(), - Color::magenta(), - Color::yellow(), - Color::blue(), - Color::red()}}; RxRadioState radio_state_{}; - // Message log settings - static constexpr size_t MAX_LOG_LINES = 32; // Limit to prevent memory issues - std::vector log_messages{}; // Stored log lines + // Message storage for console redraw + static constexpr size_t MAX_MESSAGES = 20; + std::vector messages{}; // Helper methods - void log_message(const std::string& message); // Add message with word wrap - void rebuild_menu(); // Rebuild menu after color change or overflow - void update_freq(rf::Frequency f); // Update tuned frequency - void cycle_color(); // Cycle through text colors + void log_message(const std::string& message); + void redraw_console(); + void update_freq(rf::Frequency f); // UI Elements - Row 0, dynamically positioned RxFrequencyField field_frequency{ @@ -63,25 +51,18 @@ class FlexAppView : public View { VGAGainField field_vga{ {UI_POS_X(18), UI_POS_Y(0)}}; - // Color cycle button - Button button_color{ - {UI_POS_X(21), UI_POS_Y(0), UI_POS_WIDTH(5), UI_POS_HEIGHT(1)}, - "COLOR"}; - RSSI rssi{ - {UI_POS_X(26), 0, UI_POS_WIDTH(4), 4}}; + {UI_POS_X(21), 0, UI_POS_WIDTH(9), 4}}; - // Message display area - scrollable menu view - MenuView menu_view{ - {0, 1 * 16, screen_width, screen_height - 1 * 16}, - true}; + // Message display area (below controls, account for status bar) + Console console{ + {0, 1 * 16, screen_width, screen_height - 2 * 16}}; // Persistent settings manager app_settings::SettingsManager settings_{ "rx_flex", app_settings::Mode::RX, - {{"frequency", &frequency_value}, - {"color_index", ¤t_color_index}}}; + {{"frequency", &frequency_value}}}; // Message handlers void on_packet(const FlexPacketMessage* message);