#pragma once #include #include #include #include #include #include #include #include "cleanup_plan.h" #include "service.h" #include "storage_monitor.h" namespace roro { // Owns the microSD card. All card access happens on this Service's own task (the SD driver isn't // safe across tasks, and a failed mount blocks for seconds): it mounts and watches usage, writes // queued Log lines in batches, lists files for Storage Clean-up, deletes, and formats. class StorageService : public Service { public: explicit StorageService(EventBus& bus) : monitor_(bus), bus_(bus) {} const char* name() const override { return "storage"; } void start() override; void stop() override; StorageState state() const; // Queues one line for a Log file (created with its folders as needed). Dropped while Logs are // paused (over 90 % full, or no card) or if too much is already waiting. void appendLine(const std::string& path, const std::string& line); uint32_t droppedLines() const { return dropped_; } // Storage Clean-up: list every file of every category, then delete a selection. void requestListing(); bool listingReady() const; std::vector> listing() const; // one vector per kCleanupCategories entry void requestDelete(std::vector paths); // Runs `job` on the storage task, where card access is safe (e.g. reading an Update File). void runJob(std::function job); // Erases the whole card: one partition spanning the card, formatted FAT32. bool requestFormat(); bool formatting() const { return formatRequested_; } private: static constexpr uint32_t kWakeMs = 1000; static constexpr uint32_t kPollEvery = 15; // wake-ups between usage checks static constexpr size_t kMaxPendingBytes = 16 * 1024; static void taskEntry(void* self); void loop(); void poll(); bool mount(); void format(); void writePending(); void list(); void remove(const std::vector& paths); void lock() const { xSemaphoreTake(lock_, portMAX_DELAY); } void unlock() const { xSemaphoreGive(lock_); } StorageMonitor monitor_; EventBus& bus_; bool mounted_ = false; TaskHandle_t task_ = nullptr; mutable SemaphoreHandle_t lock_ = nullptr; // Shared with other tasks, guarded by lock_. std::deque> pending_; size_t pendingBytes_ = 0; uint32_t dropped_ = 0; bool listingRequested_ = false; bool listingReady_ = false; std::vector> listing_; std::vector toDelete_; std::vector> jobs_; volatile bool formatRequested_ = false; }; } // namespace roro