Compare commits

...

8 Commits

Author SHA1 Message Date
Paul Bender 5aee0c4b54
Merge 887f4ced89 into 7070810621 2025-10-12 22:04:56 +00:00
Paul Bender 887f4ced89 Update changelog. 2025-10-12 15:04:04 -07:00
Paul Bender 97db2af80e Fix formatting. 2025-10-12 14:21:18 -07:00
Paul Bender b803d3b4d3 Added more test coverage. 2025-10-12 14:19:17 -07:00
Paul Bender 57409f96dc Generate an error for all time functions when the century bit is set. 2025-10-11 18:02:49 -07:00
Paul Bender 25f695d20a Replace some_or_invalid_error with idiomatic Rust. 2025-10-11 08:35:24 -07:00
Paul Bender e7c41a6424 Generate error when century bit is set in functions already reading the century bit 2025-10-11 07:46:15 -07:00
Paul Bender 29084a7b9d Limit setting year to 20th century. 2025-10-11 07:45:04 -07:00
6 changed files with 286 additions and 146 deletions

View File

@ -8,6 +8,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
<!-- next-header --> <!-- next-header -->
## [Unreleased] - ReleaseDate ## [Unreleased] - ReleaseDate
### Added
- [breaking-change] Return Error::InvalidInputData when attempting to set the year to something
outside of the range 2000-2099 because all chips have a problem with the year 2100 and beyond.
- [breaking-change] Return Error::InvalidDeviceCentury when attempting to get a date and/or time value
and the the device's century bit is set because all chips have a problem withe year 2100 and beyond.
## [0.7.0] - 2025-10-11 ## [0.7.0] - 2025-10-11
### Added ### Added

View File

