From 41ba8251b289efe72ba3948f30f6474a5453ee50 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Fri, 10 Nov 2023 18:11:53 +0100 Subject: [PATCH 01/16] Adding initial support for configuring parameters via USB --- Cargo.lock | 66 +++++++++++++-- Cargo.toml | 10 ++- memory.x | 6 ++ src/hardware/flash.rs | 82 +++++++++++++++++++ src/hardware/mod.rs | 1 + src/hardware/serial_terminal.rs | 141 ++++++++++++++++++++++++++++++-- src/hardware/setup.rs | 11 ++- 7 files changed, 295 insertions(+), 22 deletions(-) create mode 100644 src/hardware/flash.rs diff --git a/Cargo.lock b/Cargo.lock index c7ebcc4bb..0d6f38fda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,12 @@ dependencies = [ "as-slice", ] +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "as-slice" version = "0.1.5" @@ -425,6 +431,12 @@ dependencies = [ "paste", ] +[[package]] +name = "menu" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03d7f798bfe97329ad6df937951142eec93886b37d87010502dd25e8cc75fd5" + [[package]] name = "miniconf" version = "0.9.0" @@ -594,6 +606,15 @@ dependencies = [ "num_enum_derive 0.5.11", ] +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", +] + [[package]] name = "num_enum" version = "0.7.1" @@ -614,6 +635,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "num_enum_derive" version = "0.7.1" @@ -631,6 +663,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "portable-atomic" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -783,6 +821,16 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "sequential-storage" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f108ff563239c0bbfcd6e72a82404d0d4682e18bbaf5a90fea1e2893318f7f9" +dependencies = [ + "arrayvec", + "embedded-storage", +] + [[package]] name = "serde" version = "1.0.190" @@ -904,6 +952,7 @@ dependencies = [ "cortex-m-rt", "cortex-m-rtic", "embedded-hal", + "embedded-storage", "enum-iterator", "fugit", "heapless", @@ -911,6 +960,7 @@ dependencies = [ "lm75", "log", "mcp230xx", + "menu", "miniconf", "minimq", "mono-clock", @@ -921,6 +971,7 @@ dependencies = [ "rand_xorshift", "rtt-logger", "rtt-target", + "sequential-storage", "serde", "serde-json-core", "shared-bus 0.3.1", @@ -953,8 +1004,6 @@ dependencies = [ [[package]] name = "stm32h7xx-hal" version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42323c63e7ee7b6979d9370ef7f381860bbd16653bd24a30cf26e78877dbf3fb" dependencies = [ "bare-metal 1.0.0", "cast", @@ -996,8 +1045,6 @@ dependencies = [ [[package]] name = "synopsys-usb-otg" version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678f3707a7b1fd4863023292c42f73c6bab0e9b0096f41ae612d1af0ff221b45" dependencies = [ "cortex-m 0.7.7", "embedded-hal", @@ -1037,17 +1084,18 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "usb-device" version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508" +dependencies = [ + "heapless", + "num_enum 0.6.1", + "portable-atomic", +] [[package]] name = "usbd-serial" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db75519b86287f12dcf0d171c7cf4ecc839149fe9f3b720ac4cfce52959e1dfe" dependencies = [ "embedded-hal", - "nb 0.1.3", + "nb 1.1.0", "usb-device", ] diff --git a/Cargo.toml b/Cargo.toml index 44333108b..0088d71da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,9 @@ default-target = "thumbv7em-none-eabihf" members = ["ad9959"] [dependencies] +embedded-storage = "0.3" +sequential-storage = "0.4" +menu = "0.3" cortex-m = { version = "0.7.7", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = { version = "0.7", features = ["device"] } log = { version = "0.4", features = ["max_level_trace", "release_max_level_info"] } @@ -61,15 +64,16 @@ rand_xorshift = "0.3.0" rand_core = "0.6.4" minimq = "0.8.0" # patch with https://github.com/rust-embedded-community/usb-device/pull/129 -usb-device = "0.2.9" -usbd-serial = "0.1.1" +usbd-serial = {path = "../../rust-embedded-community/usbd-serial"} # Keep this synced with the miniconf version in py/setup.py miniconf = "0.9.0" smoltcp-nal = { version = "0.4.1", features = ["shared-stack"]} bbqueue = "0.5" +usb-device = { path = "../../rust-embedded-community/usb-device" } [dependencies.stm32h7xx-hal] -version = "0.15.0" +path = "../stm32h7xx-hal" +#version = "0.15.0" features = ["stm32h743v", "rt", "ethernet", "xspi", "usb_hs"] [features] diff --git a/memory.x b/memory.x index 02afe9eba..ade59a942 100644 --- a/memory.x +++ b/memory.x @@ -44,3 +44,9 @@ BUG(cortex-m-rt): .itcm is not 8-byte aligned"); ASSERT(__siitcm % 4 == 0, " BUG(cortex-m-rt): the LMA of .itcm is not 4-byte aligned"); + +/* Place the stack in AXISRAM. + * Note: This is done because the sequential-storage crate needs to buffer flash sectors on + * the stack, each of which are 128KB. This can cause for excessive stack sizes. + */ +_stack_start = ORIGIN(AXISRAM) + LENGTH(AXISRAM); diff --git a/src/hardware/flash.rs b/src/hardware/flash.rs new file mode 100644 index 000000000..5afb162a5 --- /dev/null +++ b/src/hardware/flash.rs @@ -0,0 +1,82 @@ +use stm32h7xx_hal::flash::{UnlockedFlashBank, LockedFlashBank}; +use embedded_storage::nor_flash::NorFlash; +#[derive(Debug)] +pub enum StorageError { + JsonDe(serde_json_core::de::Error), + JsonSer(serde_json_core::ser::Error), +} + +impl From for StorageError { + fn from(e: serde_json_core::de::Error) -> Self { + Self::JsonDe(e) + } +} + +impl From for StorageError { + fn from(e: serde_json_core::ser::Error) -> Self { + Self::JsonSer(e) + } +} + +impl sequential_storage::map::StorageItemError for StorageError { + fn is_buffer_too_small(&self) -> bool { + match self { + Self::JsonSer(serde_json_core::ser::Error::BufferFull) => true, + Self::JsonDe(serde_json_core::de::Error::EofWhileParsingString) => true, + Self::JsonDe(serde_json_core::de::Error::EofWhileParsingList) => true, + Self::JsonDe(serde_json_core::de::Error::EofWhileParsingObject) => true, + Self::JsonDe(serde_json_core::de::Error::EofWhileParsingNumber) => true, + Self::JsonDe(serde_json_core::de::Error::EofWhileParsingValue) => true, + _ => false, + } + } +} + +macro_rules! storage_item { + ($len:literal, $key:literal, $name:ident) => { + pub struct $name(pub heapless::String<$len>); + + impl sequential_storage::map::StorageItem for $name { + type Key = &'static str; + type Error = StorageError; + + fn serialize_into(&self, buffer: &mut [u8]) -> Result { + Ok(serde_json_core::to_slice(&self.0, buffer)?) + } + + fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), Self::Error> { + Ok(serde_json_core::from_slice(buffer).map(|(item, size)| (Self(item), size))?) + } + + fn key(&self) -> Self::Key { + $key + } + } + } +} + + +storage_item!(23, "id", MqttIdentifier); +storage_item!(255, "broker", BrokerAddress); + +pub struct FlashSettings { + flash: LockedFlashBank, +} + +impl FlashSettings { + pub fn new(flash: LockedFlashBank) -> Self { + Self { flash } + } + + pub fn store_item(&mut self, item: impl sequential_storage::map::StorageItem) { + let mut bank = self.flash.unlocked(); + let range = (bank.address() as u32)..((bank.address() + bank.len()) as u32); + sequential_storage::map::store_item::<_, _, { ::ERASE_SIZE } >(&mut bank, range, item).unwrap(); + } + + pub fn fetch_item>(&mut self, key: &'static str) -> Option { + let mut bank = self.flash.unlocked(); + let range = (bank.address() as u32)..((bank.address() + bank.len()) as u32); + sequential_storage::map::fetch_item(&mut bank, range, key).unwrap() + } +} diff --git a/src/hardware/mod.rs b/src/hardware/mod.rs index 3f58bb8e5..9cd12f24b 100644 --- a/src/hardware/mod.rs +++ b/src/hardware/mod.rs @@ -16,6 +16,7 @@ pub mod setup; pub mod shared_adc; pub mod signal_generator; pub mod timers; +pub mod flash; mod eeprom; diff --git a/src/hardware/serial_terminal.rs b/src/hardware/serial_terminal.rs index 649ad2836..17a73dcb3 100644 --- a/src/hardware/serial_terminal.rs +++ b/src/hardware/serial_terminal.rs @@ -1,5 +1,55 @@ use super::UsbBus; use core::fmt::Write; +use crate::hardware::flash::{MqttIdentifier, BrokerAddress, FlashSettings}; + +struct Context { + output: OutputBuffer, + flash: FlashSettings, +} + +const ROOT_MENU: menu::Menu = menu::Menu { + label: "root", + items: &[ + &menu::Item { + command: "read", + help: Some("Read a property from the device: + +Available Properties: +* id: The MQTT ID of the device +* broker: The MQTT broker address"), + item_type: menu::ItemType::Callback { + function: handle_property_read, + parameters: &[menu::Parameter::Optional { + parameter_name: "property", + help: Some("The name of the property to read. If not specified, all properties are read"), + }] + }, + }, + &menu::Item { + command: "write", + help: Some("Write a property to the device: + +Available Properties: +* id: The MQTT ID of the device +* broker: The MQTT broker address"), + item_type: menu::ItemType::Callback { + function: handle_property_write, + parameters: &[ + menu::Parameter::Mandatory { + parameter_name: "property", + help: Some("The name of the property to write: [id, broker]"), + }, + menu::Parameter::Mandatory { + parameter_name: "value", + help: Some("Specifies the value to be written to the property."), + }, + ] + }, + }, + ], + entry: None, + exit: None, +}; static OUTPUT_BUFFER: bbqueue::BBBuffer<512> = bbqueue::BBBuffer::new(); @@ -25,22 +75,101 @@ impl Write for OutputBuffer { } } +impl core::fmt::Write for Context { + /// Write data to the serial terminal. + /// + /// # Note + /// The terminal uses an internal buffer. Overflows of the output buffer are silently ignored. + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.output.write_str(s) + } +} + +fn handle_property_read( + _menu: &menu::Menu, + item: &menu::Item, + args: &[&str], + context: &mut Context, +) { + let props: heapless::Vec<&'_ str, 2> = if let Some(prop) = menu::argument_finder(item, args, "property").unwrap() { + heapless::Vec::from_slice(&[prop]).unwrap() + } else { + heapless::Vec::from_slice(&["id", "broker"]).unwrap() + }; + + for prop in props { + write!(&mut context.output, "{prop}: ").unwrap(); + match prop { + "id" => { + let value = context.flash.fetch_item::("mqtt-id").unwrap().0; + writeln!(&mut context.output, "{value}").unwrap(); + } + + "broker" => { + let value = context.flash.fetch_item::("broker").unwrap().0; + writeln!(&mut context.output, "{value}").unwrap(); + } + + _ => { + writeln!(&mut context.output, "Unknown property").unwrap(); + return; + } + } + } +} + +fn handle_property_write( + _menu: &menu::Menu, + item: &menu::Item, + args: &[&str], + context: &mut Context, +) { + let property = menu::argument_finder(item, args, "property") + .unwrap() + .unwrap(); + let value = menu::argument_finder(item, args, "value").unwrap().unwrap(); + + // Now, write the new value into memory. + // TODO: Validate it first? + match property { + "id" => context.flash.store_item(MqttIdentifier(heapless::String::from(value))), + "broker" => context.flash.store_item(BrokerAddress(heapless::String::from(value))), + other => { + writeln!(&mut context.output, "Unknown property: {other}").unwrap(); + return; + } + } + + writeln!( + &mut context.output, + "Settings in memory may differ from currently operating settings. \ +Reset device to apply settings." + ) + .unwrap(); +} + pub struct SerialTerminal { usb_device: usb_device::device::UsbDevice<'static, UsbBus>, usb_serial: usbd_serial::SerialPort<'static, UsbBus>, + menu: menu::Runner<'static, Context>, output: bbqueue::Consumer<'static, 512>, - buffer: OutputBuffer, } impl SerialTerminal { pub fn new( usb_device: usb_device::device::UsbDevice<'static, UsbBus>, usb_serial: usbd_serial::SerialPort<'static, UsbBus>, + flash: FlashSettings, ) -> Self { let (producer, consumer) = OUTPUT_BUFFER.try_split().unwrap(); + let input_buffer = cortex_m::singleton!(: [u8; 255] = [0; 255]).unwrap(); + let context = Context { + output: OutputBuffer { producer }, + flash, + }; Self { - buffer: OutputBuffer { producer }, + menu: menu::Runner::new(&ROOT_MENU, input_buffer, context), usb_device, usb_serial, output: consumer, @@ -79,17 +208,17 @@ impl SerialTerminal { match self.usb_serial.read(&mut buffer) { Ok(count) => { for &value in &buffer[..count] { - writeln!(self.buffer, "echo: {}", value as char).unwrap(); + self.menu.input_byte(value); } } Err(usbd_serial::UsbError::WouldBlock) => {} Err(_) => { - // Clear the output buffer if USB is not connected. - while let Ok(grant) = self.output.read() { + self.menu.prompt(true); + self.output.read().map(|grant| { let len = grant.buf().len(); grant.release(len); - } + }).ok(); } } } diff --git a/src/hardware/setup.rs b/src/hardware/setup.rs index 0873aca43..4f10cccaf 100644 --- a/src/hardware/setup.rs +++ b/src/hardware/setup.rs @@ -19,6 +19,7 @@ use super::{ shared_adc::SharedAdc, timers, DigitalInput0, DigitalInput1, EemDigitalInput0, EemDigitalInput1, EemDigitalOutput0, EemDigitalOutput1, EthernetPhy, NetworkStack, SystemTimer, Systick, UsbBus, AFE0, AFE1, + flash::FlashSettings, }; const NUM_TCP_SOCKETS: usize = 4; @@ -1061,15 +1062,17 @@ pub fn setup( usb_bus.as_ref().unwrap(), usb_device::device::UsbVidPid(0x1209, 0x392F), ) - .manufacturer("ARTIQ/Sinara") - .product("Stabilizer") - .serial_number(serial_number.as_ref().unwrap()) + .strings(&[usb_device::device::StringDescriptors::default().manufacturer("ARTIQ/Sinara").product("Stabilizer").serial_number(serial_number.as_ref().unwrap())]).unwrap() .device_class(usbd_serial::USB_CLASS_CDC) .build(); (usb_device, serial) }; + let (_, flash_bank2) = device.FLASH.split(); + + let settings = FlashSettings::new(flash_bank2.unwrap()); + let stabilizer = StabilizerDevices { systick, afes, @@ -1084,7 +1087,7 @@ pub fn setup( timestamp_timer, digital_inputs, eem_gpio, - usb_serial: SerialTerminal::new(usb_device, usb_serial), + usb_serial: SerialTerminal::new(usb_device, usb_serial, settings), }; // info!("Version {} {}", build_info::PKG_VERSION, build_info::GIT_VERSION.unwrap()); From f4b312f98d5646503e2fe541185675eeb27e426c Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Fri, 10 Nov 2023 18:31:16 +0100 Subject: [PATCH 02/16] Use flash-backed config --- src/bin/dual-iir.rs | 5 +-- src/bin/lockin.rs | 3 +- src/hardware/flash.rs | 62 ++++++++++++++++++++++++--------- src/hardware/mod.rs | 2 +- src/hardware/serial_terminal.rs | 44 +++++++++++++++++------ src/hardware/setup.rs | 9 +++-- src/net/mod.rs | 56 +++++++++++++---------------- 7 files changed, 115 insertions(+), 66 deletions(-) diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index 5c27e50d4..8dad0af5b 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -208,7 +208,7 @@ mod app { let clock = SystemTimer::new(|| monotonics::now().ticks() as u32); // Configure the microcontroller - let (stabilizer, _pounder) = hardware::setup::setup( + let (mut stabilizer, _pounder) = hardware::setup::setup( c.core, c.device, clock, @@ -222,7 +222,8 @@ mod app { clock, env!("CARGO_BIN_NAME"), stabilizer.net.mac_address, - option_env!("BROKER").unwrap_or("mqtt"), + stabilizer.usb_serial.flash().fetch_item("broker"), + stabilizer.usb_serial.flash().fetch_item("id"), ); let generator = network.configure_streaming(StreamFormat::AdcDacData); diff --git a/src/bin/lockin.rs b/src/bin/lockin.rs index a116b4da1..4efc9c883 100644 --- a/src/bin/lockin.rs +++ b/src/bin/lockin.rs @@ -262,7 +262,8 @@ mod app { clock, env!("CARGO_BIN_NAME"), stabilizer.net.mac_address, - option_env!("BROKER").unwrap_or("mqtt"), + stabilizer.usb_serial.flash().fetch_item("broker"), + stabilizer.usb_serial.flash().fetch_item("id"), ); let generator = network.configure_streaming(StreamFormat::AdcDacData); diff --git a/src/hardware/flash.rs b/src/hardware/flash.rs index 5afb162a5..80f15493c 100644 --- a/src/hardware/flash.rs +++ b/src/hardware/flash.rs @@ -1,5 +1,5 @@ -use stm32h7xx_hal::flash::{UnlockedFlashBank, LockedFlashBank}; use embedded_storage::nor_flash::NorFlash; +use stm32h7xx_hal::flash::{LockedFlashBank, UnlockedFlashBank}; #[derive(Debug)] pub enum StorageError { JsonDe(serde_json_core::de::Error), @@ -22,11 +22,21 @@ impl sequential_storage::map::StorageItemError for StorageError { fn is_buffer_too_small(&self) -> bool { match self { Self::JsonSer(serde_json_core::ser::Error::BufferFull) => true, - Self::JsonDe(serde_json_core::de::Error::EofWhileParsingString) => true, - Self::JsonDe(serde_json_core::de::Error::EofWhileParsingList) => true, - Self::JsonDe(serde_json_core::de::Error::EofWhileParsingObject) => true, - Self::JsonDe(serde_json_core::de::Error::EofWhileParsingNumber) => true, - Self::JsonDe(serde_json_core::de::Error::EofWhileParsingValue) => true, + Self::JsonDe(serde_json_core::de::Error::EofWhileParsingString) => { + true + } + Self::JsonDe(serde_json_core::de::Error::EofWhileParsingList) => { + true + } + Self::JsonDe(serde_json_core::de::Error::EofWhileParsingObject) => { + true + } + Self::JsonDe(serde_json_core::de::Error::EofWhileParsingNumber) => { + true + } + Self::JsonDe(serde_json_core::de::Error::EofWhileParsingValue) => { + true + } _ => false, } } @@ -40,22 +50,27 @@ macro_rules! storage_item { type Key = &'static str; type Error = StorageError; - fn serialize_into(&self, buffer: &mut [u8]) -> Result { + fn serialize_into( + &self, + buffer: &mut [u8], + ) -> Result { Ok(serde_json_core::to_slice(&self.0, buffer)?) } - fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), Self::Error> { - Ok(serde_json_core::from_slice(buffer).map(|(item, size)| (Self(item), size))?) + fn deserialize_from( + buffer: &[u8], + ) -> Result<(Self, usize), Self::Error> { + Ok(serde_json_core::from_slice(buffer) + .map(|(item, size)| (Self(item), size))?) } fn key(&self) -> Self::Key { $key } } - } + }; } - storage_item!(23, "id", MqttIdentifier); storage_item!(255, "broker", BrokerAddress); @@ -68,15 +83,30 @@ impl FlashSettings { Self { flash } } - pub fn store_item(&mut self, item: impl sequential_storage::map::StorageItem) { + pub fn store_item( + &mut self, + item: impl sequential_storage::map::StorageItem, + ) { let mut bank = self.flash.unlocked(); - let range = (bank.address() as u32)..((bank.address() + bank.len()) as u32); - sequential_storage::map::store_item::<_, _, { ::ERASE_SIZE } >(&mut bank, range, item).unwrap(); + let range = + (bank.address() as u32)..((bank.address() + bank.len()) as u32); + sequential_storage::map::store_item::< + _, + _, + { ::ERASE_SIZE }, + >(&mut bank, range, item) + .unwrap(); } - pub fn fetch_item>(&mut self, key: &'static str) -> Option { + pub fn fetch_item< + I: sequential_storage::map::StorageItem, + >( + &mut self, + key: &'static str, + ) -> Option { let mut bank = self.flash.unlocked(); - let range = (bank.address() as u32)..((bank.address() + bank.len()) as u32); + let range = + (bank.address() as u32)..((bank.address() + bank.len()) as u32); sequential_storage::map::fetch_item(&mut bank, range, key).unwrap() } } diff --git a/src/hardware/mod.rs b/src/hardware/mod.rs index 9cd12f24b..a75cd1f39 100644 --- a/src/hardware/mod.rs +++ b/src/hardware/mod.rs @@ -9,6 +9,7 @@ pub mod cpu_temp_sensor; pub mod dac; pub mod delay; pub mod design_parameters; +pub mod flash; pub mod input_stamper; pub mod pounder; pub mod serial_terminal; @@ -16,7 +17,6 @@ pub mod setup; pub mod shared_adc; pub mod signal_generator; pub mod timers; -pub mod flash; mod eeprom; diff --git a/src/hardware/serial_terminal.rs b/src/hardware/serial_terminal.rs index 17a73dcb3..b48a20e00 100644 --- a/src/hardware/serial_terminal.rs +++ b/src/hardware/serial_terminal.rs @@ -1,6 +1,6 @@ use super::UsbBus; +use crate::hardware::flash::{BrokerAddress, FlashSettings, MqttIdentifier}; use core::fmt::Write; -use crate::hardware::flash::{MqttIdentifier, BrokerAddress, FlashSettings}; struct Context { output: OutputBuffer, @@ -91,7 +91,9 @@ fn handle_property_read( args: &[&str], context: &mut Context, ) { - let props: heapless::Vec<&'_ str, 2> = if let Some(prop) = menu::argument_finder(item, args, "property").unwrap() { + let props: heapless::Vec<&'_ str, 2> = if let Some(prop) = + menu::argument_finder(item, args, "property").unwrap() + { heapless::Vec::from_slice(&[prop]).unwrap() } else { heapless::Vec::from_slice(&["id", "broker"]).unwrap() @@ -101,12 +103,20 @@ fn handle_property_read( write!(&mut context.output, "{prop}: ").unwrap(); match prop { "id" => { - let value = context.flash.fetch_item::("mqtt-id").unwrap().0; + let value = context + .flash + .fetch_item::("mqtt-id") + .map(|inner| inner.0) + .unwrap_or_else(|| "".into()); writeln!(&mut context.output, "{value}").unwrap(); } "broker" => { - let value = context.flash.fetch_item::("broker").unwrap().0; + let value = context + .flash + .fetch_item::("broker") + .map(|inner| inner.0) + .unwrap_or_else(|| "mqtt".into()); writeln!(&mut context.output, "{value}").unwrap(); } @@ -132,8 +142,12 @@ fn handle_property_write( // Now, write the new value into memory. // TODO: Validate it first? match property { - "id" => context.flash.store_item(MqttIdentifier(heapless::String::from(value))), - "broker" => context.flash.store_item(BrokerAddress(heapless::String::from(value))), + "id" => context + .flash + .store_item(MqttIdentifier(heapless::String::from(value))), + "broker" => context + .flash + .store_item(BrokerAddress(heapless::String::from(value))), other => { writeln!(&mut context.output, "Unknown property: {other}").unwrap(); return; @@ -163,7 +177,8 @@ impl SerialTerminal { ) -> Self { let (producer, consumer) = OUTPUT_BUFFER.try_split().unwrap(); - let input_buffer = cortex_m::singleton!(: [u8; 255] = [0; 255]).unwrap(); + let input_buffer = + cortex_m::singleton!(: [u8; 255] = [0; 255]).unwrap(); let context = Context { output: OutputBuffer { producer }, flash, @@ -176,6 +191,10 @@ impl SerialTerminal { } } + pub fn flash(&mut self) -> &mut FlashSettings { + &mut self.menu.context.flash + } + fn flush(&mut self) { let read = match self.output.read() { Ok(grant) => grant, @@ -215,10 +234,13 @@ impl SerialTerminal { Err(usbd_serial::UsbError::WouldBlock) => {} Err(_) => { self.menu.prompt(true); - self.output.read().map(|grant| { - let len = grant.buf().len(); - grant.release(len); - }).ok(); + self.output + .read() + .map(|grant| { + let len = grant.buf().len(); + grant.release(len); + }) + .ok(); } } } diff --git a/src/hardware/setup.rs b/src/hardware/setup.rs index 4f10cccaf..bbf3e2518 100644 --- a/src/hardware/setup.rs +++ b/src/hardware/setup.rs @@ -14,12 +14,11 @@ use smoltcp_nal::smoltcp; use super::{ adc, afe, cpu_temp_sensor::CpuTempSensor, dac, delay, design_parameters, - eeprom, input_stamper::InputStamper, pounder, + eeprom, flash::FlashSettings, input_stamper::InputStamper, pounder, pounder::dds_output::DdsOutput, serial_terminal::SerialTerminal, shared_adc::SharedAdc, timers, DigitalInput0, DigitalInput1, EemDigitalInput0, EemDigitalInput1, EemDigitalOutput0, EemDigitalOutput1, EthernetPhy, NetworkStack, SystemTimer, Systick, UsbBus, AFE0, AFE1, - flash::FlashSettings, }; const NUM_TCP_SOCKETS: usize = 4; @@ -1062,7 +1061,11 @@ pub fn setup( usb_bus.as_ref().unwrap(), usb_device::device::UsbVidPid(0x1209, 0x392F), ) - .strings(&[usb_device::device::StringDescriptors::default().manufacturer("ARTIQ/Sinara").product("Stabilizer").serial_number(serial_number.as_ref().unwrap())]).unwrap() + .strings(&[usb_device::device::StringDescriptors::default() + .manufacturer("ARTIQ/Sinara") + .product("Stabilizer") + .serial_number(serial_number.as_ref().unwrap())]) + .unwrap() .device_class(usbd_serial::USB_CLASS_CDC) .build(); diff --git a/src/net/mod.rs b/src/net/mod.rs index 7e3b7b66b..cf8d6e118 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -13,7 +13,10 @@ pub mod data_stream; pub mod network_processor; pub mod telemetry; -use crate::hardware::{EthernetPhy, NetworkManager, NetworkStack, SystemTimer}; +use crate::hardware::{ + flash::{BrokerAddress, MqttIdentifier}, + EthernetPhy, NetworkManager, NetworkStack, SystemTimer, +}; use data_stream::{DataStream, FrameGenerator}; use network_processor::NetworkProcessor; use telemetry::TelemetryClient; @@ -95,23 +98,34 @@ where clock: SystemTimer, app: &str, mac: smoltcp_nal::smoltcp::wire::EthernetAddress, - broker: &str, + broker: Option, + id: Option, ) -> Self { let stack_manager = cortex_m::singleton!(: NetworkManager = NetworkManager::new(stack)) .unwrap(); + let id = if let Some(id) = id { + id.0 + } else { + let mut id: String<23> = String::new(); + write!(&mut id, "{mac}").unwrap(); + id + }; + + let broker = broker.map(|b| b.0).unwrap_or_else(|| "mqtt".into()); + let processor = NetworkProcessor::new(stack_manager.acquire_stack(), phy); - let prefix = get_device_prefix(app, mac); + let prefix = get_device_prefix(app, &id); let store = cortex_m::singleton!(: MqttStorage = MqttStorage::default()) .unwrap(); let named_broker = miniconf::minimq::broker::NamedBroker::new( - broker, + &broker, stack_manager.acquire_stack(), ) .unwrap(); @@ -124,13 +138,13 @@ where named_broker, &mut store.settings, ) - .client_id(&get_client_id(app, "settings", mac)) + .client_id(&id) .unwrap(), ) .unwrap(); let named_broker = minimq::broker::NamedBroker::new( - broker, + &broker, stack_manager.acquire_stack(), ) .unwrap(); @@ -141,7 +155,7 @@ where // The telemetry client doesn't receive any messages except MQTT control packets. // As such, we don't need much of the buffer for RX. .rx_buffer(minimq::config::BufferConfig::Maximum(100)) - .client_id(&get_client_id(app, "tlm", mac)) + .client_id(&id) .unwrap(), ); @@ -215,41 +229,19 @@ where } } -/// Get an MQTT client ID for a client. -/// -/// # Args -/// * `app` - The name of the application -/// * `client` - The unique tag of the client -/// * `mac` - The MAC address of the device. -/// -/// # Returns -/// A client ID that may be used for MQTT client identification. -fn get_client_id( - app: &str, - client: &str, - mac: smoltcp_nal::smoltcp::wire::EthernetAddress, -) -> String<64> { - let mut identifier = String::new(); - write!(&mut identifier, "{app}-{mac}-{client}").unwrap(); - identifier -} - /// Get the MQTT prefix of a device. /// /// # Args /// * `app` - The name of the application that is executing. -/// * `mac` - The ethernet MAC address of the device. +/// * `id` - The MQTT ID of the device. /// /// # Returns /// The MQTT prefix used for this device. -pub fn get_device_prefix( - app: &str, - mac: smoltcp_nal::smoltcp::wire::EthernetAddress, -) -> String<128> { +pub fn get_device_prefix(app: &str, id: &str) -> String<128> { // Note(unwrap): The mac address + binary name must be short enough to fit into this string. If // they are defined too long, this will panic and the device will fail to boot. let mut prefix: String<128> = String::new(); - write!(&mut prefix, "dt/sinara/{app}/{mac}").unwrap(); + write!(&mut prefix, "dt/sinara/{app}/{id}").unwrap(); prefix } From bf3b15ca19e06d327fe72162bcdbb5cb017077e6 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 13 Nov 2023 13:00:32 +0100 Subject: [PATCH 03/16] Simplifying flash backing --- Cargo.lock | 19 +---- Cargo.toml | 1 - src/bin/dual-iir.rs | 6 +- src/bin/lockin.rs | 6 +- src/hardware/flash.rs | 145 ++++++++++++-------------------- src/hardware/serial_terminal.rs | 72 +++++----------- src/hardware/setup.rs | 2 +- src/net/mod.rs | 27 ++---- 8 files changed, 92 insertions(+), 186 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d6f38fda..8b406516c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,12 +21,6 @@ dependencies = [ "as-slice", ] -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - [[package]] name = "as-slice" version = "0.1.5" @@ -821,16 +815,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -[[package]] -name = "sequential-storage" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f108ff563239c0bbfcd6e72a82404d0d4682e18bbaf5a90fea1e2893318f7f9" -dependencies = [ - "arrayvec", - "embedded-storage", -] - [[package]] name = "serde" version = "1.0.190" @@ -971,7 +955,6 @@ dependencies = [ "rand_xorshift", "rtt-logger", "rtt-target", - "sequential-storage", "serde", "serde-json-core", "shared-bus 0.3.1", @@ -1083,7 +1066,7 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "usb-device" -version = "0.2.9" +version = "0.3.0" dependencies = [ "heapless", "num_enum 0.6.1", diff --git a/Cargo.toml b/Cargo.toml index 0088d71da..14aba4662 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,6 @@ members = ["ad9959"] [dependencies] embedded-storage = "0.3" -sequential-storage = "0.4" menu = "0.3" cortex-m = { version = "0.7.7", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = { version = "0.7", features = ["device"] } diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index 8dad0af5b..2479985a2 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -216,14 +216,14 @@ mod app { SAMPLE_TICKS, ); + let flash = stabilizer.usb_serial.flash(); let mut network = NetworkUsers::new( stabilizer.net.stack, stabilizer.net.phy, clock, env!("CARGO_BIN_NAME"), - stabilizer.net.mac_address, - stabilizer.usb_serial.flash().fetch_item("broker"), - stabilizer.usb_serial.flash().fetch_item("id"), + &flash.settings.broker, + &flash.settings.id, ); let generator = network.configure_streaming(StreamFormat::AdcDacData); diff --git a/src/bin/lockin.rs b/src/bin/lockin.rs index 4efc9c883..18f8e6e34 100644 --- a/src/bin/lockin.rs +++ b/src/bin/lockin.rs @@ -256,14 +256,14 @@ mod app { SAMPLE_TICKS, ); + let flash = stabilizer.usb_serial.flash(); let mut network = NetworkUsers::new( stabilizer.net.stack, stabilizer.net.phy, clock, env!("CARGO_BIN_NAME"), - stabilizer.net.mac_address, - stabilizer.usb_serial.flash().fetch_item("broker"), - stabilizer.usb_serial.flash().fetch_item("id"), + &flash.settings.broker, + &flash.settings.id, ); let generator = network.configure_streaming(StreamFormat::AdcDacData); diff --git a/src/hardware/flash.rs b/src/hardware/flash.rs index 80f15493c..5952f2e04 100644 --- a/src/hardware/flash.rs +++ b/src/hardware/flash.rs @@ -1,112 +1,75 @@ -use embedded_storage::nor_flash::NorFlash; +use embedded_storage::nor_flash::{ReadNorFlash, NorFlash}; use stm32h7xx_hal::flash::{LockedFlashBank, UnlockedFlashBank}; -#[derive(Debug)] -pub enum StorageError { - JsonDe(serde_json_core::de::Error), - JsonSer(serde_json_core::ser::Error), -} +use core::fmt::Write; -impl From for StorageError { - fn from(e: serde_json_core::de::Error) -> Self { - Self::JsonDe(e) - } +#[derive(miniconf::Tree)] +pub struct Settings { + pub broker: heapless::String<255>, + pub id: heapless::String<23>, } -impl From for StorageError { - fn from(e: serde_json_core::ser::Error) -> Self { - Self::JsonSer(e) - } -} +impl Settings { + fn new(mac: smoltcp_nal::smoltcp::wire::EthernetAddress) -> Self { + let mut id = heapless::String::new(); + write!(&mut id, "{mac}").unwrap(); -impl sequential_storage::map::StorageItemError for StorageError { - fn is_buffer_too_small(&self) -> bool { - match self { - Self::JsonSer(serde_json_core::ser::Error::BufferFull) => true, - Self::JsonDe(serde_json_core::de::Error::EofWhileParsingString) => { - true - } - Self::JsonDe(serde_json_core::de::Error::EofWhileParsingList) => { - true - } - Self::JsonDe(serde_json_core::de::Error::EofWhileParsingObject) => { - true - } - Self::JsonDe(serde_json_core::de::Error::EofWhileParsingNumber) => { - true - } - Self::JsonDe(serde_json_core::de::Error::EofWhileParsingValue) => { - true - } - _ => false, + Self { + broker: "mqtt".into(), + id, } } } -macro_rules! storage_item { - ($len:literal, $key:literal, $name:ident) => { - pub struct $name(pub heapless::String<$len>); - - impl sequential_storage::map::StorageItem for $name { - type Key = &'static str; - type Error = StorageError; +pub struct FlashSettings { + flash: LockedFlashBank, + pub settings: Settings, +} - fn serialize_into( - &self, - buffer: &mut [u8], - ) -> Result { - Ok(serde_json_core::to_slice(&self.0, buffer)?) - } +impl FlashSettings { + pub fn new(mut flash: LockedFlashBank, mac: smoltcp_nal::smoltcp::wire::EthernetAddress) -> Self { + let mut settings = Settings::new(mac); + let mut buffer = [0u8; 256]; + let mut offset: usize = 0; - fn deserialize_from( - buffer: &[u8], - ) -> Result<(Self, usize), Self::Error> { - Ok(serde_json_core::from_slice(buffer) - .map(|(item, size)| (Self(item), size))?) + // We iteratively read the settings from flash to allow for easy expansion of the settings + // without losing data in the future when new fields are added. + flash.read(offset as u32, &mut buffer[..]).unwrap(); + settings.broker = { + match serde_json_core::from_slice(&buffer[..]) { + Ok((item, size)) => { + offset += size; + item + } + Err(_) => { + settings.broker + } } + }; - fn key(&self) -> Self::Key { - $key + flash.read(offset as u32, &mut buffer[..]).unwrap(); + settings.id = { + match serde_json_core::from_slice(&buffer[..]) { + Ok((item, size)) => { + offset += size; + item + } + Err(_) => { + settings.id + } } - } - }; -} - -storage_item!(23, "id", MqttIdentifier); -storage_item!(255, "broker", BrokerAddress); - -pub struct FlashSettings { - flash: LockedFlashBank, -} + }; -impl FlashSettings { - pub fn new(flash: LockedFlashBank) -> Self { - Self { flash } + Self { flash, settings } } - pub fn store_item( - &mut self, - item: impl sequential_storage::map::StorageItem, - ) { + pub fn save(&mut self) { let mut bank = self.flash.unlocked(); - let range = - (bank.address() as u32)..((bank.address() + bank.len()) as u32); - sequential_storage::map::store_item::< - _, - _, - { ::ERASE_SIZE }, - >(&mut bank, range, item) - .unwrap(); - } + let mut data = [0; 512]; + let mut offset: usize = 0; + offset += serde_json_core::to_slice(&self.settings.broker, &mut data[offset..]).unwrap(); + offset += serde_json_core::to_slice(&self.settings.id, &mut data[offset..]).unwrap(); - pub fn fetch_item< - I: sequential_storage::map::StorageItem, - >( - &mut self, - key: &'static str, - ) -> Option { - let mut bank = self.flash.unlocked(); - let range = - (bank.address() as u32)..((bank.address() + bank.len()) as u32); - sequential_storage::map::fetch_item(&mut bank, range, key).unwrap() + bank.erase(0, UnlockedFlashBank::ERASE_SIZE as u32).unwrap(); + bank.write(0, &data[..offset]).unwrap(); } } diff --git a/src/hardware/serial_terminal.rs b/src/hardware/serial_terminal.rs index b48a20e00..9ca452b14 100644 --- a/src/hardware/serial_terminal.rs +++ b/src/hardware/serial_terminal.rs @@ -1,6 +1,7 @@ use super::UsbBus; -use crate::hardware::flash::{BrokerAddress, FlashSettings, MqttIdentifier}; +use crate::hardware::flash::FlashSettings; use core::fmt::Write; +use miniconf::JsonCoreSlash; struct Context { output: OutputBuffer, @@ -15,8 +16,8 @@ const ROOT_MENU: menu::Menu = menu::Menu { help: Some("Read a property from the device: Available Properties: -* id: The MQTT ID of the device -* broker: The MQTT broker address"), +* /id: The MQTT ID of the device +* /broker: The MQTT broker address"), item_type: menu::ItemType::Callback { function: handle_property_read, parameters: &[menu::Parameter::Optional { @@ -30,8 +31,8 @@ Available Properties: help: Some("Write a property to the device: Available Properties: -* id: The MQTT ID of the device -* broker: The MQTT broker address"), +* /id: The MQTT ID of the device +* /broker: The MQTT broker address"), item_type: menu::ItemType::Callback { function: handle_property_write, parameters: &[ @@ -96,35 +97,14 @@ fn handle_property_read( { heapless::Vec::from_slice(&[prop]).unwrap() } else { - heapless::Vec::from_slice(&["id", "broker"]).unwrap() + heapless::Vec::from_slice(&["/id", "/broker"]).unwrap() }; - for prop in props { - write!(&mut context.output, "{prop}: ").unwrap(); - match prop { - "id" => { - let value = context - .flash - .fetch_item::("mqtt-id") - .map(|inner| inner.0) - .unwrap_or_else(|| "".into()); - writeln!(&mut context.output, "{value}").unwrap(); - } - - "broker" => { - let value = context - .flash - .fetch_item::("broker") - .map(|inner| inner.0) - .unwrap_or_else(|| "mqtt".into()); - writeln!(&mut context.output, "{value}").unwrap(); - } - - _ => { - writeln!(&mut context.output, "Unknown property").unwrap(); - return; - } - } + let mut buf = [0u8; 256]; + for path in props { + let len = context.flash.settings.get_json(&path, &mut buf).unwrap(); + let stringified = core::str::from_utf8(&buf[..len]).unwrap(); + write!(&mut context.output, "{path}: {stringified}").unwrap(); } } @@ -141,25 +121,19 @@ fn handle_property_write( // Now, write the new value into memory. // TODO: Validate it first? - match property { - "id" => context - .flash - .store_item(MqttIdentifier(heapless::String::from(value))), - "broker" => context - .flash - .store_item(BrokerAddress(heapless::String::from(value))), - other => { - writeln!(&mut context.output, "Unknown property: {other}").unwrap(); - return; + match context.flash.settings.set_json(property, value.as_bytes()) { + Ok(_) => { + writeln!( + &mut context.output, + "Settings in memory may differ from currently operating settings. \ + Reset device to apply settings." + ) + .unwrap(); + } + Err(e) => { + writeln!(&mut context.output, "Failed to update {property}: {e:?}").unwrap(); } } - - writeln!( - &mut context.output, - "Settings in memory may differ from currently operating settings. \ -Reset device to apply settings." - ) - .unwrap(); } pub struct SerialTerminal { diff --git a/src/hardware/setup.rs b/src/hardware/setup.rs index bbf3e2518..7f7037c3d 100644 --- a/src/hardware/setup.rs +++ b/src/hardware/setup.rs @@ -1074,7 +1074,7 @@ pub fn setup( let (_, flash_bank2) = device.FLASH.split(); - let settings = FlashSettings::new(flash_bank2.unwrap()); + let settings = FlashSettings::new(flash_bank2.unwrap(), network_devices.mac_address.clone()); let stabilizer = StabilizerDevices { systick, diff --git a/src/net/mod.rs b/src/net/mod.rs index cf8d6e118..bc18566fa 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -14,7 +14,6 @@ pub mod network_processor; pub mod telemetry; use crate::hardware::{ - flash::{BrokerAddress, MqttIdentifier}, EthernetPhy, NetworkManager, NetworkStack, SystemTimer, }; use data_stream::{DataStream, FrameGenerator}; @@ -87,7 +86,6 @@ where /// * `phy` - The ethernet PHY connecting the network. /// * `clock` - A `SystemTimer` implementing `Clock`. /// * `app` - The name of the application. - /// * `mac` - The MAC address of the network. /// * `broker` - The domain name of the MQTT broker to use. /// /// # Returns @@ -97,35 +95,24 @@ where phy: EthernetPhy, clock: SystemTimer, app: &str, - mac: smoltcp_nal::smoltcp::wire::EthernetAddress, - broker: Option, - id: Option, + broker: &str, + id: &str, ) -> Self { let stack_manager = cortex_m::singleton!(: NetworkManager = NetworkManager::new(stack)) .unwrap(); - let id = if let Some(id) = id { - id.0 - } else { - let mut id: String<23> = String::new(); - write!(&mut id, "{mac}").unwrap(); - id - }; - - let broker = broker.map(|b| b.0).unwrap_or_else(|| "mqtt".into()); - let processor = NetworkProcessor::new(stack_manager.acquire_stack(), phy); - let prefix = get_device_prefix(app, &id); + let prefix = get_device_prefix(app, id); let store = cortex_m::singleton!(: MqttStorage = MqttStorage::default()) .unwrap(); let named_broker = miniconf::minimq::broker::NamedBroker::new( - &broker, + broker, stack_manager.acquire_stack(), ) .unwrap(); @@ -138,13 +125,13 @@ where named_broker, &mut store.settings, ) - .client_id(&id) + .client_id(id) .unwrap(), ) .unwrap(); let named_broker = minimq::broker::NamedBroker::new( - &broker, + broker, stack_manager.acquire_stack(), ) .unwrap(); @@ -155,7 +142,7 @@ where // The telemetry client doesn't receive any messages except MQTT control packets. // As such, we don't need much of the buffer for RX. .rx_buffer(minimq::config::BufferConfig::Maximum(100)) - .client_id(&id) + .client_id(id) .unwrap(), ); From d536b8c69e775c0473db24399de9a9da56d97d25 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 13 Nov 2023 13:46:49 +0100 Subject: [PATCH 04/16] Revamping flash settings --- src/bin/dual-iir.rs | 2 +- src/bin/lockin.rs | 4 ++-- src/hardware/flash.rs | 12 ++++++++---- src/hardware/serial_terminal.rs | 5 +++-- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index 2479985a2..e629f451f 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -67,7 +67,7 @@ const BATCH_SIZE: usize = 8; // The logarithm of the number of 100MHz timer ticks between each sample. With a value of 2^7 = // 128, there is 1.28uS per sample, corresponding to a sampling frequency of 781.25 KHz. -const SAMPLE_TICKS_LOG2: u8 = 7; +const SAMPLE_TICKS_LOG2: u8 = 8; const SAMPLE_TICKS: u32 = 1 << SAMPLE_TICKS_LOG2; const SAMPLE_PERIOD: f32 = SAMPLE_TICKS as f32 * hardware::design_parameters::TIMER_PERIOD; diff --git a/src/bin/lockin.rs b/src/bin/lockin.rs index 18f8e6e34..e0accc39e 100644 --- a/src/bin/lockin.rs +++ b/src/bin/lockin.rs @@ -37,7 +37,7 @@ use core::{ use fugit::ExtU64; use mutex_trait::prelude::*; -use idsp::{Accu, Chain, Complex, ComplexExt, Filter, Lockin, Lowpass, RPLL}; +use idsp::{Accu, Complex, ComplexExt, Filter, Lockin, Lowpass, Repeat, RPLL}; use stabilizer::{ hardware::{ @@ -237,7 +237,7 @@ mod app { adcs: (Adc0Input, Adc1Input), dacs: (Dac0Output, Dac1Output), pll: RPLL, - lockin: Lockin>>, + lockin: Lockin>>, signal_generator: signal_generator::SignalGenerator, generator: FrameGenerator, cpu_temp_sensor: stabilizer::hardware::cpu_temp_sensor::CpuTempSensor, diff --git a/src/hardware/flash.rs b/src/hardware/flash.rs index 5952f2e04..300f6d95f 100644 --- a/src/hardware/flash.rs +++ b/src/hardware/flash.rs @@ -34,26 +34,30 @@ impl FlashSettings { // We iteratively read the settings from flash to allow for easy expansion of the settings // without losing data in the future when new fields are added. flash.read(offset as u32, &mut buffer[..]).unwrap(); + let len = buffer.iter().skip(1).position(|x| x == &b'"').unwrap_or(0) + 2; settings.broker = { - match serde_json_core::from_slice(&buffer[..]) { + match serde_json_core::from_slice(&buffer[..len]) { Ok((item, size)) => { offset += size; item } - Err(_) => { + Err(e) => { + log::warn!("Failed to decode broker from flash settings memory - using default: {e:?}"); settings.broker } } }; flash.read(offset as u32, &mut buffer[..]).unwrap(); + let len = buffer.iter().skip(1).position(|x| x == &b'"').unwrap_or(0) + 2; settings.id = { - match serde_json_core::from_slice(&buffer[..]) { + match serde_json_core::from_slice(&buffer[..len]) { Ok((item, size)) => { offset += size; item } - Err(_) => { + Err(e) => { + log::warn!("Failed to MQTT ID from flash settings memory - using default: {e:?}"); settings.id } } diff --git a/src/hardware/serial_terminal.rs b/src/hardware/serial_terminal.rs index 9ca452b14..7bea02c64 100644 --- a/src/hardware/serial_terminal.rs +++ b/src/hardware/serial_terminal.rs @@ -102,9 +102,9 @@ fn handle_property_read( let mut buf = [0u8; 256]; for path in props { - let len = context.flash.settings.get_json(&path, &mut buf).unwrap(); + let len = context.flash.settings.get_json(path, &mut buf).unwrap(); let stringified = core::str::from_utf8(&buf[..len]).unwrap(); - write!(&mut context.output, "{path}: {stringified}").unwrap(); + writeln!(&mut context.output, "{path}: {stringified}").unwrap(); } } @@ -123,6 +123,7 @@ fn handle_property_write( // TODO: Validate it first? match context.flash.settings.set_json(property, value.as_bytes()) { Ok(_) => { + context.flash.save(); writeln!( &mut context.output, "Settings in memory may differ from currently operating settings. \ From daaa7fee6fef99fcdc7aceaec72cd33dc01cc191 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 13 Nov 2023 13:51:53 +0100 Subject: [PATCH 05/16] Reverting unintended changes --- Cargo.lock | 45 +++++++++++-------------------------------- Cargo.toml | 7 +++---- memory.x | 6 ------ src/bin/dual-iir.rs | 2 +- src/bin/lockin.rs | 4 ++-- src/hardware/setup.rs | 8 +++----- 6 files changed, 20 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b406516c..693d2a05f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -600,15 +600,6 @@ dependencies = [ "num_enum_derive 0.5.11", ] -[[package]] -name = "num_enum" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" -dependencies = [ - "num_enum_derive 0.6.1", -] - [[package]] name = "num_enum" version = "0.7.1" @@ -629,17 +620,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "num_enum_derive" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - [[package]] name = "num_enum_derive" version = "0.7.1" @@ -657,12 +637,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" -[[package]] -name = "portable-atomic" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -986,7 +960,9 @@ dependencies = [ [[package]] name = "stm32h7xx-hal" -version = "0.15.0" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08bcfbdbe4458133f2fd55994a5c4f1b4bf28084f0218e93cdbc19d7c70219f" dependencies = [ "bare-metal 1.0.0", "cast", @@ -1028,6 +1004,8 @@ dependencies = [ [[package]] name = "synopsys-usb-otg" version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678f3707a7b1fd4863023292c42f73c6bab0e9b0096f41ae612d1af0ff221b45" dependencies = [ "cortex-m 0.7.7", "embedded-hal", @@ -1066,19 +1044,18 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "usb-device" -version = "0.3.0" -dependencies = [ - "heapless", - "num_enum 0.6.1", - "portable-atomic", -] +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508" [[package]] name = "usbd-serial" version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db75519b86287f12dcf0d171c7cf4ecc839149fe9f3b720ac4cfce52959e1dfe" dependencies = [ "embedded-hal", - "nb 1.1.0", + "nb 0.1.3", "usb-device", ] diff --git a/Cargo.toml b/Cargo.toml index 14aba4662..6e0fc2f7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,16 +63,15 @@ rand_xorshift = "0.3.0" rand_core = "0.6.4" minimq = "0.8.0" # patch with https://github.com/rust-embedded-community/usb-device/pull/129 -usbd-serial = {path = "../../rust-embedded-community/usbd-serial"} +usb-device = "0.2.9" +usbd-serial = "0.1.1" # Keep this synced with the miniconf version in py/setup.py miniconf = "0.9.0" smoltcp-nal = { version = "0.4.1", features = ["shared-stack"]} bbqueue = "0.5" -usb-device = { path = "../../rust-embedded-community/usb-device" } [dependencies.stm32h7xx-hal] -path = "../stm32h7xx-hal" -#version = "0.15.0" +version = "0.15.0" features = ["stm32h743v", "rt", "ethernet", "xspi", "usb_hs"] [features] diff --git a/memory.x b/memory.x index ade59a942..02afe9eba 100644 --- a/memory.x +++ b/memory.x @@ -44,9 +44,3 @@ BUG(cortex-m-rt): .itcm is not 8-byte aligned"); ASSERT(__siitcm % 4 == 0, " BUG(cortex-m-rt): the LMA of .itcm is not 4-byte aligned"); - -/* Place the stack in AXISRAM. - * Note: This is done because the sequential-storage crate needs to buffer flash sectors on - * the stack, each of which are 128KB. This can cause for excessive stack sizes. - */ -_stack_start = ORIGIN(AXISRAM) + LENGTH(AXISRAM); diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index e629f451f..2479985a2 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -67,7 +67,7 @@ const BATCH_SIZE: usize = 8; // The logarithm of the number of 100MHz timer ticks between each sample. With a value of 2^7 = // 128, there is 1.28uS per sample, corresponding to a sampling frequency of 781.25 KHz. -const SAMPLE_TICKS_LOG2: u8 = 8; +const SAMPLE_TICKS_LOG2: u8 = 7; const SAMPLE_TICKS: u32 = 1 << SAMPLE_TICKS_LOG2; const SAMPLE_PERIOD: f32 = SAMPLE_TICKS as f32 * hardware::design_parameters::TIMER_PERIOD; diff --git a/src/bin/lockin.rs b/src/bin/lockin.rs index e0accc39e..18f8e6e34 100644 --- a/src/bin/lockin.rs +++ b/src/bin/lockin.rs @@ -37,7 +37,7 @@ use core::{ use fugit::ExtU64; use mutex_trait::prelude::*; -use idsp::{Accu, Complex, ComplexExt, Filter, Lockin, Lowpass, Repeat, RPLL}; +use idsp::{Accu, Chain, Complex, ComplexExt, Filter, Lockin, Lowpass, RPLL}; use stabilizer::{ hardware::{ @@ -237,7 +237,7 @@ mod app { adcs: (Adc0Input, Adc1Input), dacs: (Dac0Output, Dac1Output), pll: RPLL, - lockin: Lockin>>, + lockin: Lockin>>, signal_generator: signal_generator::SignalGenerator, generator: FrameGenerator, cpu_temp_sensor: stabilizer::hardware::cpu_temp_sensor::CpuTempSensor, diff --git a/src/hardware/setup.rs b/src/hardware/setup.rs index 7f7037c3d..329518b8d 100644 --- a/src/hardware/setup.rs +++ b/src/hardware/setup.rs @@ -1061,11 +1061,9 @@ pub fn setup( usb_bus.as_ref().unwrap(), usb_device::device::UsbVidPid(0x1209, 0x392F), ) - .strings(&[usb_device::device::StringDescriptors::default() - .manufacturer("ARTIQ/Sinara") - .product("Stabilizer") - .serial_number(serial_number.as_ref().unwrap())]) - .unwrap() + .manufacturer("ARTIQ/Sinara") + .product("Stabilizer") + .serial_number(serial_number.as_ref().unwrap()) .device_class(usbd_serial::USB_CLASS_CDC) .build(); From 3200acf8a6750aea9ee7aa18061a8e2613347100 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 13 Nov 2023 14:01:08 +0100 Subject: [PATCH 06/16] fixing client ID issues --- src/net/mod.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/net/mod.rs b/src/net/mod.rs index bc18566fa..d0ad140f0 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -125,7 +125,7 @@ where named_broker, &mut store.settings, ) - .client_id(id) + .client_id(&get_client_id(id, "settings")) .unwrap(), ) .unwrap(); @@ -142,7 +142,7 @@ where // The telemetry client doesn't receive any messages except MQTT control packets. // As such, we don't need much of the buffer for RX. .rx_buffer(minimq::config::BufferConfig::Maximum(100)) - .client_id(id) + .client_id(&get_client_id(id, "tlm")) .unwrap(), ); @@ -216,6 +216,23 @@ where } } +/// Get an MQTT client ID for a client. +/// +/// # Args +/// * `id` - The base client ID +/// * `mode` - The operating mode of this client. (i.e. tlm, settings) +/// +/// # Returns +/// A client ID that may be used for MQTT client identification. +fn get_client_id( + id: &str, + mode: &str, +) -> String<64> { + let mut identifier = String::new(); + write!(&mut identifier, "{id}-{mode}").unwrap(); + identifier +} + /// Get the MQTT prefix of a device. /// /// # Args From 4112c8fa5940e493c4e67fb69d59b82bb719f584 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 13 Nov 2023 14:05:26 +0100 Subject: [PATCH 07/16] Updating broker docs --- book/src/setup.md | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/book/src/setup.md b/book/src/setup.md index e00d26bac..74b5bfb88 100644 --- a/book/src/setup.md +++ b/book/src/setup.md @@ -40,10 +40,8 @@ Stabilizer requires an MQTT broker that supports MQTTv5. The MQTT broker is used to distribute and exchange elemetry data and to view/change application settings. The broker must be reachable by both the host-side applications used to interact with the application on Stabilizer and by the application running on Stabilizer. -Determine the IPv4 address of the broker as seen from the network Stabilizer is -connected to. The broker IP address must be stable. It will be used later -during firmware build. -The broker must be reachable on port 1883 on that IP address. +The broker must be reachable on port 1883 on that IP address - it may either be an IP address or a +fully qualified domain name. Firewalls between Stabilizer and the broker may need to be configured to allow connections from Stabilizer to that port and IP address. @@ -83,23 +81,21 @@ docker run -p 1883:1883 --name mosquitto -v ${pwd}/mosquitto.conf:/mosquitto/con git clone https://github.com/quartiq/stabilizer cd stabilizer ``` -5. Build firmware specifying the MQTT broker IP. Replace `10.34.16.1` by the - stable and reachable broker IPv4 address determined above. +5. Build firmware ```bash # Bash - BROKER="10.34.16.1" cargo build --release + cargo build --release # Powershell - # Note: This sets the broker for all future builds as well. - $env:BROKER='10.34.16.1'; cargo build --release + cargo build --release ``` 6. Extract the application binary (substitute `dual-iir` below with the desired application name) ```bash # Bash - BROKER="10.34.16.1" cargo objcopy --release --bin dual-iir -- -O binary dual-iir.bin + cargo objcopy --release --bin dual-iir -- -O binary dual-iir.bin # Powershell - $env:BROKER='10.34.16.1'; cargo objcopy --release --bin dual-iir -- -O binary dual-iir.bin + cargo objcopy --release --bin dual-iir -- -O binary dual-iir.bin ``` ## Flashing @@ -163,16 +159,29 @@ described [above](#st-link-virtual-mass-storage). 2. Build and run firmware on the device ```bash # Bash - BROKER="10.34.16.1" cargo run --release --bin dual-iir + cargo run --release --bin dual-iir # Powershell - $Env:BROKER='10.34.16.1'; cargo run --release --bin dual-iir + cargo run --release --bin dual-iir ``` When using debug (non `--release`) mode, decrease the sampling frequency significantly. The added error checking code and missing optimizations may lead to the application missing timer deadlines and panicing. +## Set the MQTT broker + +The MQTT broker can be configured via the USB port on Stabilizer's front. Connect a USB cable and +open up the serial port in a serial terminal of your choice. `pyserial` provides a simple, +easy-to-use terminal emulator: +```sh +python -m serial +``` + +Once you have opened the port, you can use the provided menu to update the MQTT broker address. The +address can be an IP address or a domain name. Once the broker has been updated, power cycle +stabilizer to have the new broker address take affect. + ## Verify MQTT connection Once your MQTT broker and Stabilizer are both running, verify that the application @@ -190,7 +199,8 @@ Broker. ![MQTT Explorer Configuration](assets/mqtt-explorer.png) -> **Note:** In MQTT explorer, use the same broker address that you used when building the firmware. +> **Note:** In MQTT explorer, use the same broker address that you set in the Stabilizer serial +> terminal. In addition to the `alive` status, telemetry messages are published at regular intervals when Stabilizer has connected to the broker. Once you observe incoming telemetry, From 853288667340464efdca9942384e4233588025f0 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 13 Nov 2023 14:08:54 +0100 Subject: [PATCH 08/16] Adding reset command --- book/src/setup.md | 2 +- src/hardware/serial_terminal.rs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/book/src/setup.md b/book/src/setup.md index 74b5bfb88..1b280ee23 100644 --- a/book/src/setup.md +++ b/book/src/setup.md @@ -180,7 +180,7 @@ python -m serial Once you have opened the port, you can use the provided menu to update the MQTT broker address. The address can be an IP address or a domain name. Once the broker has been updated, power cycle -stabilizer to have the new broker address take affect. +stabilizer to have the new broker address take effect. ## Verify MQTT connection diff --git a/src/hardware/serial_terminal.rs b/src/hardware/serial_terminal.rs index 7bea02c64..c88e14598 100644 --- a/src/hardware/serial_terminal.rs +++ b/src/hardware/serial_terminal.rs @@ -11,6 +11,14 @@ struct Context { const ROOT_MENU: menu::Menu = menu::Menu { label: "root", items: &[ + &menu::Item { + command: "reset", + help: Some("Reset Stabilizer to force new settings to take effect."), + item_type: menu::ItemType::Callback { + function: handle_reset, + parameters: &[] + }, + }, &menu::Item { command: "read", help: Some("Read a property from the device: @@ -86,6 +94,15 @@ impl core::fmt::Write for Context { } } +fn handle_reset( + _menu: &menu::Menu, + _item: &menu::Item, + _args: &[&str], + _context: &mut Context, +) { + cortex_m::peripheral::SCB::sys_reset(); +} + fn handle_property_read( _menu: &menu::Menu, item: &menu::Item, From 5e59ea660b1aa80823e551dcab697efb873ad154 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 13 Nov 2023 14:17:51 +0100 Subject: [PATCH 09/16] Fixing after testing --- src/hardware/flash.rs | 26 ++++++++++++++++++-------- src/hardware/serial_terminal.rs | 13 +++++++++++-- src/hardware/setup.rs | 3 ++- src/net/mod.rs | 9 ++------- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/hardware/flash.rs b/src/hardware/flash.rs index 300f6d95f..6e0642973 100644 --- a/src/hardware/flash.rs +++ b/src/hardware/flash.rs @@ -1,6 +1,6 @@ -use embedded_storage::nor_flash::{ReadNorFlash, NorFlash}; -use stm32h7xx_hal::flash::{LockedFlashBank, UnlockedFlashBank}; use core::fmt::Write; +use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; +use stm32h7xx_hal::flash::{LockedFlashBank, UnlockedFlashBank}; #[derive(miniconf::Tree)] pub struct Settings { @@ -26,7 +26,10 @@ pub struct FlashSettings { } impl FlashSettings { - pub fn new(mut flash: LockedFlashBank, mac: smoltcp_nal::smoltcp::wire::EthernetAddress) -> Self { + pub fn new( + mut flash: LockedFlashBank, + mac: smoltcp_nal::smoltcp::wire::EthernetAddress, + ) -> Self { let mut settings = Settings::new(mac); let mut buffer = [0u8; 256]; let mut offset: usize = 0; @@ -34,7 +37,8 @@ impl FlashSettings { // We iteratively read the settings from flash to allow for easy expansion of the settings // without losing data in the future when new fields are added. flash.read(offset as u32, &mut buffer[..]).unwrap(); - let len = buffer.iter().skip(1).position(|x| x == &b'"').unwrap_or(0) + 2; + let len = + buffer.iter().skip(1).position(|x| x == &b'"').unwrap_or(0) + 2; settings.broker = { match serde_json_core::from_slice(&buffer[..len]) { Ok((item, size)) => { @@ -49,11 +53,11 @@ impl FlashSettings { }; flash.read(offset as u32, &mut buffer[..]).unwrap(); - let len = buffer.iter().skip(1).position(|x| x == &b'"').unwrap_or(0) + 2; + let len = + buffer.iter().skip(1).position(|x| x == &b'"').unwrap_or(0) + 2; settings.id = { match serde_json_core::from_slice(&buffer[..len]) { Ok((item, size)) => { - offset += size; item } Err(e) => { @@ -70,8 +74,14 @@ impl FlashSettings { let mut bank = self.flash.unlocked(); let mut data = [0; 512]; let mut offset: usize = 0; - offset += serde_json_core::to_slice(&self.settings.broker, &mut data[offset..]).unwrap(); - offset += serde_json_core::to_slice(&self.settings.id, &mut data[offset..]).unwrap(); + offset += serde_json_core::to_slice( + &self.settings.broker, + &mut data[offset..], + ) + .unwrap(); + offset += + serde_json_core::to_slice(&self.settings.id, &mut data[offset..]) + .unwrap(); bank.erase(0, UnlockedFlashBank::ERASE_SIZE as u32).unwrap(); bank.write(0, &data[..offset]).unwrap(); diff --git a/src/hardware/serial_terminal.rs b/src/hardware/serial_terminal.rs index c88e14598..3423cfdb3 100644 --- a/src/hardware/serial_terminal.rs +++ b/src/hardware/serial_terminal.rs @@ -119,7 +119,15 @@ fn handle_property_read( let mut buf = [0u8; 256]; for path in props { - let len = context.flash.settings.get_json(path, &mut buf).unwrap(); + let len = match context.flash.settings.get_json(path, &mut buf) { + Err(e) => { + writeln!(&mut context.output, "Failed to read {path}: {e}") + .unwrap(); + return; + } + Ok(len) => len, + }; + let stringified = core::str::from_utf8(&buf[..len]).unwrap(); writeln!(&mut context.output, "{path}: {stringified}").unwrap(); } @@ -149,7 +157,8 @@ fn handle_property_write( .unwrap(); } Err(e) => { - writeln!(&mut context.output, "Failed to update {property}: {e:?}").unwrap(); + writeln!(&mut context.output, "Failed to update {property}: {e:?}") + .unwrap(); } } } diff --git a/src/hardware/setup.rs b/src/hardware/setup.rs index 329518b8d..2e825c724 100644 --- a/src/hardware/setup.rs +++ b/src/hardware/setup.rs @@ -1072,7 +1072,8 @@ pub fn setup( let (_, flash_bank2) = device.FLASH.split(); - let settings = FlashSettings::new(flash_bank2.unwrap(), network_devices.mac_address.clone()); + let settings = + FlashSettings::new(flash_bank2.unwrap(), network_devices.mac_address); let stabilizer = StabilizerDevices { systick, diff --git a/src/net/mod.rs b/src/net/mod.rs index d0ad140f0..884bd912a 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -13,9 +13,7 @@ pub mod data_stream; pub mod network_processor; pub mod telemetry; -use crate::hardware::{ - EthernetPhy, NetworkManager, NetworkStack, SystemTimer, -}; +use crate::hardware::{EthernetPhy, NetworkManager, NetworkStack, SystemTimer}; use data_stream::{DataStream, FrameGenerator}; use network_processor::NetworkProcessor; use telemetry::TelemetryClient; @@ -224,10 +222,7 @@ where /// /// # Returns /// A client ID that may be used for MQTT client identification. -fn get_client_id( - id: &str, - mode: &str, -) -> String<64> { +fn get_client_id(id: &str, mode: &str) -> String<64> { let mut identifier = String::new(); write!(&mut identifier, "{id}-{mode}").unwrap(); identifier From 2a30adea0bf27fe1a228898ddd378f685bd9b474 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 13 Nov 2023 14:31:12 +0100 Subject: [PATCH 10/16] Using postcard --- Cargo.lock | 18 ++++++++++++++++++ Cargo.toml | 1 + src/hardware/flash.rs | 38 ++++++++++++++++---------------------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 693d2a05f..0a0b1c76a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,6 +126,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + [[package]] name = "cortex-m" version = "0.6.7" @@ -637,6 +643,17 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "postcard" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +dependencies = [ + "cobs", + "heapless", + "serde", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -925,6 +942,7 @@ dependencies = [ "mutex-trait", "num_enum 0.7.1", "paste", + "postcard", "rand_core", "rand_xorshift", "rtt-logger", diff --git a/Cargo.toml b/Cargo.toml index 6e0fc2f7a..e3e721970 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ usbd-serial = "0.1.1" miniconf = "0.9.0" smoltcp-nal = { version = "0.4.1", features = ["shared-stack"]} bbqueue = "0.5" +postcard = "1" [dependencies.stm32h7xx-hal] version = "0.15.0" diff --git a/src/hardware/flash.rs b/src/hardware/flash.rs index 6e0642973..0e651b07c 100644 --- a/src/hardware/flash.rs +++ b/src/hardware/flash.rs @@ -31,18 +31,17 @@ impl FlashSettings { mac: smoltcp_nal::smoltcp::wire::EthernetAddress, ) -> Self { let mut settings = Settings::new(mac); - let mut buffer = [0u8; 256]; - let mut offset: usize = 0; + let mut buffer = [0u8; 512]; + flash.read(0, &mut buffer[..]).unwrap(); + + let mut data = &buffer[..]; // We iteratively read the settings from flash to allow for easy expansion of the settings // without losing data in the future when new fields are added. - flash.read(offset as u32, &mut buffer[..]).unwrap(); - let len = - buffer.iter().skip(1).position(|x| x == &b'"').unwrap_or(0) + 2; settings.broker = { - match serde_json_core::from_slice(&buffer[..len]) { - Ok((item, size)) => { - offset += size; + match postcard::take_from_bytes(data) { + Ok((item, remainder)) => { + data = remainder; item } Err(e) => { @@ -52,14 +51,9 @@ impl FlashSettings { } }; - flash.read(offset as u32, &mut buffer[..]).unwrap(); - let len = - buffer.iter().skip(1).position(|x| x == &b'"').unwrap_or(0) + 2; settings.id = { - match serde_json_core::from_slice(&buffer[..len]) { - Ok((item, size)) => { - item - } + match postcard::from_bytes(data) { + Ok(item) => item, Err(e) => { log::warn!("Failed to MQTT ID from flash settings memory - using default: {e:?}"); settings.id @@ -72,16 +66,16 @@ impl FlashSettings { pub fn save(&mut self) { let mut bank = self.flash.unlocked(); + let mut data = [0; 512]; let mut offset: usize = 0; - offset += serde_json_core::to_slice( - &self.settings.broker, - &mut data[offset..], - ) - .unwrap(); offset += - serde_json_core::to_slice(&self.settings.id, &mut data[offset..]) - .unwrap(); + postcard::to_slice(&self.settings.broker, &mut data[offset..]) + .unwrap() + .len(); + offset += postcard::to_slice(&self.settings.id, &mut data[offset..]) + .unwrap() + .len(); bank.erase(0, UnlockedFlashBank::ERASE_SIZE as u32).unwrap(); bank.write(0, &data[..offset]).unwrap(); From 316adb5948b0f1efa9696f2d2782e640d1fa6bdc Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 13 Nov 2023 14:39:18 +0100 Subject: [PATCH 11/16] Adding list command --- src/hardware/serial_terminal.rs | 78 ++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/src/hardware/serial_terminal.rs b/src/hardware/serial_terminal.rs index 3423cfdb3..b5b51e40c 100644 --- a/src/hardware/serial_terminal.rs +++ b/src/hardware/serial_terminal.rs @@ -1,7 +1,8 @@ use super::UsbBus; use crate::hardware::flash::FlashSettings; +use crate::hardware::flash::Settings; use core::fmt::Write; -use miniconf::JsonCoreSlash; +use miniconf::{JsonCoreSlash, TreeKey}; struct Context { output: OutputBuffer, @@ -19,34 +20,34 @@ const ROOT_MENU: menu::Menu = menu::Menu { parameters: &[] }, }, + &menu::Item { + command: "list", + help: Some("List all available properties."), + item_type: menu::ItemType::Callback { + function: handle_list, + parameters: &[], + }, + }, &menu::Item { command: "read", - help: Some("Read a property from the device: - -Available Properties: -* /id: The MQTT ID of the device -* /broker: The MQTT broker address"), + help: Some("Read a property from the device."), item_type: menu::ItemType::Callback { function: handle_property_read, - parameters: &[menu::Parameter::Optional { + parameters: &[menu::Parameter::Mandatory { parameter_name: "property", - help: Some("The name of the property to read. If not specified, all properties are read"), + help: Some("The name of the property to read."), }] }, }, &menu::Item { command: "write", - help: Some("Write a property to the device: - -Available Properties: -* /id: The MQTT ID of the device -* /broker: The MQTT broker address"), + help: Some("Read a property to the device."), item_type: menu::ItemType::Callback { function: handle_property_write, parameters: &[ menu::Parameter::Mandatory { parameter_name: "property", - help: Some("The name of the property to write: [id, broker]"), + help: Some("The name of the property to write."), }, menu::Parameter::Mandatory { parameter_name: "value", @@ -94,6 +95,19 @@ impl core::fmt::Write for Context { } } +fn handle_list( + _menu: &menu::Menu, + _item: &menu::Item, + _args: &[&str], + context: &mut Context, +) { + writeln!(context, "Available properties:").unwrap(); + for path in Settings::iter_paths::>("/") { + let path = path.unwrap(); + writeln!(context, "* {path}").unwrap(); + } +} + fn handle_reset( _menu: &menu::Menu, _item: &menu::Item, @@ -109,28 +123,21 @@ fn handle_property_read( args: &[&str], context: &mut Context, ) { - let props: heapless::Vec<&'_ str, 2> = if let Some(prop) = - menu::argument_finder(item, args, "property").unwrap() - { - heapless::Vec::from_slice(&[prop]).unwrap() - } else { - heapless::Vec::from_slice(&["/id", "/broker"]).unwrap() - }; + let path = menu::argument_finder(item, args, "property") + .unwrap() + .unwrap(); let mut buf = [0u8; 256]; - for path in props { - let len = match context.flash.settings.get_json(path, &mut buf) { - Err(e) => { - writeln!(&mut context.output, "Failed to read {path}: {e}") - .unwrap(); - return; - } - Ok(len) => len, - }; + let len = match context.flash.settings.get_json(path, &mut buf) { + Err(e) => { + writeln!(context, "Failed to read {path}: {e}").unwrap(); + return; + } + Ok(len) => len, + }; - let stringified = core::str::from_utf8(&buf[..len]).unwrap(); - writeln!(&mut context.output, "{path}: {stringified}").unwrap(); - } + let stringified = core::str::from_utf8(&buf[..len]).unwrap(); + writeln!(context, "{path}: {stringified}").unwrap(); } fn handle_property_write( @@ -150,15 +157,14 @@ fn handle_property_write( Ok(_) => { context.flash.save(); writeln!( - &mut context.output, + context, "Settings in memory may differ from currently operating settings. \ Reset device to apply settings." ) .unwrap(); } Err(e) => { - writeln!(&mut context.output, "Failed to update {property}: {e:?}") - .unwrap(); + writeln!(context, "Failed to update {property}: {e:?}").unwrap(); } } } From 0b941ff5d12a3579efd577ac73035509583997de Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 13 Nov 2023 14:45:04 +0100 Subject: [PATCH 12/16] Using postcard for complete serialization --- src/hardware/flash.rs | 46 ++++++++++--------------------------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/src/hardware/flash.rs b/src/hardware/flash.rs index 0e651b07c..e16a4a547 100644 --- a/src/hardware/flash.rs +++ b/src/hardware/flash.rs @@ -2,7 +2,7 @@ use core::fmt::Write; use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use stm32h7xx_hal::flash::{LockedFlashBank, UnlockedFlashBank}; -#[derive(miniconf::Tree)] +#[derive(serde::Serialize, serde::Deserialize, miniconf::Tree)] pub struct Settings { pub broker: heapless::String<255>, pub id: heapless::String<23>, @@ -30,34 +30,16 @@ impl FlashSettings { mut flash: LockedFlashBank, mac: smoltcp_nal::smoltcp::wire::EthernetAddress, ) -> Self { - let mut settings = Settings::new(mac); let mut buffer = [0u8; 512]; flash.read(0, &mut buffer[..]).unwrap(); - let mut data = &buffer[..]; - - // We iteratively read the settings from flash to allow for easy expansion of the settings - // without losing data in the future when new fields are added. - settings.broker = { - match postcard::take_from_bytes(data) { - Ok((item, remainder)) => { - data = remainder; - item - } - Err(e) => { - log::warn!("Failed to decode broker from flash settings memory - using default: {e:?}"); - settings.broker - } - } - }; - - settings.id = { - match postcard::from_bytes(data) { - Ok(item) => item, - Err(e) => { - log::warn!("Failed to MQTT ID from flash settings memory - using default: {e:?}"); - settings.id - } + let settings = match postcard::from_bytes(&buffer) { + Ok(settings) => settings, + Err(_) => { + log::warn!( + "Failed to load settings from flash. Using defaults" + ); + Settings::new(mac) } }; @@ -68,16 +50,8 @@ impl FlashSettings { let mut bank = self.flash.unlocked(); let mut data = [0; 512]; - let mut offset: usize = 0; - offset += - postcard::to_slice(&self.settings.broker, &mut data[offset..]) - .unwrap() - .len(); - offset += postcard::to_slice(&self.settings.id, &mut data[offset..]) - .unwrap() - .len(); - + let serialized = postcard::to_slice(&self.settings, &mut data).unwrap(); bank.erase(0, UnlockedFlashBank::ERASE_SIZE as u32).unwrap(); - bank.write(0, &data[..offset]).unwrap(); + bank.write(0, serialized).unwrap(); } } From b7d333ebcec8e68cd7646c2efc913d50f2fd073b Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 13 Nov 2023 14:53:00 +0100 Subject: [PATCH 13/16] Updating read to allow no args --- src/hardware/serial_terminal.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/hardware/serial_terminal.rs b/src/hardware/serial_terminal.rs index b5b51e40c..12d6d704c 100644 --- a/src/hardware/serial_terminal.rs +++ b/src/hardware/serial_terminal.rs @@ -33,9 +33,9 @@ const ROOT_MENU: menu::Menu = menu::Menu { help: Some("Read a property from the device."), item_type: menu::ItemType::Callback { function: handle_property_read, - parameters: &[menu::Parameter::Mandatory { + parameters: &[menu::Parameter::Optional { parameter_name: "property", - help: Some("The name of the property to read."), + help: Some("The name of the property to read. If not specified, all properties are read."), }] }, }, @@ -123,21 +123,26 @@ fn handle_property_read( args: &[&str], context: &mut Context, ) { - let path = menu::argument_finder(item, args, "property") - .unwrap() - .unwrap(); - let mut buf = [0u8; 256]; - let len = match context.flash.settings.get_json(path, &mut buf) { - Err(e) => { - writeln!(context, "Failed to read {path}: {e}").unwrap(); - return; - } - Ok(len) => len, + if let Some(path) = menu::argument_finder(item, args, "property").unwrap() { + let len = match context.flash.settings.get_json(path, &mut buf) { + Err(e) => { + writeln!(context, "Failed to read {path}: {e}").unwrap(); + return; + } + Ok(len) => len, + }; + + let stringified = core::str::from_utf8(&buf[..len]).unwrap(); + writeln!(context, "{path}: {stringified}").unwrap(); }; - let stringified = core::str::from_utf8(&buf[..len]).unwrap(); - writeln!(context, "{path}: {stringified}").unwrap(); + for path in Settings::iter_paths::>("/") { + let path = path.unwrap(); + let len = context.flash.settings.get_json(&path, &mut buf).unwrap(); + let stringified = core::str::from_utf8(&buf[..len]).unwrap(); + writeln!(context, "{path}: {stringified}").unwrap(); + } } fn handle_property_write( From 6f171975624442b05a68dee490f8802ecc7af40a Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 14 Nov 2023 11:13:57 +0100 Subject: [PATCH 14/16] Updating after review --- src/hardware/flash.rs | 8 +++ src/hardware/serial_terminal.rs | 90 +++++++++++++++++++-------------- 2 files changed, 60 insertions(+), 38 deletions(-) diff --git a/src/hardware/flash.rs b/src/hardware/flash.rs index e16a4a547..a8a91de68 100644 --- a/src/hardware/flash.rs +++ b/src/hardware/flash.rs @@ -6,6 +6,9 @@ use stm32h7xx_hal::flash::{LockedFlashBank, UnlockedFlashBank}; pub struct Settings { pub broker: heapless::String<255>, pub id: heapless::String<23>, + #[serde(skip)] + #[tree(skip)] + pub mac: smoltcp_nal::smoltcp::wire::EthernetAddress, } impl Settings { @@ -16,8 +19,13 @@ impl Settings { Self { broker: "mqtt".into(), id, + mac, } } + + pub fn reset(&mut self) { + *self = Self::new(self.mac) + } } pub struct FlashSettings { diff --git a/src/hardware/serial_terminal.rs b/src/hardware/serial_terminal.rs index 12d6d704c..b5f280aab 100644 --- a/src/hardware/serial_terminal.rs +++ b/src/hardware/serial_terminal.rs @@ -13,16 +13,24 @@ const ROOT_MENU: menu::Menu = menu::Menu { label: "root", items: &[ &menu::Item { - command: "reset", - help: Some("Reset Stabilizer to force new settings to take effect."), + command: "reboot", + help: Some("Reboot the device to force new settings to take effect."), item_type: menu::ItemType::Callback { - function: handle_reset, + function: handle_device_reboot, + parameters: &[] + }, + }, + &menu::Item { + command: "factory-reset", + help: Some("Reset the device settings to default values."), + item_type: menu::ItemType::Callback { + function: handle_settings_reset, parameters: &[] }, }, &menu::Item { command: "list", - help: Some("List all available properties."), + help: Some("List all available settings and their current values."), item_type: menu::ItemType::Callback { function: handle_list, parameters: &[], @@ -30,28 +38,28 @@ const ROOT_MENU: menu::Menu = menu::Menu { }, &menu::Item { command: "read", - help: Some("Read a property from the device."), + help: Some("Read a setting_from the device."), item_type: menu::ItemType::Callback { - function: handle_property_read, - parameters: &[menu::Parameter::Optional { - parameter_name: "property", - help: Some("The name of the property to read. If not specified, all properties are read."), + function: handle_setting_read, + parameters: &[menu::Parameter::Mandatory { + parameter_name: "item", + help: Some("The name of the setting to read."), }] }, }, &menu::Item { command: "write", - help: Some("Read a property to the device."), + help: Some("Update a a setting in the device."), item_type: menu::ItemType::Callback { - function: handle_property_write, + function: handle_setting_write, parameters: &[ menu::Parameter::Mandatory { - parameter_name: "property", - help: Some("The name of the property to write."), + parameter_name: "item", + help: Some("The name of the setting to write."), }, menu::Parameter::Mandatory { parameter_name: "value", - help: Some("Specifies the value to be written to the property."), + help: Some("Specifies the value to be written. Values must be JSON-encoded"), }, ] }, @@ -102,13 +110,17 @@ fn handle_list( context: &mut Context, ) { writeln!(context, "Available properties:").unwrap(); + + let mut buf = [0; 256]; for path in Settings::iter_paths::>("/") { let path = path.unwrap(); - writeln!(context, "* {path}").unwrap(); + let len = context.flash.settings.get_json(&path, &mut buf).unwrap(); + let stringified = core::str::from_utf8(&buf[..len]).unwrap(); + writeln!(context, "{path}: {stringified}").unwrap(); } } -fn handle_reset( +fn handle_device_reboot( _menu: &menu::Menu, _item: &menu::Item, _args: &[&str], @@ -117,48 +129,50 @@ fn handle_reset( cortex_m::peripheral::SCB::sys_reset(); } -fn handle_property_read( +fn handle_settings_reset( + _menu: &menu::Menu, + _item: &menu::Item, + _args: &[&str], + context: &mut Context, +) { + context.flash.settings.reset(); + context.flash.save(); +} + +fn handle_setting_read( _menu: &menu::Menu, item: &menu::Item, args: &[&str], context: &mut Context, ) { let mut buf = [0u8; 256]; - if let Some(path) = menu::argument_finder(item, args, "property").unwrap() { - let len = match context.flash.settings.get_json(path, &mut buf) { - Err(e) => { - writeln!(context, "Failed to read {path}: {e}").unwrap(); - return; - } - Ok(len) => len, - }; - - let stringified = core::str::from_utf8(&buf[..len]).unwrap(); - writeln!(context, "{path}: {stringified}").unwrap(); + let key = menu::argument_finder(item, args, "item").unwrap().unwrap(); + let len = match context.flash.settings.get_json(key, &mut buf) { + Err(e) => { + writeln!(context, "Failed to read {key}: {e}").unwrap(); + return; + } + Ok(len) => len, }; - for path in Settings::iter_paths::>("/") { - let path = path.unwrap(); - let len = context.flash.settings.get_json(&path, &mut buf).unwrap(); - let stringified = core::str::from_utf8(&buf[..len]).unwrap(); - writeln!(context, "{path}: {stringified}").unwrap(); - } + let stringified = core::str::from_utf8(&buf[..len]).unwrap(); + writeln!(context, "{key}: {stringified}").unwrap(); } -fn handle_property_write( +fn handle_setting_write( _menu: &menu::Menu, item: &menu::Item, args: &[&str], context: &mut Context, ) { - let property = menu::argument_finder(item, args, "property") + let key = menu::argument_finder(item, args, "item") .unwrap() .unwrap(); let value = menu::argument_finder(item, args, "value").unwrap().unwrap(); // Now, write the new value into memory. // TODO: Validate it first? - match context.flash.settings.set_json(property, value.as_bytes()) { + match context.flash.settings.set_json(key, value.as_bytes()) { Ok(_) => { context.flash.save(); writeln!( @@ -169,7 +183,7 @@ fn handle_property_write( .unwrap(); } Err(e) => { - writeln!(context, "Failed to update {property}: {e:?}").unwrap(); + writeln!(context, "Failed to update {key}: {e:?}").unwrap(); } } } From 6182e1c790d6b1f1f5a8e824419c6f877bdcd4f1 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 14 Nov 2023 11:20:05 +0100 Subject: [PATCH 15/16] Listing default values, updating buffer size --- src/hardware/flash.rs | 2 +- src/hardware/serial_terminal.rs | 26 +++++++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/hardware/flash.rs b/src/hardware/flash.rs index a8a91de68..60c73d991 100644 --- a/src/hardware/flash.rs +++ b/src/hardware/flash.rs @@ -2,7 +2,7 @@ use core::fmt::Write; use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use stm32h7xx_hal::flash::{LockedFlashBank, UnlockedFlashBank}; -#[derive(serde::Serialize, serde::Deserialize, miniconf::Tree)] +#[derive(Clone, serde::Serialize, serde::Deserialize, miniconf::Tree)] pub struct Settings { pub broker: heapless::String<255>, pub id: heapless::String<23>, diff --git a/src/hardware/serial_terminal.rs b/src/hardware/serial_terminal.rs index b5f280aab..6f9d0c69d 100644 --- a/src/hardware/serial_terminal.rs +++ b/src/hardware/serial_terminal.rs @@ -111,12 +111,26 @@ fn handle_list( ) { writeln!(context, "Available properties:").unwrap(); + let mut defaults = context.flash.settings.clone(); + defaults.reset(); + let mut buf = [0; 256]; + let mut default_buf = [0; 256]; for path in Settings::iter_paths::>("/") { let path = path.unwrap(); - let len = context.flash.settings.get_json(&path, &mut buf).unwrap(); - let stringified = core::str::from_utf8(&buf[..len]).unwrap(); - writeln!(context, "{path}: {stringified}").unwrap(); + let current_value = { + let len = context.flash.settings.get_json(&path, &mut buf).unwrap(); + core::str::from_utf8(&buf[..len]).unwrap() + }; + let default_value = { + let len = defaults.get_json(&path, &mut default_buf).unwrap(); + core::str::from_utf8(&default_buf[..len]).unwrap() + }; + writeln!( + context, + "{path}: {current_value} [default: {default_value}]" + ) + .unwrap(); } } @@ -165,9 +179,7 @@ fn handle_setting_write( args: &[&str], context: &mut Context, ) { - let key = menu::argument_finder(item, args, "item") - .unwrap() - .unwrap(); + let key = menu::argument_finder(item, args, "item").unwrap().unwrap(); let value = menu::argument_finder(item, args, "value").unwrap().unwrap(); // Now, write the new value into memory. @@ -204,7 +216,7 @@ impl SerialTerminal { let (producer, consumer) = OUTPUT_BUFFER.try_split().unwrap(); let input_buffer = - cortex_m::singleton!(: [u8; 255] = [0; 255]).unwrap(); + cortex_m::singleton!(: [u8; 256] = [0; 256]).unwrap(); let context = Context { output: OutputBuffer { producer }, flash, From 908922f2abbed669ebe725a2cb6d66b5a4832185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 14 Nov 2023 11:50:00 +0100 Subject: [PATCH 16/16] read/write -> get/set --- src/hardware/serial_terminal.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/hardware/serial_terminal.rs b/src/hardware/serial_terminal.rs index 6f9d0c69d..3f5ec6dcb 100644 --- a/src/hardware/serial_terminal.rs +++ b/src/hardware/serial_terminal.rs @@ -16,7 +16,7 @@ const ROOT_MENU: menu::Menu = menu::Menu { command: "reboot", help: Some("Reboot the device to force new settings to take effect."), item_type: menu::ItemType::Callback { - function: handle_device_reboot, + function: handle_reboot, parameters: &[] }, }, @@ -24,7 +24,7 @@ const ROOT_MENU: menu::Menu = menu::Menu { command: "factory-reset", help: Some("Reset the device settings to default values."), item_type: menu::ItemType::Callback { - function: handle_settings_reset, + function: handle_reset, parameters: &[] }, }, @@ -37,10 +37,10 @@ const ROOT_MENU: menu::Menu = menu::Menu { }, }, &menu::Item { - command: "read", + command: "get", help: Some("Read a setting_from the device."), item_type: menu::ItemType::Callback { - function: handle_setting_read, + function: handle_get, parameters: &[menu::Parameter::Mandatory { parameter_name: "item", help: Some("The name of the setting to read."), @@ -48,10 +48,10 @@ const ROOT_MENU: menu::Menu = menu::Menu { }, }, &menu::Item { - command: "write", + command: "set", help: Some("Update a a setting in the device."), item_type: menu::ItemType::Callback { - function: handle_setting_write, + function: handle_set, parameters: &[ menu::Parameter::Mandatory { parameter_name: "item", @@ -134,7 +134,7 @@ fn handle_list( } } -fn handle_device_reboot( +fn handle_reboot( _menu: &menu::Menu, _item: &menu::Item, _args: &[&str], @@ -143,7 +143,7 @@ fn handle_device_reboot( cortex_m::peripheral::SCB::sys_reset(); } -fn handle_settings_reset( +fn handle_reset( _menu: &menu::Menu, _item: &menu::Item, _args: &[&str], @@ -153,7 +153,7 @@ fn handle_settings_reset( context.flash.save(); } -fn handle_setting_read( +fn handle_get( _menu: &menu::Menu, item: &menu::Item, args: &[&str], @@ -173,7 +173,7 @@ fn handle_setting_read( writeln!(context, "{key}: {stringified}").unwrap(); } -fn handle_setting_write( +fn handle_set( _menu: &menu::Menu, item: &menu::Item, args: &[&str],