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 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
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
match result {
|
||||||
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])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
//!
|
//!
|
||||||
|
|
|
@ -9,45 +9,65 @@ 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]) ],
|
||||||
|
[ SpiTrans::transfer(vec![Register::$register, 0], vec![Register::$register, $binary_value]) ]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
get_test!(can_get_ds3232, $method, new_ds3232, $value,
|
macro_rules! get_param_read_two_test {
|
||||||
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_value]) ]);
|
($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,
|
macro_rules! _set_param_test {
|
||||||
[ SpiTrans::transfer(vec![Register::$register, 0], vec![Register::$register, $binary_value]) ]);
|
($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]) ],
|
||||||
|
[ SpiTrans::write(vec![Register::$register + 0x80, $binary_value]) ]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
set_test!(can_set_ds3232, $method, new_ds3232, $value,
|
macro_rules! read_set_param_write_two_test {
|
||||||
[ I2cTrans::write(DEV_ADDR, vec![Register::$register, $binary_value]) ]);
|
($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::transfer(vec![Register::$register, 0], vec![Register::$register, $binary_value1_read]),
|
||||||
[ SpiTrans::write(vec![Register::$register + 0x80, $binary_value]) ]);
|
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,
|
[ SpiTrans::transfer(vec![Register::$register, 0], vec![Register::$register, $binary_value_read]),
|
||||||
[ I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_value_read]),
|
SpiTrans::write(vec![Register::$register + 0x80, $binary_value_write]) ]);
|
||||||
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);
|
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