use field_offset::offset_of; use stm32l4xx_hal::prelude::{_embedded_hal_blocking_i2c_Read, _embedded_hal_blocking_i2c_Write}; use tock_registers::{ interfaces::{ReadWriteable, Readable}, register_bitfields, register_structs, registers::InMemoryRegister, }; register_bitfields![ u8, T_SECOND [ Value OFFSET(0) NUMBITS(7) [], ], T_MINUTE [ Value OFFSET(0) NUMBITS(7) [], ], T_HOUR [ Value OFFSET(0) NUMBITS(6) [], n24 OFFSET(6) NUMBITS(1) [], ], T_DAY [ Value OFFSET(0) NUMBITS(3) [], ], T_DATE [ Value OFFSET(0) NUMBITS(6) [], ], T_MONTH [ Value OFFSET(0) NUMBITS(5) [], Century OFFSET(7) NUMBITS(1) [], ], T_YEAR [ Value OFFSET(0) NUMBITS(8) [], ], A_SECOND [ Value OFFSET(0) NUMBITS(7) [], M1 OFFSET(7) NUMBITS(1) [], ], A_MINUTE [ Value OFFSET(0) NUMBITS(7) [], M2 OFFSET(7) NUMBITS(1) [], ], A_HOUR [ Value OFFSET(0) NUMBITS(6) [], n24 OFFSET(6) NUMBITS(1) [], M3 OFFSET(7) NUMBITS(1) [], ], A_DAY_DATE [ Value OFFSET(0) NUMBITS(6) [], nDT OFFSET(6) NUMBITS(1) [], M4 OFFSET(7) NUMBITS(1) [], ], CONTROL_1 [ A1IE 0, A2IE 1, INTCN 2, RS1 3, RS2 4, CONV 5, BBSQW 6, nEOSC 7, ], CONTROL_2 [ A1F 0, A2F 1, BSY 2, EN32KHZ 3, OSF 7, ], AGING_OFFSET [ Value OFFSET(0) NUMBITS(7) [], Sign OFFSET(7) NUMBITS(1) [], ], TEMP_MSB [ Value OFFSET(0) NUMBITS(7) [], Sign OFFSET(7) NUMBITS(1) [], ], TEMP_LSB [ Value OFFSET(6) NUMBITS(2) [], ], ]; register_structs! { Ds3231Registers { (0x00 => second: InMemoryRegister), (0x01 => minute: InMemoryRegister), (0x02 => hour: InMemoryRegister), (0x03 => weekday: InMemoryRegister), (0x04 => day: InMemoryRegister), (0x05 => month: InMemoryRegister), (0x06 => year: InMemoryRegister), (0x07 => a1_second: InMemoryRegister), (0x08 => a1_minute: InMemoryRegister), (0x09 => a1_hour: InMemoryRegister), (0x0A => a1_day_date: InMemoryRegister), (0x0B => a2_minute: InMemoryRegister), (0x0C => a2_hour: InMemoryRegister), (0x0D => a2_day_date: InMemoryRegister), (0x0E => control_1: InMemoryRegister), (0x0F => control_2: InMemoryRegister), (0x10 => aging_offset: InMemoryRegister), (0x11 => temp_msb: InMemoryRegister), (0x12 => temp_lsb: InMemoryRegister), (0x13 => @END), } } pub enum Weekday { Sunday = 0, Monday = 1, Tuesday = 2, Wednesday = 3, Thursday = 4, Friday = 5, Saturday = 6, } impl Ds3231Registers { fn i2c_read_regs(&mut self, i2c: &mut impl _embedded_hal_blocking_i2c_Read) {} fn set_time(second: &u32, minute: &u32, hour: &u32) {} fn set_date(weekday: &Weekday, day: &u32, month: &u32, year: &u32, century: &u32) {} fn get_time(second: &mut u32, minute: &mut u32, hour: &mut u32) {} fn get_date( weekday: &mut Weekday, day: &mut u32, month: &mut u32, year: &mut u32, century: &mut u32, ) { } } fn init(address: u8, i2c: &mut impl _embedded_hal_blocking_i2c_Write) { } #[inline] fn bcd_to_decimal(value: u8) -> u8 { ((value >> 4) * 10) + (value & 0xF) } #[inline] fn decimal_to_bcd(value: u8) -> u8 { ((value / 10) << 4) | (value % 10) } pub fn in_dst(weekday: Weekday, day: u32, month: u32, hour_24: u32) -> bool { let prev_sunday: i32 = day as i32 - weekday as i32; match month { 0..=2 | 12.. => false, 4..=10 => true, 3 => match prev_sunday { ..8 => false, 15.. => true, d if d == day as i32 => hour_24 >= 2, _ => true, }, 11 => match prev_sunday { ..=0 => true, 8.. => false, d if d == day as i32 => hour_24 < 2, _ => false, }, } } #[cfg(test)] mod test { use super::*; #[test] fn dst_test() { // 2020 - begins Mar 8th @ 2AM (Sunday), ends Nov 1st @ 2AM (Sunday) assert!(in_dst(Weekday::Sunday, 8, 3, 1) == false); assert!(in_dst(Weekday::Sunday, 8, 3, 2) == true); assert!(in_dst(Weekday::Sunday, 8, 3, 3) == true); assert!(in_dst(Weekday::Sunday, 1, 11, 1) == true); assert!(in_dst(Weekday::Sunday, 1, 11, 2) == false); assert!(in_dst(Weekday::Sunday, 1, 11, 3) == false); // 2021 - begins Mar 14th @ 2AM (Sunday), ends Nov 7th @ 2AM (Sunday) assert!(in_dst(Weekday::Sunday, 14, 3, 1) == false); assert!(in_dst(Weekday::Sunday, 14, 3, 2) == true); assert!(in_dst(Weekday::Sunday, 14, 3, 3) == true); assert!(in_dst(Weekday::Sunday, 7, 11, 1) == true); assert!(in_dst(Weekday::Sunday, 7, 11, 2) == false); assert!(in_dst(Weekday::Sunday, 7, 11, 3) == false); // 2022 - begins Mar 13th @ 2AM (Sunday), ends Nov 6th @ 2AM (Sunday) assert!(in_dst(Weekday::Sunday, 13, 3, 1) == false); assert!(in_dst(Weekday::Sunday, 13, 3, 2) == true); assert!(in_dst(Weekday::Sunday, 13, 3, 3) == true); assert!(in_dst(Weekday::Sunday, 6, 11, 1) == true); assert!(in_dst(Weekday::Sunday, 6, 11, 2) == false); assert!(in_dst(Weekday::Sunday, 6, 11, 3) == false); // 2023 - begins Mar 12th @ 2AM (Sunday), ends Nov 5th @ 2AM (Sunday) assert!(in_dst(Weekday::Sunday, 12, 3, 1) == false); assert!(in_dst(Weekday::Sunday, 12, 3, 2) == true); assert!(in_dst(Weekday::Sunday, 12, 3, 3) == true); assert!(in_dst(Weekday::Sunday, 5, 11, 1) == true); assert!(in_dst(Weekday::Sunday, 5, 11, 2) == false); assert!(in_dst(Weekday::Sunday, 5, 11, 3) == false); // Sanity check other dates in 2021 assert!(in_dst(Weekday::Friday, 1, 1, 0) == false); assert!(in_dst(Weekday::Monday, 1, 2, 0) == false); assert!(in_dst(Weekday::Monday, 1, 3, 0) == false); assert!(in_dst(Weekday::Thursday, 1, 4, 0) == true); assert!(in_dst(Weekday::Saturday, 1, 5, 0) == true); assert!(in_dst(Weekday::Tuesday, 1, 6, 0) == true); assert!(in_dst(Weekday::Thursday, 1, 7, 0) == true); assert!(in_dst(Weekday::Sunday, 1, 8, 0) == true); assert!(in_dst(Weekday::Wednesday, 1, 9, 0) == true); assert!(in_dst(Weekday::Friday, 1, 10, 0) == true); assert!(in_dst(Weekday::Monday, 1, 11, 0) == true); assert!(in_dst(Weekday::Wednesday, 1, 12, 0) == false); } }