Automatically deduce register address by type

This commit is contained in:
BlackMark 2020-05-17 18:59:19 +02:00
parent db5197b3b1
commit c3f9aa6a13

View File

@ -154,7 +154,7 @@ class DS3231 {
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);
writePartialRegister<DATE_START_OFFSET, DATE_END_OFFSET>(timeReg);
}
static void setTime(const Time &time)
{
@ -166,7 +166,7 @@ class DS3231 {
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);
writePartialRegister<TIME_START_OFFSET, TIME_END_OFFSET>(timeReg);
}
static void setDateTime(const DateTime &dateTime)
{
@ -184,7 +184,7 @@ class DS3231 {
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);
writePartialRegister<START_OFFSET, END_OFFSET>(timeReg);
}
private:
@ -224,9 +224,31 @@ class DS3231 {
}
}
template <uint8_t Address, uint8_t StartOffset, uint8_t EndOffset, typename Register>
template <uint8_t StartOffset, uint8_t EndOffset, typename Register>
static void writePartialRegister(const Register &reg)
{
constexpr auto getRegisterAddress = []() {
if constexpr (util::is_same_v<Register, detail::TimeReg>) {
return TIME_REG_ADDR;
} else if constexpr (util::is_same_v<Register, detail::Alarm1Reg>) {
return ALARM1_REG_ADDR;
} else if constexpr (util::is_same_v<Register, detail::Alarm2Reg>) {
return ALARM2_REG_ADDR;
} else if constexpr (util::is_same_v<Register, detail::ControlReg>) {
return CONTROL_REG_ADDR;
} else if constexpr (util::is_same_v<Register, detail::ControlStatusReg>) {
return CONTROL_STATUS_REG_ADDR;
} else if constexpr (util::is_same_v<Register, detail::AgingOffsetReg>) {
return AGING_OFFSET_REG_ADDR;
} else if constexpr (util::is_same_v<Register, detail::TempReg>) {
return TEMP_REG_ADDR;
} else {
static_assert(util::always_false_v<Register>, "Invalid register type");
}
};
constexpr auto ADDRESS = getRegisterAddress();
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");
@ -234,26 +256,8 @@ class DS3231 {
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(util::is_same_v<Register, detail::TimeReg>, "Invalid register type");
} else if constexpr (Address == ALARM1_REG_ADDR) {
static_assert(util::is_same_v<Register, detail::Alarm1Reg>, "Invalid register type");
} else if constexpr (Address == ALARM2_REG_ADDR) {
static_assert(util::is_same_v<Register, detail::Alarm2Reg>, "Invalid register type");
} else if constexpr (Address == CONTROL_REG_ADDR) {
static_assert(util::is_same_v<Register, detail::ControlReg>, "Invalid register type");
} else if constexpr (Address == CONTROL_STATUS_REG_ADDR) {
static_assert(util::is_same_v<Register, detail::ControlStatusReg>, "Invalid register type");
} else if constexpr (Address == AGING_OFFSET_REG_ADDR) {
static_assert(util::is_same_v<Register, detail::AgingOffsetReg>, "Invalid register type");
} else if constexpr (Address == TEMP_REG_ADDR) {
static_assert(util::is_same_v<Register, detail::TempReg>, "Invalid register type");
} else {
static_assert(util::always_false_v<Register>, "Invalid register address");
}
i2c_t::template start<I2C_ADDRESS>(false);
i2c_t::write(Address + StartOffset);
i2c_t::write(ADDRESS + StartOffset);
i2c_t::template writeBytes<WRITE_SIZE>(reinterpret_cast<const uint8_t *>(&reg) + StartOffset);
i2c_t::stop();
}