From 561143cfb0c41489f2c54785d0fbdeaced813b40 Mon Sep 17 00:00:00 2001 From: "E.T." Date: Fri, 6 Mar 2026 20:05:44 +0100 Subject: [PATCH] Improve SD Card Status Display and Error Handling (#3079) Summary: Fixed SD card mount error detection by enabling immediate mounting, made the status icon clickable to access settings, and added real-time status display (including filesystem type) in the SD card settings page. Changes: - Changed f_mount() to immediate mounting for error detection - Made SD card status icon clickable, linking to an enhanced sd card settings page that now includes live display of card status and filesystem type - Removed "SDCard Error" menu item --- firmware/application/apps/ui_settings.cpp | 85 ++++++++++++++++++- firmware/application/apps/ui_settings.hpp | 39 +++++++-- firmware/application/sd_card.cpp | 2 +- firmware/application/ui_navigation.cpp | 26 +++--- firmware/application/ui_navigation.hpp | 3 +- .../application/ui_sd_card_status_view.cpp | 4 +- .../application/ui_sd_card_status_view.hpp | 3 +- 7 files changed, 136 insertions(+), 26 deletions(-) diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index c4f2c2562..1e9d83375 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -35,6 +35,7 @@ #include "ui_external_items_menu_loader.hpp" #include "ui_ss_viewer.hpp" #include "ui_fileman.hpp" +#include "ui_sd_card_debug.hpp" #include "portapack_persistent_memory.hpp" #include "lpc43xx_cpp.hpp" @@ -446,7 +447,11 @@ void SetUIView::focus() { /* SetSDCardView *********************************************/ SetSDCardView::SetSDCardView(NavigationView& nav) { - add_children({&labels, + add_children({&status_labels, + &text_card_status, + &text_filesystem_type, + &button_more_info, + &labels, &checkbox_sdcard_speed, &button_test_sdcard_high_speed, &text_sdcard_test_status, @@ -455,6 +460,10 @@ SetSDCardView::SetSDCardView(NavigationView& nav) { checkbox_sdcard_speed.set_value(pmem::config_sdcard_high_speed_io()); + button_more_info.on_select = [&nav, this](Button&) { + nav.push(); + }; + button_test_sdcard_high_speed.on_select = [&nav, this](Button&) { pmem::set_config_sdcard_high_speed_io(true, false); text_sdcard_test_status.set("!! HIGH SPEED MODE ON !!"); @@ -472,7 +481,79 @@ SetSDCardView::SetSDCardView(NavigationView& nav) { } void SetSDCardView::focus() { - button_save.focus(); + button_cancel.focus(); +} + +void SetSDCardView::on_show() { + sd_card_status_signal_token = sd_card::status_signal += [this](const sd_card::Status) { + update_sd_card_status(); + }; + + update_sd_card_status(); +} + +void SetSDCardView::on_hide() { + sd_card::status_signal -= sd_card_status_signal_token; +} + +void SetSDCardView::update_sd_card_status() { + using sd_card::Status; + + const auto status = sd_card::status(); + + // Update card status text + switch (status) { + case Status::NotPresent: + text_card_status.set("Not Inserted"); + text_filesystem_type.set("---"); + break; + case Status::Present: + text_card_status.set("Inserted"); + text_filesystem_type.set("---"); + break; + case Status::Mounted: + text_card_status.set("Mounted"); + // Determine filesystem type + { + const auto fs_type = sd_card::fs.fs_type; + std::string fs_name; + switch (fs_type) { + case FS_FAT12: + fs_name = "FAT12"; + break; + case FS_FAT16: + fs_name = "FAT16"; + break; + case FS_FAT32: + fs_name = "FAT32"; + break; + case FS_EXFAT: + fs_name = "exFAT"; + break; + default: + fs_name = "Unknown"; + break; + } + text_filesystem_type.set(fs_name); + } + break; + case Status::ConnectError: + text_card_status.set("Connect Error"); + text_filesystem_type.set("---"); + break; + case Status::MountError: + text_card_status.set("Mount Error"); + text_filesystem_type.set("---"); + break; + case Status::IOError: + text_card_status.set("I/O Error"); + text_filesystem_type.set("---"); + break; + default: + text_card_status.set("Unknown"); + text_filesystem_type.set("---"); + break; + } } /* SetConverterSettingsView ******************************/ diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 30750ce5b..0a8898a03 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -34,6 +34,7 @@ #include "ui_navigation.hpp" #include "bitmap.hpp" #include "ff.h" +#include "sd_card.hpp" #include "portapack_persistent_memory.hpp" #include "irq_controls.hpp" @@ -424,36 +425,60 @@ class SetSDCardView : public View { public: SetSDCardView(NavigationView& nav); + void on_show() override; + void on_hide() override; + void focus() override; std::string title() const override { return "SD Card"; }; private: + SignalToken sd_card_status_signal_token{}; + // Status section (top half) + Labels status_labels{ + {{10, 24}, "Card Status:", Theme::getInstance()->fg_light->foreground}, + {{10, 48}, "Filesystem:", Theme::getInstance()->fg_light->foreground}}; + + Text text_card_status{ + {120, 24, 110, 16}, + ""}; + + Text text_filesystem_type{ + {120, 48, 110, 16}, + ""}; + + Button button_more_info{ + {UI_POS_X_CENTER(20), 90, UI_POS_WIDTH(20), UI_POS_HEIGHT(2)}, + "More Info"}; + + // Settings section (bottom half) Labels labels{ // 01234567890123456789012345678 - {{UI_POS_X_CENTER(26), 120 - 48}, " HIGH SPEED SDCARD IO ", Theme::getInstance()->fg_light->foreground}, - {{UI_POS_X_CENTER(26), 120 - 32}, " May or may not work !! ", Theme::getInstance()->fg_light->foreground}}; + {{UI_POS_X_CENTER(26), 140}, " HIGH SPEED SDCARD IO ", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X_CENTER(26), 156}, " May or may not work !! ", Theme::getInstance()->fg_light->foreground}}; Checkbox checkbox_sdcard_speed{ - {UI_POS_X_CENTER(26), 120}, + {UI_POS_X_CENTER(26), 180}, 20, "enable high speed IO"}; Button button_test_sdcard_high_speed{ - {UI_POS_X_CENTER(27), 152, UI_POS_WIDTH(27), UI_POS_HEIGHT(2)}, + {UI_POS_X_CENTER(27), 210, UI_POS_WIDTH(27), UI_POS_HEIGHT(2)}, "TEST BUTTON (NO PMEM SAVE)"}; Text text_sdcard_test_status{ - {UI_POS_X_CENTER(28), 198, UI_POS_WIDTH(28), UI_POS_HEIGHT(1)}, + {UI_POS_X_CENTER(28), 256, UI_POS_WIDTH(28), UI_POS_HEIGHT(1)}, ""}; Button button_save{ - {UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)}, + {UI_POS_X_CENTER(12) - UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32}, "Save"}; Button button_cancel{ - {UI_POS_X_CENTER(16) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)}, + {UI_POS_X_CENTER(12) + UI_POS_WIDTH(8), UI_POS_Y_BOTTOM(4), 12 * 8, 32}, "Cancel"}; + + void update_sd_card_status(); }; class SetConverterSettingsView : public View { diff --git a/firmware/application/sd_card.cpp b/firmware/application/sd_card.cpp index 6edfe9aa8..d7a14bc61 100644 --- a/firmware/application/sd_card.cpp +++ b/firmware/application/sd_card.cpp @@ -36,7 +36,7 @@ bool card_present = false; Status status_{Status::NotPresent}; FRESULT mount() { - return f_mount(&fs, reinterpret_cast(_T("")), 0); + return f_mount(&fs, reinterpret_cast(_T("")), 1); } } /* namespace */ diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 6ecef1b4f..342ad2a2d 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -301,6 +301,10 @@ SystemStatusView::SystemStatusView( this->on_clk(); }; + sd_card_status_view.on_select = [this](ImageButton&) { + this->on_sd_card(); + }; + // Initialize toggle buttons toggle_speaker.set_value(pmem::config_speaker_disable()); toggle_mute.set_value(pmem::config_audio_mute()); @@ -507,6 +511,16 @@ void SystemStatusView::on_clk() { refresh(); } +void SystemStatusView::on_sd_card() { + if (!nav_.is_valid()) return; + if (sd_info_up) return; + sd_info_up = true; + nav_.push(); + nav_.set_on_pop([this]() { + sd_info_up = false; + }); +} + void SystemStatusView::on_title() { if (nav_.is_top()) nav_.push(); @@ -806,12 +820,6 @@ void add_external_items(NavigationView& nav, app_location_t location, BtnGridVie } // clang-format on -bool verify_sdcard_format() { - FATFS* fs = &sd_card::fs; - return (fs->fs_type == FS_FAT32 || fs->fs_type == FS_EXFAT) || !(sd_card::status() == sd_card::Status::Mounted); - /* ^ to satisfy those users that not use an sd*/ -} - /* ReceiversMenuView *****************************************************/ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) @@ -913,12 +921,6 @@ void SystemMenuView::on_populate() { add_apps(nav_, *this, HOME); add_external_items(nav_, app_location_t::HOME, *this, 0); add_item({"HackRF", Theme::getInstance()->fg_cyan->foreground, &bitmap_icon_hackrf, [this]() { hackrf_mode(nav_); }}); - if (!verify_sdcard_format()) { // Moved to the end... after sd status change event, fstype wasn't populated fast enough.. - insert_item({"SDCard Error", Theme::getInstance()->error_dark->foreground, nullptr, [this]() { - nav_.display_modal("Error", "SD Card is not exFAT/FAT32"); - }}, - 0, true); - } } /* SystemView ************************************************************/ diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 650800e29..64c3e6bb4 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -62,7 +62,6 @@ namespace ui { void add_apps(NavigationView& nav, BtnGridView& grid, app_location_t loc); void add_external_items(NavigationView& nav, app_location_t location, BtnGridView& grid, uint8_t error_tile_pos, bool show_error_tile = true); -bool verify_sdcard_format(); enum modal_t { INFO = 0, @@ -202,6 +201,7 @@ class SystemStatusView : public View { static constexpr auto default_title = ""; bool batt_was_inited = false; // if the battery was off on tart, but later turned on. bool batt_info_up = false; // to prevent show multiple batt info dialog + bool sd_info_up = false; // to prevent show multiple sd info dialog NavigationView& nav_; @@ -303,6 +303,7 @@ class SystemStatusView : public View { void on_title(); void refresh(); void on_clk(); + void on_sd_card(); void on_tx_disabled(); void rtc_battery_workaround(); void on_battery_data(const BatteryStateMessage* msg); diff --git a/firmware/application/ui_sd_card_status_view.cpp b/firmware/application/ui_sd_card_status_view.cpp index 7736aaff0..c9e0327f8 100644 --- a/firmware/application/ui_sd_card_status_view.cpp +++ b/firmware/application/ui_sd_card_status_view.cpp @@ -83,7 +83,7 @@ const Color color_sd_card(const sd_card::Status status) { SDCardStatusView::SDCardStatusView( const Rect parent_rect) - : Image{parent_rect, &bitmap_sd_card_unknown, detail::color_sd_card_unknown, Theme::getInstance()->bg_dark->background} { + : ImageButton{parent_rect, &bitmap_sd_card_unknown, detail::color_sd_card_unknown, Theme::getInstance()->bg_dark->background} { } void SDCardStatusView::on_show() { @@ -101,7 +101,7 @@ void SDCardStatusView::paint(Painter& painter) { set_bitmap(&detail::bitmap_sd_card(status)); set_foreground(detail::color_sd_card(status)); - Image::paint(painter); + ImageButton::paint(painter); } void SDCardStatusView::on_status(const sd_card::Status) { diff --git a/firmware/application/ui_sd_card_status_view.hpp b/firmware/application/ui_sd_card_status_view.hpp index e6f7bd03b..aff8d243e 100644 --- a/firmware/application/ui_sd_card_status_view.hpp +++ b/firmware/application/ui_sd_card_status_view.hpp @@ -26,10 +26,11 @@ #include "theme.hpp" #include "ui_widget.hpp" #include "sd_card.hpp" +#include namespace ui { -class SDCardStatusView : public Image { +class SDCardStatusView : public ImageButton { public: SDCardStatusView(const Rect parent_rect);