use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, rpc_service::RpcService}; use esp_hal::peripherals::FLASH; use esp_radio::wifi::sta::StationConfig; use esp_storage::FlashStorage; use heapless::String; use int_enum::IntEnum; use postcard::to_slice; use sequential_storage::{ cache::{Cache, Uncached}, map::{Key, MapConfig, MapStorage}, }; use serde::{Deserialize, Serialize}; use thiserror::Error; pub static CONFIG_SERVICE: RpcService = RpcService::new(); pub struct ConfigService { storage: MapStorage< ConfigKey, BlockingAsync>, Cache, >, data_buffer: [u8; 256], } impl ConfigService { pub async fn set_wifi_creds(&mut self, value: WifiCredentials) -> Result<(), ConfigError> { let mut buf = [0u8; 256]; to_slice(&value, &mut buf)?; self.storage .store_item(&mut self.data_buffer, &ConfigKey::Wifi, &buf) .await .map_err(|e| ConfigError::FlashError(e))?; // TODO: send the change to the wifi service // WIFI_SERVICE // .call(|s| s.set_station_config(esp_radio::wifi::Config::Station(value.into()))) // .await; Ok(()) } } #[derive(Debug, Deserialize, Serialize)] pub struct WifiCredentials { pub ssid: String<32>, pub password: String<32>, } impl From for StationConfig { fn from(value: WifiCredentials) -> Self { Self::default() .with_ssid(value.ssid.as_str()) .with_password(value.password.as_str().into()) } } pub async fn start_config(spawner: Spawner, flash: FLASH<'static>) { let storage = MapStorage::::new( BlockingAsync::new(FlashStorage::new(flash)), const { MapConfig::new(0x3F_0000..0x40_0000) }, Cache::new_uncached(), ); let service = ConfigService { storage: storage, data_buffer: [0u8; 256], }; spawner.spawn(handler(service).unwrap()); } #[embassy_executor::task] async fn handler(mut service: ConfigService) -> ! { CONFIG_SERVICE.run(&mut service).await } #[derive(Debug, Clone, Copy, PartialEq, Eq, IntEnum)] #[repr(u8)] enum ConfigKey { Wifi, } impl Key for ConfigKey { fn get_len(_: &[u8]) -> Result { Ok(1) } fn serialize_into( &self, buffer: &mut [u8], ) -> Result { let val = buffer .get_mut(0) .ok_or(sequential_storage::map::SerializationError::BufferTooSmall)?; *val = self.clone().into(); Ok(1) } fn deserialize_from( buffer: &[u8], ) -> Result<(Self, usize), sequential_storage::map::SerializationError> { let val = *buffer .get(0) .ok_or(sequential_storage::map::SerializationError::BufferTooSmall)?; Ok(( val.try_into() .map_err(|_| sequential_storage::map::SerializationError::InvalidData)?, 1, )) } } #[derive(Error, Debug)] pub enum ConfigError { #[error("Error serializing data: {0}")] SerializationError(#[from] postcard::Error), #[error("Error storing data on the flash: {0:?}")] FlashError(sequential_storage::Error), }