use embedded_hal::i2c::I2c;
use crate::{error::Error, registers::Register};
pub const I2C_ADDR: u8 = 0x68;
pub const DEFAULT_BASE_CENTURY: u8 = 20;
pub struct Ds3231<I2C> {
i2c: I2C,
pub(crate) base_century: u8,
}
impl<I2C: embedded_hal::i2c::I2c> rtc_hal::error::ErrorType for Ds3231<I2C> {
type Error = crate::error::Error<I2C::Error>;
}
impl<I2C, E> Ds3231<I2C>
where
I2C: I2c<Error = E>,
E: core::fmt::Debug,
{
pub fn new(i2c: I2C) -> Self {
Self {
i2c,
base_century: DEFAULT_BASE_CENTURY,
}
}
pub fn set_base_century(&mut self, base_century: u8) -> Result<(), Error<E>> {
if base_century < 19 {
return Err(Error::InvalidBaseCentury);
}
self.base_century = base_century;
Ok(())
}
pub fn release_i2c(self) -> I2C {
self.i2c
}
pub(crate) fn write_register(&mut self, register: Register, value: u8) -> Result<(), Error<E>> {
self.i2c.write(I2C_ADDR, &[register.addr(), value])?;
Ok(())
}
pub(crate) fn read_register(&mut self, register: Register) -> Result<u8, Error<E>> {
let mut data = [0u8; 1];
self.i2c
.write_read(I2C_ADDR, &[register.addr()], &mut data)
.map_err(Error::I2c)?;
Ok(data[0])
}
pub(crate) fn read_register_bytes(
&mut self,
register: Register,
buffer: &mut [u8],
) -> Result<(), Error<E>> {
self.i2c.write_read(I2C_ADDR, &[register.addr()], buffer)?;
Ok(())
}
pub(crate) fn write_raw_bytes(&mut self, data: &[u8]) -> Result<(), Error<E>> {
self.i2c.write(I2C_ADDR, data).map_err(Error::I2c)
}
pub(crate) fn set_register_bits(
&mut self,
register: Register,
mask: u8,
) -> Result<(), Error<E>> {
let current = self.read_register(register)?;
let new_value = current | mask;
if new_value != current {
self.write_register(register, new_value)
} else {
Ok(())
}
}
pub(crate) fn clear_register_bits(
&mut self,
register: Register,
mask: u8,
) -> Result<(), Error<E>> {
let current = self.read_register(register)?;
let new_value = current & !mask;
if new_value != current {
self.write_register(register, new_value)
} else {
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::Error;
use crate::registers::Register;
use embedded_hal_mock::eh1::i2c::{Mock as I2cMock, Transaction as I2cTransaction};
const DS3231_ADDR: u8 = 0x68;
#[test]
fn test_new() {
let i2c_mock = I2cMock::new(&[]);
let ds3231 = Ds3231::new(i2c_mock);
assert_eq!(ds3231.base_century, DEFAULT_BASE_CENTURY);
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_set_base_century_valid() {
let i2c_mock = I2cMock::new(&[]);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.set_base_century(21);
assert!(result.is_ok());
assert_eq!(ds3231.base_century, 21);
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_set_base_century_minimum_valid() {
let i2c_mock = I2cMock::new(&[]);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.set_base_century(19);
assert!(result.is_ok());
assert_eq!(ds3231.base_century, 19);
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_set_base_century_invalid() {
let i2c_mock = I2cMock::new(&[]);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.set_base_century(18);
assert!(matches!(result, Err(Error::InvalidBaseCentury)));
assert_eq!(ds3231.base_century, DEFAULT_BASE_CENTURY);
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_write_register() {
let expectations = vec![I2cTransaction::write(
DS3231_ADDR,
vec![Register::Control.addr(), 0x42],
)];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.write_register(Register::Control, 0x42);
assert!(result.is_ok());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_write_register_error() {
let expectations = vec![
I2cTransaction::write(DS3231_ADDR, vec![Register::Control.addr(), 0x42])
.with_error(embedded_hal::i2c::ErrorKind::Other),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.write_register(Register::Control, 0x42);
assert!(result.is_err());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_read_register() {
let expectations = vec![I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Control.addr()],
vec![0x55],
)];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.read_register(Register::Control);
assert_eq!(result.unwrap(), 0x55);
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_read_register_error() {
let expectations = vec![
I2cTransaction::write_read(DS3231_ADDR, vec![Register::Control.addr()], vec![0x00])
.with_error(embedded_hal::i2c::ErrorKind::Other),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.read_register(Register::Control);
assert!(result.is_err());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_read_register_bytes() {
let expectations = vec![I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Seconds.addr()],
vec![0x11, 0x22, 0x33],
)];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let mut buffer = [0u8; 3];
let result = ds3231.read_register_bytes(Register::Seconds, &mut buffer);
assert!(result.is_ok());
assert_eq!(buffer, [0x11, 0x22, 0x33]);
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_read_register_bytes_error() {
let expectations = vec![
I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Seconds.addr()],
vec![0x00, 0x00],
)
.with_error(embedded_hal::i2c::ErrorKind::Other),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let mut buffer = [0u8; 2];
let result = ds3231.read_register_bytes(Register::Seconds, &mut buffer);
assert!(result.is_err());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_write_raw_bytes() {
let expectations = vec![I2cTransaction::write(DS3231_ADDR, vec![0x0E, 0x1C, 0x00])];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.write_raw_bytes(&[0x0E, 0x1C, 0x00]);
assert!(result.is_ok());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_write_raw_bytes_error() {
let expectations = vec![
I2cTransaction::write(DS3231_ADDR, vec![0x0E, 0x1C])
.with_error(embedded_hal::i2c::ErrorKind::Other),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.write_raw_bytes(&[0x0E, 0x1C]);
assert!(result.is_err());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_set_register_bits_change_needed() {
let expectations = vec![
I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Control.addr()],
vec![0b0000_1000],
),
I2cTransaction::write(DS3231_ADDR, vec![Register::Control.addr(), 0b0001_1000]),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.set_register_bits(Register::Control, 0b0001_0000);
assert!(result.is_ok());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_set_register_bits_no_change_needed() {
let expectations = vec![I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Control.addr()],
vec![0b0001_1000],
)];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.set_register_bits(Register::Control, 0b0001_0000);
assert!(result.is_ok());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_set_register_bits_multiple_bits() {
let expectations = vec![
I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Control.addr()],
vec![0b0000_0000],
),
I2cTransaction::write(DS3231_ADDR, vec![Register::Control.addr(), 0b1010_0101]),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.set_register_bits(Register::Control, 0b1010_0101);
assert!(result.is_ok());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_set_register_bits_read_error() {
let expectations = vec![
I2cTransaction::write_read(DS3231_ADDR, vec![Register::Control.addr()], vec![0x00])
.with_error(embedded_hal::i2c::ErrorKind::Other),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.set_register_bits(Register::Control, 0b0001_0000);
assert!(result.is_err());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_set_register_bits_write_error() {
let expectations = vec![
I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Control.addr()],
vec![0b0000_0000],
),
I2cTransaction::write(DS3231_ADDR, vec![Register::Control.addr(), 0b0001_0000])
.with_error(embedded_hal::i2c::ErrorKind::Other),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.set_register_bits(Register::Control, 0b0001_0000);
assert!(result.is_err());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_clear_register_bits_change_needed() {
let expectations = vec![
I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Control.addr()],
vec![0b1111_1111],
),
I2cTransaction::write(DS3231_ADDR, vec![Register::Control.addr(), 0b1110_1111]),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.clear_register_bits(Register::Control, 0b0001_0000);
assert!(result.is_ok());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_clear_register_bits_no_change_needed() {
let expectations = vec![I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Control.addr()],
vec![0b1110_1111],
)];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.clear_register_bits(Register::Control, 0b0001_0000);
assert!(result.is_ok());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_clear_register_bits_multiple_bits() {
let expectations = vec![
I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Control.addr()],
vec![0b1111_1111],
),
I2cTransaction::write(DS3231_ADDR, vec![Register::Control.addr(), 0b0101_1010]),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.clear_register_bits(Register::Control, 0b1010_0101);
assert!(result.is_ok());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_clear_register_bits_read_error() {
let expectations = vec![
I2cTransaction::write_read(DS3231_ADDR, vec![Register::Control.addr()], vec![0x00])
.with_error(embedded_hal::i2c::ErrorKind::Other),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.clear_register_bits(Register::Control, 0b0001_0000);
assert!(result.is_err());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_clear_register_bits_write_error() {
let expectations = vec![
I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Control.addr()],
vec![0b1111_1111],
),
I2cTransaction::write(DS3231_ADDR, vec![Register::Control.addr(), 0b1110_1111])
.with_error(embedded_hal::i2c::ErrorKind::Other),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.clear_register_bits(Register::Control, 0b0001_0000);
assert!(result.is_err());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_constants() {
assert_eq!(I2C_ADDR, 0x68);
assert_eq!(DEFAULT_BASE_CENTURY, 20);
}
#[test]
fn test_set_register_bits_preserves_other_bits() {
let expectations = vec![
I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Control.addr()],
vec![0b1000_0010],
),
I2cTransaction::write(DS3231_ADDR, vec![Register::Control.addr(), 0b1001_0010]),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.set_register_bits(Register::Control, 0b0001_0000);
assert!(result.is_ok());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
#[test]
fn test_clear_register_bits_preserves_other_bits() {
let expectations = vec![
I2cTransaction::write_read(
DS3231_ADDR,
vec![Register::Control.addr()],
vec![0b1001_0010],
),
I2cTransaction::write(DS3231_ADDR, vec![Register::Control.addr(), 0b1000_0010]),
];
let i2c_mock = I2cMock::new(&expectations);
let mut ds3231 = Ds3231::new(i2c_mock);
let result = ds3231.clear_register_bits(Register::Control, 0b0001_0000);
assert!(result.is_ok());
let mut i2c_mock = ds3231.release_i2c();
i2c_mock.done();
}
}