diff --git a/Software/MainBoard/rust/src/hal/esp.rs b/Software/MainBoard/rust/src/hal/esp.rs index a69faad..4985e1a 100644 --- a/Software/MainBoard/rust/src/hal/esp.rs +++ b/Software/MainBoard/rust/src/hal/esp.rs @@ -7,6 +7,7 @@ use serde::Serialize; use crate::fat_error::{ContextExt, FatError, FatResult}; use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem; +use crate::hal::shared_flash::MutexFlashStorage; use alloc::string::ToString; use alloc::sync::Arc; use alloc::{format, string::String, vec, vec::Vec}; @@ -36,7 +37,6 @@ use esp_radio::wifi::{ AccessPointConfig, AccessPointInfo, AuthMethod, ClientConfig, ModeConfig, ScanConfig, ScanTypeConfig, WifiController, WifiDevice, WifiStaState, }; -use esp_storage::FlashStorage; use littlefs2::fs::Filesystem; use littlefs2_core::{FileType, PathBuf, SeekFrom}; use log::{info, warn}; @@ -127,8 +127,8 @@ pub struct Esp<'a> { // RTC-capable GPIO used as external wake source (store the raw peripheral) pub wake_gpio1: esp_hal::peripherals::GPIO1<'static>, - pub ota: Ota<'static, FlashStorage<'static>>, - pub ota_target: &'static mut FlashRegion<'static, FlashStorage<'static>>, + pub ota: Ota<'static, MutexFlashStorage>, + pub ota_target: &'static mut FlashRegion<'static, MutexFlashStorage>, pub current: AppPartitionSubType, pub slot0_state: OtaImageState, pub slot1_state: OtaImageState, diff --git a/Software/MainBoard/rust/src/hal/little_fs2storage_adapter.rs b/Software/MainBoard/rust/src/hal/little_fs2storage_adapter.rs index 78cf032..987a7b7 100644 --- a/Software/MainBoard/rust/src/hal/little_fs2storage_adapter.rs +++ b/Software/MainBoard/rust/src/hal/little_fs2storage_adapter.rs @@ -1,6 +1,6 @@ +use crate::hal::shared_flash::MutexFlashStorage; use embedded_storage::nor_flash::{check_erase, NorFlash, ReadNorFlash}; use esp_bootloader_esp_idf::partitions::FlashRegion; -use esp_storage::FlashStorage; use littlefs2::consts::U4096 as lfsCache; use littlefs2::consts::U512 as lfsLookahead; use littlefs2::driver::Storage as lfs2Storage; @@ -9,7 +9,7 @@ use littlefs2::io::Result as lfs2Result; use log::error; pub struct LittleFs2Filesystem { - pub(crate) storage: &'static mut FlashRegion<'static, FlashStorage<'static>>, + pub(crate) storage: &'static mut FlashRegion<'static, MutexFlashStorage>, } impl lfs2Storage for LittleFs2Filesystem { diff --git a/Software/MainBoard/rust/src/hal/mod.rs b/Software/MainBoard/rust/src/hal/mod.rs index 4a8d8a9..c995dcf 100644 --- a/Software/MainBoard/rust/src/hal/mod.rs +++ b/Software/MainBoard/rust/src/hal/mod.rs @@ -4,11 +4,13 @@ pub mod esp; mod initial_hal; mod little_fs2storage_adapter; pub(crate) mod rtc; +mod shared_flash; mod v3_hal; mod v3_shift_register; mod v4_hal; pub(crate) mod v4_sensor; mod water; + use crate::alloc::string::ToString; use crate::hal::rtc::{DS3231Module, RTCModuleInteraction}; use esp_hal::peripherals::Peripherals; @@ -79,7 +81,7 @@ use crate::hal::water::TankSensor; use crate::log::LOG_ACCESS; use embassy_sync::mutex::Mutex; use embassy_sync::once_lock::OnceLock; -use embedded_storage::nor_flash::ReadNorFlash; +use embedded_storage::ReadStorage; use esp_alloc as _; use esp_backtrace as _; use esp_bootloader_esp_idf::ota::{Ota, OtaImageState}; @@ -101,6 +103,7 @@ use littlefs2::object_safe::DynStorage; use log::{error, info, warn}; use portable_atomic::AtomicBool; use serde::Serialize; +use shared_flash::MutexFlashStorage; pub static TIME_ACCESS: OnceLock> = OnceLock::new(); @@ -306,7 +309,15 @@ impl PlantHal { [u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN], [0u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN] ); - let flash_storage = mk_static!(FlashStorage, FlashStorage::new(peripherals.FLASH)); + + let bullshit = MutexFlashStorage { + inner: Arc::new(CriticalSectionMutex::new(RefCell::new(FlashStorage::new( + peripherals.FLASH, + )))), + }; + let flash_storage = mk_static!(MutexFlashStorage, bullshit.clone()); + let flash_storage_2 = mk_static!(MutexFlashStorage, bullshit.clone()); + let flash_storage_3 = mk_static!(MutexFlashStorage, bullshit.clone()); let pt = esp_bootloader_esp_idf::partitions::read_partition_table(flash_storage, tablebuffer)?; @@ -320,8 +331,8 @@ impl PlantHal { ); let ota_data = mk_static!( - FlashRegion, - ota_data.as_embedded_storage(flash_storage) + FlashRegion, + ota_data.as_embedded_storage(flash_storage_2) ); let state_0 = ota_state(AppPartitionSubType::Ota0, ota_data); @@ -353,7 +364,7 @@ impl PlantHal { let ota_target = mk_static!(PartitionEntry, ota_target); let ota_target = mk_static!( - FlashRegion, + FlashRegion, ota_target.as_embedded_storage(flash_storage) ); @@ -365,8 +376,8 @@ impl PlantHal { let data_partition = mk_static!(PartitionEntry, data_partition); let data = mk_static!( - FlashRegion, - data_partition.as_embedded_storage(flash_storage) + FlashRegion, + data_partition.as_embedded_storage(flash_storage_3) ); let lfs2filesystem = mk_static!(LittleFs2Filesystem, LittleFs2Filesystem { storage: data }); let alloc = mk_static!(Allocation, lfs2Filesystem::allocate()); @@ -584,15 +595,18 @@ impl PlantHal { } } -fn ota_state(slot: AppPartitionSubType, ota_data: &mut FlashRegion) -> OtaImageState { +fn ota_state( + slot: AppPartitionSubType, + ota_data: &mut FlashRegion, +) -> OtaImageState { // Read and log OTA states for both slots before constructing Ota // Each OTA select entry is 32 bytes: [seq:4][label:20][state:4][crc:4] // Offsets within the OTA data partition: slot0 @ 0x0000, slot1 @ 0x1000 let mut slot_buf = [0u8; 32]; if slot == AppPartitionSubType::Ota0 { - let _ = ota_data.read(0x0000, &mut slot_buf); + let _ = ReadStorage::read(ota_data, 0x0000, &mut slot_buf); } else { - let _ = ota_data.read(0x1000, &mut slot_buf); + let _ = ReadStorage::read(ota_data, 0x1000, &mut slot_buf); } let raw_state = u32::from_le_bytes(slot_buf[24..28].try_into().unwrap_or([0xff; 4])); @@ -600,7 +614,7 @@ fn ota_state(slot: AppPartitionSubType, ota_data: &mut FlashRegion } fn get_current_slot_and_fix_ota_data( - ota: &mut Ota, + ota: &mut Ota, state0: OtaImageState, state1: OtaImageState, ) -> Result { diff --git a/Software/MainBoard/rust/src/hal/shared_flash.rs b/Software/MainBoard/rust/src/hal/shared_flash.rs new file mode 100644 index 0000000..69bd76e --- /dev/null +++ b/Software/MainBoard/rust/src/hal/shared_flash.rs @@ -0,0 +1,63 @@ +use alloc::sync::Arc; +use core::cell::RefCell; +use core::ops::{Deref, DerefMut}; +use embassy_sync::blocking_mutex::CriticalSectionMutex; +use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; +use embedded_storage::ReadStorage; +use esp_storage::{FlashStorage, FlashStorageError}; + +#[derive(Clone)] +pub struct MutexFlashStorage { + pub(crate) inner: Arc>>>, +} + +impl ReadStorage for MutexFlashStorage { + type Error = FlashStorageError; + + fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), FlashStorageError> { + self.inner + .lock(|f| ReadStorage::read(f.borrow_mut().deref_mut(), offset, bytes)) + } + + fn capacity(&self) -> usize { + self.inner + .lock(|f| ReadStorage::capacity(f.borrow().deref())) + } +} + +impl embedded_storage::Storage for MutexFlashStorage { + fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + NorFlash::write(self, offset, bytes) + } +} + +impl ErrorType for MutexFlashStorage { + type Error = FlashStorageError; +} + +impl ReadNorFlash for MutexFlashStorage { + const READ_SIZE: usize = 0; + + fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { + ReadStorage::read(self, offset, bytes) + } + + fn capacity(&self) -> usize { + ReadStorage::capacity(self) + } +} + +impl NorFlash for MutexFlashStorage { + const WRITE_SIZE: usize = 0; + const ERASE_SIZE: usize = 0; + + fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + self.inner + .lock(|f| NorFlash::erase(f.borrow_mut().deref_mut(), from, to)) + } + + fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + self.inner + .lock(|f| NorFlash::write(f.borrow_mut().deref_mut(), offset, bytes)) + } +} diff --git a/Software/MainBoard/rust/src/hal/v4_sensor.rs b/Software/MainBoard/rust/src/hal/v4_sensor.rs index d618616..f38a47b 100644 --- a/Software/MainBoard/rust/src/hal/v4_sensor.rs +++ b/Software/MainBoard/rust/src/hal/v4_sensor.rs @@ -101,8 +101,9 @@ impl SensorInteraction for SensorImpl { Timer::after_millis(10).await; let mut moistures = Moistures::default(); - let _ = Self::wait_for_can_measurements(&mut twai, &mut moistures).with_timeout(Duration::from_millis(5000)).await; - + let _ = Self::wait_for_can_measurements(&mut twai, &mut moistures) + .with_timeout(Duration::from_millis(5000)) + .await; can_power.set_low(); @@ -170,7 +171,7 @@ impl SensorImpl { can_power.set_low(); twai_config.replace(config); - let result= moistures.into(); + let result = moistures.into(); info!("Autodetection result: {result:?}"); Ok(result) @@ -182,7 +183,6 @@ impl SensorImpl { as_async: &mut Twai<'_, Async>, moistures: &mut Moistures, ) -> FatResult<()> { - loop { match as_async.receive_async().await { Ok(can_frame) => match can_frame.id() { @@ -200,7 +200,7 @@ impl SensorImpl { let plant = msg.1 as usize; let sensor = msg.2; let data = can_frame.data(); - + match sensor { SensorSlot::A => { moistures.sensor_a_hz[plant] = data[0] as f32; @@ -319,4 +319,4 @@ impl From for DetectionResult { } result } -} \ No newline at end of file +} diff --git a/Software/MainBoard/rust/src/plant_state.rs b/Software/MainBoard/rust/src/plant_state.rs index b4d2cca..87649c6 100644 --- a/Software/MainBoard/rust/src/plant_state.rs +++ b/Software/MainBoard/rust/src/plant_state.rs @@ -120,8 +120,12 @@ impl PlantState { let raw = moistures.sensor_a_hz[plant_id]; match map_range_moisture( raw, - board.board_hal.get_config().plants[plant_id].moisture_sensor_min_frequency.map(|a| a as f32), - board.board_hal.get_config().plants[plant_id].moisture_sensor_max_frequency.map(|b| b as f32), + board.board_hal.get_config().plants[plant_id] + .moisture_sensor_min_frequency + .map(|a| a as f32), + board.board_hal.get_config().plants[plant_id] + .moisture_sensor_max_frequency + .map(|b| b as f32), ) { Ok(moisture_percent) => MoistureSensorState::MoistureValue { raw_hz: raw, @@ -137,8 +141,12 @@ impl PlantState { let raw = moistures.sensor_b_hz[plant_id]; match map_range_moisture( raw, - board.board_hal.get_config().plants[plant_id].moisture_sensor_min_frequency.map(|a| a as f32), - board.board_hal.get_config().plants[plant_id].moisture_sensor_max_frequency.map(|b| b as f32) + board.board_hal.get_config().plants[plant_id] + .moisture_sensor_min_frequency + .map(|a| a as f32), + board.board_hal.get_config().plants[plant_id] + .moisture_sensor_max_frequency + .map(|b| b as f32), ) { Ok(moisture_percent) => MoistureSensorState::MoistureValue { raw_hz: raw, @@ -196,8 +204,12 @@ impl PlantState { (Some(moisture_a), Some(moisture_b)) => { (Some(((moisture_a + moisture_b) / 2.) as u8), (None, None)) } - (Some(moisture_percent), _) => (Some(moisture_percent as u8), (None, self.sensor_b.is_err())), - (_, Some(moisture_percent)) => (Some(moisture_percent as u8), (self.sensor_a.is_err(), None)), + (Some(moisture_percent), _) => { + (Some(moisture_percent as u8), (None, self.sensor_b.is_err())) + } + (_, Some(moisture_percent)) => { + (Some(moisture_percent as u8), (self.sensor_a.is_err(), None)) + } _ => (None, (self.sensor_a.is_err(), self.sensor_b.is_err())), } }