Improve handling of sd card changes during runtime

- mount if an sd card is inserted
 - unmount if it's removed
custom
jacqueline 1 year ago
parent 9039a97ab4
commit c399199bfc
  1. 2
      src/drivers/storage.cpp
  2. 3
      src/system_fsm/include/system_events.hpp
  3. 13
      src/system_fsm/include/system_fsm.hpp
  4. 76
      src/system_fsm/running.cpp
  5. 7
      src/system_fsm/system_fsm.cpp

@ -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);
} }

@ -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 {

@ -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;

@ -25,13 +25,40 @@ 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() {
if (mountStorage()) {
events::Ui().Dispatch(StorageMounted{});
}
}
void Running::exit() {
unmountStorage();
}
void Running::react(const KeyLockChanged& ev) {
if (IdleCondition()) {
transit<Idle>();
}
}
void Running::react(const audio::PlaybackFinished& ev) {
if (IdleCondition()) {
transit<Idle>();
}
}
void Running::react(const SdDetectChanged& ev) {
if (ev.has_sd_card) {
if (!sStorage && mountStorage()) {
events::Ui().Dispatch(StorageMounted{});
}
} else {
unmountStorage();
}
}
auto Running::mountStorage() -> bool {
ESP_LOGI(kTag, "mounting sd card"); ESP_LOGI(kTag, "mounting sd card");
vTaskDelay(pdMS_TO_TICKS(250));
auto storage_res = drivers::SdStorage::Create(sServices->gpios()); auto storage_res = drivers::SdStorage::Create(sServices->gpios());
if (storage_res.has_error()) { if (storage_res.has_error()) {
ESP_LOGW(kTag, "failed to mount!"); ESP_LOGW(kTag, "failed to mount!");
@ -44,12 +71,9 @@ void Running::entry() {
sServices->sd(drivers::SdState::kNotPresent); sServices->sd(drivers::SdState::kNotPresent);
break; break;
} }
return false;
events::System().Dispatch(StorageError{});
events::Audio().Dispatch(StorageError{});
events::Ui().Dispatch(StorageError{});
return;
} }
sStorage.reset(storage_res.value()); sStorage.reset(storage_res.value());
sServices->sd(drivers::SdState::kMounted); sServices->sd(drivers::SdState::kMounted);
@ -59,43 +83,21 @@ void Running::entry() {
database::Database::Open(*sFileGatherer, sServices->tag_parser(), database::Database::Open(*sFileGatherer, sServices->tag_parser(),
sServices->collator(), sServices->bg_worker()); sServices->collator(), sServices->bg_worker());
if (database_res.has_error()) { if (database_res.has_error()) {
ESP_LOGW(kTag, "failed to open!"); unmountStorage();
events::System().Dispatch(StorageError{}); return false;
events::Audio().Dispatch(StorageError{});
events::Ui().Dispatch(StorageError{});
return;
} }
sServices->database( sServices->database(
std::unique_ptr<database::Database>{database_res.value()}); std::unique_ptr<database::Database>{database_res.value()});
ESP_LOGI(kTag, "storage loaded okay"); ESP_LOGI(kTag, "storage loaded okay");
StorageMounted ev{}; return true;
events::System().Dispatch(ev);
events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
void Running::exit() { auto Running::unmountStorage() -> void {
sServices->database({}); sServices->database({});
sStorage.reset(); sStorage.reset();
} }
void Running::react(const KeyLockChanged& ev) {
if (IdleCondition()) {
transit<Idle>();
}
}
void Running::react(const audio::PlaybackFinished& ev) {
if (IdleCondition()) {
transit<Idle>();
}
}
void Running::react(const StorageError& ev) {
ESP_LOGW(kTag, "error loading storage");
// TODO.
}
} // namespace states } // namespace states
} // namespace system_fsm } // namespace system_fsm

@ -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&) {

Loading…
Cancel
Save