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:
@@ -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;
|
||||||
|
|||||||
+53
-51
@@ -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
|
||||||
|
|||||||
@@ -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&) {
|
||||||
|
|||||||
Reference in New Issue
Block a user