#pragma once #include #include #include #include #include "tbeam_supreme_adapter.h" enum class SdWatchState : uint8_t { UNKNOWN = 0, ABSENT, MOUNTED }; enum class SdEvent : uint8_t { NO_CARD, CARD_MOUNTED, CARD_REMOVED }; using SdStatusCallback = void (*)(SdEvent event, const char* message); struct SdWatcherConfig { bool enableSdRailCycle = true; bool enablePinDumps = true; bool recoveryRailCycleOnFullScan = true; uint32_t recoveryRailOffMs = 250; uint32_t recoveryRailOnSettleMs = 700; uint32_t startupWarmupMs = 1500; uint32_t pollIntervalAbsentMs = 1000; uint32_t pollIntervalMountedMs = 2000; uint32_t fullScanIntervalMs = 10000; uint8_t votesToPresent = 2; uint8_t votesToAbsent = 5; }; class StartupSdManager { public: explicit StartupSdManager(Print& serial = Serial); bool begin(const SdWatcherConfig& cfg, SdStatusCallback callback = nullptr); void update(); bool isMounted() const { return watchState_ == SdWatchState::MOUNTED; } SdWatchState state() const { return watchState_; } bool consumeMountedEvent(); bool consumeRemovedEvent(); void printCardInfo(); bool ensureDirRecursive(const char* path); bool rewriteFile(const char* path, const char* payload); void permissionsDemo(const char* path); private: void logf(const char* fmt, ...); void notify(SdEvent event, const char* message); void forceSpiDeselected(); void dumpSdPins(const char* tag); bool initPmuForSdPower(); void cycleSdRail(uint32_t offMs = 250, uint32_t onSettleMs = 600); bool tryMountWithBus(SPIClass& bus, const char* busName, uint32_t hz, bool verbose); bool mountPreferred(bool verbose); bool mountCardFullScan(); bool verifyMountedCard(); const char* cardTypeToString(uint8_t type); void setStateMounted(); void setStateAbsent(); Print& serial_; SdWatcherConfig cfg_{}; SdStatusCallback callback_ = nullptr; SPIClass sdSpiH_{HSPI}; SPIClass sdSpiF_{FSPI}; SPIClass* sdSpi_ = nullptr; const char* sdBusName_ = "none"; uint32_t sdFreq_ = 0; XPowersLibInterface* pmu_ = nullptr; SdWatchState watchState_ = SdWatchState::UNKNOWN; uint8_t presentVotes_ = 0; uint8_t absentVotes_ = 0; uint32_t lastPollMs_ = 0; uint32_t lastFullScanMs_ = 0; uint32_t logSeq_ = 0; bool mountedEventPending_ = false; bool removedEventPending_ = false; };