From 56e7885f2fd2f78d3230e15fd9c151f1d0f6a5fb Mon Sep 17 00:00:00 2001 From: Sachymetsu Date: Sun, 28 Dec 2025 18:03:24 +0000 Subject: [PATCH] feat: Custom error handling, rtc improvements --- Cargo.lock | 16 ++++++++-------- README.md | 6 +++--- src/errors.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 5 +++-- src/net.rs | 19 ++++++++++++------- src/rtc.rs | 30 +++++++++++------------------- src/utils.rs | 8 +++++--- 7 files changed, 84 insertions(+), 42 deletions(-) create mode 100644 src/errors.rs diff --git a/Cargo.lock b/Cargo.lock index b7d5d62..4e5b5e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1524,9 +1524,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f59e70c4aef1e55797c2e8fd94a4f2a973fc972cfde0e0b05f683667b0cd39dd" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" dependencies = [ "critical-section", ] @@ -1574,9 +1574,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0" dependencies = [ "unicode-ident", ] @@ -1720,7 +1720,7 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "sachy-config" version = "0.1.0" -source = "git+https://tangled.org/sachy.dev/sachy-embed-core#5826f16db7829033015ac5dc85f7ec811e4e113c" +source = "git+https://tangled.org/sachy.dev/sachy-embed-core#45c0bea9459a848bac56c5ceb4fe9b22305a351b" dependencies = [ "facet", "facet-kdl", @@ -1730,7 +1730,7 @@ dependencies = [ [[package]] name = "sachy-fmt" version = "0.1.0" -source = "git+https://tangled.org/sachy.dev/sachy-embed-core#5826f16db7829033015ac5dc85f7ec811e4e113c" +source = "git+https://tangled.org/sachy.dev/sachy-embed-core#45c0bea9459a848bac56c5ceb4fe9b22305a351b" dependencies = [ "defmt 1.0.1", ] @@ -1738,7 +1738,7 @@ dependencies = [ [[package]] name = "sachy-mdns" version = "0.1.0" -source = "git+https://tangled.org/sachy.dev/sachy-embed-core#5826f16db7829033015ac5dc85f7ec811e4e113c" +source = "git+https://tangled.org/sachy.dev/sachy-embed-core#45c0bea9459a848bac56c5ceb4fe9b22305a351b" dependencies = [ "defmt 1.0.1", "embassy-time", @@ -1749,7 +1749,7 @@ dependencies = [ [[package]] name = "sachy-sntp" version = "0.1.0" -source = "git+https://tangled.org/sachy.dev/sachy-embed-core#5826f16db7829033015ac5dc85f7ec811e4e113c" +source = "git+https://tangled.org/sachy.dev/sachy-embed-core#45c0bea9459a848bac56c5ceb4fe9b22305a351b" dependencies = [ "chrono", "defmt 1.0.1", diff --git a/README.md b/README.md index d21d257..dee0ca8 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,11 @@ Pico Strike! is a Rust written firmware to have a RPi Pico W (RP2040) do lightni - [x] PWM Driver for tuning detector circuit voltage - [x] ADC zero-copy DMA reading from detection circuit - [x] Heap allocated resources -- [ ] Error Handling -- [ ] Panic handling and resetting of device +- [x] Error Handling +- [x] Panic handling and resetting of device - [ ] ~~Intelligent tuning of noise thresholds, and detection heuristics~~ - [x] Simpler, more sensitive and anti-noise heuristic -- [ ] Zero-copy/loading of env configuration data +- [x] Zero-copy/loading of env configuration data ## Network - [x] Wifi stack setup diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..39c8d28 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,42 @@ +use alloc::collections::TryReserveError; +use embassy_rp::rtc::RtcError; +use sachy_sntp::SntpError; + + +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum PicoError { + InvalidSntpTime(SntpError), + InvalidRtcTime, + AllocationError, +} + +impl core::fmt::Display for PicoError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + PicoError::InvalidSntpTime(reason) => write!(f, "Invalid SNTP time: {reason:?}"), + PicoError::InvalidRtcTime => write!(f, "Invalid RTC time: Year is out of bounds"), + PicoError::AllocationError => write!(f, "Failed to allocate memory"), + } + } +} + +impl core::error::Error for PicoError {} + +impl From for PicoError { + fn from(value: SntpError) -> Self { + Self::InvalidSntpTime(value) + } +} + +impl From for PicoError { + fn from(_value: RtcError) -> Self { + Self::InvalidRtcTime + } +} + +impl From for PicoError { + fn from(_value: TryReserveError) -> Self { + Self::AllocationError + } +} diff --git a/src/main.rs b/src/main.rs index 6190ee1..97105d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,16 +7,17 @@ mod adc; mod allocator; mod detector; +mod errors; mod locks; mod net; +#[cfg(not(feature = "defmt"))] +mod panic_handler; mod pwm; mod rtc; mod state; mod updates; mod utils; mod wifi; -#[cfg(not(feature = "defmt"))] -mod panic_handler; use crate::{allocator::PicoHeap, rtc::GlobalRtc}; use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; diff --git a/src/net.rs b/src/net.rs index a8ace3c..55a7e94 100644 --- a/src/net.rs +++ b/src/net.rs @@ -35,14 +35,19 @@ pub async fn udp_stack(stack: embassy_net::Stack<'static>, rtc: GlobalRtc<'stati unwrap!(stack.join_multicast_group(GROUP_ADDR_V4)); if !rtc.is_running().await { - let addr = stack.dns_query("pool.ntp.org", dns::DnsQueryType::A).await; - let addr = unwrap!(addr); - - match udp.resolve_time(addr.as_slice()).await { - Ok(time) => { - unwrap!(rtc.set_rtc_datetime(time).await, "Failed to set time"); + loop { + let Ok(addr) = stack.dns_query("pool.ntp.org", dns::DnsQueryType::A).await else { + error!("Failed to query DNS for an NTP server. Retrying..."); + continue; + }; + + match udp.resolve_time(addr.as_slice()).await { + Ok(time) => { + unwrap!(rtc.set_rtc_datetime(time).await); + break; + } + Err(e) => error!("Failed to resolve SNTP time: {}", e), } - Err(e) => error!("Failed to resolve SNTP time: {}", e), } } diff --git a/src/rtc.rs b/src/rtc.rs index 9bdee5e..267a027 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -3,15 +3,14 @@ use chrono::{DateTime as ChronoTime, Datelike, TimeDelta, Timelike, Utc}; use embassy_rp::{ peripherals, - rtc::{DateTime, DateTimeError, DayOfWeek, Rtc, RtcError}, + rtc::{DateTime, DayOfWeek, Rtc}, }; use embassy_sync::mutex::Mutex; use embassy_time::Instant; -use sachy_fmt::unwrap; use sachy_sntp::SntpTimestamp; use static_cell::StaticCell; -use crate::locks::RtcLock; +use crate::{errors::PicoError, locks::RtcLock}; struct RtcInner<'device> { rtc: Rtc<'device, peripherals::RTC>, @@ -50,18 +49,14 @@ impl GlobalRtc<'_> { inner.timestamp + TimeDelta::microseconds(elapsed) } - pub async fn set_rtc_datetime(&self, timestamp: SntpTimestamp) -> Result<(), RtcError> { - let timestamp = unwrap!(timestamp.try_to_naive_datetime()); - let year = timestamp.year(); + pub async fn set_rtc_datetime(&self, timestamp: SntpTimestamp) -> Result<(), PicoError> { + let timestamp = timestamp.try_to_utc()?; - if !(0..=4096).contains(&year) { - return Err(RtcError::InvalidDateTime(DateTimeError::InvalidYear)); - } - - let ms = timestamp.and_utc(); - - let timestamp: DateTime = DateTime { - year: year as u16, + let mut inner = self.0.lock().await; + inner.offset = Instant::now(); + inner.timestamp = timestamp; + inner.rtc.set_datetime(DateTime { + year: timestamp.year() as u16, month: timestamp.month() as u8, day: timestamp.day() as u8, day_of_week: match timestamp.weekday() { @@ -76,11 +71,8 @@ impl GlobalRtc<'_> { hour: timestamp.hour() as u8, minute: timestamp.minute() as u8, second: timestamp.second() as u8, - }; + })?; - let mut inner = self.0.lock().await; - inner.offset = Instant::now(); - inner.timestamp = ms; - inner.rtc.set_datetime(timestamp) + Ok(()) } } diff --git a/src/utils.rs b/src/utils.rs index 40ec1ba..acf4719 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,10 +1,12 @@ -use alloc::{boxed::Box, collections::TryReserveError, vec::Vec}; +use alloc::{boxed::Box, vec::Vec}; + +use crate::errors::PicoError; pub fn static_alloc(value: T) -> &'static mut T { Box::leak(Box::new(value)) } -pub fn try_buffer(capacity: usize) -> Result, TryReserveError> { +pub fn try_buffer(capacity: usize) -> Result, PicoError> { let mut buffer = Vec::new(); buffer.try_reserve_exact(capacity)?; @@ -17,7 +19,7 @@ pub fn try_buffer(capacity: usize) -> Result, TryReserveError pub fn try_static_timestamped_block_vecs( block_num: usize, block_capacity: usize, -) -> Result<&'static mut [(i64, Vec)], TryReserveError> { +) -> Result<&'static mut [(i64, Vec)], PicoError> { let mut blocks = Vec::new(); blocks.try_reserve_exact(block_num)?; -- 2.51.2