mirror of https://github.com/eldruin/ds323x-rs
Add functions to get/set the year
parent
2cf7855293
commit
ccca20aa4a
|
@ -12,6 +12,7 @@ This driver allows you to:
|
|||
- Read/write the weekday.
|
||||
- Read/write the day.
|
||||
- Read/write the month.
|
||||
- Read/write the year.
|
||||
|
||||
## The devices
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
extern crate embedded_hal as hal;
|
||||
use super::super::{ Ds323x, Register, BitFlags, Error };
|
||||
use interface::{ ReadRegister, WriteRegister };
|
||||
use interface::{ ReadData, WriteData };
|
||||
|
||||
/// Hours in either 12-hour (AM/PM) or 24-hour format
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -17,7 +17,7 @@ pub enum Hours {
|
|||
|
||||
impl<DI, IC, E> Ds323x<DI, IC>
|
||||
where
|
||||
DI: ReadRegister<Error = E> + WriteRegister<Error = E>
|
||||
DI: ReadData<Error = E> + WriteData<Error = E>
|
||||
{
|
||||
/// Read the seconds.
|
||||
pub fn get_seconds(&mut self) -> Result<u8, Error<E>> {
|
||||
|
@ -64,6 +64,20 @@ where
|
|||
Ok(packed_bcd_to_decimal(value))
|
||||
}
|
||||
|
||||
/// Read the year [2000-2100].
|
||||
pub fn get_year(&mut self) -> Result<u16, Error<E>> {
|
||||
let mut data = [0; 2];
|
||||
self.iface.read_two_registers(Register::MONTH, &mut data)?;
|
||||
let century = data[0] & BitFlags::CENTURY;
|
||||
let year = packed_bcd_to_decimal(data[1]);
|
||||
if century != 0 {
|
||||
Ok(2100 + (year as u16))
|
||||
}
|
||||
else {
|
||||
Ok(2000 + (year as u16))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_register_decimal(&mut self, register: u8) -> Result<u8, Error<E>> {
|
||||
let data = self.iface.read_register(register)?;
|
||||
Ok(packed_bcd_to_decimal(data))
|
||||
|
@ -143,6 +157,26 @@ where
|
|||
self.iface.write_register(Register::MONTH, value)
|
||||
}
|
||||
|
||||
/// Set the year [2000-2100].
|
||||
///
|
||||
/// Will return an `Error::InvalidInputData` if the year is out of range.
|
||||
pub fn set_year(&mut self, year: u16) -> Result<(), Error<E>> {
|
||||
if year < 2000 || year > 2100 {
|
||||
return Err(Error::InvalidInputData);
|
||||
}
|
||||
let data = self.iface.read_register(Register::MONTH)?;
|
||||
let month_bcd = data & !BitFlags::CENTURY;
|
||||
if year > 2099 {
|
||||
let data = [ BitFlags::CENTURY | month_bcd,
|
||||
decimal_to_packed_bcd((year - 2100) as u8) ];
|
||||
self.iface.write_two_registers(Register::MONTH, &data)
|
||||
}
|
||||
else {
|
||||
let data = [ month_bcd, decimal_to_packed_bcd((year - 2000) as u8) ];
|
||||
self.iface.write_two_registers(Register::MONTH, &data)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_register_decimal(&mut self, register: u8, decimal_number: u8) -> Result<(), Error<E>> {
|
||||
self.iface.write_register(register, decimal_to_packed_bcd(decimal_number))
|
||||
}
|
||||
|
|
|
@ -19,15 +19,17 @@ pub struct SpiInterface<SPI, CS> {
|
|||
pub(crate) cs: CS
|
||||
}
|
||||
|
||||
/// Write to a register
|
||||
pub trait WriteRegister {
|
||||
/// Write data
|
||||
pub trait WriteData {
|
||||
/// Error type
|
||||
type Error;
|
||||
/// Write to an u8 register
|
||||
fn write_register(&mut self, register: u8, data: u8) -> Result<(), Error<Self::Error>>;
|
||||
/// Write to two consecutive u8 registers
|
||||
fn write_two_registers(&mut self, first_register: u8, data: &[u8; 2]) -> Result<(), Error<Self::Error>>;
|
||||
}
|
||||
|
||||
impl<I2C, E> WriteRegister for I2cInterface<I2C>
|
||||
impl<I2C, E> WriteData for I2cInterface<I2C>
|
||||
where
|
||||
I2C: blocking::i2c::Write<Error = E>
|
||||
{
|
||||
|
@ -38,9 +40,16 @@ where
|
|||
.write(DEVICE_ADDRESS, &payload)
|
||||
.map_err(Error::Comm)
|
||||
}
|
||||
|
||||
fn write_two_registers(&mut self, first_register: u8, data: &[u8; 2]) -> Result<(), Error<Self::Error>> {
|
||||
let payload: [u8; 3] = [first_register, data[0], data[1]];
|
||||
self.i2c
|
||||
.write(DEVICE_ADDRESS, &payload)
|
||||
.map_err(Error::Comm)
|
||||
}
|
||||
}
|
||||
|
||||
impl<SPI, CS, E> WriteRegister for SpiInterface<SPI, CS>
|
||||
impl<SPI, CS, E> WriteData for SpiInterface<SPI, CS>
|
||||
where
|
||||
SPI: blocking::spi::Write<u8, Error = E>,
|
||||
CS: hal::digital::OutputPin
|
||||
|
@ -57,18 +66,32 @@ where
|
|||
self.cs.set_high();
|
||||
result
|
||||
}
|
||||
|
||||
fn write_two_registers(&mut self, first_register: u8, data: &[u8; 2]) -> Result<(), Error<E>> {
|
||||
self.cs.set_low();
|
||||
|
||||
let payload: [u8; 3] = [first_register + 0x80, data[0], data[1]];
|
||||
let result = self.spi
|
||||
.write(&payload)
|
||||
.map_err(Error::Comm);
|
||||
|
||||
self.cs.set_high();
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Read a register
|
||||
pub trait ReadRegister {
|
||||
/// Read data
|
||||
pub trait ReadData {
|
||||
/// Error type
|
||||
type Error;
|
||||
/// Read an u8 register
|
||||
fn read_register(&mut self, register: u8) -> Result<u8, Error<Self::Error>>;
|
||||
/// Read two u8 registers
|
||||
fn read_two_registers(&mut self, register: u8, data: &mut [u8; 2]) -> Result<(), Error<Self::Error>>;
|
||||
}
|
||||
|
||||
impl<I2C, E> ReadRegister for I2cInterface<I2C>
|
||||
impl<I2C, E> ReadData for I2cInterface<I2C>
|
||||
where
|
||||
I2C: blocking::i2c::WriteRead<Error = E>
|
||||
{
|
||||
|
@ -80,9 +103,15 @@ where
|
|||
.map_err(Error::Comm)
|
||||
.and(Ok(data[0]))
|
||||
}
|
||||
|
||||
fn read_two_registers(&mut self, register: u8, data: &mut [u8; 2]) -> Result<(), Error<Self::Error>> {
|
||||
self.i2c
|
||||
.write_read(DEVICE_ADDRESS, &[register], &mut data[..])
|
||||
.map_err(Error::Comm)
|
||||
}
|
||||
}
|
||||
|
||||
impl<SPI, CS, E> ReadRegister for SpiInterface<SPI, CS>
|
||||
impl<SPI, CS, E> ReadData for SpiInterface<SPI, CS>
|
||||
where
|
||||
SPI: blocking::spi::Transfer<u8, Error = E>,
|
||||
CS: hal::digital::OutputPin
|
||||
|
@ -91,13 +120,29 @@ where
|
|||
fn read_register(&mut self, register: u8) -> Result<u8, Error<E>> {
|
||||
self.cs.set_low();
|
||||
let mut data = [register, 0];
|
||||
{
|
||||
let result = self.spi
|
||||
.transfer(&mut data)
|
||||
.map_err(Error::Comm);
|
||||
self.cs.set_high();
|
||||
result?;
|
||||
}
|
||||
Ok(data[1])
|
||||
match result {
|
||||
Ok(result) => Ok(result[1]),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_two_registers(&mut self, register: u8, data: &mut [u8; 2]) -> Result<(), Error<Self::Error>> {
|
||||
self.cs.set_low();
|
||||
let mut payload = [register, 0, 0];
|
||||
let result = self.spi
|
||||
.transfer(&mut payload)
|
||||
.map_err(Error::Comm);
|
||||
self.cs.set_high();
|
||||
match result {
|
||||
Ok(result) => { data[0] = result[1];
|
||||
data[1] = result[2];
|
||||
Ok(())
|
||||
},
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//! - Read/write the weekday.
|
||||
//! - Read/write the day.
|
||||
//! - Read/write the month.
|
||||
//! - Read/write the year.
|
||||
//!
|
||||
//! ## The devices
|
||||
//!
|
||||
|
|
|
@ -9,43 +9,63 @@ use common::{ DEVICE_ADDRESS as DEV_ADDR, Register, new_ds3231,
|
|||
extern crate ds323x;
|
||||
use ds323x::{ Hours, Error };
|
||||
|
||||
macro_rules! _get_param_test {
|
||||
($method:ident, $value:expr, $i2c_transactions:expr, $spi_transactions:expr) => {
|
||||
get_test!(can_get_ds3231, $method, new_ds3231, $value, $i2c_transactions);
|
||||
get_test!(can_get_ds3232, $method, new_ds3232, $value, $i2c_transactions);
|
||||
get_test!(can_get_ds3234, $method, new_ds3234, $value, $spi_transactions);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! get_param_test {
|
||||
($method:ident, $register:ident, $value:expr, $binary_value:expr) => {
|
||||
get_test!(can_get_ds3231, $method, new_ds3231, $value,
|
||||
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_value]) ]);
|
||||
|
||||
get_test!(can_get_ds3232, $method, new_ds3232, $value,
|
||||
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_value]) ]);
|
||||
|
||||
get_test!(can_get_ds3234, $method, new_ds3234, $value,
|
||||
_get_param_test!($method, $value,
|
||||
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_value]) ],
|
||||
[ SpiTrans::transfer(vec![Register::$register, 0], vec![Register::$register, $binary_value]) ]);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! get_param_read_two_test {
|
||||
($method:ident, $value:expr, $register1:ident, $bin1:expr, $bin2:expr) => {
|
||||
_get_param_test!($method, $value,
|
||||
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register1], vec![$bin1, $bin2]) ],
|
||||
[ SpiTrans::transfer(vec![Register::$register1, 0, 0], vec![Register::$register1, $bin1, $bin2]) ]);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! _set_param_test {
|
||||
($method:ident, $value:expr, $i2c_transactions:expr, $spi_transactions:expr) => {
|
||||
set_test!(can_set_ds3231, $method, new_ds3231, $value, $i2c_transactions);
|
||||
set_test!(can_set_ds3232, $method, new_ds3232, $value, $i2c_transactions);
|
||||
set_test!(can_set_ds3234, $method, new_ds3234, $value, $spi_transactions);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! set_param_test {
|
||||
($method:ident, $register:ident, $value:expr, $binary_value:expr) => {
|
||||
set_test!(can_set_ds3231, $method, new_ds3231, $value,
|
||||
[ I2cTrans::write(DEV_ADDR, vec![Register::$register, $binary_value]) ]);
|
||||
|
||||
set_test!(can_set_ds3232, $method, new_ds3232, $value,
|
||||
[ I2cTrans::write(DEV_ADDR, vec![Register::$register, $binary_value]) ]);
|
||||
|
||||
set_test!(can_set_ds3234, $method, new_ds3234, $value,
|
||||
_set_param_test!($method, $value,
|
||||
[ I2cTrans::write(DEV_ADDR, vec![Register::$register, $binary_value]) ],
|
||||
[ SpiTrans::write(vec![Register::$register + 0x80, $binary_value]) ]);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_set_param_write_two_test {
|
||||
($method:ident, $value:expr, $register:ident, $binary_value1_read:expr, $bin1:expr, $bin2:expr) => {
|
||||
_set_param_test!($method, $value,
|
||||
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_value1_read]),
|
||||
I2cTrans::write(DEV_ADDR, vec![Register::$register, $bin1, $bin2]) ],
|
||||
|
||||
[ SpiTrans::transfer(vec![Register::$register, 0], vec![Register::$register, $binary_value1_read]),
|
||||
SpiTrans::write(vec![Register::$register + 0x80, $bin1, $bin2]) ]);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_set_param_test {
|
||||
($method:ident, $register:ident, $value:expr, $binary_value_read:expr, $binary_value_write:expr) => {
|
||||
set_test!(can_read_set_ds3231, $method, new_ds3231, $value,
|
||||
_set_param_test!($method, $value,
|
||||
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_value_read]),
|
||||
I2cTrans::write(DEV_ADDR, vec![Register::$register, $binary_value_write]) ]);
|
||||
I2cTrans::write(DEV_ADDR, vec![Register::$register, $binary_value_write]) ],
|
||||
|
||||
set_test!(can_read_set_ds3232, $method, new_ds3232, $value,
|
||||
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_value_read]),
|
||||
I2cTrans::write(DEV_ADDR, vec![Register::$register, $binary_value_write]) ]);
|
||||
|
||||
set_test!(can_read_set_ds3234, $method, new_ds3234, $value,
|
||||
[ SpiTrans::transfer(vec![Register::$register, 0], vec![Register::$register, $binary_value_read]),
|
||||
SpiTrans::write(vec![Register::$register + 0x80, $binary_value_write]) ]);
|
||||
};
|
||||
|
@ -134,3 +154,18 @@ mod month {
|
|||
read_set_param_test!(set_month, MONTH, 12, 0b1000_0010, 0b1001_0010);
|
||||
}
|
||||
}
|
||||
|
||||
mod year {
|
||||
use super::*;
|
||||
mod century0 {
|
||||
use super::*;
|
||||
get_param_read_two_test!(get_year, 2099, MONTH, 0, 0b1001_1001);
|
||||
read_set_param_write_two_test!(set_year, 2099, MONTH, 0b1001_0010, 0b0001_0010, 0b1001_1001);
|
||||
}
|
||||
mod century1 {
|
||||
use super::*;
|
||||
get_param_read_two_test!(get_year, 2100, MONTH, 0b1000_0000, 0);
|
||||
read_set_param_write_two_test!(set_year, 2100, MONTH, 0b0001_0010, 0b1001_0010, 0);
|
||||
}
|
||||
set_invalid_param_test!(set_year, 2101);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue