diff --git a/Cargo.lock b/Cargo.lock index 895f006..1686c28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,7 +116,7 @@ dependencies = [ "embassy-futures", "embedded-hal 1.0.0", "embedded-hal-bus 0.3.0", - "embedded-io", + "embedded-io 0.6.1", "embedded-storage", "embedded-storage-async", "enc424j600", @@ -145,7 +145,7 @@ dependencies = [ "serde", "serde-json-core", "serde_with", - "serial-settings", + "serial_settings", "smlang 0.8.0", "smoltcp-nal", "stm32f4xx-hal", @@ -275,6 +275,16 @@ dependencies = [ "darling_macro 0.20.10", ] +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + [[package]] name = "darling_core" version = "0.14.4" @@ -303,6 +313,19 @@ dependencies = [ "syn 2.0.99", ] +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.99", +] + [[package]] name = "darling_macro" version = "0.14.4" @@ -325,6 +348,17 @@ dependencies = [ "syn 2.0.99", ] +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.99", +] + [[package]] name = "debouncr" version = "0.2.2" @@ -446,14 +480,19 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +[[package]] +name = "embedded-io" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eb1aa714776b75c7e67e1da744b81a129b3ff919c8712b5e1b32252c1f07cc7" + [[package]] name = "embedded-nal" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a943fad5ed3d3f8a00f1e80f6bba371f1e7f0df28ec38477535eb318dc19cc" +checksum = "c56a28be191a992f28f178ec338a0bf02f63d7803244add736d026a471e6ed77" dependencies = [ "nb 1.1.0", - "no-std-net", ] [[package]] @@ -724,6 +763,16 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "heapless" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" +dependencies = [ + "hash32 0.3.1", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.5.0" @@ -858,7 +907,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb20200e7bbede2f1f10ad3aac9ae0f4755233795801dbb42a241c19713ec875" dependencies = [ - "embedded-io", + "embedded-io 0.6.1", "rustversion", ] @@ -871,10 +920,10 @@ dependencies = [ [[package]] name = "miniconf" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1503186d3a89d933300e616a919e10b089a8c3379956589d009556ed5ea1b3c4" +version = "0.20.1" +source = "git+https://github.com/quartiq/miniconf.git#696455b8a58f4ff454fe0326bedd2446a20a2c9b" dependencies = [ + "heapless 0.8.0", "itoa", "miniconf_derive", "postcard", @@ -885,11 +934,10 @@ dependencies = [ [[package]] name = "miniconf_derive" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbe8f870567988a09000856955ae194f2dfb1ff73ff615988a44d0fc2385df7b" +version = "0.20.0" +source = "git+https://github.com/quartiq/miniconf.git#696455b8a58f4ff454fe0326bedd2446a20a2c9b" dependencies = [ - "darling 0.20.10", + "darling 0.23.0", "proc-macro2", "quote", "syn 2.0.99", @@ -897,43 +945,40 @@ dependencies = [ [[package]] name = "miniconf_mqtt" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18beed978188ff9ec7ce6f1a10a0d0e6d821fb4742021498662f4ddaa8e02892" +version = "0.20.0" +source = "git+https://github.com/quartiq/miniconf.git#696455b8a58f4ff454fe0326bedd2446a20a2c9b" dependencies = [ - "embedded-io", - "heapless 0.8.0", + "embedded-io 0.7.1", + "heapless 0.9.2", "log", "miniconf", "minimq", - "serde-json-core", "smlang 0.8.0", "strum", ] [[package]] name = "minimq" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c63955f174d014ef627e6f21dda747c24a294be94234e91ae30a9b2173784e1" +checksum = "8aca206883c70c23d8a8179533c0dad0f7c9abe6574c0dc0908e913203b6b6e3" dependencies = [ "bit_field", "embedded-nal", "embedded-time", - "heapless 0.7.17", + "heapless 0.8.0", "num_enum", "serde", - "smlang 0.6.0", + "smlang 0.8.0", "varint-rs", ] [[package]] name = "minireq" version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ccb1b67c4fa24f360531cbf7e67d7ce6f1ba980431a7461ed741ed707a1beb" +source = "git+https://github.com/quartiq/minireq#fb58f34e06d68801d86b6c96d8acf48f62b6435d" dependencies = [ - "embedded-io", + "embedded-io 0.6.1", "heapless 0.8.0", "log", "minimq", @@ -952,9 +997,9 @@ dependencies = [ [[package]] name = "nanorand" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +checksum = "6e3d189da485332e96ba8a5ef646a311871abd7915bf06ac848a9117f19cf6e4" [[package]] name = "nb" @@ -971,12 +1016,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" -[[package]] -name = "no-std-net" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" - [[package]] name = "num" version = "0.3.1" @@ -1383,12 +1422,11 @@ dependencies = [ ] [[package]] -name = "serial-settings" +name = "serial_settings" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0022c5aba5f3f97b82d5d9ddc34e53385761a0959bc3159fc0b6509a51bcb794" +source = "git+https://github.com/quartiq/stabilizer#5d7a40dc960a01bd93f0bbd6a86850f5f6265e45" dependencies = [ - "embedded-io", + "embedded-io 0.6.1", "heapless 0.8.0", "log", "menu", @@ -1458,8 +1496,9 @@ dependencies = [ [[package]] name = "smoltcp" -version = "0.11.0" -source = "git+https://github.com/smoltcp-rs/smoltcp?rev=53caf70f640d5ccb3cd1492e1cb178bc7dfa3cdd#53caf70f640d5ccb3cd1492e1cb178bc7dfa3cdd" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb" dependencies = [ "bitflags 1.3.2", "byteorder", @@ -1470,13 +1509,12 @@ dependencies = [ [[package]] name = "smoltcp-nal" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975f15c4c77e7798c236b542032891f0cafe5f2e103debe59d069d50a645ed8a" +version = "0.7.0" +source = "git+https://github.com/quartiq/smoltcp-nal#0c683a0bf75e8ca2e74c57914da03873897aaa39" dependencies = [ "embedded-nal", "embedded-time", - "heapless 0.7.17", + "heapless 0.8.0", "nanorand", "shared-bus", "smoltcp", @@ -1524,7 +1562,7 @@ dependencies = [ "embedded-hal 0.2.7", "embedded-hal 1.0.0", "embedded-hal-nb", - "embedded-io", + "embedded-io 0.6.1", "embedded-storage", "enumflags2", "fugit", @@ -1557,23 +1595,22 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.4" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" dependencies = [ "heck", "proc-macro2", "quote", - "rustversion", "syn 2.0.99", ] @@ -1732,7 +1769,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "065e4eaf93db81d5adac82d9cef8f8da314cb640fa7f89534b972383f1cf80fc" dependencies = [ "embedded-hal 0.2.7", - "embedded-io", + "embedded-io 0.6.1", "nb 1.1.0", "usb-device", ] @@ -1778,12 +1815,11 @@ dependencies = [ [[package]] name = "w5500" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1126ec36b5eebffd22607d00573db3c05808cf84caebfcbe4525c250f0420235" +checksum = "b9c89c027282c4cf46de82c6c5f0267d16ca84985b414b13ddb5707acf8ea564" dependencies = [ "bit_field", - "byteorder", "derive-try-from-primitive", "embedded-hal 1.0.0", "embedded-nal", diff --git a/Cargo.toml b/Cargo.toml index 224332d..6f96658 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,20 +51,20 @@ usbd-serial = "0.2.2" encdec = { version = "0.10", default-features = false } crc-any = { version = "2.5.0", default-features = false } panic-persist = { version = "0.3", features = ["custom-panic-handler", "utf8"] } -miniconf = { version = "0.18.0", features = ["json-core", "derive", "postcard"]} +miniconf = { version = "0.20", features = ["json-core", "derive", "postcard"]} # NOTE: Keep this in sync with `py/pyproject.toml`. -miniconf_mqtt = "0.18.0" +miniconf_mqtt = "0.20" # NOTE: Keep this in sync with the version used by `miniconf_mqtt`. -minimq = "0.9.0" -w5500 = "0.5" +minimq = "0.10.0" +w5500 = "0.6" smlang= "0.8" minireq = "0.5" rtt-target = { version = "0.6", optional = true } enum-iterator = { version = "2.1", default-features = false } enc424j600 = "0.4" embedded-hal = "1" -smoltcp-nal = { version = "0.5", features=["shared-stack"] } -serial-settings = "0.2" +smoltcp-nal = { version = "0.7", features=["shared-stack"] } +serial_settings = "0.2" stm32f4xx-hal = {version = "0.22.1", features = ["stm32f407", "usb_fs"] } postcard = "1" @@ -78,11 +78,13 @@ built = { version = "0.7", features = ["git2"], default-features = false } path = "ad5627" version = "0.2" -[patch.crates-io.smoltcp] -# Locking to a patch where the poll() function no longer loops infinitely during packet floods. This -# can be removed once smoltcp is re-released. -git = "https://github.com/smoltcp-rs/smoltcp" -rev = "53caf70f640d5ccb3cd1492e1cb178bc7dfa3cdd" +[patch.crates-io] +miniconf = { git = "https://github.com/quartiq/miniconf.git" } +miniconf_mqtt = { git = "https://github.com/quartiq/miniconf.git" } +miniconf_derive = { git = "https://github.com/quartiq/miniconf.git" } +minireq = { git = "https://github.com/quartiq/minireq" } +serial_settings = { git = "https://github.com/quartiq/stabilizer" } +smoltcp-nal = { git = "https://github.com/quartiq/smoltcp-nal" } [dependencies.ads7924] path = "ads7924" diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..292fe49 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" diff --git a/src/hardware/external_mac.rs b/src/hardware/external_mac.rs index 97df944..2c7d1e2 100644 --- a/src/hardware/external_mac.rs +++ b/src/hardware/external_mac.rs @@ -62,11 +62,11 @@ pub struct RxToken { } impl smoltcp::phy::RxToken for RxToken { - fn consume(mut self, f: F) -> R + fn consume(self, f: F) -> R where - F: FnOnce(&mut [u8]) -> R, + F: FnOnce(&[u8]) -> R, { - f(&mut self.frame_buffer[..self.length]) + f(&self.frame_buffer[..self.length]) } } diff --git a/src/hardware/mod.rs b/src/hardware/mod.rs index 726fe1e..0606136 100644 --- a/src/hardware/mod.rs +++ b/src/hardware/mod.rs @@ -48,7 +48,7 @@ pub enum Mac { pub type SerialSettingsPlatform = crate::settings::flash::SerialSettingsPlatform; -pub type SerialTerminal = serial_settings::Runner<'static, SerialSettingsPlatform, 5>; +pub type SerialTerminal = serial_settings::Runner<'static, SerialSettingsPlatform>; pub type NetworkStack = smoltcp_nal::NetworkStack<'static, Mac, SystemTimer>; diff --git a/src/hardware/rf_channel.rs b/src/hardware/rf_channel.rs index 4afa31c..64b3a8a 100644 --- a/src/hardware/rf_channel.rs +++ b/src/hardware/rf_channel.rs @@ -362,7 +362,7 @@ impl RfChannel { .set_voltage( settings .output_power_transform - .invert(*settings.output_interlock_threshold), + .invert(settings.output_interlock_threshold), ad5627::Dac::B, ) .map_err(|e| match e { @@ -417,10 +417,10 @@ impl RfChannel { let bias_changed = new_settings.bias_voltage != settings.bias_voltage; let output_interlock_updated = settings .output_power_transform - .map(*settings.output_interlock_threshold) + .map(settings.output_interlock_threshold) != new_settings .output_power_transform - .map(*new_settings.output_interlock_threshold); + .map(new_settings.output_interlock_threshold); let reflected_interlock_updated = settings .reflected_power_transform .map(platform::MAXIMUM_REFLECTED_POWER_DBM) @@ -456,7 +456,7 @@ impl RfChannel { fn apply_bias(&mut self) -> Result { // The bias voltage is the inverse of the DAC output voltage. - let bias_voltage = -*self.settings().bias_voltage; + let bias_voltage = -self.settings().bias_voltage; match self.devices.bias_dac.set_voltage(bias_voltage) { Err(dac7571::Error::Bounds) => Err(Error::Bounds), @@ -576,7 +576,7 @@ impl RfChannel { /// Get the current bias voltage programmed to the RF amplification transistor. pub fn get_bias_voltage(&self) -> f32 { - *self.settings.settings().bias_voltage + self.settings.settings().bias_voltage } pub fn settings(&self) -> &ChannelSettings { @@ -697,7 +697,7 @@ impl sm::StateMachineContext for RfChannel { /// Ok if the channel can power up. Err otherwise. fn guard_powerup(&self) -> Result { let settings = self.settings.settings(); - Ok(*settings.state != ChannelState::Off) + Ok(settings.state != ChannelState::Off) } /// Check to see if it's currently acceptable to enable the RF output switch. @@ -717,12 +717,12 @@ impl sm::StateMachineContext for RfChannel { // As a workaround, we need to ensure that the interlock level is above the output power // detector level. When RF is disabled, the power detectors output a near-zero value, so // 100mV should be a sufficient level. - if *settings.output_interlock_threshold < settings.output_power_transform.map(0.100) { + if settings.output_interlock_threshold < settings.output_power_transform.map(0.100) { return Ok(false); } // Do not enable output if it shouldn't be enabled due to settings. - if *settings.state != ChannelState::Enabled { + if settings.state != ChannelState::Enabled { return Ok(false); } @@ -739,7 +739,7 @@ impl sm::StateMachineContext for RfChannel { // It is only valid to enable the output if the channel is powered. assert!(self.pins.enable_power.is_set_high()); - assert!(*settings.output_interlock_threshold > settings.output_power_transform.map(0.100)); + assert!(settings.output_interlock_threshold > settings.output_power_transform.map(0.100)); self.apply_bias().unwrap(); self.pins.signal_on.set_high(); @@ -870,7 +870,7 @@ impl sm::StateMachine { pub fn handle_settings(&mut self, settings: &ChannelSettings) -> Result<(), Error> { self.context_mut().apply_settings(settings)?; - match (self.state(), *settings.state) { + match (self.state(), settings.state) { // It's always acceptable to power off. (_, ChannelState::Off) => { self.process_event(sm::Events::Disable).ok(); diff --git a/src/net/mod.rs b/src/net/mod.rs index c42b202..7cf33ed 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -2,7 +2,7 @@ use crate::hardware::{NetworkStack, SystemTimer}; -use core::fmt::Write; +use core::{fmt::Write, num::NonZero}; use heapless::String; pub mod mqtt_control; @@ -139,6 +139,8 @@ impl NetworkDevices { pub fn process(&mut self) -> bool { self.telemetry.update(); - self.stack.lock(|stack| stack.poll()).unwrap_or(true) + self.stack + .lock(|stack| stack.poll_n(const { NonZero::new(1).unwrap() })) + .unwrap_or(true) } } diff --git a/src/net/mqtt_control.rs b/src/net/mqtt_control.rs index 85d935b..8ad7b46 100644 --- a/src/net/mqtt_control.rs +++ b/src/net/mqtt_control.rs @@ -5,18 +5,18 @@ use crate::{ Channel, }; -use minimq::{DeferredPublication, Publication}; +use heapless::{String, Vec}; +use miniconf::{IntoKeys, Keys, NodeIter, Path, TreeSchema}; +use minimq::Publication; +use serde::Serialize; +use serial_settings::Platform; use super::NetworkStackProxy; use core::fmt::Write; -use heapless::{String, Vec}; -use serde::Serialize; use crate::hardware::SerialSettingsPlatform; use crate::settings::Settings; -use miniconf::{IntoKeys, Keys, Path, TreeKey}; -use serial_settings::Platform; /// Default metadata message if formatting errors occur. const DEFAULT_METADATA: &str = "{\"message\":\"Truncated: See USB terminal\"}"; @@ -124,12 +124,9 @@ impl TelemetryClient { // All telemtry is published in a best-effort manner. self.mqtt .client() - .publish( - DeferredPublication::new(|buf| serde_json_core::to_slice(telemetry, buf)) - .topic(&topic) - .finish() - .unwrap(), - ) + .publish(Publication::new(&topic, |buf: &mut [u8]| { + serde_json_core::to_slice(telemetry, buf) + })) .ok(); } @@ -155,23 +152,15 @@ impl TelemetryClient { if mqtt .client() - .publish( - DeferredPublication::new(|buf| serde_json_core::to_slice(&metadata, buf)) - .topic(&topic) - .finish() - .unwrap(), - ) + .publish(Publication::new(&topic, |buf: &mut [u8]| { + serde_json_core::to_slice(&metadata, buf) + })) .is_err() { // Note(unwrap): We can guarantee that this message will be sent because we checked // for ability to publish above. mqtt.client() - .publish( - Publication::new(DEFAULT_METADATA.as_bytes()) - .topic(&topic) - .finish() - .unwrap(), - ) + .publish(Publication::new(&topic, DEFAULT_METADATA.as_bytes())) .unwrap(); } @@ -250,25 +239,33 @@ pub fn save_settings_to_flash( let settings = channel.context().settings(); - let channel_root: Path<_, '/'> = Path("/booster/channel"); + let channel_root = Path::new("/booster/channel", '/'); let mut buf = [0u8; 256]; - for channel_path in Settings::nodes::, '/'>, 4>() - .root(channel_root.into_keys().chain([request.channel as usize])) - .unwrap() - { - let (channel_path, _) = channel_path.unwrap(); + + let it = NodeIter::>, 4>::with_root( + Settings::SCHEMA, + channel_root.into_keys().chain([request.channel as usize]), + '/', + ); + + for channel_path in it.unwrap() { + let channel_path = channel_path.unwrap(); let mut data: Vec = Vec::new(); data.resize(data.capacity(), 0).unwrap(); let flavor = postcard::ser_flavors::Slice::new(&mut data); - let len = miniconf::postcard::get_by_key(settings, channel_path.split('/').skip(4), flavor) - .unwrap() - .len(); + let len = miniconf::postcard::get_by_key( + settings, + channel_path.as_ref().split('/').skip(4), + flavor, + ) + .unwrap() + .len(); data.truncate(len); settings_platform - .store(&mut buf[..], channel_path.0.as_bytes(), &data) + .store(&mut buf[..], channel_path.as_ref().as_bytes(), &data) .map_err(|_| "Failed to save to flash")?; } diff --git a/src/settings/eeprom/main_board.rs b/src/settings/eeprom/main_board.rs index acd2173..c92e898 100644 --- a/src/settings/eeprom/main_board.rs +++ b/src/settings/eeprom/main_board.rs @@ -46,8 +46,8 @@ fn identifier_is_valid(id: &str) -> bool { pub struct IpAddr(pub smoltcp_nal::smoltcp::wire::Ipv4Address); impl IpAddr { - pub fn new(bytes: &[u8]) -> Self { - Self(smoltcp::wire::Ipv4Address::from_bytes(bytes)) + pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self { + Self(smoltcp::wire::Ipv4Address::new(a, b, c, d)) } } @@ -78,11 +78,11 @@ impl encdec::Encode for IpAddr { type Error = encdec::Error; fn encode_len(&self) -> Result { - Ok(self.0 .0.len()) + Ok(self.0.octets().len()) } fn encode(&self, buff: &mut [u8]) -> Result { - self.0 .0.encode(buff) + self.0.octets().encode(buff) } } @@ -91,8 +91,8 @@ impl encdec::DecodeOwned for IpAddr { type Error = encdec::Error; fn decode_owned(buff: &[u8]) -> Result<(Self::Output, usize), Self::Error> { - let (data, size) = <[u8; 4]>::decode_owned(buff)?; - Ok((Self::new(&data[..]), size)) + let ([a, b, c, d], size) = <[u8; 4]>::decode_owned(buff)?; + Ok((Self::new(a, b, c, d), size)) } } diff --git a/src/settings/eeprom/rf_channel.rs b/src/settings/eeprom/rf_channel.rs index c9988ec..dbdc6ab 100644 --- a/src/settings/eeprom/rf_channel.rs +++ b/src/settings/eeprom/rf_channel.rs @@ -4,13 +4,11 @@ use super::{ sinara::{BoardId as SinaraBoardId, SinaraConfiguration}, SemVersion, }; -use crate::{ - hardware::platform, hardware::I2cProxy, linear_transformation::LinearTransformation, Error, -}; +use crate::{hardware::I2cProxy, linear_transformation::LinearTransformation, Error}; use encdec::{Decode, DecodeOwned, Encode}; use enum_iterator::Sequence; use microchip_24aa02e48::Microchip24AA02E48; -use miniconf::{Leaf, Tree}; +use miniconf::Tree; use serde::{Deserialize, Serialize}; /// The expected semver of the BoosterChannelSettings. This version must be updated whenever the @@ -74,55 +72,85 @@ impl DecodeOwned for ChannelState { } } -/// Represents booster channel-specific configuration values. -#[derive(Tree, Encode, Debug, Copy, Clone, PartialEq)] -pub struct ChannelSettings { - // dBm - #[tree(validate=self.validate_output_interlock_threshold)] - pub output_interlock_threshold: Leaf, +mod validate_output_interlock_threshold { + pub use miniconf::{ + leaf::{self, *}, + Keys, SerdeError, + }; + use serde::Deserializer; + + use super::ChannelSettings; + use crate::hardware::platform::MAX_OUTPUT_POWER_DBM; + + /// [`TreeDeserialize::deserialize_by_key()`] + pub fn deserialize_by_key<'de, D: Deserializer<'de>>( + value: &mut ChannelSettings, + keys: impl Keys, + de: D, + ) -> Result<(), SerdeError> { + leaf::deserialize_by_key(&mut value.output_interlock_threshold, keys, de)?; + + if value.output_interlock_threshold > MAX_OUTPUT_POWER_DBM { + value.output_interlock_threshold = MAX_OUTPUT_POWER_DBM; + } - // V - #[tree(validate=self.validate_bias_voltage)] - pub bias_voltage: Leaf, + // Verify the interlock is mappable to a DAC threshold. + let dac_voltage = value + .output_power_transform + .invert(value.output_interlock_threshold); + let dac_voltage_clamped = dac_voltage.clamp(0.0, ad5627::MAX_VOLTAGE); + if dac_voltage_clamped != dac_voltage { + value.output_interlock_threshold = + value.output_power_transform.map(dac_voltage_clamped); + } + + Ok(()) + } +} + +mod validate_bias_voltage { + pub use miniconf::{leaf::*, Keys, SerdeError}; + use serde::{Deserialize, Deserializer}; - pub state: Leaf, + use crate::hardware::platform::BIAS_DAC_VCC; - pub input_power_transform: Leaf, + /// [`TreeDeserialize::deserialize_by_key()`] + pub fn deserialize_by_key<'de, D: Deserializer<'de>>( + value: &mut f32, + mut keys: impl Keys, + de: D, + ) -> Result<(), SerdeError> { + keys.finalize()?; + Deserialize::deserialize_in_place(de, value).map_err(SerdeError::Inner)?; - pub output_power_transform: Leaf, + *value = -(-*value).clamp(0.0, BIAS_DAC_VCC); - pub reflected_power_transform: Leaf, + Ok(()) + } } -impl DecodeOwned for ChannelSettings { - type Output = ChannelSettings; +/// Represents booster channel-specific configuration values. +#[derive(Tree, Encode, DecodeOwned, Serialize, Debug, Copy, Clone, PartialEq)] +pub struct ChannelSettings { + // dBm + #[tree(with=validate_output_interlock_threshold, defer=*self)] + pub output_interlock_threshold: f32, - type Error = encdec::Error; + // V + #[tree(with=validate_bias_voltage)] + pub bias_voltage: f32, - fn decode_owned(buff: &[u8]) -> Result<(Self::Output, usize), Self::Error> { - #[derive(Debug, DecodeOwned)] - struct ChannelSettingsDecoder { - pub output_interlock_threshold: f32, - pub bias_voltage: f32, - pub state: ChannelState, - pub input_power_transform: LinearTransformation, - pub output_power_transform: LinearTransformation, - pub reflected_power_transform: LinearTransformation, - } + #[tree(with=miniconf::leaf)] + pub state: ChannelState, - let (inner, inner_len) = ChannelSettingsDecoder::decode_owned(buff)?; - Ok(( - ChannelSettings { - output_interlock_threshold: Leaf(inner.output_interlock_threshold), - bias_voltage: Leaf(inner.bias_voltage), - state: Leaf(inner.state), - input_power_transform: Leaf(inner.input_power_transform), - output_power_transform: Leaf(inner.output_power_transform), - reflected_power_transform: Leaf(inner.reflected_power_transform), - }, - inner_len, - )) - } + #[tree(with=miniconf::leaf)] + pub input_power_transform: LinearTransformation, + + #[tree(with=miniconf::leaf)] + pub output_power_transform: LinearTransformation, + + #[tree(with=miniconf::leaf)] + pub reflected_power_transform: LinearTransformation, } impl Default for ChannelSettings { @@ -130,12 +158,12 @@ impl Default for ChannelSettings { fn default() -> Self { Self { // dBm - output_interlock_threshold: Leaf(20.0), + output_interlock_threshold: 20.0, // V - bias_voltage: Leaf(-3.2), + bias_voltage: -3.2, - state: Leaf(ChannelState::Off), + state: ChannelState::Off, // When operating at 100MHz, the power detectors specify the following output // characteristics for -10 dBm to 10 dBm: @@ -144,44 +172,16 @@ impl Default for ChannelSettings { // // All of the power meters are preceded by attenuators which are incorporated in // the offset. - output_power_transform: Leaf(LinearTransformation::new( - 1.0 / 0.035, - -35.6 + 19.8 + 10.0, - )), + output_power_transform: LinearTransformation::new(1.0 / 0.035, -35.6 + 19.8 + 10.0), // The input power and reflected power detectors have an op-amp gain of 1.5 - reflected_power_transform: Leaf(LinearTransformation::new( + reflected_power_transform: LinearTransformation::new( 1.0 / 1.5 / 0.035, -35.6 + 19.8 + 10.0, - )), - - input_power_transform: Leaf(LinearTransformation::new(1.0 / 1.5 / 0.035, -35.6 + 8.9)), - } - } -} - -impl ChannelSettings { - fn validate_bias_voltage(&mut self, depth: usize) -> Result { - *self.bias_voltage = -(-*self.bias_voltage).clamp(0.0, platform::BIAS_DAC_VCC); - Ok(depth) - } - - fn validate_output_interlock_threshold(&mut self, depth: usize) -> Result { - // Ensure the output interlock is within acceptable values. - if *self.output_interlock_threshold > platform::MAX_OUTPUT_POWER_DBM { - *self.output_interlock_threshold = platform::MAX_OUTPUT_POWER_DBM; - } + ), - // Verify the interlock is mappable to a DAC threshold. - let dac_voltage = self - .output_power_transform - .invert(*self.output_interlock_threshold); - let dac_voltage_clamped = dac_voltage.clamp(0.0, ad5627::MAX_VOLTAGE); - if dac_voltage_clamped != dac_voltage { - *self.output_interlock_threshold = self.output_power_transform.map(dac_voltage_clamped); + input_power_transform: LinearTransformation::new(1.0 / 1.5 / 0.035, -35.6 + 8.9), } - - Ok(depth) } } @@ -214,7 +214,7 @@ impl VersionedChannelData { let (data, _) = VersionedChannelData::decode_owned(data).or(Err(Error::Invalid))?; // Validate configuration parameters. - if *data.settings.bias_voltage < -3.3 || *data.settings.bias_voltage > 0.0 { + if data.settings.bias_voltage < -3.3 || data.settings.bias_voltage > 0.0 { return Err(Error::Invalid); } @@ -234,8 +234,8 @@ impl VersionedChannelData { // We will never store `Powered` in EEPROM, since this is never desired. Cache the current // power state while we serialize to ensure we only serialize Enabled and Off. let mut versioned_copy = *self; - if *versioned_copy.settings.state == ChannelState::Powered { - *versioned_copy.settings.state = ChannelState::Off; + if versioned_copy.settings.state == ChannelState::Powered { + versioned_copy.settings.state = ChannelState::Off; } let mut buffer: [u8; 64] = [0; 64]; diff --git a/src/settings/flash.rs b/src/settings/flash.rs index 7995564..76c474a 100644 --- a/src/settings/flash.rs +++ b/src/settings/flash.rs @@ -1,7 +1,7 @@ //! Booster NGFW Application use heapless::{String, Vec}; -use miniconf::{Path, TreeDeserializeOwned, TreeKey, TreeSerialize}; +use miniconf::{Path, TreeDeserializeOwned, TreeSerialize}; use crate::hardware::{flash::Flash, metadata::ApplicationMetadata, platform}; use embassy_futures::block_on; @@ -43,13 +43,13 @@ pub struct SerialSettingsPlatform { impl SerialSettingsPlatform where - C: TreeDeserializeOwned + TreeSerialize + TreeKey, + C: TreeDeserializeOwned + TreeSerialize, { pub fn load(structure: &mut C, storage: &mut Flash) { // Loop over flash and read settings let mut buffer = [0u8; 512]; - for path in C::nodes::, '/'>, 8>() { - let (path, _node) = path.unwrap(); + for path in C::nodes::>, 8>() { + let path = path.unwrap(); // Try to fetch the setting from flash. let value: &[u8] = match block_on(fetch_item( @@ -60,7 +60,7 @@ where &SettingsKey(path.clone().into_inner().into_bytes()), )) { Err(e) => { - log::warn!("Failed to fetch `{}` from flash: {e:?}", path.as_str()); + log::warn!("Failed to fetch `{}` from flash: {e:?}", path); continue; } Ok(Some(value)) => value, @@ -73,14 +73,11 @@ where continue; } - log::info!("Loading initial `{}` from flash", path.as_str()); + log::info!("Loading initial `{}` from flash", path); let flavor = postcard::de_flavors::Slice::new(value); if let Err(e) = miniconf::postcard::set_by_key(structure, &path, flavor) { - log::warn!( - "Failed to deserialize `{}` from flash: {e:?}", - path.as_str() - ); + log::warn!("Failed to deserialize `{}` from flash: {e:?}", path); } } } diff --git a/src/settings/runtime_settings.rs b/src/settings/runtime_settings.rs index d1fa568..c30fe61 100644 --- a/src/settings/runtime_settings.rs +++ b/src/settings/runtime_settings.rs @@ -6,13 +6,33 @@ use miniconf::{Leaf, Tree}; use crate::hardware::chassis_fans::DEFAULT_FAN_SPEED; use crate::net::mqtt_control::DEFAULT_TELEMETRY_PERIOD_SECS; +mod validate_fan_speed { + pub use miniconf::{ + leaf::{self, *}, + Keys, SerdeError, + }; + use serde::Deserializer; + + pub fn deserialize_by_key<'de, D: Deserializer<'de>>( + value: &mut f32, + keys: impl Keys, + de: D, + ) -> Result<(), SerdeError> { + leaf::deserialize_by_key(value, keys, de)?; + + *value = value.clamp(0.0, 1.0); + + Ok(()) + } +} + #[derive(Clone, Debug, Tree)] pub struct RuntimeSettings { pub channel: [Option; 8], /// The normalized fan speed. 1.0 corresponds to 100% on and 0.0 corresponds to completely /// off. - #[tree(validate=self.validate_fan_speed)] + #[tree(with=validate_fan_speed)] pub fan_speed: Leaf, /// The configured telemetry period in seconds. @@ -30,11 +50,6 @@ impl Default for RuntimeSettings { } impl RuntimeSettings { - fn validate_fan_speed(&mut self, depth: usize) -> Result { - *self.fan_speed = self.fan_speed.clamp(0.0, 1.0); - Ok(depth) - } - pub fn reset(&mut self) { for channel in self.channel.iter_mut().flatten() { *channel = ChannelSettings::default();