From 29084a7b9d5d6629addd168dda98b406ffbce171 Mon Sep 17 00:00:00 2001 From: Paul Bender Date: Fri, 10 Oct 2025 12:57:58 -0700 Subject: [PATCH 1/2] Limit setting year to 20th century. --- src/ds323x/datetime.rs | 50 ++++++++++++------------------------------ tests/datetime.rs | 28 +++-------------------- 2 files changed, 17 insertions(+), 61 deletions(-) diff --git a/src/ds323x/datetime.rs b/src/ds323x/datetime.rs index 41fd610..1a48e4c 100644 --- a/src/ds323x/datetime.rs +++ b/src/ds323x/datetime.rs @@ -36,10 +36,9 @@ where } 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); } - let (month, year) = month_year_to_registers(datetime.month() as u8, datetime.year() as u16); let mut payload = [ Register::SECONDS, decimal_to_packed_bcd(datetime.second() as u8), @@ -47,8 +46,8 @@ where hours_to_register(Hours::H24(datetime.hour() as u8))?, datetime.weekday().number_from_sunday() as u8, decimal_to_packed_bcd(datetime.day() as u8), - month, - year, + decimal_to_packed_bcd(datetime.month() as u8), + decimal_to_packed_bcd((datetime.year() - 2000) as u8), ]; self.iface.write_data(&mut payload) } @@ -174,39 +173,30 @@ where } fn set_year(&mut self, year: u16) -> Result<(), Self::Error> { - if !(2000..=2100).contains(&year) { + if !(2000..=2099).contains(&year) { return Err(Error::InvalidInputData); } let data = self.iface.read_register(Register::MONTH)?; let month_bcd = data & !BitFlags::CENTURY; - if year > 2099 { - let mut data = [ - Register::MONTH, - BitFlags::CENTURY | month_bcd, - decimal_to_packed_bcd((year - 2100) as u8), - ]; - 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) - } + + 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> { - if date.year() < 2000 || date.year() > 2100 { + if !(2000..=2099).contains(&date.year()) { return Err(Error::InvalidInputData); } - let (month, year) = month_year_to_registers(date.month() as u8, date.year() as u16); let mut payload = [ Register::DOW, date.weekday().number_from_sunday() as u8, decimal_to_packed_bcd(date.day() as u8), - month, - year, + decimal_to_packed_bcd(date.month() as u8), + decimal_to_packed_bcd((date.year() - 2000) as u8), ]; self.iface.write_data(&mut payload) } @@ -251,18 +241,6 @@ fn year_from_registers(month: u8, year: u8) -> u16 { } } -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 { hours_data & BitFlags::H24_H12 == 0 } diff --git a/tests/datetime.rs b/tests/datetime.rs index a10acb8..eb465c3 100644 --- a/tests/datetime.rs +++ b/tests/datetime.rs @@ -206,18 +206,7 @@ mod year { 0b1001_1001 ); - get_param_read_array_test!(century1_get, year, 2100, MONTH, [0b1000_0000, 0], [0, 0]); - read_set_param_write_two_test!( - century1_set, - set_year, - 2100, - MONTH, - 0b0001_0010, - 0b1001_0010, - 0 - ); - - set_invalid_param_range_test!(invalid, set_year, 1999, 2101); + set_invalid_param_range_test!(invalid, set_year, 1999, 2100); } macro_rules! invalid_dt_test { @@ -233,7 +222,7 @@ macro_rules! invalid_dt_test { } #[test] 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(&[]); assert_invalid_input_data!(dev.set_datetime(&dt)); $destroy_method(dev); @@ -247,7 +236,7 @@ macro_rules! invalid_dt_test { } #[test] fn date_too_big() { - let d = new_date(2101, 1, 2); + let d = new_date(2100, 1, 2); let mut dev = $create_method(&[]); assert_invalid_input_data!(dev.set_date(&d)); $destroy_method(dev); @@ -339,17 +328,6 @@ macro_rules! dt_test { $destroy_method(dev); } - #[test] - fn set_date_century() { - let d = new_date(2100, 8, 13); - let mut dev = $create_method(&$mac_trans_write!( - DOW, - [0b0000_0110, 0b0001_0011, 0b1000_1000, 0] - )); - dev.set_date(&d).unwrap(); - $destroy_method(dev); - } - #[test] fn get_time() { let t = NaiveTime::from_hms_opt(23, 59, 58).unwrap(); From e7c41a64241d50a3a604660af56f2ddcccfee847 Mon Sep 17 00:00:00 2001 From: Paul Bender Date: Fri, 10 Oct 2025 13:17:53 -0700 Subject: [PATCH 2/2] Generate error when century bit is set in functions already reading the century bit --- src/ds323x/datetime.rs | 56 ++++++++++++++++++++++++------------------ src/lib.rs | 5 ++++ tests/datetime.rs | 6 ----- 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/ds323x/datetime.rs b/src/ds323x/datetime.rs index 1a48e4c..3491ea7 100644 --- a/src/ds323x/datetime.rs +++ b/src/ds323x/datetime.rs @@ -19,11 +19,13 @@ where let mut data = [0; 8]; self.iface.read_data(&mut data)?; - let year = year_from_registers( - data[Register::MONTH as usize + 1], - data[Register::YEAR as usize + 1], - ); - let month = packed_bcd_to_decimal(data[Register::MONTH as usize + 1] & !BitFlags::CENTURY); + let century = data[Register::MONTH as usize + 1] & BitFlags::CENTURY; + if century != 0 { + return Err(Error::InvalidDeviceCentury); + } + + 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 hour = hours_from_register(data[Register::HOURS as usize + 1]); let minute = packed_bcd_to_decimal(data[Register::MINUTES as usize + 1]); @@ -91,15 +93,28 @@ where fn month(&mut self) -> Result { 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 { let mut data = [0; 3]; data[0] = Register::MONTH; self.iface.read_data(&mut data)?; - Ok(year_from_registers(data[1], data[2])) + + let century = data[1] & BitFlags::CENTURY; + if century != 0 { + return Err(Error::InvalidDeviceCentury); + } + + let year = 2000 + (packed_bcd_to_decimal(data[2]) as u16); + + Ok(year) } fn date(&mut self) -> Result { @@ -108,12 +123,15 @@ where self.iface.read_data(&mut data)?; let offset = Register::DOM as usize; - let year = year_from_registers( - data[Register::MONTH as usize + 1 - offset], - data[Register::YEAR as usize + 1 - offset], - ); - let month = - packed_bcd_to_decimal(data[Register::MONTH as usize + 1 - offset] & !BitFlags::CENTURY); + + let century = data[Register::MONTH as usize + 1 - offset] & BitFlags::CENTURY; + if century != 0 { + return Err(Error::InvalidDeviceCentury); + } + + 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 date = NaiveDate::from_ymd_opt(year.into(), month.into(), day.into()); some_or_invalid_error(date) @@ -231,16 +249,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 is_24h_format(hours_data: u8) -> bool { hours_data & BitFlags::H24_H12 == 0 } diff --git a/src/lib.rs b/src/lib.rs index 5efa490..f98afda 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -388,6 +388,11 @@ pub enum Error { /// It was not possible to read a valid date and/or time. /// The device is probably missing initialization. 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 diff --git a/tests/datetime.rs b/tests/datetime.rs index eb465c3..ec88bdf 100644 --- a/tests/datetime.rs +++ b/tests/datetime.rs @@ -185,12 +185,6 @@ mod month { get_param_test!(get, month, MONTH, 1, 1); read_set_param_test!(set, set_month, MONTH, 12, 0b0000_0010, 0b0001_0010); set_invalid_param_range_test!(invalid, set_month, 0, 13); - - 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 {