130 lines
4.4 KiB
Rust
130 lines
4.4 KiB
Rust
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<u16> = crc::Crc::<u16>::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<BackupHeader>;
|
|
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<DateTime<Utc>>;
|
|
async fn set_rtc_time(&mut self, time: &DateTime<Utc>) -> 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<I2cDevice<'static, CriticalSectionRawMutex, I2c<'static, Blocking>>>,
|
|
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<BackupHeader> {
|
|
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<DateTime<Utc>> {
|
|
Ok(self.rtc.datetime()?.and_utc())
|
|
}
|
|
|
|
async fn set_rtc_time(&mut self, time: &DateTime<Utc>) -> FatResult<()> {
|
|
let naive_time = time.naive_utc();
|
|
Ok(self.rtc.set_datetime(&naive_time)?)
|
|
}
|
|
}
|