#ifndef SD_MANAGER_H #define SD_MANAGER_H #include #include #include #include "pin_config.h" #include "acuvim_registers.h" class MqttClient; class SdManager { public: SdManager(); bool begin(const char* deviceId); bool isAvailable() { return _mounted; } void setRetentionDays(uint16_t days) { _retentionDays = days; } bool bufferTelemetry(const AcuvimData& data); uint32_t getQueuedCount() { return _queuedCount; } bool hasQueuedData() { return _queuedCount > 0; } bool drainBatch(MqttClient& mqtt, int batchSize = 5); uint64_t getTotalSpace(); uint64_t getUsedSpace(); uint64_t getFreeSpace(); uint32_t getFileCount(); uint32_t cleanup(uint32_t maxAgeDays = 0); uint16_t getRetentionDays() { return _retentionDays; } void loop(); private: SPIClass _hspi; bool _mounted; char _deviceId[32]; uint16_t _retentionDays; String _currentFileName; uint32_t _recordsInCurrentFile; uint32_t _currentFileSize; uint32_t _queuedCount; bool _drainActive; String _drainFilePath; uint32_t _drainByteOffset; unsigned long _lastCardCheckMs; unsigned long _lastCleanupMs; static const unsigned long CARD_CHECK_INTERVAL_MS = 30000; static const unsigned long CLEANUP_INTERVAL_MS = 3600000; static const uint32_t MAX_FILE_SIZE = 500 * 1024; static const uint32_t MAX_RECORDS_PER_FILE = 5000; void ensureDirectories(); String generateFileName(); bool rotateFile(); bool shouldRotate(); void checkCard(); uint32_t countExistingRecords(); String getDateString(); uint32_t getEpochTime(); String findOldestFile(const char* dir); }; #endif