Improve handling of sd card changes during runtime

- mount if an sd card is inserted
 - unmount if it's removed
This commit is contained in:
jacqueline
2024-01-30 09:55:31 +11:00
parent 9039a97ab4
commit c399199bfc
5 changed files with 76 additions and 53 deletions
+1 -1
View File
@@ -118,7 +118,7 @@ SdStorage::~SdStorage() {
sdspi_host_remove_device(this->handle_); sdspi_host_remove_device(this->handle_);
sdspi_host_deinit(); sdspi_host_deinit();
gpio_.WriteSync(IGpios::Pin::kSdPowerEnable, 1); gpio_.WriteSync(IGpios::Pin::kSdPowerEnable, 0);
gpio_.WriteSync(IGpios::Pin::kSdMuxDisable, 1); gpio_.WriteSync(IGpios::Pin::kSdMuxDisable, 1);
} }
+3
View File
@@ -49,6 +49,9 @@ struct KeyLockChanged : tinyfsm::Event {
struct HasPhonesChanged : tinyfsm::Event { struct HasPhonesChanged : tinyfsm::Event {
bool has_headphones; bool has_headphones;
}; };
struct SdDetectChanged : tinyfsm::Event {
bool has_sd_card;
};
struct ChargingStatusChanged : tinyfsm::Event {}; struct ChargingStatusChanged : tinyfsm::Event {};
struct BatteryStateChanged : tinyfsm::Event { struct BatteryStateChanged : tinyfsm::Event {
+12 -1
View File
@@ -59,6 +59,7 @@ class SystemState : public tinyfsm::Fsm<SystemState> {
virtual void react(const StorageMounted&) {} virtual void react(const StorageMounted&) {}
virtual void react(const StorageError&) {} virtual void react(const StorageError&) {}
virtual void react(const KeyLockChanged&) {} virtual void react(const KeyLockChanged&) {}
virtual void react(const SdDetectChanged&) {}
virtual void react(const audio::PlaybackFinished&) {} virtual void react(const audio::PlaybackFinished&) {}
virtual void react(const internal::IdleTimeout&) {} virtual void react(const internal::IdleTimeout&) {}
@@ -95,12 +96,22 @@ class Running : public SystemState {
void exit() override; void exit() override;
void react(const KeyLockChanged&) override; void react(const KeyLockChanged&) override;
void react(const StorageError&) override; void react(const SdDetectChanged&) override;
void react(const audio::PlaybackFinished&) override; void react(const audio::PlaybackFinished&) override;
using SystemState::react; using SystemState::react;
private:
auto mountStorage() -> bool;
auto unmountStorage() -> void;
bool storage_mounted_;
}; };
/**
* State for when the screen is off, controls locked, and music paused. Prelude
* to shutting off power completely.
*/
class Idle : public SystemState { class Idle : public SystemState {
public: public:
void entry() override; void entry() override;
+53 -51
View File
@@ -25,59 +25,14 @@ namespace states {
static database::IFileGatherer* sFileGatherer; static database::IFileGatherer* sFileGatherer;
/*
* Ensure the storage and database are both available. If either of these fails
* to open, then we assume it's an issue with the underlying SD card.
*/
void Running::entry() { void Running::entry() {
ESP_LOGI(kTag, "mounting sd card"); if (mountStorage()) {
vTaskDelay(pdMS_TO_TICKS(250)); events::Ui().Dispatch(StorageMounted{});
auto storage_res = drivers::SdStorage::Create(sServices->gpios());
if (storage_res.has_error()) {
ESP_LOGW(kTag, "failed to mount!");
switch (storage_res.error()) {
case drivers::SdStorage::FAILED_TO_MOUNT:
sServices->sd(drivers::SdState::kNotFormatted);
break;
case drivers::SdStorage::FAILED_TO_READ:
default:
sServices->sd(drivers::SdState::kNotPresent);
break;
}
events::System().Dispatch(StorageError{});
events::Audio().Dispatch(StorageError{});
events::Ui().Dispatch(StorageError{});
return;
} }
sStorage.reset(storage_res.value());
sServices->sd(drivers::SdState::kMounted);
ESP_LOGI(kTag, "opening database");
sFileGatherer = new database::FileGathererImpl();
auto database_res =
database::Database::Open(*sFileGatherer, sServices->tag_parser(),
sServices->collator(), sServices->bg_worker());
if (database_res.has_error()) {
ESP_LOGW(kTag, "failed to open!");
events::System().Dispatch(StorageError{});
events::Audio().Dispatch(StorageError{});
events::Ui().Dispatch(StorageError{});
return;
}
sServices->database(
std::unique_ptr<database::Database>{database_res.value()});
ESP_LOGI(kTag, "storage loaded okay");
StorageMounted ev{};
events::System().Dispatch(ev);
events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
void Running::exit() { void Running::exit() {
sServices->database({}); unmountStorage();
sStorage.reset();
} }
void Running::react(const KeyLockChanged& ev) { void Running::react(const KeyLockChanged& ev) {
@@ -92,9 +47,56 @@ void Running::react(const audio::PlaybackFinished& ev) {
} }
} }
void Running::react(const StorageError& ev) { void Running::react(const SdDetectChanged& ev) {
ESP_LOGW(kTag, "error loading storage"); if (ev.has_sd_card) {
// TODO. if (!sStorage && mountStorage()) {
events::Ui().Dispatch(StorageMounted{});
}
} else {
unmountStorage();
}
}
auto Running::mountStorage() -> bool {
ESP_LOGI(kTag, "mounting sd card");
auto storage_res = drivers::SdStorage::Create(sServices->gpios());
if (storage_res.has_error()) {
ESP_LOGW(kTag, "failed to mount!");
switch (storage_res.error()) {
case drivers::SdStorage::FAILED_TO_MOUNT:
sServices->sd(drivers::SdState::kNotFormatted);
break;
case drivers::SdStorage::FAILED_TO_READ:
default:
sServices->sd(drivers::SdState::kNotPresent);
break;
}
return false;
}
sStorage.reset(storage_res.value());
sServices->sd(drivers::SdState::kMounted);
ESP_LOGI(kTag, "opening database");
sFileGatherer = new database::FileGathererImpl();
auto database_res =
database::Database::Open(*sFileGatherer, sServices->tag_parser(),
sServices->collator(), sServices->bg_worker());
if (database_res.has_error()) {
unmountStorage();
return false;
}
sServices->database(
std::unique_ptr<database::Database>{database_res.value()});
ESP_LOGI(kTag, "storage loaded okay");
return true;
}
auto Running::unmountStorage() -> void {
sServices->database({});
sStorage.reset();
} }
} // namespace states } // namespace states
+7
View File
@@ -48,11 +48,13 @@ void SystemState::react(const internal::GpioInterrupt&) {
auto& gpios = sServices->gpios(); auto& gpios = sServices->gpios();
bool prev_key_lock = gpios.IsLocked(); bool prev_key_lock = gpios.IsLocked();
bool prev_has_headphones = !gpios.Get(drivers::Gpios::Pin::kPhoneDetect); bool prev_has_headphones = !gpios.Get(drivers::Gpios::Pin::kPhoneDetect);
bool prev_has_sd = gpios.Get(drivers::Gpios::Pin::kSdCardDetect);
gpios.Read(); gpios.Read();
bool key_lock = gpios.IsLocked(); bool key_lock = gpios.IsLocked();
bool has_headphones = !gpios.Get(drivers::Gpios::Pin::kPhoneDetect); bool has_headphones = !gpios.Get(drivers::Gpios::Pin::kPhoneDetect);
bool has_sd = gpios.Get(drivers::Gpios::Pin::kSdCardDetect);
if (key_lock != prev_key_lock) { if (key_lock != prev_key_lock) {
KeyLockChanged ev{.locking = key_lock}; KeyLockChanged ev{.locking = key_lock};
@@ -64,6 +66,11 @@ void SystemState::react(const internal::GpioInterrupt&) {
HasPhonesChanged ev{.has_headphones = has_headphones}; HasPhonesChanged ev{.has_headphones = has_headphones};
events::Audio().Dispatch(ev); events::Audio().Dispatch(ev);
} }
if (has_sd != prev_has_sd) {
SdDetectChanged ev{.has_sd_card = !has_sd};
events::System().Dispatch(ev);
events::Ui().Dispatch(ev);
}
} }
void SystemState::react(const internal::SamdInterrupt&) { void SystemState::react(const internal::SamdInterrupt&) {