#pragma once #include #include namespace tbeam { struct DateTime { uint16_t year = 0; uint8_t month = 0; uint8_t day = 0; uint8_t hour = 0; uint8_t minute = 0; uint8_t second = 0; uint8_t weekday = 0; }; struct ClockConfig { uint8_t rtcAddress = 0x51; int sda = -1; int scl = -1; bool beginWire = true; }; class TBeamClock { public: explicit TBeamClock(TwoWire& wire = Wire1); bool begin(const ClockConfig& config = ClockConfig{}); void update(); bool readRtc(DateTime& out, bool& lowVoltageFlag) const; bool readValidRtc(DateTime& out, int64_t* epochOut = nullptr) const; bool writeRtc(const DateTime& dt) const; bool ready() const { return ready_; } bool valid() const { return valid_; } bool lowVoltage() const { return lowVoltage_; } const DateTime& lastRtc() const { return lastRtc_; } int64_t lastEpoch() const { return lastEpoch_; } const char* lastError() const { return lastError_; } static bool isValidDateTime(const DateTime& dt); static int64_t toEpochSeconds(const DateTime& dt); static bool fromEpochSeconds(int64_t seconds, DateTime& out); static void formatIsoUtc(const DateTime& dt, char* out, size_t outSize); static void formatCompactUtc(const DateTime& dt, char* out, size_t outSize); static void makeRunId(const DateTime& dt, const char* boardId, char* out, size_t outSize); static bool parseDateTime(const char* text, DateTime& out); private: static uint8_t toBcd(uint8_t value); static uint8_t fromBcd(uint8_t value); static bool isLeapYear(uint16_t year); static uint8_t daysInMonth(uint16_t year, uint8_t month); static int64_t daysFromCivil(int year, unsigned month, unsigned day); void setError(const char* message) const; void clearError() const; TwoWire& wire_; ClockConfig config_{}; bool ready_ = false; bool valid_ = false; bool lowVoltage_ = false; DateTime lastRtc_{}; int64_t lastEpoch_ = 0; mutable char lastError_[128] = {}; }; } // namespace tbeam