//! Common implementation use super::{decimal_to_packed_bcd, hours_to_register, packed_bcd_to_decimal}; use crate::{ interface::{ReadData, WriteData}, BitFlags, DateTimeAccess, Datelike, Ds323x, Error, Hours, NaiveDate, NaiveDateTime, NaiveTime, Register, Rtcc, Timelike, }; impl DateTimeAccess for Ds323x where DI: ReadData> + WriteData>, { type Error = Error; fn datetime(&mut self) -> Result { let mut data = [0; 8]; self.iface.read_data(&mut data)?; 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 = get_h24(hours_from_register(data[Register::HOURS 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 date = NaiveDate::from_ymd_opt(year.into(), month.into(), day.into()) .ok_or(Error::InvalidDeviceState)?; let time = NaiveTime::from_hms_opt(hour.into(), minute.into(), second.into()) .ok_or(Error::InvalidDeviceState)?; let datetime = NaiveDateTime::new(date, time); Ok(datetime) } fn set_datetime(&mut self, datetime: &NaiveDateTime) -> Result<(), Self::Error> { if !(2000..=2099).contains(&datetime.year()) { return Err(Error::InvalidInputData); } let mut payload = [ Register::SECONDS, decimal_to_packed_bcd(datetime.second() as u8), decimal_to_packed_bcd(datetime.minute() as u8), hours_to_register(Hours::H24(datetime.hour() as u8))?, datetime.weekday().number_from_sunday() as u8, decimal_to_packed_bcd(datetime.day() as u8), decimal_to_packed_bcd(datetime.month() as u8), decimal_to_packed_bcd((datetime.year() - 2000) as u8), ]; self.iface.write_data(&mut payload) } } impl Rtcc for Ds323x where DI: ReadData> + WriteData>, { fn seconds(&mut self) -> Result { 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) } fn minutes(&mut self) -> Result { 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) } fn hours(&mut self) -> Result { 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)?; Ok(hours_from_register(data)) } fn time(&mut self) -> Result { 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]; self.iface.read_data(&mut data)?; 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 second = packed_bcd_to_decimal(data[Register::SECONDS as usize + 1]); NaiveTime::from_hms_opt(hour.into(), minute.into(), second.into()) .ok_or(Error::InvalidDeviceState) } fn weekday(&mut self) -> Result { 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) } fn day(&mut self) -> Result { 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) } fn month(&mut self) -> Result { let data = self.iface.read_register(Register::MONTH)?; let century = data & BitFlags::CENTURY; if century != 0 { return Err(Error::InvalidDeviceCentury); } Ok(packed_bcd_to_decimal(data)) } fn year(&mut self) -> Result { let data = self.iface.read_register(Register::MONTH)?; let century = data & BitFlags::CENTURY; if century != 0 { return Err(Error::InvalidDeviceCentury); } Ok(2000 + (self.read_register_decimal(Register::YEAR)? as u16)) } fn date(&mut self) -> Result { let mut data = [0; 4]; data[0] = Register::DOM; self.iface.read_data(&mut data)?; let offset = Register::DOM as usize; 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]); NaiveDate::from_ymd_opt(year.into(), month.into(), day.into()) .ok_or(Error::InvalidDeviceState) } fn set_seconds(&mut self, seconds: u8) -> Result<(), Self::Error> { if seconds > 59 { return Err(Error::InvalidInputData); } self.write_register_decimal(Register::SECONDS, seconds) } fn set_minutes(&mut self, minutes: u8) -> Result<(), Self::Error> { if minutes > 59 { return Err(Error::InvalidInputData); } self.write_register_decimal(Register::MINUTES, minutes) } fn set_hours(&mut self, hours: Hours) -> Result<(), Self::Error> { let value = hours_to_register(hours)?; self.iface.write_register(Register::HOURS, value) } fn set_time(&mut self, time: &NaiveTime) -> Result<(), Self::Error> { let mut payload = [ Register::SECONDS, decimal_to_packed_bcd(time.second() as u8), decimal_to_packed_bcd(time.minute() as u8), hours_to_register(Hours::H24(time.hour() as u8))?, ]; self.iface.write_data(&mut payload) } fn set_weekday(&mut self, weekday: u8) -> Result<(), Self::Error> { if !(1..=7).contains(&weekday) { return Err(Error::InvalidInputData); } self.iface.write_register(Register::DOW, weekday) } fn set_day(&mut self, day: u8) -> Result<(), Self::Error> { if !(1..=31).contains(&day) { return Err(Error::InvalidInputData); } self.write_register_decimal(Register::DOM, day) } fn set_month(&mut self, month: u8) -> Result<(), Self::Error> { if !(1..=12).contains(&month) { return Err(Error::InvalidInputData); } // keep the century bit let data = self.iface.read_register(Register::MONTH)?; let value = (data & BitFlags::CENTURY) | decimal_to_packed_bcd(month); self.iface.write_register(Register::MONTH, value) } fn set_year(&mut self, year: u16) -> Result<(), Self::Error> { if !(2000..=2099).contains(&year) { return Err(Error::InvalidInputData); } let data = self.iface.read_register(Register::MONTH)?; let month_bcd = data & !BitFlags::CENTURY; 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 !(2000..=2099).contains(&date.year()) { return Err(Error::InvalidInputData); } let mut payload = [ Register::DOW, date.weekday().number_from_sunday() as u8, decimal_to_packed_bcd(date.day() as u8), decimal_to_packed_bcd(date.month() as u8), decimal_to_packed_bcd((date.year() - 2000) as u8), ]; self.iface.write_data(&mut payload) } } impl Ds323x where DI: ReadData> + WriteData>, { fn read_register_decimal(&mut self, register: u8) -> Result> { let data = self.iface.read_register(register)?; Ok(packed_bcd_to_decimal(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)) } } fn hours_from_register(data: u8) -> Hours { if is_24h_format(data) { Hours::H24(packed_bcd_to_decimal(data & !BitFlags::H24_H12)) } else if is_am(data) { Hours::AM(packed_bcd_to_decimal( data & !(BitFlags::H24_H12 | BitFlags::AM_PM), )) } else { Hours::PM(packed_bcd_to_decimal( data & !(BitFlags::H24_H12 | BitFlags::AM_PM), )) } } fn is_24h_format(hours_data: u8) -> bool { hours_data & BitFlags::H24_H12 == 0 } fn is_am(hours_data: u8) -> bool { hours_data & BitFlags::AM_PM == 0 } fn get_h24(hour: Hours) -> u8 { match hour { Hours::H24(h) => h, Hours::AM(h) => h, Hours::PM(h) => h + 12, } } #[cfg(test)] mod tests { use super::*; #[test] fn can_convert_to_h24() { assert_eq!(0, get_h24(Hours::H24(0))); assert_eq!(0, get_h24(Hours::AM(0))); assert_eq!(12, get_h24(Hours::PM(0))); assert_eq!(1, get_h24(Hours::H24(1))); assert_eq!(1, get_h24(Hours::AM(1))); assert_eq!(13, get_h24(Hours::PM(1))); assert_eq!(23, get_h24(Hours::H24(23))); assert_eq!(12, get_h24(Hours::AM(12))); assert_eq!(23, get_h24(Hours::PM(11))); } }