use crate::fat_error::FatResult; use crate::hal::Box; use async_trait::async_trait; use bincode::config::Configuration; use bincode::{config, Decode, Encode}; use chrono::{DateTime, Utc}; use ds323x::ic::DS3231; use ds323x::interface::I2cInterface; use ds323x::{DateTimeAccess, Ds323x}; use eeprom24x::addr_size::TwoBytes; use eeprom24x::page_size::B32; use eeprom24x::unique_serial::No; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embedded_storage::{ReadStorage, Storage}; use esp_hal::delay::Delay; use esp_hal::i2c::master::I2c; use esp_hal::Blocking; use serde::{Deserialize, Serialize}; pub const X25: crc::Crc = crc::Crc::::new(&crc::CRC_16_IBM_SDLC); const CONFIG: Configuration = config::standard(); // #[async_trait(?Send)] pub trait RTCModuleInteraction { async fn get_backup_info(&mut self) -> FatResult; async fn get_backup_config(&mut self, chunk: usize) -> FatResult<([u8; 32], usize, u16)>; async fn backup_config(&mut self, offset: usize, bytes: &[u8]) -> FatResult<()>; async fn backup_config_finalize(&mut self, crc: u16, length: usize) -> FatResult<()>; async fn get_rtc_time(&mut self) -> FatResult>; async fn set_rtc_time(&mut self, time: &DateTime) -> FatResult<()>; } // const BACKUP_HEADER_MAX_SIZE: usize = 64; #[derive(Serialize, Deserialize, PartialEq, Debug, Default, Encode, Decode)] pub struct BackupHeader { pub timestamp: i64, crc16: u16, pub size: u16, } // pub struct DS3231Module { pub(crate) rtc: Ds323x< I2cInterface>>, DS3231, >, pub(crate) storage: eeprom24x::Storage< I2cDevice<'static, CriticalSectionRawMutex, I2c<'static, Blocking>>, B32, TwoBytes, No, Delay, >, } #[async_trait(?Send)] impl RTCModuleInteraction for DS3231Module { async fn get_backup_info(&mut self) -> FatResult { let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE]; self.storage.read(0, &mut header_page_buffer)?; let (header, len): (BackupHeader, usize) = bincode::decode_from_slice(&header_page_buffer[..], CONFIG)?; log::info!("Raw header is {header_page_buffer:?} with size {len}"); Ok(header) } async fn get_backup_config(&mut self, chunk: usize) -> FatResult<([u8; 32], usize, u16)> { let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE]; self.storage.read(0, &mut header_page_buffer)?; let (header, _header_size): (BackupHeader, usize) = bincode::decode_from_slice(&header_page_buffer[..], CONFIG)?; let mut buf = [0_u8; 32]; let offset = chunk * buf.len() + BACKUP_HEADER_MAX_SIZE; let end: usize = header.size as usize + BACKUP_HEADER_MAX_SIZE; let current_end = offset + buf.len(); let chunk_size = if current_end > end { end - offset } else { buf.len() }; if chunk_size == 0 { Ok((buf, 0, header.crc16)) } else { self.storage.read(offset as u32, &mut buf)?; //&buf[..chunk_size]; Ok((buf, chunk_size, header.crc16)) } } async fn backup_config(&mut self, offset: usize, bytes: &[u8]) -> FatResult<()> { //skip header and write after self.storage .write((BACKUP_HEADER_MAX_SIZE + offset) as u32, bytes)?; Ok(()) } async fn backup_config_finalize(&mut self, crc: u16, length: usize) -> FatResult<()> { let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE]; let time = self.get_rtc_time().await?.timestamp_millis(); let header = BackupHeader { crc16: crc, timestamp: time, size: length as u16, }; let config = config::standard(); let encoded = bincode::encode_into_slice(&header, &mut header_page_buffer, config)?; log::info!("Raw header is {header_page_buffer:?} with size {encoded}"); self.storage.write(0, &header_page_buffer)?; Ok(()) } async fn get_rtc_time(&mut self) -> FatResult> { Ok(self.rtc.datetime()?.and_utc()) } async fn set_rtc_time(&mut self, time: &DateTime) -> FatResult<()> { let naive_time = time.naive_utc(); Ok(self.rtc.set_datetime(&naive_time)?) } }