diff --git a/Cargo.lock b/Cargo.lock index 17aa59a..31711e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c583acf993cf4245c4acb0a2cc2ab1f9cc097de73411bb6d3647ff6af2b1013d" +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "autocfg" version = "1.5.1" @@ -203,6 +212,7 @@ dependencies = [ "esp-radio", "esp-rtos", "esp-storage", + "heapless 0.9.3", "int-enum", "picoserve", "portable-atomic", @@ -213,6 +223,7 @@ dependencies = [ "sntpc-net-embassy", "sntpc-time-embassy", "static_cell", + "thiserror", ] [[package]] @@ -1362,6 +1373,20 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32 0.2.1", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + [[package]] name = "heapless" version = "0.8.0" @@ -1382,6 +1407,7 @@ checksum = "25ba4bd83f9415b58b4ed8dc5714c76e626a105be4646c02630ad730ad3b5aa4" dependencies = [ "defmt 1.1.1", "hash32 0.3.1", + "serde_core", "stable_deref_trait", ] @@ -1735,6 +1761,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" dependencies = [ "cobs", + "defmt 1.1.1", + "heapless 0.7.17", "serde", ] @@ -1884,6 +1912,15 @@ dependencies = [ "rustversion", ] +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.23" @@ -1908,6 +1945,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "sequential-storage" version = "8.0.1" @@ -2051,6 +2094,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0f368519fc6c85fc1afdb769fb5a51123f6158013e143656e25a3485a0d401c" +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" diff --git a/Cargo.toml b/Cargo.toml index 17b2a67..b23ce9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,9 +63,11 @@ picoserve = { version = "0.19", features = ["defmt", "embassy", "json"] } sequential-storage = "8.0" esp-storage = { version = "0.9", features = ["defmt", "esp32c6"] } -postcard = { version = "1.1", default-features = false } +postcard = { version = "1.1", default-features = false, features = ["defmt", "heapless"] } serde = { version = "1.0", default-features = false, features = ["derive"] } int-enum = "1.2.0" +heapless = { version = "0.9.3", features = ["defmt", "serde"] } +thiserror = { version = "2.0.20", default-features = false } # For fine tuning these settings, please refer to https://doc.rust-lang.org/cargo/reference/profiles.html diff --git a/src/config.rs b/src/config.rs index f7c70b3..652255b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,26 +1,64 @@ use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embedded_rpc::RpcService; +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, SerializationError}, + map::{Key, MapConfig, MapStorage}, }; +use serde::{Deserialize, Serialize}; +use thiserror::Error; -pub enum ConfigCommand { - SetStationCreds(), -} - -impl ConfigCommand { - pub async fn set_station_creds() {} -} - -pub static CONFIG_SERVICE: RpcService = +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)), @@ -28,29 +66,17 @@ pub async fn start_config(spawner: Spawner, flash: FLASH<'static>) { Cache::new_uncached(), ); - spawner.spawn(config_handler(storage).unwrap()); + let service = ConfigService { + storage: storage, + data_buffer: [0u8; 256], + }; + + spawner.spawn(handler(service).unwrap()); } #[embassy_executor::task] -async fn config_handler(mut storage: MapStorage>, Cache>) { - let mut data_buffer = [0u8; 256]; - - loop { - let (req, served) = CONFIG_SERVICE.serve().await; - - match req { - ConfigCommand::SetStationCreds() => { - todo!() - // if storage - // .store_item(&mut data_buffer, &ConfigKey::Wifi, ) - // .await - // .is_ok() - // { - // served.respond(()); - // } - } - } - } +async fn handler(mut service: ConfigService) -> ! { + CONFIG_SERVICE.run(&mut service).await } #[derive(Debug, Clone, Copy, PartialEq, Eq, IntEnum)] @@ -60,18 +86,40 @@ enum ConfigKey { } impl Key for ConfigKey { - fn get_len(_: &[u8]) -> Result { + fn get_len(_: &[u8]) -> Result { Ok(1) } - fn serialize_into(&self, buffer: &mut [u8]) -> Result { - let val = buffer.get_mut(0).ok_or(SerializationError::BufferTooSmall)?; + 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), SerializationError> { - let val = *buffer.get(0).ok_or(SerializationError::BufferTooSmall)?; - Ok((val.try_into().map_err(|_| {SerializationError::InvalidData})?, 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), +}