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 day.
- Read/write the month.
- Read/write the year.
## The devices

View File

@ -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))
}

View File

@ -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?;
let result = self.spi
.transfer(&mut data)
.map_err(Error::Comm);
self.cs.set_high();
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 day.
//! - Read/write the month.
//! - Read/write the year.
//!
//! ## The devices
//!

View File

@ -9,45 +9,65 @@ 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_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]) ]);
};
}
get_test!(can_get_ds3232, $method, new_ds3232, $value,
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$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]) ]);
};
}
get_test!(can_get_ds3234, $method, new_ds3234, $value,
[ SpiTrans::transfer(vec![Register::$register, 0], vec![Register::$register, $binary_value]) ]);
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_param_test!($method, $value,
[ I2cTrans::write(DEV_ADDR, vec![Register::$register, $binary_value]) ],
[ SpiTrans::write(vec![Register::$register + 0x80, $binary_value]) ]);
};
}
set_test!(can_set_ds3232, $method, new_ds3232, $value,
[ I2cTrans::write(DEV_ADDR, vec![Register::$register, $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]) ],
set_test!(can_set_ds3234, $method, new_ds3234, $value,
[ SpiTrans::write(vec![Register::$register + 0x80, $binary_value]) ]);
[ 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,
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_value_read]),
I2cTrans::write(DEV_ADDR, vec![Register::$register, $binary_value_write]) ]);
_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]) ],
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]) ]);
[ 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);
}