Compare commits
8 Commits
54b8917705
...
11211be9b9
| Author | SHA1 | Date | |
|---|---|---|---|
| 11211be9b9 | |||
| 8c50aa4688 | |||
| a65b30f9df | |||
| cd5317db5b | |||
| 92096b6101 | |||
| 80cce4671f | |||
| c728d99f97 | |||
| 8e653ebd44 |
92
ds3231.hpp
92
ds3231.hpp
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "../clock.hpp"
|
#include "../clock.hpp"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "../i2c/i2c.hpp"
|
#include "../i2c/i2c.hpp"
|
||||||
#include "../type/type.hpp"
|
#include "../type/type.hpp"
|
||||||
|
|
||||||
@@ -24,7 +26,7 @@ struct Time {
|
|||||||
struct DateTime : Date, Time {
|
struct DateTime : Date, Time {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename I2cDriver>
|
template <typename I2cDriver, bool SetDayOfWeek = true>
|
||||||
class DS3231 {
|
class DS3231 {
|
||||||
public:
|
public:
|
||||||
static constexpr auto I2C_ADDRESS = 0x68;
|
static constexpr auto I2C_ADDRESS = 0x68;
|
||||||
@@ -85,9 +87,50 @@ class DS3231 {
|
|||||||
return dateTime;
|
return dateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setDate(const Date &date) {}
|
static void setDate(const Date &date)
|
||||||
static void setTime(const Time &time) {}
|
{
|
||||||
static void setDateTime(const DateTime &dateTime) {}
|
detail::TimeReg timeReg;
|
||||||
|
timeReg.setYear(date.year);
|
||||||
|
timeReg.setMonth(date.month);
|
||||||
|
timeReg.setDate(date.day);
|
||||||
|
if constexpr (SetDayOfWeek)
|
||||||
|
timeReg.setDay(calcDayOfWeek(date.year, date.month, date.day) + 1);
|
||||||
|
|
||||||
|
constexpr auto DATE_START_OFFSET = offsetof(detail::TimeReg, day);
|
||||||
|
constexpr auto DATE_END_OFFSET = offsetof(detail::TimeReg, year);
|
||||||
|
|
||||||
|
writePartialRegister<TIME_REG_ADDR, DATE_START_OFFSET, DATE_END_OFFSET>(timeReg);
|
||||||
|
}
|
||||||
|
static void setTime(const Time &time)
|
||||||
|
{
|
||||||
|
detail::TimeReg timeReg;
|
||||||
|
timeReg.setHours(time.hour);
|
||||||
|
timeReg.setMinutes(time.minute);
|
||||||
|
timeReg.setSeconds(time.second);
|
||||||
|
|
||||||
|
constexpr auto TIME_START_OFFSET = offsetof(detail::TimeReg, seconds);
|
||||||
|
constexpr auto TIME_END_OFFSET = offsetof(detail::TimeReg, hours);
|
||||||
|
|
||||||
|
writePartialRegister<TIME_REG_ADDR, TIME_START_OFFSET, TIME_END_OFFSET>(timeReg);
|
||||||
|
}
|
||||||
|
static void setDateTime(const DateTime &dateTime)
|
||||||
|
{
|
||||||
|
detail::TimeReg timeReg;
|
||||||
|
timeReg.setYear(dateTime.year);
|
||||||
|
timeReg.setMonth(dateTime.month);
|
||||||
|
timeReg.setDate(dateTime.day);
|
||||||
|
if constexpr (SetDayOfWeek)
|
||||||
|
timeReg.setDay(calcDayOfWeek(dateTime.year, dateTime.month, dateTime.day) + 1);
|
||||||
|
|
||||||
|
timeReg.setHours(dateTime.hour);
|
||||||
|
timeReg.setMinutes(dateTime.minute);
|
||||||
|
timeReg.setSeconds(dateTime.second);
|
||||||
|
|
||||||
|
constexpr auto START_OFFSET = offsetof(detail::TimeReg, seconds);
|
||||||
|
constexpr auto END_OFFSET = offsetof(detail::TimeReg, year);
|
||||||
|
|
||||||
|
writePartialRegister<TIME_REG_ADDR, START_OFFSET, END_OFFSET>(timeReg);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <uint8_t Address, typename Register>
|
template <uint8_t Address, typename Register>
|
||||||
@@ -125,6 +168,47 @@ class DS3231 {
|
|||||||
static_assert(type::always_false_v<decltype(Address)>, "Invalid register address");
|
static_assert(type::always_false_v<decltype(Address)>, "Invalid register address");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <uint8_t Address, uint8_t StartOffset, uint8_t EndOffset, typename Register>
|
||||||
|
static void writePartialRegister(const Register ®)
|
||||||
|
{
|
||||||
|
static_assert(StartOffset <= EndOffset, "Invalid offset range");
|
||||||
|
static_assert(StartOffset < sizeof(Register), "Start offset out of bounds");
|
||||||
|
static_assert(EndOffset < sizeof(Register), "End offset out of bounds");
|
||||||
|
|
||||||
|
constexpr auto WRITE_SIZE = EndOffset + 1 - StartOffset;
|
||||||
|
static_assert(StartOffset + WRITE_SIZE <= sizeof(Register), "Writing out of bounds");
|
||||||
|
|
||||||
|
if constexpr (Address == TIME_REG_ADDR) {
|
||||||
|
static_assert(type::is_same_v<Register, detail::TimeReg>, "Invalid register type");
|
||||||
|
} else if constexpr (Address == ALARM1_REG_ADDR) {
|
||||||
|
static_assert(type::is_same_v<Register, detail::Alarm1Reg>, "Invalid register type");
|
||||||
|
} else if constexpr (Address == ALARM2_REG_ADDR) {
|
||||||
|
static_assert(type::is_same_v<Register, detail::Alarm2Reg>, "Invalid register type");
|
||||||
|
} else if constexpr (Address == CONTROL_REG_ADDR) {
|
||||||
|
static_assert(type::is_same_v<Register, detail::ControlReg>, "Invalid register type");
|
||||||
|
} else if constexpr (Address == CONTROL_STATUS_REG_ADDR) {
|
||||||
|
static_assert(type::is_same_v<Register, detail::ControlStatusReg>, "Invalid register type");
|
||||||
|
} else if constexpr (Address == AGING_OFFSET_REG_ADDR) {
|
||||||
|
static_assert(type::is_same_v<Register, detail::AgingOffsetReg>, "Invalid register type");
|
||||||
|
} else if constexpr (Address == TEMP_REG_ADDR) {
|
||||||
|
static_assert(type::is_same_v<Register, detail::TempReg>, "Invalid register type");
|
||||||
|
} else {
|
||||||
|
static_assert(type::always_false_v<Register>, "Invalid register address");
|
||||||
|
}
|
||||||
|
|
||||||
|
I2cDriver::template start<I2C_ADDRESS>(false);
|
||||||
|
I2cDriver::write(Address + StartOffset);
|
||||||
|
I2cDriver::template writeBytes<WRITE_SIZE>(reinterpret_cast<const uint8_t *>(®) + StartOffset);
|
||||||
|
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
|
} // namespace rtc
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ struct [[gnu::packed]] FlagsImpl
|
|||||||
{
|
{
|
||||||
static_assert(sizeof(FlagsT) == sizeof(uint8_t), "Must use uint8_t enum class flags");
|
static_assert(sizeof(FlagsT) == sizeof(uint8_t), "Must use uint8_t enum class flags");
|
||||||
|
|
||||||
uint8_t data;
|
uint8_t data = 0;
|
||||||
using Flags = FlagsT;
|
using Flags = FlagsT;
|
||||||
|
|
||||||
FlagsImpl() : data(0) {}
|
FlagsImpl() : data(0) {}
|
||||||
|
|||||||
@@ -100,13 +100,13 @@ static inline void setEncodedDate(uint8_t ®, const uint8_t &value)
|
|||||||
|
|
||||||
struct [[gnu::packed]] TimeReg
|
struct [[gnu::packed]] TimeReg
|
||||||
{
|
{
|
||||||
uint8_t seconds;
|
uint8_t seconds = 0;
|
||||||
uint8_t minutes;
|
uint8_t minutes = 0;
|
||||||
uint8_t hours;
|
uint8_t hours = 0;
|
||||||
uint8_t day;
|
uint8_t day = 1; // Range 1-7 according to datasheet
|
||||||
uint8_t date;
|
uint8_t date = 0;
|
||||||
uint8_t month_century;
|
uint8_t month_century = 0;
|
||||||
uint8_t year;
|
uint8_t year = 0;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -189,10 +189,10 @@ static_assert(sizeof(TimeReg) == 7, "Invalid time register size");
|
|||||||
|
|
||||||
struct [[gnu::packed]] Alarm1Reg
|
struct [[gnu::packed]] Alarm1Reg
|
||||||
{
|
{
|
||||||
uint8_t seconds;
|
uint8_t seconds = 0;
|
||||||
uint8_t minutes;
|
uint8_t minutes = 0;
|
||||||
uint8_t hours;
|
uint8_t hours = 0;
|
||||||
uint8_t day_date;
|
uint8_t day_date = 0;
|
||||||
|
|
||||||
enum class AlarmRate {
|
enum class AlarmRate {
|
||||||
ONCE_PER_S = 0b1111,
|
ONCE_PER_S = 0b1111,
|
||||||
@@ -284,9 +284,9 @@ static_assert(sizeof(Alarm1Reg) == 4, "Invalid alarm1 register size");
|
|||||||
|
|
||||||
struct [[gnu::packed]] Alarm2Reg
|
struct [[gnu::packed]] Alarm2Reg
|
||||||
{
|
{
|
||||||
uint8_t minutes;
|
uint8_t minutes = 0;
|
||||||
uint8_t hours;
|
uint8_t hours = 0;
|
||||||
uint8_t day_date;
|
uint8_t day_date = 0;
|
||||||
|
|
||||||
enum class AlarmRate {
|
enum class AlarmRate {
|
||||||
ONCE_PER_M = 0b111,
|
ONCE_PER_M = 0b111,
|
||||||
@@ -397,7 +397,7 @@ static_assert(sizeof(ControlStatusReg) == 1, "Invalid control/status register si
|
|||||||
|
|
||||||
struct [[gnu::packed]] AgingOffsetReg
|
struct [[gnu::packed]] AgingOffsetReg
|
||||||
{
|
{
|
||||||
uint8_t data;
|
uint8_t data = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(AgingOffsetReg) == 1, "Invalid aging offset register size");
|
static_assert(sizeof(AgingOffsetReg) == 1, "Invalid aging offset register size");
|
||||||
@@ -406,8 +406,8 @@ static_assert(sizeof(AgingOffsetReg) == 1, "Invalid aging offset register size")
|
|||||||
|
|
||||||
struct [[gnu::packed]] TempReg
|
struct [[gnu::packed]] TempReg
|
||||||
{
|
{
|
||||||
uint8_t msb_temp;
|
uint8_t msb_temp = 0;
|
||||||
uint8_t lsb_temp;
|
uint8_t lsb_temp = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(TempReg) == 2, "Invalid temperature register size");
|
static_assert(sizeof(TempReg) == 2, "Invalid temperature register size");
|
||||||
|
|||||||
Reference in New Issue
Block a user