Repo for designs & driver for a TA7642 powered lightning detector

feat: TimerSource tweaks, Config API

authored by sachy.dev and committed by

Tangled 2210a4d3 163e8938

+121 -21
+60 -1
Cargo.lock
··· 70 70 71 71 [[package]] 72 72 name = "bitflags" 73 + version = "1.3.2" 74 + source = "registry+https://github.com/rust-lang/crates.io-index" 75 + checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 76 + 77 + [[package]] 78 + name = "bitflags" 73 79 version = "2.10.0" 74 80 source = "registry+https://github.com/rust-lang/crates.io-index" 75 81 checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" ··· 190 196 checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e" 191 197 192 198 [[package]] 199 + name = "defmt" 200 + version = "1.0.1" 201 + source = "registry+https://github.com/rust-lang/crates.io-index" 202 + checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" 203 + dependencies = [ 204 + "bitflags 1.3.2", 205 + "defmt-macros", 206 + ] 207 + 208 + [[package]] 209 + name = "defmt-macros" 210 + version = "1.0.1" 211 + source = "registry+https://github.com/rust-lang/crates.io-index" 212 + checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" 213 + dependencies = [ 214 + "defmt-parser", 215 + "proc-macro-error2", 216 + "proc-macro2", 217 + "quote", 218 + "syn", 219 + ] 220 + 221 + [[package]] 222 + name = "defmt-parser" 223 + version = "1.0.0" 224 + source = "registry+https://github.com/rust-lang/crates.io-index" 225 + checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" 226 + dependencies = [ 227 + "thiserror", 228 + ] 229 + 230 + [[package]] 193 231 name = "digest" 194 232 version = "0.10.7" 195 233 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 295 333 version = "0.1.0" 296 334 dependencies = [ 297 335 "critical-section", 336 + "defmt", 298 337 "embassy-rp", 299 338 "embassy-sync", 300 339 "embassy-time", ··· 868 907 source = "registry+https://github.com/rust-lang/crates.io-index" 869 908 checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" 870 909 dependencies = [ 871 - "bitflags", 910 + "bitflags 2.10.0", 872 911 ] 873 912 874 913 [[package]] ··· 1061 1100 checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 1062 1101 dependencies = [ 1063 1102 "winapi-util", 1103 + ] 1104 + 1105 + [[package]] 1106 + name = "thiserror" 1107 + version = "2.0.18" 1108 + source = "registry+https://github.com/rust-lang/crates.io-index" 1109 + checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" 1110 + dependencies = [ 1111 + "thiserror-impl", 1112 + ] 1113 + 1114 + [[package]] 1115 + name = "thiserror-impl" 1116 + version = "2.0.18" 1117 + source = "registry+https://github.com/rust-lang/crates.io-index" 1118 + checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" 1119 + dependencies = [ 1120 + "proc-macro2", 1121 + "quote", 1122 + "syn", 1064 1123 ] 1065 1124 1066 1125 [[package]]
+3
embassy-strike-driver/Cargo.toml
··· 9 9 10 10 [features] 11 11 default = [] 12 + debug = ["defmt"] 12 13 alloc = [] 13 14 heapless = ["dep:heapless"] 15 + defmt = ["dep:defmt"] 14 16 rp2040 = ["dep:embassy-rp", "embassy-rp/rp2040"] 15 17 rp235xa = ["dep:embassy-rp", "embassy-rp/rp235xa"] 16 18 rp235xb = ["dep:embassy-rp", "embassy-rp/rp235xb"] ··· 20 22 embassy-sync.workspace = true 21 23 embassy-rp = { workspace = true, optional = true } 22 24 heapless = { version = "0.9.2", optional = true } 25 + defmt = { workspace = true, optional = true } 23 26 24 27 [dev-dependencies] 25 28 embassy-time = { workspace = true, features = ["mock-driver", "generic-queue-8"] }
+3 -3
embassy-strike-driver/src/drivers.rs
··· 18 18 dma: Peri<'device, T>, 19 19 } 20 20 21 - pub struct RpAdcDriver<'device, M: RawMutex, T: dma::Channel> { 21 + pub struct AdcDriver<'device, M: RawMutex, T: dma::Channel> { 22 22 inner: Mutex<M, AdcInner<'device, T>>, 23 23 } 24 24 ··· 43 43 } 44 44 } 45 45 46 - impl<'device, M: RawMutex, T: dma::Channel> RpAdcDriver<'device, M, T> { 46 + impl<'device, M: RawMutex, T: dma::Channel> AdcDriver<'device, M, T> { 47 47 pub fn new( 48 48 inner: Peri<'device, ADC>, 49 49 pin: Peri<'device, impl AdcPin + 'device>, ··· 60 60 } 61 61 } 62 62 63 - impl<'device, M: RawMutex, T: dma::Channel> AdcSource for RpAdcDriver<'device, M, T> { 63 + impl<'device, M: RawMutex, T: dma::Channel> AdcSource for AdcDriver<'device, M, T> { 64 64 async fn sample_average(&self, samples: &mut [u16]) -> u16 { 65 65 self.sample(samples).await; 66 66
+52 -16
embassy-strike-driver/src/lib.rs
··· 11 11 12 12 use core::cell::Cell; 13 13 14 + #[cfg(feature = "debug")] 15 + use defmt::info; 14 16 use embassy_sync::{ 15 17 blocking_mutex::raw::NoopRawMutex, 16 18 zerocopy_channel::{Channel, Receiver, Sender}, ··· 23 25 pub type ZeroCopyChannel<'device> = Channel<'device, NoopRawMutex, (i64, [u16; BLOCK_SIZE])>; 24 26 25 27 #[derive(Debug)] 28 + #[cfg_attr(feature = "defmt", derive(defmt::Format))] 26 29 struct DetectorState { 27 30 max_duty: Cell<u8>, 28 31 duty: Cell<u8>, ··· 44 47 } 45 48 46 49 #[derive(Debug)] 50 + #[cfg_attr(feature = "defmt", derive(defmt::Format))] 47 51 pub struct DetectorConfig { 48 52 blip_threshold: Cell<u16>, 49 53 blip_size: Cell<usize>, 50 54 } 51 55 52 - impl Default for DetectorConfig { 53 - fn default() -> Self { 56 + impl DetectorConfig { 57 + pub const fn new(blip_threshold: u16, blip_size: usize) -> Self { 54 58 Self { 55 - blip_threshold: Cell::new(14), 56 - blip_size: Cell::new(2), 59 + blip_threshold: Cell::new(blip_threshold), 60 + blip_size: Cell::new(blip_size), 57 61 } 62 + } 63 + 64 + pub const fn blip_threshold(&self) -> u16 { 65 + self.blip_threshold.get() 66 + } 67 + 68 + pub const fn blip_size(&self) -> usize { 69 + self.blip_size.get() 70 + } 71 + 72 + pub fn set_blip_threshold(&self, blip_threshold: u16) { 73 + self.blip_threshold.set(blip_threshold); 74 + } 75 + 76 + pub fn set_blip_size(&self, blip_size: usize) { 77 + self.blip_size.set(blip_size); 78 + } 79 + } 80 + 81 + impl Default for DetectorConfig { 82 + fn default() -> Self { 83 + Self::new(14, 2) 58 84 } 59 85 } 60 86 61 87 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 88 + #[cfg_attr(feature = "defmt", derive(defmt::Format))] 62 89 pub enum DetectorUpdate<'a> { 63 90 Tick { 64 91 timestamp: i64, ··· 74 101 pub struct DetectorDriver<T: TimeSource, P: PwmSource, A: AdcSource> { 75 102 state: DetectorState, 76 103 config: DetectorConfig, 77 - timer_source: T, 104 + timer: T, 78 105 pwm: P, 79 106 adc: A, 80 107 } ··· 85 112 P: PwmSource, 86 113 A: AdcSource, 87 114 { 88 - pub fn new(config: DetectorConfig, timer_source: T, pwm: P, adc: A) -> Self { 115 + pub fn new(config: DetectorConfig, timer: T, pwm: P, adc: A) -> Self { 89 116 Self { 90 117 state: Default::default(), 91 118 config, 92 - timer_source, 119 + timer, 93 120 pwm, 94 121 adc, 95 122 } 96 123 } 97 124 98 - pub fn reset_timer_source(&mut self) { 99 - self.timer_source = T::get_source(); 125 + pub fn reset_timer_source(&mut self, timer_source: T::Source) { 126 + self.timer.reset_from_source(timer_source); 100 127 } 101 128 102 129 pub fn get_timestamp(&self) -> i64 { 103 - self.timer_source.timestamp() 130 + self.timer.timestamp() 104 131 } 105 132 106 133 pub fn set_blip_threshold(&self, threshold: u16) { ··· 116 143 self.pwm.set_duty(duty); 117 144 Timer::after_secs(2).await; 118 145 let mut act_value = self.adc.sample_average(samples).await; 146 + #[cfg(feature = "debug")] 147 + info!("START: {}", act_value); 119 148 120 149 while act_value < 1364 { 121 150 duty += 2; 122 151 if duty >= 256 { 152 + #[cfg(feature = "debug")] 153 + info!("RESET: {} @ Duty {}", act_value, duty); 123 154 duty = 0; 124 155 self.pwm.set_duty(duty); 125 156 Timer::after_secs(2).await; ··· 129 160 self.pwm.set_duty(duty); 130 161 Timer::after_millis(250).await; 131 162 act_value = self.adc.sample_average(samples).await; 163 + #[cfg(feature = "debug")] 164 + info!("UPDATE: {} @ Duty {}", act_value, duty); 132 165 } 133 166 self.state.max_duty.set(duty as u8); 134 167 duty = (duty / 6) * 5; ··· 137 170 // Allow voltage level to stabilize after tuning 138 171 Timer::after_secs(2).await; 139 172 let avg = self.adc.sample_average(samples).await; 173 + #[cfg(feature = "debug")] 174 + info!("SET: {} @ Duty {}/{}", avg, duty, self.state.max_duty.get()); 140 175 self.state.avg.set(avg); 141 176 } 142 177 ··· 147 182 ) { 148 183 loop { 149 184 let (time, samples) = dma.send().await; 150 - *time = self.timer_source.timestamp(); 185 + *time = self.get_timestamp(); 151 186 self.adc.sample(samples).await; 152 187 dma.send_done(); 153 188 } ··· 238 273 } 239 274 None => { 240 275 update(DetectorUpdate::Tick { 241 - timestamp: self.timer_source.timestamp(), 276 + timestamp: self.get_timestamp(), 242 277 level: warn_level - 255, 243 278 }); 244 279 } ··· 296 331 struct MockTimeSource; 297 332 298 333 impl TimeSource for MockTimeSource { 299 - fn get_source() -> Self { 300 - Self 301 - } 334 + type Source = (); 335 + 336 + fn reset_from_source(&mut self, _source: Self::Source) {} 337 + 302 338 fn timestamp(&self) -> i64 { 303 339 0 304 340 } ··· 528 564 ) 529 565 }); 530 566 531 - assert_eq!(peaks.len(), 3); 532 567 assert!(called.get()); 568 + assert_eq!(peaks.len(), 3); 533 569 534 570 detector.adc.sample(&mut samples).await; 535 571
+3 -1
embassy-strike-driver/src/traits.rs
··· 1 1 pub trait TimeSource { 2 + type Source; 3 + 2 4 fn timestamp(&self) -> i64; 3 - fn get_source() -> Self; 5 + fn reset_from_source(&mut self, source: Self::Source); 4 6 } 5 7 6 8 pub trait AdcSource {