@ -1,8 +1,6 @@
//! Common implementation //! Common implementation
use super::{ use super::{decimal_to_packed_bcd, hours_to_register, packed_bcd_to_decimal};
decimal_to_packed_bcd, hours_to_register, packed_bcd_to_decimal, some_or_invalid_error,
};
use crate::{ use crate::{
interface::{ReadData, WriteData}, interface::{ReadData, WriteData},
BitFlags, DateTimeAccess, Datelike, Ds323x, Error, Hours, NaiveDate, NaiveDateTime, NaiveTime, BitFlags, DateTimeAccess, Datelike, Ds323x, Error, Hours, NaiveDate, NaiveDateTime, NaiveTime,
@ -19,27 +17,31 @@ where
let mut data = [0; 8]; let mut data = [0; 8];
self.iface.read_data(&mut data)?; self.iface.read_data(&mut data)?;
let year = year_from_registers( let century = data[Register::MONTH as usize + 1] & BitFlags::CENTURY;
data[Register::MONTH as usize + 1], if century != 0 {
data[Register::YEAR as usize + 1], return Err(Error::InvalidDeviceCentury);
); }
let month = packed_bcd_to_decimal(data[Register::MONTH as usize + 1] & !BitFlags::CENTURY);
let year = 2000 + (packed_bcd_to_decimal(data[Register::YEAR as usize + 1]) as u16);
let month = packed_bcd_to_decimal(data[Register::MONTH as usize + 1]);
let day = packed_bcd_to_decimal(data[Register::DOM as usize + 1]); let day = packed_bcd_to_decimal(data[Register::DOM as usize + 1]);
let hour = hours_from_register(data[Register::HOURS as usize + 1]); let hour = get_h24(hours_from_register(data[Register::HOURS as usize + 1]));
let minute = packed_bcd_to_decimal(data[Register::MINUTES as usize + 1]); let minute = packed_bcd_to_decimal(data[Register::MINUTES as usize + 1]);
let second = packed_bcd_to_decimal(data[Register::SECONDS as usize + 1]); let second = packed_bcd_to_decimal(data[Register::SECONDS as usize + 1]);
let date = NaiveDate::from_ymd_opt(year.into(), month.into(), day.into()); let date = NaiveDate::from_ymd_opt(year.into(), month.into(), day.into())
let date = some_or_invalid_error(date)?; .ok_or(Error::InvalidDeviceState)?;
let datetime = date.and_hms_opt(get_h24(hour).into(), minute.into(), second.into()); let time = NaiveTime::from_hms_opt(hour.into(), minute.into(), second.into())
some_or_invalid_error(datetime) .ok_or(Error::InvalidDeviceState)?;
let datetime = NaiveDateTime::new(date, time);
Ok(datetime)
} }
fn set_datetime(&mut self, datetime: &NaiveDateTime) -> Result<(), Self::Error> { fn set_datetime(&mut self, datetime: &NaiveDateTime) -> Result<(), Self::Error> {
if datetime.year() < 2000 || datetime.year() > 2100 { if !(2000..=2099).contains(&datetime.year()) {
return Err(Error::InvalidInputData); return Err(Error::InvalidInputData);
} }
let (month, year) = month_year_to_registers(datetime.month() as u8, datetime.year() as u16);
let mut payload = [ let mut payload = [
Register::SECONDS, Register::SECONDS,
decimal_to_packed_bcd(datetime.second() as u8), decimal_to_packed_bcd(datetime.second() as u8),
@ -47,8 +49,8 @@ where
hours_to_register(Hours::H24(datetime.hour() as u8))?, hours_to_register(Hours::H24(datetime.hour() as u8))?,
datetime.weekday().number_from_sunday() as u8, datetime.weekday().number_from_sunday() as u8,
decimal_to_packed_bcd(datetime.day() as u8), decimal_to_packed_bcd(datetime.day() as u8),
month, decimal_to_packed_bcd(datetime.month() as u8),
year, decimal_to_packed_bcd((datetime.year() - 2000) as u8),
]; ];
self.iface.write_data(&mut payload) self.iface.write_data(&mut payload)
} }
@ -59,48 +61,100 @@ where
DI: ReadData<Error = Error<E>> + WriteData<Error = Error<E>>, DI: ReadData<Error = Error<E>> + WriteData<Error = Error<E>>,
{ {
fn seconds(&mut self) -> Result<u8, Self::Error> { fn seconds(&mut self) -> Result<u8, Self::Error> {
let data = self.iface.read_register(Register::MONTH)?;
let century = data & BitFlags::CENTURY;
if century != 0 {
return Err(Error::InvalidDeviceCentury);
}
self.read_register_decimal(Register::SECONDS) self.read_register_decimal(Register::SECONDS)
} }
fn minutes(&mut self) -> Result<u8, Self::Error> { fn minutes(&mut self) -> Result<u8, Self::Error> {
let data = self.iface.read_register(Register::MONTH)?;
let century = data & BitFlags::CENTURY;
if century != 0 {
return Err(Error::InvalidDeviceCentury);
}
self.read_register_decimal(Register::MINUTES) self.read_register_decimal(Register::MINUTES)
} }
fn hours(&mut self) -> Result<Hours, Self::Error> { fn hours(&mut self) -> Result<Hours, Self::Error> {
let data = self.iface.read_register(Register::MONTH)?;
let century = data & BitFlags::CENTURY;
if century != 0 {
return Err(Error::InvalidDeviceCentury);
}
let data = self.iface.read_register(Register::HOURS)?; let data = self.iface.read_register(Register::HOURS)?;
Ok(hours_from_register(data)) Ok(hours_from_register(data))
} }
fn time(&mut self) -> Result<NaiveTime, Self::Error> { fn time(&mut self) -> Result<NaiveTime, Self::Error> {
let data = self.iface.read_register(Register::MONTH)?;
let century = data & BitFlags::CENTURY;
if century != 0 {
return Err(Error::InvalidDeviceCentury);
}
let mut data = [0; 4]; let mut data = [0; 4];
self.iface.read_data(&mut data)?; self.iface.read_data(&mut data)?;
let hour = hours_from_register(data[Register::HOURS as usize + 1]);
let hour = get_h24(hours_from_register(data[Register::HOURS as usize + 1]));
let minute = packed_bcd_to_decimal(data[Register::MINUTES as usize + 1]); let minute = packed_bcd_to_decimal(data[Register::MINUTES as usize + 1]);
let second = packed_bcd_to_decimal(data[Register::SECONDS as usize + 1]); let second = packed_bcd_to_decimal(data[Register::SECONDS as usize + 1]);
let time = NaiveTime::from_hms_opt(get_h24(hour).into(), minute.into(), second.into()); NaiveTime::from_hms_opt(hour.into(), minute.into(), second.into())
some_or_invalid_error(time) .ok_or(Error::InvalidDeviceState)
} }
fn weekday(&mut self) -> Result<u8, Self::Error> { fn weekday(&mut self) -> Result<u8, Self::Error> {
let data = self.iface.read_register(Register::MONTH)?;
let century = data & BitFlags::CENTURY;
if century != 0 {
return Err(Error::InvalidDeviceCentury);
}
self.read_register_decimal(Register::DOW) self.read_register_decimal(Register::DOW)
} }
fn day(&mut self) -> Result<u8, Self::Error> { fn day(&mut self) -> Result<u8, Self::Error> {
let data = self.iface.read_register(Register::MONTH)?;
let century = data & BitFlags::CENTURY;
if century != 0 {
return Err(Error::InvalidDeviceCentury);
}
self.read_register_decimal(Register::DOM) self.read_register_decimal(Register::DOM)
} }
fn month(&mut self) -> Result<u8, Self::Error> { fn month(&mut self) -> Result<u8, Self::Error> {
let data = self.iface.read_register(Register::MONTH)?; let data = self.iface.read_register(Register::MONTH)?;
let value = data & !BitFlags::CENTURY;
Ok(packed_bcd_to_decimal(value)) let century = data & BitFlags::CENTURY;
if century != 0 {
return Err(Error::InvalidDeviceCentury);
}
Ok(packed_bcd_to_decimal(data))
} }
fn year(&mut self) -> Result<u16, Self::Error> { fn year(&mut self) -> Result<u16, Self::Error> {
let mut data = [0; 3]; let data = self.iface.read_register(Register::MONTH)?;
data[0] = Register::MONTH;
self.iface.read_data(&mut data)?; let century = data & BitFlags::CENTURY;
Ok(year_from_registers(data[1], data[2])) if century != 0 {
return Err(Error::InvalidDeviceCentury);
}
Ok(2000 + (self.read_register_decimal(Register::YEAR)? as u16))
} }
fn date(&mut self) -> Result<NaiveDate, Self::Error> { fn date(&mut self) -> Result<NaiveDate, Self::Error> {
@ -109,15 +163,19 @@ where
self.iface.read_data(&mut data)?; self.iface.read_data(&mut data)?;
let offset = Register::DOM as usize; let offset = Register::DOM as usize;
let year = year_from_registers(
data[Register::MONTH as usize + 1 - offset], let century = data[Register::MONTH as usize + 1 - offset] & BitFlags::CENTURY;
data[Register::YEAR as usize + 1 - offset], if century != 0 {
); return Err(Error::InvalidDeviceCentury);
let month = }
packed_bcd_to_decimal(data[Register::MONTH as usize + 1 - offset] & !BitFlags::CENTURY);
let year =
2000 + (packed_bcd_to_decimal(data[Register::YEAR as usize + 1 - offset]) as u16);
let month = packed_bcd_to_decimal(data[Register::MONTH as usize + 1 - offset]);
let day = packed_bcd_to_decimal(data[Register::DOM as usize + 1 - offset]); let day = packed_bcd_to_decimal(data[Register::DOM as usize + 1 - offset]);
let date = NaiveDate::from_ymd_opt(year.into(), month.into(), day.into());
some_or_invalid_error(date) NaiveDate::from_ymd_opt(year.into(), month.into(), day.into())
.ok_or(Error::InvalidDeviceState)
} }
fn set_seconds(&mut self, seconds: u8) -> Result<(), Self::Error> { fn set_seconds(&mut self, seconds: u8) -> Result<(), Self::Error> {
@ -174,39 +232,30 @@ where
} }
fn set_year(&mut self, year: u16) -> Result<(), Self::Error> { fn set_year(&mut self, year: u16) -> Result<(), Self::Error> {
if !(2000..=2100).contains(&year) { if !(2000..=2099).contains(&year) {
return Err(Error::InvalidInputData); return Err(Error::InvalidInputData);
} }
let data = self.iface.read_register(Register::MONTH)?; let data = self.iface.read_register(Register::MONTH)?;
let month_bcd = data & !BitFlags::CENTURY; let month_bcd = data & !BitFlags::CENTURY;
if year > 2099 {
let mut data = [ let mut data = [
Register::MONTH, Register::MONTH,
BitFlags::CENTURY | month_bcd, month_bcd,
decimal_to_packed_bcd((year - 2100) as u8), decimal_to_packed_bcd((year - 2000) as u8),
]; ];
self.iface.write_data(&mut data) self.iface.write_data(&mut data)
} else {
let mut data = [
Register::MONTH,
month_bcd,
decimal_to_packed_bcd((year - 2000) as u8),
];
self.iface.write_data(&mut data)
}
} }
fn set_date(&mut self, date: &rtcc::NaiveDate) -> Result<(), Self::Error> { fn set_date(&mut self, date: &rtcc::NaiveDate) -> Result<(), Self::Error> {
if date.year() < 2000 || date.year() > 2100 { if !(2000..=2099).contains(&date.year()) {
return Err(Error::InvalidInputData); return Err(Error::InvalidInputData);
} }
let (month, year) = month_year_to_registers(date.month() as u8, date.year() as u16);
let mut payload = [ let mut payload = [
Register::DOW, Register::DOW,
date.weekday().number_from_sunday() as u8, date.weekday().number_from_sunday() as u8,
decimal_to_packed_bcd(date.day() as u8), decimal_to_packed_bcd(date.day() as u8),
month, decimal_to_packed_bcd(date.month() as u8),
year, decimal_to_packed_bcd((date.year() - 2000) as u8),
]; ];
self.iface.write_data(&mut payload) self.iface.write_data(&mut payload)
} }
@ -241,28 +290,6 @@ fn hours_from_register(data: u8) -> Hours {
} }
} }
fn year_from_registers(month: u8, year: u8) -> u16 {
let century = month & BitFlags::CENTURY;
let year = packed_bcd_to_decimal(year);
if century != 0 {
2100 + u16::from(year)
} else {
2000 + u16::from(year)
}
}
fn month_year_to_registers(month: u8, year: u16) -> (u8, u8) {
if year > 2099 {
let month = BitFlags::CENTURY | decimal_to_packed_bcd(month);
(month, decimal_to_packed_bcd((year - 2100) as u8))
} else {
(
decimal_to_packed_bcd(month),
decimal_to_packed_bcd((year - 2000) as u8),
)
}
}
fn is_24h_format(hours_data: u8) -> bool { fn is_24h_format(hours_data: u8) -> bool {
hours_data & BitFlags::H24_H12 == 0 hours_data & BitFlags::H24_H12 == 0
} }

