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
This commit is contained in:
E.T.
2026-03-06 20:05:44 +01:00
committed by GitHub
parent 678ee2963e
commit 561143cfb0
7 changed files with 136 additions and 26 deletions
+83 -2
View File
@@ -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<SDCardDebugView>();
};
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 ******************************/
+32 -7
View File
@@ -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 {
+1 -1
View File
@@ -36,7 +36,7 @@ bool card_present = false;
Status status_{Status::NotPresent};
FRESULT mount() {
return f_mount(&fs, reinterpret_cast<const TCHAR*>(_T("")), 0);
return f_mount(&fs, reinterpret_cast<const TCHAR*>(_T("")), 1);
}
} /* namespace */
+14 -12
View File
@@ -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<SetSDCardView>();
nav_.set_on_pop([this]() {
sd_info_up = false;
});
}
void SystemStatusView::on_title() {
if (nav_.is_top())
nav_.push<AboutView>();
@@ -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 ************************************************************/
+2 -1
View File
@@ -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);
@@ -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) {
@@ -26,10 +26,11 @@
#include "theme.hpp"
#include "ui_widget.hpp"
#include "sd_card.hpp"
#include <functional>
namespace ui {
class SDCardStatusView : public Image {
class SDCardStatusView : public ImageButton {
public:
SDCardStatusView(const Rect parent_rect);