diff --git a/Cargo.lock b/Cargo.lock index 5acd7c5..82bdd96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,9 +49,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "az" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" +checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" [[package]] name = "backtrace" @@ -151,9 +151,9 @@ dependencies = [ [[package]] name = "btuuid" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0acfef8a77a02866e04f7e2ad3f4c7b32d575696c49c4bbad742b4aecb8e4a3" +checksum = "f5f48f1e9b0aad0a4f05d17bdeae0fa20ff798e272a03a6940ca27ad9c5a6ae7" dependencies = [ "defmt 0.3.100", ] @@ -176,15 +176,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "chrono" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" -dependencies = [ - "num-traits", -] - [[package]] name = "cobs" version = "0.3.0" @@ -577,6 +568,17 @@ dependencies = [ "smart-leds", ] +[[package]] +name = "embassy-strike-driver" +version = "0.1.0" +source = "git+https://tangled.org/sachy.dev/strike-sensor#589b83a18cf89f76e5d50fdd2b3908ef0fd70833" +dependencies = [ + "defmt 1.0.1", + "embassy-rp", + "embassy-sync", + "embassy-time", +] + [[package]] name = "embassy-sync" version = "0.7.2" @@ -759,9 +761,9 @@ dependencies = [ [[package]] name = "fixed" -version = "1.29.0" +version = "1.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707070ccf8c4173548210893a0186e29c266901b71ed20cd9e2ca0193dfe95c3" +checksum = "c566da967934c6c7ee0458a9773de9b2a685bd2ce26a3b28ddfc740e640182f5" dependencies = [ "az", "bytemuck", @@ -958,6 +960,28 @@ dependencies = [ "either", ] +[[package]] +name = "jiff" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50" +dependencies = [ + "jiff-static", + "portable-atomic", + "portable-atomic-util", +] + +[[package]] +name = "jiff-static" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "keccak" version = "0.1.5" @@ -1237,7 +1261,6 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" name = "pico-strike" version = "0.1.0" dependencies = [ - "chrono", "cortex-m", "cortex-m-rt", "critical-section", @@ -1250,9 +1273,11 @@ dependencies = [ "embassy-futures", "embassy-net", "embassy-rp", + "embassy-strike-driver", "embassy-sync", "embassy-time", "heapless 0.8.0", + "jiff", "panic-probe", "portable-atomic", "postcard", @@ -1335,6 +1360,15 @@ dependencies = [ "critical-section", ] +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "postcard" version = "1.1.3" @@ -1378,18 +1412,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -1483,9 +1517,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc_version" @@ -1518,7 +1552,7 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "sachy-config" version = "0.1.0" -source = "git+https://tangled.org/sachy.dev/sachy-embed-core#ddd979631521a586c4e8b1df7bf8cef817921c98" +source = "git+https://tangled.org/sachy.dev/sachy-embed-core#7f489f3300e0769817b6b8f7394eb36c8e3f8a03" dependencies = [ "miette", "toml_edit", @@ -1527,7 +1561,7 @@ dependencies = [ [[package]] name = "sachy-fmt" version = "0.1.0" -source = "git+https://tangled.org/sachy.dev/sachy-embed-core#ddd979631521a586c4e8b1df7bf8cef817921c98" +source = "git+https://tangled.org/sachy.dev/sachy-embed-core#7f489f3300e0769817b6b8f7394eb36c8e3f8a03" dependencies = [ "defmt 1.0.1", ] @@ -1535,7 +1569,7 @@ dependencies = [ [[package]] name = "sachy-mdns" version = "0.1.0" -source = "git+https://tangled.org/sachy.dev/sachy-embed-core#ddd979631521a586c4e8b1df7bf8cef817921c98" +source = "git+https://tangled.org/sachy.dev/sachy-embed-core#7f489f3300e0769817b6b8f7394eb36c8e3f8a03" dependencies = [ "defmt 1.0.1", "embassy-time", @@ -1546,12 +1580,12 @@ dependencies = [ [[package]] name = "sachy-sntp" version = "0.1.0" -source = "git+https://tangled.org/sachy.dev/sachy-embed-core#ddd979631521a586c4e8b1df7bf8cef817921c98" +source = "git+https://tangled.org/sachy.dev/sachy-embed-core#7f489f3300e0769817b6b8f7394eb36c8e3f8a03" dependencies = [ - "chrono", "defmt 1.0.1", "embassy-net", "embassy-time", + "jiff", "sachy-fmt", ] @@ -1633,9 +1667,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "smallvec" @@ -1693,7 +1727,7 @@ dependencies = [ [[package]] name = "striker-proto" version = "0.1.0" -source = "git+https://tangled.org/sachy.dev/striker#66ac11c20cfedbe0da31e0ca83ce460143e5aa74" +source = "git+https://tangled.org/sachy.dev/striker#9ba3ebbda1208b254b6677d7c385cf79de61bad6" dependencies = [ "postcard", "serde", @@ -1813,18 +1847,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -2050,18 +2084,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.33" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +checksum = "fdea86ddd5568519879b8187e1cf04e24fce28f7fe046ceecbce472ff19a2572" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.33" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +checksum = "0c15e1b46eff7c6c91195752e0eeed8ef040e391cdece7c25376957d5f15df22" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 2b4302d..e290d23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,20 +38,25 @@ panic-probe = { version = "1.0", features = ["print-defmt"], optional = true } critical-section = "1.2.0" static_cell = "2.1" heapless = { version = "0.8" } -chrono = { version = "0.4", default-features = false } +jiff = { version = "0.2", default-features = false } portable-atomic = { version = "1.5", features = ["critical-section"] } serde = { version = "1.0.210", default-features = false, features = ["alloc"] } postcard = { version = "1.1.3", features = ["alloc"], default-features = false } rlsf = { version = "0.2.1", default-features = false } sachy-sntp = { git = "https://tangled.org/sachy.dev/sachy-embed-core", package = "sachy-sntp", default-features = false, features = [ "embassy-net", - "chrono", + "jiff", ] } sachy-mdns = { git = "https://tangled.org/sachy.dev/sachy-embed-core", package = "sachy-mdns", features = [ "server", ] } sachy-fmt = { git = "https://tangled.org/sachy.dev/sachy-embed-core", package = "sachy-fmt" } striker-proto = { git = "https://tangled.org/sachy.dev/striker", package = "striker-proto" } +embassy-strike-driver = { git = "https://tangled.org/sachy.dev/strike-sensor", package = "embassy-strike-driver", features = [ + "rp2040", + "alloc", + "debug" +] } embassy-embedded-hal = { version = "0.5.0" } embassy-sync = { version = "0.7.2" } diff --git a/pico-config.example.toml b/pico-config.example.toml index 5bbb265..3c4174a 100644 --- a/pico-config.example.toml +++ b/pico-config.example.toml @@ -4,8 +4,8 @@ PASSWORD = "astrongpassword123" HOST_NAME = "strike" [constants] -HEAP_SIZE = { type = "usize", value = 65536 } -BLOCK_SIZE = { type = "usize", value = 512 } -HOST_PORT = { type = "u16", value = 6125 } -BLIP_THRESHOLD = { type = "u16", value = 12 } -BLIP_SIZE = { type = "usize", value = 2 } +HEAP_SIZE = { type = "usize", value = "65536" } +BLOCK_SIZE = { type = "usize", value = "512" } +HOST_PORT = { type = "u16", value = "6125" } +BLIP_THRESHOLD = { type = "u16", value = "18" } +BLIP_SIZE = { type = "usize", value = "2" } diff --git a/src/adc.rs b/src/adc.rs deleted file mode 100644 index ab039ac..0000000 --- a/src/adc.rs +++ /dev/null @@ -1,63 +0,0 @@ -use embassy_rp::{ - Peri, - adc::{self, Adc, AdcPin, Async, Config}, - dma, - peripherals::ADC, -}; -use embassy_sync::{blocking_mutex::raw::RawMutex, mutex::Mutex}; - -use crate::Irqs; - -struct AdcInner<'device, T: dma::Channel> { - adc: Adc<'device, Async>, - pin: adc::Channel<'device>, - dma: Peri<'device, T>, -} - -pub struct AdcDriver<'device, M: RawMutex, T: dma::Channel> { - inner: Mutex>, -} - -impl AdcInner<'_, T> { - /// Samples at 100Khz, or 10us per sample. If a sampling fails due to conversion error, - /// it tries again until the sampling succeeds. - async fn read_many(&mut self, buf: &mut [u16]) { - while self - .adc - .read_many(&mut self.pin, buf, 480, self.dma.reborrow()) - .await - .is_err() - {} - } -} - -impl<'device, M: RawMutex, T: dma::Channel> AdcDriver<'device, M, T> { - pub fn new( - inner: Peri<'device, ADC>, - pin: Peri<'device, impl AdcPin + 'device>, - dma: Peri<'device, T>, - ) -> Self { - Self { - inner: Mutex::new(AdcInner { - adc: Adc::new(inner, Irqs, Config::default()), - pin: adc::Channel::new_pin(pin, embassy_rp::gpio::Pull::None), - dma, - }), - } - } - - /// Samples at 100Khz, or 10us per sample. If a sampling fails due to conversion error, - /// it tries again until the sampling succeeds. - pub async fn sample(&self, buf: &mut [u16]) { - // Gain a lock to the inner ADC state, then do a read. - self.inner.lock().await.read_many(buf).await; - } - - pub async fn sample_average(&self, buf: &mut [u16]) -> u16 { - self.sample(buf).await; - - let len = buf.len() as u32; - - (buf.iter().copied().map(u32::from).sum::() / len) as u16 - } -} diff --git a/src/detector.rs b/src/detector.rs index 85d7968..33caeeb 100644 --- a/src/detector.rs +++ b/src/detector.rs @@ -1,23 +1,17 @@ -mod analysis; -mod data; - -use core::cell::Cell; - use alloc::vec::Vec; use sachy_fmt::{info, unwrap}; use embassy_futures::select::select3; use embassy_rp::peripherals::DMA_CH1; -use embassy_sync::{ - blocking_mutex::raw::NoopRawMutex, - zerocopy_channel::{Channel as ZChannel, Receiver, Sender}, +use embassy_strike_driver::{ + DetectorConfig, DetectorDriver, ZeroCopyChannel, + drivers::rp::{AdcDriver, PwmDriver}, }; -use embassy_time::{Duration, Instant, Ticker, Timer}; +use embassy_sync::{blocking_mutex::raw::NoopRawMutex, zerocopy_channel::Channel as ZChannel}; +use embassy_time::Timer; use crate::{ - adc::AdcDriver, - constants::{BLIP_SIZE, BLOCK_SIZE}, - pwm::PwmDriver, + constants::{BLIP_SIZE, BLIP_THRESHOLD, BLOCK_SIZE}, rtc::GlobalRtc, updates::UpdateConnection, utils::{static_alloc, try_buffer, try_static_timestamped_block_vecs}, @@ -37,16 +31,16 @@ pub async fn detector_task( info!("Allocating detector resources"); let blocks = unwrap!( - try_static_timestamped_block_vecs(4, BLOCK_SIZE), + try_static_timestamped_block_vecs::(2), "Couldn't allocate block buffers" ); - let buf_channel: &mut ZChannel)> = - static_alloc(ZChannel::new(blocks)); + let buf_channel: &mut ZeroCopyChannel = static_alloc(ZChannel::new(blocks)); let (mut sender, mut receiver) = buf_channel.split(); - let mut detector = Detector::new(adc, pwm); + let config = DetectorConfig::new(BLIP_THRESHOLD, BLIP_SIZE); + let mut detector = DetectorDriver::new(config, rtc.track_time().await, pwm, adc); let mut samples = unwrap!(try_buffer(64), "Failed to allocate sample buffer"); let mut peaks = Vec::new(); @@ -56,183 +50,19 @@ pub async fn detector_task( ); loop { - let average = detector.tune(samples.as_mut_slice()).await; + detector.tune(samples.as_mut_slice()).await; select3( - detector.sample(&mut sender, rtc), - detector.analyse(&mut receiver, average, &mut peaks), - detector.tick(rtc), + detector.sample_with_zerocopy(&mut sender), + detector.detect_with_zerocopy( + &mut receiver, + &mut peaks, + UpdateConnection::transmit_update, + ), + detector.tick(UpdateConnection::transmit_update), ) .await; - } -} - -struct Detector<'device> { - adc: AdcDriver<'device, NoopRawMutex, DMA_CH1>, - pwm: PwmDriver<'device>, - state: DetectorState, -} - -#[derive(Debug)] -struct DetectorState { - strikes: Cell, - warn_level: Cell, -} - -impl Default for DetectorState { - fn default() -> Self { - Self { - strikes: Cell::new(0), - warn_level: Cell::new(255), - } - } -} - -impl<'device> Detector<'device> { - fn new(adc: AdcDriver<'device, NoopRawMutex, DMA_CH1>, mut pwm: PwmDriver<'device>) -> Self { - pwm.enable(); - - Self { - adc, - pwm, - state: DetectorState::default(), - } - } -} - -impl Detector<'_> { - async fn tune(&mut self, samples: &mut [u16]) -> u16 { - info!("Tuning Detector for correct voltage settings"); - let mut duty = 0; - self.pwm.set_duty(duty); - Timer::after_secs(2).await; - let mut act_value = self.adc.sample_average(samples).await; - - info!("initial ACT: {}", act_value); - - while act_value < 1364 { - duty += 2; - if duty >= 256 { - duty = 0; - self.pwm.set_duty(duty); - Timer::after_secs(2).await; - act_value = self.adc.sample_average(samples).await; - info!("Restarting tuning"); - continue; - } - self.pwm.set_duty(duty); - Timer::after_millis(250).await; - act_value = self.adc.sample_average(samples).await; - info!("ACT: {}, Duty: {}", act_value, duty); - } - - duty = (duty / 3) * 2; - self.pwm.set_duty(duty); - info!("Set detection duty to: {}", duty); - // Allow voltage level to stabilize after tuning - Timer::after_secs(2).await; - info!("Ready for strike detection"); - - self.adc.sample_average(samples).await - } - - async fn sample( - &self, - data: &mut Sender<'static, NoopRawMutex, (i64, Vec)>, - rtc: GlobalRtc<'static>, - ) { - let track_time = rtc.track_time().await; - - loop { - let (timestamp, buf) = data.send().await; - *timestamp = track_time.timestamp(); - self.adc.sample(buf).await; - data.send_done(); - } - } - - async fn analyse( - &self, - data: &mut Receiver<'static, NoopRawMutex, (i64, Vec)>, - mut average: u16, - peaks: &mut Vec, - ) { - loop { - peaks.clear(); - - let (timestamp, buf) = data.receive().await; - - let new_avg = - analysis::analyse_buffer_by_stepped_windows(buf.as_slice(), average, peaks); - - let blips = peaks.len(); - - if blips >= BLIP_SIZE { - self.state - .strikes - .update(|strike| strike.saturating_add(32)); - - if let Some(net_data) = UpdateConnection::can_update() { - data::transmit_strike( - *timestamp, - buf.as_slice(), - peaks.as_slice(), - average, - &net_data, - ); - } - - info!( - "Strikes detected at {}s! avg {}, signal strength: {}, blip {}, level {}", - Instant::now().as_secs(), - average, - blips, - peaks.iter().max(), - self.state.warn_level.get() - ); - } - - data.receive_done(); - - average = new_avg; - } - } - - async fn tick(&self, rtc: GlobalRtc<'static>) { - let mut inactive: Option = None; - let mut interval = Ticker::every(Duration::from_secs(1)); - let track_time = rtc.track_time().await; - - loop { - interval.next().await; - let strikes = self.state.strikes.get(); - let mut warn_level = self.state.warn_level.get(); - - if strikes > 32 { - warn_level = warn_level.saturating_add(strikes); - } - - let decay = warn_level >> 8; - - self.state.strikes.set(0); - self.state.warn_level.set(warn_level - decay); - match inactive { - Some(_) if decay > 0 => { - inactive = None; - } - Some(val) if val.elapsed() >= Duration::from_secs(3600) => break, - None if decay == 0 => { - inactive = Some(Instant::now()); - } - None => { - if let Some(net_data) = UpdateConnection::can_update() { - let now = track_time.timestamp(); - data::transmit_level_update(now, decay, &net_data); - } - } - _ => continue, - } - } + detector.reset_timer_source(rtc).await; } } diff --git a/src/detector/analysis.rs b/src/detector/analysis.rs deleted file mode 100644 index 0d8f972..0000000 --- a/src/detector/analysis.rs +++ /dev/null @@ -1,30 +0,0 @@ -use alloc::vec::Vec; - -use crate::constants::{BLIP_THRESHOLD, BLOCK_SIZE}; - -pub(super) fn analyse_buffer_by_stepped_windows( - buf: &[u16], - average: u16, - peaks: &mut Vec, -) -> u16 { - const CHUNK_SIZE: usize = BLOCK_SIZE / 32; - const CHUNK_STEP: usize = CHUNK_SIZE / 2; - - let mut total = 0u32; - let mut len = 0u32; - - for (i, window) in buf.windows(CHUNK_SIZE).enumerate().step_by(CHUNK_STEP) { - let window_total = window.iter().copied().sum::(); - let window_avg = window_total / CHUNK_SIZE as u16; - let diff = average.saturating_sub(window_avg); - - if diff > BLIP_THRESHOLD { - peaks.push(i as u16); - } else { - total += window_total as u32; - len += CHUNK_SIZE as u32; - } - } - - (total / len) as u16 -} diff --git a/src/detector/data.rs b/src/detector/data.rs deleted file mode 100644 index fe3a31e..0000000 --- a/src/detector/data.rs +++ /dev/null @@ -1,32 +0,0 @@ -use striker_proto::{StrikerResponse, Update}; - -use crate::updates::NetDataSender; - -pub(super) fn transmit_level_update(timestamp: i64, warn_level: u16, net_data: &NetDataSender) { - net_data - .try_send(StrikerResponse::Update(Update::Warning { - timestamp, - level: warn_level, - })) - .ok(); -} - -pub(super) fn transmit_strike( - timestamp: i64, - samples: &[u16], - peaks: &[u16], - average: u16, - net_data: &NetDataSender, -) { - net_data - .try_send(StrikerResponse::Update(Update::Strike { - timestamp, - peaks: peaks.to_vec(), - samples: samples - .iter() - .map(|&sample| (average as i16).saturating_sub_unsigned(sample)) - .collect(), - average, - })) - .ok(); -} diff --git a/src/main.rs b/src/main.rs index 7e6c68a..5d7a4bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ #![no_std] #![no_main] -mod adc; mod allocator; mod detector; mod errors; @@ -12,7 +11,6 @@ mod locks; mod net; #[cfg(not(feature = "defmt"))] mod panic_handler; -mod pwm; mod rpc; mod rtc; mod state; @@ -29,7 +27,6 @@ use embassy_rp::{ multicore::{Stack, spawn_core1}, peripherals::PIO0, pio::{InterruptHandler, Pio}, - pwm::Config as PwmConfig, rtc::{self as rp_rtc, Rtc}, }; use sachy_fmt::*; @@ -64,10 +61,9 @@ fn main() -> ! { unwrap!(HEAP.init()); info!("Initialising drivers"); - let mut c = PwmConfig::default(); - c.top = u8::MAX as u16; - let pwm = pwm::PwmDriver::new(p.PWM_SLICE5, p.PIN_27, c); - let adc = adc::AdcDriver::new(p.ADC, p.PIN_26, p.DMA_CH1); + let pwm = embassy_strike_driver::drivers::rp::PwmDriver::new(p.PWM_SLICE5, p.PIN_27); + let adc = + embassy_strike_driver::drivers::rp::AdcDriver::new(p.ADC, p.PIN_26, p.DMA_CH1, Irqs); let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); diff --git a/src/pwm.rs b/src/pwm.rs deleted file mode 100644 index 944c9c5..0000000 --- a/src/pwm.rs +++ /dev/null @@ -1,45 +0,0 @@ -use embassy_rp::{ - Peri, - pwm::{ChannelBPin, Config as PwmConfig, Pwm, Slice}, -}; - -pub struct PwmDriver<'device> { - config: PwmConfig, - pwm: Pwm<'device>, -} - -impl<'device> PwmDriver<'device> { - pub fn new( - slice: Peri<'device, T>, - b: Peri<'device, impl ChannelBPin>, - config: PwmConfig, - ) -> Self - where - T: Slice, - { - let pwm = Pwm::new_output_b(slice, b, config.clone()); - - Self { pwm, config } - } - - pub fn set_duty(&mut self, duty: u16) { - self.config.compare_b = duty.clamp(0, self.config.top); - self.pwm.set_config(&self.config); - } - - pub fn enable(&mut self) { - self.config.enable = true; - self.pwm.set_config(&self.config); - } - - pub fn disable(&mut self) { - self.config.enable = false; - self.pwm.set_config(&self.config); - } -} - -impl Drop for PwmDriver<'_> { - fn drop(&mut self) { - self.disable(); - } -} diff --git a/src/rtc.rs b/src/rtc.rs index 1837474..7ec431f 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -6,13 +6,17 @@ use core::{ task::Poll, }; -use chrono::{DateTime as ChronoTime, Datelike, TimeDelta, Timelike, Utc}; use embassy_rp::{ peripherals, rtc::{DateTime, DateTimeFilter, DayOfWeek, Rtc}, }; +use embassy_strike_driver::traits::TimeSource; use embassy_sync::{rwlock::RwLock, waitqueue::AtomicWaker}; use embassy_time::Instant; +use jiff::{ + SignedDuration, Timestamp, + tz::{Offset, TimeZone}, +}; use sachy_sntp::SntpTimestamp; use static_cell::StaticCell; @@ -23,7 +27,7 @@ static ALARM_OCCURRED: AtomicBool = AtomicBool::new(false); struct RtcInner<'device> { rtc: Rtc<'device, peripherals::RTC>, - timestamp: ChronoTime, + timestamp: Timestamp, offset: Instant, } @@ -51,11 +55,11 @@ impl GlobalRtc<'_> { inner.rtc.is_running() && inner.rtc.alarm_scheduled().is_some() } - async fn get_timestamp(&self) -> ChronoTime { + async fn get_timestamp(&self) -> Timestamp { let inner = self.0.read().await; let elapsed = inner.offset.elapsed().as_micros() as i64; - inner.timestamp + TimeDelta::microseconds(elapsed) + inner.timestamp + SignedDuration::from_micros(elapsed) } pub async fn track_time(&self) -> TimeTracker { @@ -66,34 +70,35 @@ impl GlobalRtc<'_> { } pub async fn set_rtc_datetime(&self, timestamp: SntpTimestamp) -> Result<(), PicoError> { - let timestamp = timestamp.try_to_utc()?; + let timestamp = timestamp.try_to_unix_timestamp()?; + let zoned = timestamp.to_zoned(TimeZone::fixed(Offset::UTC)); let mut inner = self.0.write().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() { - chrono::Weekday::Mon => DayOfWeek::Monday, - chrono::Weekday::Tue => DayOfWeek::Tuesday, - chrono::Weekday::Wed => DayOfWeek::Wednesday, - chrono::Weekday::Thu => DayOfWeek::Thursday, - chrono::Weekday::Fri => DayOfWeek::Friday, - chrono::Weekday::Sat => DayOfWeek::Saturday, - chrono::Weekday::Sun => DayOfWeek::Sunday, + year: zoned.year() as u16, + month: zoned.month() as u8, + day: zoned.day() as u8, + day_of_week: match zoned.weekday() { + jiff::civil::Weekday::Monday => DayOfWeek::Monday, + jiff::civil::Weekday::Tuesday => DayOfWeek::Tuesday, + jiff::civil::Weekday::Wednesday => DayOfWeek::Wednesday, + jiff::civil::Weekday::Thursday => DayOfWeek::Thursday, + jiff::civil::Weekday::Friday => DayOfWeek::Friday, + jiff::civil::Weekday::Saturday => DayOfWeek::Saturday, + jiff::civil::Weekday::Sunday => DayOfWeek::Sunday, }, - hour: timestamp.hour() as u8, - minute: timestamp.minute() as u8, - second: timestamp.second() as u8, + hour: zoned.hour() as u8, + minute: zoned.minute() as u8, + second: zoned.second() as u8, })?; // Schedule the next alarm from now in order to reset the RTC // the next day on the same hour, on the hour. inner.rtc.schedule_alarm( DateTimeFilter::default() - .hour(timestamp.hour() as u8) + .hour(zoned.hour() as u8) .minute(0) .second(0), ); @@ -127,15 +132,22 @@ impl GlobalRtc<'_> { } pub struct TimeTracker { - timestamp: ChronoTime, + timestamp: Timestamp, offset: Instant, } -impl TimeTracker { +impl TimeSource for TimeTracker { + type Source = GlobalRtc<'static>; + #[inline] - pub fn timestamp(&self) -> i64 { + fn timestamp(&self) -> i64 { let elapsed = self.offset.elapsed().as_micros() as i64; - (self.timestamp + TimeDelta::microseconds(elapsed)).timestamp_micros() + (self.timestamp + SignedDuration::from_micros(elapsed)).as_microsecond() + } + + async fn reset_from_source(&mut self, source: Self::Source) { + self.timestamp = source.get_timestamp().await; + self.offset = Instant::now(); } } diff --git a/src/updates.rs b/src/updates.rs index c987205..f87c878 100644 --- a/src/updates.rs +++ b/src/updates.rs @@ -1,5 +1,7 @@ +use embassy_strike_driver::DetectorUpdate; use embassy_sync::channel::{Channel, Receiver, Sender}; -use striker_proto::StrikerResponse; +use sachy_fmt::info; +use striker_proto::{StrikerResponse, Update}; use crate::{ locks::NetDataLock, @@ -34,4 +36,42 @@ impl UpdateConnection { pub fn can_update() -> Option { Self::is_connected().then(|| NET_CHANNEL.sender()) } + + pub fn transmit_update(update: DetectorUpdate<'_>) { + let sender = Self::can_update(); + + match update { + DetectorUpdate::Tick { timestamp, level } => { + sender.and_then(|sender| { + sender + .try_send(StrikerResponse::Update(Update::Warning { + timestamp, + level, + })) + .ok() + }); + } + DetectorUpdate::Detection { + timestamp, + average, + samples, + peaks, + } => { + info!("STRIKE @ {}: Peaks {}", timestamp, peaks); + sender.and_then(|sender| { + sender + .try_send(StrikerResponse::Update(Update::Strike { + timestamp, + peaks: peaks.to_vec(), + samples: samples + .iter() + .map(|&sample| (average as i16).saturating_sub_unsigned(sample)) + .collect(), + average, + })) + .ok() + }); + } + }; + } } diff --git a/src/utils.rs b/src/utils.rs index 4c37e3f..377fca6 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -27,19 +27,13 @@ pub fn try_static_buffer_with( Ok(try_buffer_with(capacity, f)?.leak()) } -pub fn try_static_timestamped_block_vecs( +pub fn try_static_timestamped_block_vecs( block_num: usize, - block_capacity: usize, -) -> Result<&'static mut [(i64, Vec)], PicoError> { +) -> Result<&'static mut [(i64, [T; CAP])], PicoError> { let mut blocks = Vec::new(); blocks.try_reserve_exact(block_num)?; - - for _ in 0..block_num { - let block = try_buffer(block_capacity)?; - - blocks.push((0, block)); - } + blocks.resize_with(block_num, || (0, [T::default(); CAP])); Ok(blocks.leak()) }