View File

@ -28,34 +28,10 @@ fn hours_to_register<E>(hours: Hours) -> Result<u8, Error<E>> {
} }
} }
fn some_or_invalid_error<T, E>(data: Option<T>) -> Result<T, Error<E>> {
if let Some(data) = data {
Ok(data)
} else {
Err(Error::InvalidDeviceState)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn if_some_then_get_inner() {
match some_or_invalid_error::<u8, ()>(Some(1)) {
Ok(1) => (),
_ => panic!(),
}
}
#[test]
fn if_none_then_error() {
match some_or_invalid_error::<u8, ()>(None) {
Err(Error::InvalidDeviceState) => (),
_ => panic!(),
}
}
#[test] #[test]
fn can_convert_packed_bcd_to_decimal() { fn can_convert_packed_bcd_to_decimal() {
assert_eq!(0, packed_bcd_to_decimal(0b0000_0000)); assert_eq!(0, packed_bcd_to_decimal(0b0000_0000));

View File

@ -388,6 +388,11 @@ pub enum Error<E> {
/// It was not possible to read a valid date and/or time. /// It was not possible to read a valid date and/or time.
/// The device is probably missing initialization. /// The device is probably missing initialization.
InvalidDeviceState, InvalidDeviceState,
/// Device century is not the 20th century.
///
/// The device does not produce valid dates for centuries
/// other than the 20th century.
InvalidDeviceCentury,
} }
/// Square-wave output frequency /// Square-wave output frequency

View File

@ -23,6 +23,7 @@ impl Register {
pub const DOW: u8 = 0x03; pub const DOW: u8 = 0x03;
pub const DOM: u8 = 0x04; pub const DOM: u8 = 0x04;
pub const MONTH: u8 = 0x05; pub const MONTH: u8 = 0x05;
pub const YEAR: u8 = 0x06;
pub const ALARM1_SECONDS: u8 = 0x07; pub const ALARM1_SECONDS: u8 = 0x07;
pub const ALARM2_MINUTES: u8 = 0x0B; pub const ALARM2_MINUTES: u8 = 0x0B;
pub const CONTROL: u8 = 0x0E; pub const CONTROL: u8 = 0x0E;
@ -36,6 +37,7 @@ pub struct BitFlags;
#[allow(unused)] #[allow(unused)]
impl BitFlags { impl BitFlags {
pub const CENTURY: u8 = 0b1000_0000;
pub const EOSC: u8 = 0b1000_0000; pub const EOSC: u8 = 0b1000_0000;
pub const BBSQW: u8 = 0b0100_0000; pub const BBSQW: u8 = 0b0100_0000;
pub const TEMP_CONV: u8 = 0b0010_0000; pub const TEMP_CONV: u8 = 0b0010_0000;
@ -123,6 +125,16 @@ macro_rules! assert_invalid_input_data {
}; };
} }
#[macro_export]
macro_rules! assert_invalid_device_century {
($result:expr) => {
match $result {
Err(Error::InvalidDeviceCentury) => (),
_ => panic!("InvalidDeviceCentury error not returned."),
}
};
}
#[macro_export] #[macro_export]
macro_rules! set_invalid_test { macro_rules! set_invalid_test {
($name:ident, $method:ident, $create_method:ident, $destroy_method:ident, $value:expr) => { ($name:ident, $method:ident, $create_method:ident, $destroy_method:ident, $value:expr) => {
@ -135,6 +147,19 @@ macro_rules! set_invalid_test {
}; };
} }
#[macro_export]
macro_rules! get_invalid_test {
($name:ident, $method:ident, $create_method:ident, $destroy_method:ident, $transactions:expr) => {
#[test]
fn $name() {
let trans = $transactions;
let mut dev = $create_method(&trans);
assert_invalid_device_century!(dev.$method());
$destroy_method(dev);
}
};
}
#[macro_export] #[macro_export]
macro_rules! call_test { macro_rules! call_test {
($name:ident, $method:ident, $create_method:ident, $destroy_method:ident, $transactions:expr) => { ($name:ident, $method:ident, $create_method:ident, $destroy_method:ident, $transactions:expr) => {

View File

@ -2,8 +2,8 @@ use embedded_hal_mock::eh1::{i2c::Transaction as I2cTrans, spi::Transaction as S
use rtcc::NaiveDateTime; use rtcc::NaiveDateTime;
mod common; mod common;
use self::common::{ use self::common::{
destroy_ds3231, destroy_ds3232, destroy_ds3234, new_ds3231, new_ds3232, new_ds3234, Register, destroy_ds3231, destroy_ds3232, destroy_ds3234, new_ds3231, new_ds3232, new_ds3234, BitFlags,
DEVICE_ADDRESS as DEV_ADDR, Register, DEVICE_ADDRESS as DEV_ADDR,
}; };
#[allow(unused)] // Rust 1.31.0 is confused due to the macros #[allow(unused)] // Rust 1.31.0 is confused due to the macros
use ds323x::Rtcc; use ds323x::Rtcc;
@ -78,6 +78,31 @@ macro_rules! read_set_param_test {
}; };
} }
macro_rules! read_get_param_test {
($name:ident, $method:ident, $register:ident, $value:expr, $binary_value:expr) => {
_get_param_test!(
$name,
$method,
$value,
[
I2cTrans::write_read(DEV_ADDR, vec![Register::MONTH], vec![1]),
I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_value])
],
[
SpiTrans::transaction_start(),
SpiTrans::transfer_in_place(vec![Register::MONTH, 0], vec![Register::MONTH, 1]),
SpiTrans::transaction_end(),
SpiTrans::transaction_start(),
SpiTrans::transfer_in_place(
vec![Register::$register, 0],
vec![Register::$register, $binary_value]
),
SpiTrans::transaction_end(),
]
);
};
}
macro_rules! set_invalid_param_test { macro_rules! set_invalid_param_test {
($name:ident, $method:ident, $value:expr) => { ($name:ident, $method:ident, $value:expr) => {
mod $name { mod $name {
@ -117,6 +142,50 @@ macro_rules! set_invalid_param_range_test {
}; };
} }
macro_rules! get_invalid_device_century_test {
($name:ident, $method:ident) => {
mod $name {
use super::*;
get_invalid_test!(
cannot_get_invalid_ds3231,
$method,
new_ds3231,
destroy_ds3231,
[I2cTrans::write_read(
DEV_ADDR,
vec![Register::MONTH],
vec![BitFlags::CENTURY | 0]
)]
);
get_invalid_test!(
cannot_get_invalid_ds3232,
$method,
new_ds3232,
destroy_ds3232,
[I2cTrans::write_read(
DEV_ADDR,
vec![Register::MONTH],
vec![BitFlags::CENTURY | 0]
)]
);
get_invalid_test!(
cannot_get_invalid_ds3234,
$method,
new_ds3234,
destroy_ds3234,
[
SpiTrans::transaction_start(),
SpiTrans::transfer_in_place(
vec![Register::MONTH, 0],
vec![Register::MONTH, BitFlags::CENTURY | 0]
),
SpiTrans::transaction_end(),
]
);
}
};
}
macro_rules! for_all { macro_rules! for_all {
($name:ident) => { ($name:ident) => {
mod $name { mod $name {
@ -133,51 +202,58 @@ macro_rules! for_all {
mod seconds { mod seconds {
use super::*; use super::*;
get_param_test!(get, seconds, SECONDS, 1, 1); read_get_param_test!(get, seconds, SECONDS, 1, 1);
set_param_test!(set, set_seconds, SECONDS, 1, 1); set_param_test!(set, set_seconds, SECONDS, 1, 1);
set_invalid_param_test!(invalid, set_seconds, 60); set_invalid_param_test!(invalid, set_seconds, 60);
get_invalid_device_century_test!(invalid_century, seconds);
} }
mod minutes { mod minutes {
use super::*; use super::*;
get_param_test!(get, minutes, MINUTES, 1, 1); read_get_param_test!(get, minutes, MINUTES, 1, 1);
set_param_test!(set, set_minutes, MINUTES, 1, 1); set_param_test!(set, set_minutes, MINUTES, 1, 1);
set_invalid_param_test!(invalid, set_minutes, 60); set_invalid_param_test!(invalid, set_minutes, 60);
get_invalid_device_century_test!(invalid_century, minutes);
} }
mod hours_24h { mod hours_24h {
use super::*; use super::*;
get_param_test!(get, hours, HOURS, Hours::H24(21), 0b0010_0001); read_get_param_test!(get, hours, HOURS, Hours::H24(21), 0b0010_0001);
set_param_test!(set, set_hours, HOURS, Hours::H24(21), 0b0010_0001); set_param_test!(set, set_hours, HOURS, Hours::H24(21), 0b0010_0001);
set_invalid_param_test!(invalid, set_hours, Hours::H24(24)); set_invalid_param_test!(invalid, set_hours, Hours::H24(24));
get_invalid_device_century_test!(invalid_century, hours);
} }
mod hours_12h_am { mod hours_12h_am {
use super::*; use super::*;
get_param_test!(get, hours, HOURS, Hours::AM(12), 0b0101_0010); read_get_param_test!(get, hours, HOURS, Hours::AM(12), 0b0101_0010);
set_param_test!(set, set_hours, HOURS, Hours::AM(12), 0b0101_0010); set_param_test!(set, set_hours, HOURS, Hours::AM(12), 0b0101_0010);
set_invalid_param_range_test!(invalid, set_hours, Hours::AM(0), Hours::AM(13)); set_invalid_param_range_test!(invalid, set_hours, Hours::AM(0), Hours::AM(13));
get_invalid_device_century_test!(invalid_century, hours);
} }
mod hours_12h_pm { mod hours_12h_pm {
use super::*; use super::*;
get_param_test!(get, hours, HOURS, Hours::PM(12), 0b0111_0010); read_get_param_test!(get, hours, HOURS, Hours::PM(12), 0b0111_0010);
set_param_test!(set, set_hours, HOURS, Hours::PM(12), 0b0111_0010); set_param_test!(set, set_hours, HOURS, Hours::PM(12), 0b0111_0010);
set_invalid_param_range_test!(invalid, set_hours, Hours::PM(0), Hours::PM(13)); set_invalid_param_range_test!(invalid, set_hours, Hours::PM(0), Hours::PM(13));
get_invalid_device_century_test!(invalid_century, hours);
} }
mod weekday { mod weekday {
use super::*; use super::*;
get_param_test!(get, weekday, DOW, 1, 1); read_get_param_test!(get, weekday, DOW, 1, 1);
set_param_test!(set, set_weekday, DOW, 1, 1); set_param_test!(set, set_weekday, DOW, 1, 1);
set_invalid_param_range_test!(invalid, set_weekday, 0, 8); set_invalid_param_range_test!(invalid, set_weekday, 0, 8);
get_invalid_device_century_test!(invalid_century, weekday);
} }
mod day { mod day {
use super::*; use super::*;
get_param_test!(get, day, DOM, 1, 1); read_get_param_test!(get, day, DOM, 1, 1);
set_param_test!(set, set_day, DOM, 1, 1); set_param_test!(set, set_day, DOM, 1, 1);
set_invalid_param_range_test!(invalid, set_day, 0, 32); set_invalid_param_range_test!(invalid, set_day, 0, 32);
get_invalid_device_century_test!(invalid_century, day);
} }
mod month { mod month {
@ -185,19 +261,14 @@ mod month {
get_param_test!(get, month, MONTH, 1, 1); get_param_test!(get, month, MONTH, 1, 1);
read_set_param_test!(set, set_month, MONTH, 12, 0b0000_0010, 0b0001_0010); read_set_param_test!(set, set_month, MONTH, 12, 0b0000_0010, 0b0001_0010);
set_invalid_param_range_test!(invalid, set_month, 0, 13); set_invalid_param_range_test!(invalid, set_month, 0, 13);
get_invalid_device_century_test!(invalid_century, month);
mod keeps_century {
use super::*;
get_param_test!(get, month, MONTH, 12, 0b1001_0010);
read_set_param_test!(set, set_month, MONTH, 12, 0b1000_0010, 0b1001_0010);
}
} }
mod year { mod year {
use super::*; use super::*;
get_param_read_array_test!(century0_get, year, 2099, MONTH, [0, 0b1001_1001], [0, 0]); read_get_param_test!(get, year, YEAR, 2099, 0b1001_1001);
read_set_param_write_two_test!( read_set_param_write_two_test!(
century0_set, set,
set_year, set_year,
2099, 2099,
MONTH, MONTH,
@ -206,18 +277,8 @@ mod year {
0b1001_1001 0b1001_1001
); );
get_param_read_array_test!(century1_get, year, 2100, MONTH, [0b1000_0000, 0], [0, 0]); set_invalid_param_range_test!(invalid, set_year, 1999, 2100);
read_set_param_write_two_test!( get_invalid_device_century_test!(invalid_century, year);
century1_set,
set_year,
2100,
MONTH,
0b0001_0010,
0b1001_0010,
0
);
set_invalid_param_range_test!(invalid, set_year, 1999, 2101);
} }
macro_rules! invalid_dt_test { macro_rules! invalid_dt_test {
@ -233,7 +294,7 @@ macro_rules! invalid_dt_test {
} }
#[test] #[test]
fn datetime_too_big() { fn datetime_too_big() {
let dt = new_datetime(2101, 1, 2, 3, 4, 5); let dt = new_datetime(2100, 1, 2, 3, 4, 5);
let mut dev = $create_method(&[]); let mut dev = $create_method(&[]);
assert_invalid_input_data!(dev.set_datetime(&dt)); assert_invalid_input_data!(dev.set_datetime(&dt));
$destroy_method(dev); $destroy_method(dev);
@ -247,7 +308,7 @@ macro_rules! invalid_dt_test {
} }
#[test] #[test]
fn date_too_big() { fn date_too_big() {
let d = new_date(2101, 1, 2); let d = new_date(2100, 1, 2);
let mut dev = $create_method(&[]); let mut dev = $create_method(&[]);
assert_invalid_input_data!(dev.set_date(&d)); assert_invalid_input_data!(dev.set_date(&d));
$destroy_method(dev); $destroy_method(dev);
@ -297,6 +358,26 @@ macro_rules! dt_test {
$destroy_method(dev); $destroy_method(dev);
} }
#[test]
fn get_datetime_invalid_century() {
let _dt = new_datetime(2018, 8, 13, 23, 59, 58);
let mut dev = $create_method(&$mac_trans_read!(
SECONDS,
[
0b0101_1000,
0b0101_1001,
0b0010_0011,
0b0000_0010,
0b0001_0011,
0b0000_1000 | BitFlags::CENTURY,
0b0001_1000
],
[0, 0, 0, 0, 0, 0, 0]
));
assert_invalid_device_century!(dev.datetime());
$destroy_method(dev);
}
#[test] #[test]
fn set_datetime() { fn set_datetime() {
let dt = new_datetime(2018, 8, 13, 23, 59, 58); let dt = new_datetime(2018, 8, 13, 23, 59, 58);
@ -328,6 +409,18 @@ macro_rules! dt_test {
$destroy_method(dev); $destroy_method(dev);
} }
#[test]
fn get_date_invalid_century() {
let _d = new_date(2018, 8, 13);
let mut dev = $create_method(&$mac_trans_read!(
DOM,
[0b0001_0011, 0b0000_1000 | BitFlags::CENTURY, 0b0001_1000],
[0, 0, 0]
));
assert_invalid_device_century!(dev.date());
$destroy_method(dev);
}
#[test] #[test]
fn set_date() { fn set_date() {
let d = new_date(2018, 8, 13); let d = new_date(2018, 8, 13);
@ -340,25 +433,32 @@ macro_rules! dt_test {
} }
#[test] #[test]
fn set_date_century() { fn get_time() {
let d = new_date(2100, 8, 13); let t = NaiveTime::from_hms_opt(23, 59, 58).unwrap();
let mut dev = $create_method(&$mac_trans_write!( let month_transaction = $mac_trans_read!(MONTH, [1], [0]);
DOW, let time_transaction =
[0b0000_0110, 0b0001_0011, 0b1000_1000, 0] $mac_trans_read!(SECONDS, [0b0101_1000, 0b0101_1001, 0b0010_0011], [0, 0, 0]);
)); let mut transactions = vec![];
dev.set_date(&d).unwrap(); let mut i: usize = 0;
while i < month_transaction.len() {
transactions.push(month_transaction[i].clone());
i += 1;
}
let mut j: usize = 0;
while j < time_transaction.len() {
transactions.push(time_transaction[j].clone());
j += 1;
}
let mut dev = $create_method(&transactions);
assert_eq!(t, dev.time().unwrap());
$destroy_method(dev); $destroy_method(dev);
} }
#[test] #[test]
fn get_time() { fn get_time_invalid_century() {
let t = NaiveTime::from_hms_opt(23, 59, 58).unwrap(); let transactions = $mac_trans_read!(MONTH, [0 | BitFlags::CENTURY], [0]);
let mut dev = $create_method(&$mac_trans_read!( let mut dev = $create_method(&transactions);
SECONDS, assert_invalid_device_century!(dev.time());
[0b0101_1000, 0b0101_1001, 0b0010_0011],
[0, 0, 0]
));
assert_eq!(t, dev.time().unwrap());
$destroy_method(dev); $destroy_method(dev);
} }