diff --git a/src/main.cpp b/src/main.cpp index 60d93d8..82d1d24 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ static PowerService* power; static ClockService* clockService; static String lastKey = "-"; +static String typed; // last characters typed, for the FORMAT confirmation static String lastEvent = "-"; static bool dirty = true; @@ -55,7 +56,7 @@ static void draw() { line("Key: " + lastKey); line("Event: " + lastEvent); d.setTextColor(TFT_DARKGREY); - line("+/- brightness, d: dim test (5s/10s)"); + line(storage->formatting() ? "Formatting SD card..." : "+/- bright, d: dim test, FORMAT+enter: wipe SD"); } static void logEvent(const String& text) { @@ -103,6 +104,14 @@ static void handleKeys() { (state.enter ? " enter" : "") + (state.del ? " del" : ""); dirty = true; + if (state.enter) { + if (typed.endsWith("FORMAT") && storage->requestFormat()) logEvent("format requested"); + typed = ""; + } else { + typed += word; + if (typed.length() > 16) typed.remove(0, typed.length() - 16); + } + int brightness = settings.getInt(Setting::Brightness); if (word == "=" || word == "+") settings.setInt(Setting::Brightness, brightness + 10); if (word == "-") settings.setInt(Setting::Brightness, brightness - 10); diff --git a/src/services/storage_service.cpp b/src/services/storage_service.cpp index 8a4354b..08ed21c 100644 --- a/src/services/storage_service.cpp +++ b/src/services/storage_service.cpp @@ -1,6 +1,10 @@ #include "storage_service.h" #include +#include +#include + +#include #include "platform/pins.h" #include "platform/shared_spi.h" @@ -31,11 +35,43 @@ StorageState StorageService::state() const { void StorageService::taskEntry(void* self) { auto* service = static_cast(self); for (;;) { + if (service->formatRequested_) { + service->format(); + service->formatRequested_ = false; + } service->poll(); - vTaskDelay(pdMS_TO_TICKS(kPollMs)); + // Sleep until the next poll, or until a format request wakes us early. + ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(kPollMs)); } } +bool StorageService::requestFormat() { + if (formatRequested_ || !task_) return false; + formatRequested_ = true; + xTaskNotifyGive(task_); + return true; +} + +void StorageService::format() { + if (mounted_) SD.end(); + mounted_ = false; + + bool ok = false; + uint8_t pdrv = sdcard_init(pins::kSdCs, &sharedSpi(), 20000000); + if (pdrv != 0xFF) { + constexpr size_t kWorkSize = 4096; // FF_MAX_SS + std::unique_ptr work(new uint8_t[kWorkSize]); + LBA_t partitions[] = {100, 0}; // one partition, 100 % of the card + char drive[3] = {static_cast('0' + pdrv), ':', 0}; + MKFS_PARM options = {FM_FAT32, 0, 0, 0, 0}; + ok = f_fdisk(pdrv, partitions, work.get()) == FR_OK && + f_mkfs(drive, &options, work.get(), kWorkSize) == FR_OK; + sdcard_uninit(pdrv); + } + bus_.publish(Event::withText(EventType::Notification, ok ? "SD card formatted" : "SD card format failed", + static_cast(ok ? NotificationLevel::Info : NotificationLevel::Warning))); +} + bool StorageService::mount() { return SD.begin(pins::kSdCs, sharedSpi(), 20000000, "/sd", 5, false); } diff --git a/src/services/storage_service.h b/src/services/storage_service.h index bcfc39c..b3caa9a 100644 --- a/src/services/storage_service.h +++ b/src/services/storage_service.h @@ -12,21 +12,29 @@ namespace roro { // Runs on its own task: a failed mount blocks for seconds and must never stall the UI. class StorageService : public Service { public: - explicit StorageService(EventBus& bus) : monitor_(bus) {} + explicit StorageService(EventBus& bus) : monitor_(bus), bus_(bus) {} const char* name() const override { return "storage"; } void start() override; void stop() override; StorageState state() const; + // Erases the whole card: one partition spanning the card, formatted FAT32. Runs on the storage + // task; the result arrives as a Notification. Returns false if a format is already pending. + bool requestFormat(); + bool formatting() const { return formatRequested_; } + private: static constexpr uint32_t kPollMs = 15000; static void taskEntry(void* self); void poll(); bool mount(); + void format(); StorageMonitor monitor_; bool mounted_ = false; + EventBus& bus_; + volatile bool formatRequested_ = false; TaskHandle_t task_ = nullptr; mutable SemaphoreHandle_t lock_ = nullptr; };