From 63978c6b6d063b4195cd3970ded61e53873650da Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 5 Dec 2023 11:12:27 +0100 Subject: [PATCH 1/5] Adding metadata and persistent panic info --- CHANGELOG.md | 4 + Cargo.lock | 163 ++++++++++++++++++++++++++++++++++++++- Cargo.toml | 7 ++ build.rs | 2 + memory.x | 10 ++- src/bin/dual-iir.rs | 1 + src/bin/lockin.rs | 1 + src/hardware/metadata.rs | 42 ++++++++++ src/hardware/mod.rs | 50 ++++++++++++ src/hardware/setup.rs | 34 ++++++-- src/net/mod.rs | 10 ++- src/net/telemetry.rs | 68 ++++++++++++++-- src/settings.rs | 42 +++++++++- 13 files changed, 415 insertions(+), 19 deletions(-) create mode 100644 src/hardware/metadata.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 1549acf6c..428b7b97d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added * Serial terminal is available on USB for settings configurations * Reboot to DFU support added via the serial terminal for remote bootloading +* The `alive` topic now contains metadata about the compiler, firmware, and hardware similar to +Booster +* Panic information is now persisted after reboot and available via telemetry and the USB serial +console. ### Changed * Broker is no longer configured at compile time, but is maintained in device memory diff --git a/Cargo.lock b/Cargo.lock index 1e17444b2..ce2bf5c66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,6 +102,15 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "built" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d17f4d6e4dc36d1a02fbedc2753a096848e7c1b0772f7654eab8e2c927dd53" +dependencies = [ + "git2", +] + [[package]] name = "bytemuck" version = "1.14.0" @@ -120,6 +129,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -283,6 +302,15 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fugit" version = "0.3.7" @@ -326,6 +354,19 @@ dependencies = [ "version_check", ] +[[package]] +name = "git2" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd" +dependencies = [ + "bitflags 2.4.1", + "libc", + "libgit2-sys", + "log", + "url", +] + [[package]] name = "hash32" version = "0.2.1" @@ -374,6 +415,16 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idsp" version = "0.13.0" @@ -401,12 +452,51 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "libgit2-sys" +version = "0.16.1+1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2a2bb3680b094add03bb3732ec520ece34da31a8cd2d633d1389d0f0fb60d0c" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + [[package]] name = "libm" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libz-sys" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "lm75" version = "0.2.0" @@ -676,12 +766,33 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "panic-persist" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32bb382689ecd2c4d2d4df9fd56700ba8d43b7b31cca11018cc0e6f8aef39fd5" +dependencies = [ + "cortex-m 0.7.7", +] + [[package]] name = "paste" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + [[package]] name = "portable-atomic" version = "1.5.1" @@ -987,6 +1098,8 @@ version = "0.9.0" dependencies = [ "ad9959", "bbqueue", + "bit_field", + "built", "cortex-m 0.7.7", "cortex-m-rt", "cortex-m-rtic", @@ -1005,6 +1118,7 @@ dependencies = [ "mono-clock", "mutex-trait", "num_enum 0.7.1", + "panic-persist", "paste", "postcard", "rand_core", @@ -1107,6 +1221,21 @@ dependencies = [ "rtic-monotonic", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "typenum" version = "1.17.0" @@ -1119,12 +1248,38 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "usb-device" version = "0.3.1" @@ -1139,7 +1294,7 @@ dependencies = [ [[package]] name = "usbd-serial" version = "0.2.0" -source = "git+https://github.com/rust-embedded-community/usbd-serial#6611dc092822c60b4482e28aab2fe084c1756410" +source = "git+https://github.com/rust-embedded-community/usbd-serial?rev=096742c1c480f6f63c1a936a3c23ede7993c624d#096742c1c480f6f63c1a936a3c23ede7993c624d" dependencies = [ "embedded-hal", "embedded-io", @@ -1159,6 +1314,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 679e75e92..a6659b352 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ documentation = "https://docs.rs/stabilizer/" edition = "2021" # keep MSRV in sync in ci.yaml and Cargo.toml rust-version = "1.65" +build = "build.rs" exclude = [ ".gitignore", "doc/", @@ -34,6 +35,7 @@ default-target = "thumbv7em-none-eabihf" members = ["ad9959", "serial-settings"] [dependencies] +panic-persist = { version = "0.3", features = ["utf8", "custom-panic-handler"] } sequential-storage = "0.6" embedded-io = "0.6" embedded-storage = "0.3" @@ -71,6 +73,10 @@ miniconf = "0.9.0" smoltcp-nal = { version = "0.4.1", features = ["shared-stack"]} bbqueue = "0.5" postcard = "1" +bit_field = "0.10.2" + +[build-dependencies] +built = { version = "0.7", features = ["git2"], default-features = false } [dependencies.stm32h7xx-hal] version = "0.15.1" @@ -80,6 +86,7 @@ features = ["stm32h743v", "rt", "ethernet", "xspi", "usb_hs"] [patch.crates-io.usbd-serial] git = "https://github.com/rust-embedded-community/usbd-serial" +rev = "096742c1c480f6f63c1a936a3c23ede7993c624d" [features] nightly = [ ] diff --git a/build.rs b/build.rs index e71f6a660..f57ef7a69 100644 --- a/build.rs +++ b/build.rs @@ -1,3 +1,5 @@ fn main() { + built::write_built_file() + .expect("Failed to acquire build-time information"); println!("cargo:rerun-if-changed=memory.x"); } diff --git a/memory.x b/memory.x index ff76fc918..dfa174802 100644 --- a/memory.x +++ b/memory.x @@ -10,10 +10,16 @@ MEMORY RAM_B (rwx) : ORIGIN = 0x38800000, LENGTH = 4K FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K FLASH1 (rx) : ORIGIN = 0x08100000, LENGTH = 1024K - BOOTFLAG_RAM: ORIGIN = 0x2001FC00, LENGTH = 1K + PERSISTENT_RAM: ORIGIN = 0x2001FC00, LENGTH = 1K } -_bootflag = ORIGIN(BOOTFLAG_RAM); +/* + * Persistent memory has a u32 bootflag at the beginning and then the remainder is used for + * persisting panic information between boots. + */ +_bootflag = ORIGIN(PERSISTENT_RAM); +_panic_dump_start = ORIGIN(PERSISTENT_RAM) + 4; +_panic_dump_end = ORIGIN(PERSISTENT_RAM) + LENGTH(PERSISTENT_RAM) - 4; SECTIONS { .axisram (NOLOAD) : ALIGN(8) { diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index 92a973f82..70e2861fe 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -225,6 +225,7 @@ mod app { env!("CARGO_BIN_NAME"), &settings.broker, &settings.id, + stabilizer.metadata, ); let generator = network.configure_streaming(StreamFormat::AdcDacData); diff --git a/src/bin/lockin.rs b/src/bin/lockin.rs index 7959c5af9..c4237c8be 100644 --- a/src/bin/lockin.rs +++ b/src/bin/lockin.rs @@ -265,6 +265,7 @@ mod app { env!("CARGO_BIN_NAME"), &settings.broker, &settings.id, + stabilizer.metadata, ); let generator = network.configure_streaming(StreamFormat::AdcDacData); diff --git a/src/hardware/metadata.rs b/src/hardware/metadata.rs new file mode 100644 index 000000000..1847fc6d6 --- /dev/null +++ b/src/hardware/metadata.rs @@ -0,0 +1,42 @@ +use crate::hardware::HardwareVersion; +use serde::Serialize; + +mod build_info { + include!(concat!(env!("OUT_DIR"), "/built.rs")); +} + +#[derive(Serialize)] +pub struct ApplicationMetadata { + pub firmware_version: &'static str, + pub rust_version: &'static str, + pub profile: &'static str, + pub git_dirty: bool, + pub features: &'static str, + pub panic_info: &'static str, + pub hardware_version: HardwareVersion, +} + +impl ApplicationMetadata { + /// Construct the global metadata. + /// + /// # Note + /// This may only be called once. + /// + /// # Args + /// * `hardware_version` - The hardware version detected. + /// * `phy` - The identifier of the detected ethernet PHY. + /// + /// # Returns + /// A reference to the global metadata. + pub fn new(version: HardwareVersion) -> &'static ApplicationMetadata { + cortex_m::singleton!(: ApplicationMetadata = ApplicationMetadata { + firmware_version: build_info::GIT_VERSION.unwrap_or("Unspecified"), + rust_version: build_info::RUSTC_VERSION, + profile: build_info::PROFILE, + git_dirty: build_info::GIT_DIRTY.unwrap_or(false), + features: build_info::FEATURES_STR, + hardware_version: version, + panic_info: panic_persist::get_panic_message_utf8().unwrap_or("None"), + }).unwrap() + } +} diff --git a/src/hardware/mod.rs b/src/hardware/mod.rs index db95a64dd..477192466 100644 --- a/src/hardware/mod.rs +++ b/src/hardware/mod.rs @@ -12,6 +12,7 @@ pub mod design_parameters; mod eeprom; pub mod flash; pub mod input_stamper; +pub mod metadata; pub mod platform; pub mod pounder; pub mod setup; @@ -86,6 +87,53 @@ pub type I2c1Proxy = pub type SerialTerminal = serial_settings::Runner<'static, crate::settings::SerialSettingsPlatform>; +pub enum HardwareVersion { + Rev1_0, + Rev1_1, + Rev1_2, + Rev1_3, + Unknown(u8), +} + +impl From for HardwareVersion { + fn from(bitfield: u8) -> Self { + match bitfield { + 0b000 => HardwareVersion::Rev1_0, + 0b001 => HardwareVersion::Rev1_1, + 0b010 => HardwareVersion::Rev1_2, + 0b011 => HardwareVersion::Rev1_3, + other => HardwareVersion::Unknown(other), + } + } +} + +impl core::fmt::Display for HardwareVersion { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + HardwareVersion::Rev1_0 => write!(f, "v1.0"), + HardwareVersion::Rev1_1 => write!(f, "v1.1"), + HardwareVersion::Rev1_2 => write!(f, "v1.2"), + HardwareVersion::Rev1_3 => write!(f, "v1.3"), + HardwareVersion::Unknown(other) => { + write!(f, "Unknown ({:#b})", other) + } + } + } +} + +impl serde::Serialize for HardwareVersion { + fn serialize( + &self, + serializer: S, + ) -> Result { + use core::fmt::Write; + + let mut version_string: heapless::String<32> = heapless::String::new(); + write!(&mut version_string, "{}", self).unwrap(); + serializer.serialize_str(&version_string) + } +} + #[inline(never)] #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { @@ -115,6 +163,8 @@ fn panic(info: &core::panic::PanicInfo) -> ! { writeln!(channel, "{info}").ok(); } + panic_persist::report_panic_info(info); + // Abort asm::udf(); // Halt diff --git a/src/hardware/setup.rs b/src/hardware/setup.rs index f493bad8f..2733edaaa 100644 --- a/src/hardware/setup.rs +++ b/src/hardware/setup.rs @@ -1,6 +1,7 @@ //! Stabilizer hardware configuration //! //! This file contains all of the hardware-specific configuration of Stabilizer. +use bit_field::BitField; use core::sync::atomic::{self, AtomicBool, Ordering}; use core::{fmt::Write, ptr, slice}; use stm32h7xx_hal::{ @@ -14,11 +15,12 @@ use smoltcp_nal::smoltcp; use super::{ adc, afe, cpu_temp_sensor::CpuTempSensor, dac, delay, design_parameters, - eeprom, input_stamper::InputStamper, platform, pounder, - pounder::dds_output::DdsOutput, shared_adc::SharedAdc, timers, - DigitalInput0, DigitalInput1, EemDigitalInput0, EemDigitalInput1, - EemDigitalOutput0, EemDigitalOutput1, EthernetPhy, NetworkStack, - SerialTerminal, SystemTimer, Systick, UsbBus, UsbDevice, AFE0, AFE1, + eeprom, input_stamper::InputStamper, metadata::ApplicationMetadata, + platform, pounder, pounder::dds_output::DdsOutput, shared_adc::SharedAdc, + timers, DigitalInput0, DigitalInput1, EemDigitalInput0, EemDigitalInput1, + EemDigitalOutput0, EemDigitalOutput1, EthernetPhy, HardwareVersion, + NetworkStack, SerialTerminal, SystemTimer, Systick, UsbBus, UsbDevice, + AFE0, AFE1, }; const NUM_TCP_SOCKETS: usize = 4; @@ -119,6 +121,7 @@ pub struct StabilizerDevices { pub eem_gpio: EemGpioDevices, pub usb_serial: SerialTerminal, pub usb: UsbDevice, + pub metadata: &'static ApplicationMetadata, } /// The available Pounder-specific hardware interfaces. @@ -596,6 +599,25 @@ pub fn setup( ) }; + let metadata = { + // Read the hardware version pins. + let hardware_version = { + let hwrev0 = gpiog.pg0.into_pull_down_input(); + let hwrev1 = gpiog.pg1.into_pull_down_input(); + let hwrev2 = gpiog.pg2.into_pull_down_input(); + let hwrev3 = gpiog.pg3.into_pull_down_input(); + + HardwareVersion::from( + *0u8.set_bit(0, hwrev0.is_high()) + .set_bit(1, hwrev1.is_high()) + .set_bit(2, hwrev2.is_high()) + .set_bit(3, hwrev3.is_high()), + ) + }; + + ApplicationMetadata::new(hardware_version) + }; + let mac_addr = smoltcp::wire::EthernetAddress(eeprom::read_eui48( &mut eeprom_i2c, &mut delay, @@ -1098,6 +1120,7 @@ pub fn setup( ), storage, settings, + metadata, }, input_buffer, serialize_buffer, @@ -1121,6 +1144,7 @@ pub fn setup( eem_gpio, usb: usb_device, usb_serial, + metadata, }; // info!("Version {} {}", build_info::PKG_VERSION, build_info::GIT_VERSION.unwrap()); diff --git a/src/net/mod.rs b/src/net/mod.rs index 884bd912a..4248049dd 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::{ + metadata::ApplicationMetadata, EthernetPhy, NetworkManager, NetworkStack, + SystemTimer, +}; use data_stream::{DataStream, FrameGenerator}; use network_processor::NetworkProcessor; use telemetry::TelemetryClient; @@ -85,6 +88,8 @@ where /// * `clock` - A `SystemTimer` implementing `Clock`. /// * `app` - The name of the application. /// * `broker` - The domain name of the MQTT broker to use. + /// * `id` - The MQTT client ID base to use. + /// * `metadata` - The application metadata /// /// # Returns /// A new struct of network users. @@ -95,6 +100,7 @@ where app: &str, broker: &str, id: &str, + metadata: &'static ApplicationMetadata, ) -> Self { let stack_manager = cortex_m::singleton!(: NetworkManager = NetworkManager::new(stack)) @@ -144,7 +150,7 @@ where .unwrap(), ); - let telemetry = TelemetryClient::new(mqtt, &prefix); + let telemetry = TelemetryClient::new(mqtt, &prefix, metadata); let (generator, stream) = data_stream::setup_streaming(stack_manager.acquire_stack()); diff --git a/src/net/telemetry.rs b/src/net/telemetry.rs index e5efd28ef..d9cff7ac0 100644 --- a/src/net/telemetry.rs +++ b/src/net/telemetry.rs @@ -10,12 +10,17 @@ //! sampling frequency. Instead, the raw codes are stored and the telemetry is generated as //! required immediately before transmission. This ensures that any slower computation required //! for unit conversion can be off-loaded to lower priority tasks. +use crate::hardware::metadata::ApplicationMetadata; use heapless::{String, Vec}; +use minimq::{DeferredPublication, Publication}; use serde::Serialize; use super::NetworkReference; use crate::hardware::{adc::AdcCode, afe::Gain, dac::DacCode, SystemTimer}; +/// Default metadata message if formatting errors occur. +const DEFAULT_METADATA: &str = "{\"message\":\"Truncated: See USB terminal\"}"; + /// The telemetry client for reporting telemetry data over MQTT. pub struct TelemetryClient { mqtt: minimq::Minimq< @@ -24,8 +29,10 @@ pub struct TelemetryClient { SystemTimer, minimq::broker::NamedBroker, >, - telemetry_topic: String<128>, + prefix: String<128>, + meta_published: bool, _telemetry: core::marker::PhantomData, + metadata: &'static ApplicationMetadata, } /// The telemetry buffer is used for storing sample values during execution. @@ -114,14 +121,14 @@ impl TelemetryClient { minimq::broker::NamedBroker, >, prefix: &str, + metadata: &'static ApplicationMetadata, ) -> Self { - let mut telemetry_topic: String<128> = String::from(prefix); - telemetry_topic.push_str("/telemetry").unwrap(); - Self { mqtt, - telemetry_topic, + meta_published: false, + prefix: String::from(prefix), _telemetry: core::marker::PhantomData, + metadata, } } @@ -134,13 +141,17 @@ impl TelemetryClient { /// # Args /// * `telemetry` - The telemetry to report pub fn publish(&mut self, telemetry: &T) { + let mut topic = self.prefix.clone(); + topic.push_str("/telemetry").unwrap(); + let telemetry: Vec = serde_json_core::to_vec(telemetry).unwrap(); + self.mqtt .client() .publish( minimq::Publication::<&[u8]>::new(&telemetry) - .topic(&self.telemetry_topic) + .topic(&topic) .finish() .unwrap(), ) @@ -165,5 +176,50 @@ impl TelemetryClient { Err(error) => log::info!("Unexpected error: {:?}", error), _ => {} } + + if !self.mqtt.client().is_connected() { + self.meta_published = false; + return; + } + + // Publish application metadata + if !self.meta_published + && self.mqtt.client().can_publish(minimq::QoS::AtMostOnce) + { + let Self { + ref mut mqtt, + metadata, + .. + } = self; + + let mut topic = self.prefix.clone(); + topic.push_str("/alive/meta").unwrap(); + + if mqtt + .client() + .publish( + DeferredPublication::new(|buf| { + serde_json_core::to_slice(&metadata, buf) + }) + .topic(&topic) + .finish() + .unwrap(), + ) + .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(), + ) + .unwrap(); + } + + self.meta_published = true; + } } } diff --git a/src/settings.rs b/src/settings.rs index b6e479602..42fd86934 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -22,8 +22,7 @@ //! settings values //! 3. Unknown/unneeded settings values in flash can be actively ignored, facilitating simple flash //! storage sharing. -use crate::hardware::flash::Flash; -use crate::hardware::platform; +use crate::hardware::{flash::Flash, metadata::ApplicationMetadata, platform}; use core::fmt::Write; use miniconf::{TreeDeserialize, TreeKey, TreeSerialize}; use postcard::ser_flavors::Flavor; @@ -133,6 +132,9 @@ pub struct SerialSettingsPlatform { pub settings: Settings, /// The storage mechanism used to persist settings to between boots. pub storage: Flash, + + /// Metadata associated with the application + pub metadata: &'static ApplicationMetadata, } impl serial_settings::Platform for SerialSettingsPlatform { @@ -200,10 +202,44 @@ impl serial_settings::Platform for SerialSettingsPlatform { match cmd { "reboot" => cortex_m::peripheral::SCB::sys_reset(), "dfu" => platform::start_dfu_reboot(), + "service" => { + writeln!( + &mut self.interface, + "{:<20}: {} [{}]", + "Version", + self.metadata.firmware_version, + self.metadata.profile, + ) + .unwrap(); + writeln!( + &mut self.interface, + "{:<20}: {}", + "Hardware Revision", self.metadata.hardware_version + ) + .unwrap(); + writeln!( + &mut self.interface, + "{:<20}: {}", + "Rustc Version", self.metadata.rust_version + ) + .unwrap(); + writeln!( + &mut self.interface, + "{:<20}: {}", + "Features", self.metadata.features + ) + .unwrap(); + writeln!( + &mut self.interface, + "{:<20}: {}", + "Panic Info", self.metadata.panic_info + ) + .unwrap(); + } _ => { writeln!( self.interface_mut(), - "Invalid platform command: `{cmd}` not in [`dfu`, `reboot`]" + "Invalid platform command: `{cmd}` not in [`dfu`, `reboot`, `service`]" ) .ok(); } From 4f7e176a4ac4c27f8c0113f277fd69135f602e49 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 5 Dec 2023 11:15:46 +0100 Subject: [PATCH 2/5] Update src/hardware/metadata.rs --- src/hardware/metadata.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hardware/metadata.rs b/src/hardware/metadata.rs index 1847fc6d6..84cd632a9 100644 --- a/src/hardware/metadata.rs +++ b/src/hardware/metadata.rs @@ -24,7 +24,6 @@ impl ApplicationMetadata { /// /// # Args /// * `hardware_version` - The hardware version detected. - /// * `phy` - The identifier of the detected ethernet PHY. /// /// # Returns /// A reference to the global metadata. From ea14edf22bfceabb6320fc543d11db30c8302615 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 5 Dec 2023 12:17:57 +0100 Subject: [PATCH 3/5] Update CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Robert Jördens --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 428b7b97d..0ef2e1339 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added * Serial terminal is available on USB for settings configurations * Reboot to DFU support added via the serial terminal for remote bootloading -* The `alive` topic now contains metadata about the compiler, firmware, and hardware similar to +* The `meta` topic now contains metadata about the compiler, firmware, and hardware similar to Booster * Panic information is now persisted after reboot and available via telemetry and the USB serial console. From 20908a6a93a20ff559f0f82346ebe9a8e689b87c Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 5 Dec 2023 12:18:03 +0100 Subject: [PATCH 4/5] Update src/net/telemetry.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Robert Jördens --- src/net/telemetry.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/telemetry.rs b/src/net/telemetry.rs index d9cff7ac0..6cbbe768a 100644 --- a/src/net/telemetry.rs +++ b/src/net/telemetry.rs @@ -193,7 +193,7 @@ impl TelemetryClient { } = self; let mut topic = self.prefix.clone(); - topic.push_str("/alive/meta").unwrap(); + topic.push_str("/meta").unwrap(); if mqtt .client() From c48c27beff01d6215baca681c02b889f444f24c5 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 5 Dec 2023 13:00:26 +0100 Subject: [PATCH 5/5] Bumping MSRV to 1.66 --- .github/workflows/ci.yml | 2 +- CHANGELOG.md | 1 + Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e61cb6979..5b9aafb6f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,7 +53,7 @@ jobs: strategy: matrix: # keep MSRV in sync in ci.yaml and Cargo.toml - toolchain: [stable, '1.65.0'] + toolchain: [stable, '1.66.0'] features: [''] continue-on-error: [false] include: diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ef2e1339..b226864c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ console. ### Changed * Broker is no longer configured at compile time, but is maintained in device memory +* MSRV bumped to v1.66 ## [0.9.0](https://github.com/quartiq/stabilizer/compare/v0.8.1...v0.9.0) diff --git a/Cargo.toml b/Cargo.toml index a6659b352..4e1db96cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ readme = "README.md" documentation = "https://docs.rs/stabilizer/" edition = "2021" # keep MSRV in sync in ci.yaml and Cargo.toml -rust-version = "1.65" +rust-version = "1.66" build = "build.rs" exclude = [ ".gitignore",