From ccca20aa4aabcd9d8df95a9992149412778a2bbf Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Sun, 28 Oct 2018 17:28:55 +0100 Subject: [PATCH] Add functions to get/set the year --- README.md | 1 + src/ds323x/datetime.rs | 38 ++++++++++++++++++-- src/interface.rs | 77 +++++++++++++++++++++++++++++++--------- src/lib.rs | 1 + tests/ds323x.rs | 79 ++++++++++++++++++++++++++++++------------ 5 files changed, 156 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 08b4433..84ff483 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/src/ds323x/datetime.rs b/src/ds323x/datetime.rs index 9d1fbd7..71d8a1e 100644 --- a/src/ds323x/datetime.rs +++ b/src/ds323x/datetime.rs @@ -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 Ds323x where - DI: ReadRegister + WriteRegister + DI: ReadData + WriteData { /// Read the seconds. pub fn get_seconds(&mut self) -> Result> { @@ -64,6 +64,20 @@ where Ok(packed_bcd_to_decimal(value)) } + /// Read the year [2000-2100]. + pub fn get_year(&mut self) -> Result> { + 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> { 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> { + 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> { self.iface.write_register(register, decimal_to_packed_bcd(decimal_number)) } diff --git a/src/interface.rs b/src/interface.rs index 97497ff..9d5ccb5 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -19,15 +19,17 @@ pub struct SpiInterface { 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>; + /// Write to two consecutive u8 registers + fn write_two_registers(&mut self, first_register: u8, data: &[u8; 2]) -> Result<(), Error>; } -impl WriteRegister for I2cInterface +impl WriteData for I2cInterface where I2C: blocking::i2c::Write { @@ -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> { + let payload: [u8; 3] = [first_register, data[0], data[1]]; + self.i2c + .write(DEVICE_ADDRESS, &payload) + .map_err(Error::Comm) + } } -impl WriteRegister for SpiInterface +impl WriteData for SpiInterface where SPI: blocking::spi::Write, CS: hal::digital::OutputPin @@ -53,22 +62,36 @@ where let result = self.spi .write(&payload) .map_err(Error::Comm); - + + self.cs.set_high(); + result + } + + fn write_two_registers(&mut self, first_register: u8, data: &[u8; 2]) -> Result<(), Error> { + 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>; + /// Read two u8 registers + fn read_two_registers(&mut self, register: u8, data: &mut [u8; 2]) -> Result<(), Error>; } -impl ReadRegister for I2cInterface +impl ReadData for I2cInterface where I2C: blocking::i2c::WriteRead { @@ -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.i2c + .write_read(DEVICE_ADDRESS, &[register], &mut data[..]) + .map_err(Error::Comm) + } } -impl ReadRegister for SpiInterface +impl ReadData for SpiInterface where SPI: blocking::spi::Transfer, CS: hal::digital::OutputPin @@ -91,13 +120,29 @@ where fn read_register(&mut self, register: u8) -> Result> { 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.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]) } } diff --git a/src/lib.rs b/src/lib.rs index 768a3d5..d014de0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ //! - Read/write the weekday. //! - Read/write the day. //! - Read/write the month. +//! - Read/write the year. //! //! ## The devices //! diff --git a/tests/ds323x.rs b/tests/ds323x.rs index 7a67c33..619ec49 100644 --- a/tests/ds323x.rs +++ b/tests/ds323x.rs @@ -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); +}