Add functions to get/set the year

pull/4/head
Diego Barrios Romero 2018-10-28 17:28:55 +01:00
parent 2cf7855293
commit ccca20aa4a
5 changed files with 156 additions and 40 deletions

View File

@ -12,6 +12,7 @@ This driver allows you to:
- Read/write the weekday. - Read/write the weekday.
- Read/write the day. - Read/write the day.
- Read/write the month. - Read/write the month.
- Read/write the year.
## The devices ## The devices

View File

@ -2,7 +2,7 @@
extern crate embedded_hal as hal; extern crate embedded_hal as hal;
use super::super::{ Ds323x, Register, BitFlags, Error }; 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 /// Hours in either 12-hour (AM/PM) or 24-hour format
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -17,7 +17,7 @@ pub enum Hours {
impl<DI, IC, E> Ds323x<DI, IC> impl<DI, IC, E> Ds323x<DI, IC>
where where
DI: ReadRegister<Error = E> + WriteRegister<Error = E> DI: ReadData<Error = E> + WriteData<Error = E>
{ {
/// Read the seconds. /// Read the seconds.
pub fn get_seconds(&mut self) -> Result<u8, Error<E>> { pub fn get_seconds(&mut self) -> Result<u8, Error<E>> {
@ -64,6 +64,20 @@ where
Ok(packed_bcd_to_decimal(value)) 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>> { fn read_register_decimal(&mut self, register: u8) -> Result<u8, Error<E>> {
let data = self.iface.read_register(register)?; let data = self.iface.read_register(register)?;
Ok(packed_bcd_to_decimal(data)) Ok(packed_bcd_to_decimal(data))
@ -143,6 +157,26 @@ where
self.iface.write_register(Register::MONTH, value) 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>> { 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)) self.iface.write_register(register, decimal_to_packed_bcd(decimal_number))
} }

View File

@ -19,15 +19,17 @@ pub struct SpiInterface<SPI, CS> {
pub(crate) cs: CS pub(crate) cs: CS
} }
/// Write to a register /// Write data
pub trait WriteRegister { pub trait WriteData {
/// Error type /// Error type
type Error; type Error;
/// Write to an u8 register /// Write to an u8 register
fn write_register(&mut self, register: u8, data: u8) -> Result<(), Error<Self::Error>>; 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 where
I2C: blocking::i2c::Write<Error = E> I2C: blocking::i2c::Write<Error = E>
{ {
@ -38,9 +40,16 @@ where
.write(DEVICE_ADDRESS, &payload) .write(DEVICE_ADDRESS, &payload)
.map_err(Error::Comm) .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 where
SPI: blocking::spi::Write<u8, Error = E>, SPI: blocking::spi::Write<u8, Error = E>,
CS: hal::digital::OutputPin CS: hal::digital::OutputPin
@ -57,18 +66,32 @@ where
self.cs.set_high(); self.cs.set_high();
result 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 /// Read data
pub trait ReadRegister { pub trait ReadData {
/// Error type /// Error type
type Error; type Error;
/// Read an u8 register /// Read an u8 register
fn read_register(&mut self, register: u8) -> Result<u8, Error<Self::Error>>; 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 where
I2C: blocking::i2c::WriteRead<Error = E> I2C: blocking::i2c::WriteRead<Error = E>
{ {
@ -80,9 +103,15 @@ where
.map_err(Error::Comm) .map_err(Error::Comm)
.and(Ok(data[0])) .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 where
SPI: blocking::spi::Transfer<u8, Error = E>, SPI: blocking::spi::Transfer<u8, Error = E>,
CS: hal::digital::OutputPin CS: hal::digital::OutputPin
@ -91,13 +120,29 @@ where
fn read_register(&mut self, register: u8) -> Result<u8, Error<E>> { fn read_register(&mut self, register: u8) -> Result<u8, Error<E>> {
self.cs.set_low(); self.cs.set_low();
let mut data = [register, 0]; let mut data = [register, 0];
{
let result = self.spi let result = self.spi
.transfer(&mut data) .transfer(&mut data)
.map_err(Error::Comm); .map_err(Error::Comm);
self.cs.set_high(); self.cs.set_high();
result?; 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)
} }
Ok(data[1])
} }
} }

View File

@ -10,6 +10,7 @@
//! - Read/write the weekday. //! - Read/write the weekday.
//! - Read/write the day. //! - Read/write the day.
//! - Read/write the month. //! - Read/write the month.
//! - Read/write the year.
//! //!
//! ## The devices //! ## The devices
//! //!

View File

@ -9,43 +9,63 @@ use common::{ DEVICE_ADDRESS as DEV_ADDR, Register, new_ds3231,
extern crate ds323x; extern crate ds323x;
use ds323x::{ Hours, Error }; 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 { macro_rules! get_param_test {
($method:ident, $register:ident, $value:expr, $binary_value:expr) => { ($method:ident, $register:ident, $value:expr, $binary_value:expr) => {
get_test!(can_get_ds3231, $method, new_ds3231, $value, _get_param_test!($method, $value,
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_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,
[ SpiTrans::transfer(vec![Register::$register, 0], vec![Register::$register, $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 { macro_rules! set_param_test {
($method:ident, $register:ident, $value:expr, $binary_value:expr) => { ($method:ident, $register:ident, $value:expr, $binary_value:expr) => {
set_test!(can_set_ds3231, $method, new_ds3231, $value, _set_param_test!($method, $value,
[ I2cTrans::write(DEV_ADDR, vec![Register::$register, $binary_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,
[ SpiTrans::write(vec![Register::$register + 0x80, $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 { macro_rules! read_set_param_test {
($method:ident, $register:ident, $value:expr, $binary_value_read:expr, $binary_value_write:expr) => { ($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_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::transfer(vec![Register::$register, 0], vec![Register::$register, $binary_value_read]),
SpiTrans::write(vec![Register::$register + 0x80, $binary_value_write]) ]); 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); 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);
}