#pragma once #include "../clock.hpp" #include "../i2c/i2c.hpp" #include "../type/type.hpp" #include "registers.hpp" namespace rtc { struct Date { uint16_t year; uint8_t month; uint8_t day; }; struct Time { uint8_t hour; uint8_t minute; uint8_t second; }; struct DateTime : Date, Time { }; template class DS3231 { public: static constexpr auto I2C_ADDRESS = 0x68; static constexpr auto TIME_REG_ADDR = 0x00; static constexpr auto ALARM1_REG_ADDR = 0x07; static constexpr auto ALARM2_REG_ADDR = 0x0B; static constexpr auto CONTROL_REG_ADDR = 0x0E; static constexpr auto CONTROL_STATUS_REG_ADDR = 0x0F; static constexpr auto AGING_OFFSET_REG_ADDR = 0x10; static constexpr auto TEMP_REG_ADDR = 0x11; // Construction does not call init and is only available for convenience DS3231() = default; // Moving and copying ds3231 objects is not supported DS3231(const DS3231 &) = delete; DS3231(DS3231 &&) = delete; DS3231 &operator=(const DS3231 &) = delete; DS3231 &operator=(DS3231 &&) = delete; static inline void init() { I2cDriver::init(); } static auto getDate() { const auto timeReg = readRegister(); Date date; date.year = timeReg.getYear(); date.month = timeReg.getMonth(); date.day = timeReg.getDate(); return date; } static auto getTime() { const auto timeReg = readRegister(); Time time; time.hour = timeReg.getHours(); time.minute = timeReg.getMinutes(); time.second = timeReg.getSeconds(); return time; } static auto getDateTime() { const auto timeReg = readRegister(); DateTime dateTime; dateTime.year = timeReg.getYear(); dateTime.month = timeReg.getMonth(); dateTime.day = timeReg.getDate(); dateTime.hour = timeReg.getHours(); dateTime.minute = timeReg.getMinutes(); dateTime.second = timeReg.getSeconds(); return dateTime; } static void setDate(const Date &date) {} static void setTime(const Time &time) {} static void setDateTime(const DateTime &dateTime) {} private: template static Register readRegisterHelper() { I2cDriver::template start(false); I2cDriver::write(Address); I2cDriver::stop(); Register reg; I2cDriver::template start(true); I2cDriver::template readBytes(reinterpret_cast(®)); I2cDriver::stop(); return reg; } template static auto readRegister() { if constexpr (Address == TIME_REG_ADDR) { return readRegisterHelper(); } else if constexpr (Address == ALARM1_REG_ADDR) { return readRegisterHelper(); } else if constexpr (Address == ALARM2_REG_ADDR) { return readRegisterHelper(); } else if constexpr (Address == CONTROL_REG_ADDR) { return readRegisterHelper(); } else if constexpr (Address == CONTROL_STATUS_REG_ADDR) { return readRegisterHelper(); } else if constexpr (Address == AGING_OFFSET_REG_ADDR) { return readRegisterHelper(); } else if constexpr (Address == TEMP_REG_ADDR) { return readRegisterHelper(); } else { static_assert(type::always_false_v, "Invalid register address"); } } template static void writePartialRegister(const Register ®) { static_assert(Offset < sizeof(Register), "Offset out of bounds"); if constexpr (Address == TIME_REG_ADDR) { static_assert(type::is_same_v, "Invalid register type"); } else if constexpr (Address == ALARM1_REG_ADDR) { static_assert(type::is_same_v, "Invalid register type"); } else if constexpr (Address == ALARM2_REG_ADDR) { static_assert(type::is_same_v, "Invalid register type"); } else if constexpr (Address == CONTROL_REG_ADDR) { static_assert(type::is_same_v, "Invalid register type"); } else if constexpr (Address == CONTROL_STATUS_REG_ADDR) { static_assert(type::is_same_v, "Invalid register type"); } else if constexpr (Address == AGING_OFFSET_REG_ADDR) { static_assert(type::is_same_v, "Invalid register type"); } else if constexpr (Address == TEMP_REG_ADDR) { static_assert(type::is_same_v, "Invalid register type"); } else { static_assert(type::always_false_v, "Invalid register address"); } I2cDriver::template start(false); I2cDriver::write(Address + Offset); I2cDriver::template writeBytes(reinterpret_cast(®) + Offset); I2cDriver::stop(); } static uint8_t calcDayOfWeek(uint16_t year, uint8_t month, uint16_t day) { day += month < 3 ? year-- : year - 2; const auto dayOfWeek = (23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400); return dayOfWeek % 7; } }; } // namespace rtc