1#[macro_use]
2extern crate log;
3
4use crate::device::registers::{
5 AfeGainBoost, CalibrateOscillators, DisplayTrcoOnIrqPin, DistanceEstimation, Interrupt,
6 MaskDisturber, MinimumNumberOfLightning, NoiseFloorLevel, PowerDown, PresetDefault,
7 WatchdogThreshold,
8};
9use crate::interface::i2c::{I2cAddress, I2cInterface};
10use crate::interface::{
11 Interface, Irq, CLOCK_GENERATION_DELAY, IRQ_TRIGGER_TO_READY_DELAY, LIGHTNING_CALCULATION_DELAY,
12};
13use rppal::gpio::{InputPin, Level, Trigger};
14use rppal::i2c::I2c;
15use rppal::spi::Spi;
16use std::error;
17use std::fmt;
18use std::result::Result::Err;
19use std::sync::mpsc::{channel, Receiver, Sender};
20use std::sync::{Arc, Mutex};
21use std::thread::sleep;
22use std::time::Duration;
23
24pub(crate) mod device;
25pub mod interface;
26
27pub type IrqPin = InputPin;
28
29#[derive(Debug)]
30pub enum Error {
31 Deadlock,
32 InterfaceError(interface::Error),
33 InvalidState,
34}
35
36pub type Result<T> = ::std::result::Result<T, Error>;
37
38impl error::Error for Error {}
39impl fmt::Display for Error {
40 fn fmt(&self, _f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
41 unimplemented!()
42 }
43}
44
45impl From<crate::interface::Error> for Error {
46 fn from(error: crate::interface::Error) -> Self {
47 Error::InterfaceError(error)
48 }
49}
50
51#[derive(Clone, Copy, Debug, Eq, PartialEq)]
52pub enum SensorPlacing {
53 Indoor,
54 Outdoor,
55}
56
57#[derive(Clone, Copy, Debug, Eq, PartialEq)]
58pub enum MinimumLightningThreshold {
59 One,
60 Five,
61 Nine,
62 Sixteen,
63}
64
65#[derive(Clone, Copy, Debug, Eq, PartialEq)]
69pub struct SignalVerificationThreshold(pub(crate) u8);
70
71impl SignalVerificationThreshold {
72 pub fn new(value: u8) -> ::std::result::Result<Self, &'static str> {
73 if value > 10 {
74 return Err("Signal verification threshold must be in range 0-10");
75 }
76
77 Ok(Self(value))
78 }
79}
80
81#[derive(Clone, Copy, Debug, Eq, PartialEq)]
82pub struct NoiseFloorThreshold(pub(crate) u8);
83
84impl NoiseFloorThreshold {
85 pub fn new(value: u8) -> ::std::result::Result<Self, &'static str> {
86 if value > 11 {
87 return Err("Noise level threshold must be in range 0-11");
88 }
89
90 Ok(Self(value))
91 }
92}
93
94#[derive(Clone, Copy, Debug, Eq, PartialEq)]
95pub enum IgnoreDisturbances {
96 Yes,
97 No,
98}
99
100#[derive(Clone, Copy, Debug, Eq, PartialEq)]
102pub enum HeadOfStormDistance {
103 Kilometers(u8),
105 OutOfRange,
107 Overhead,
109}
110
111pub enum InterfaceSelection {
112 I2c(I2c, I2cAddress),
113 Spi(Spi, u8),
114}
115
116pub enum Event {
117 Disturbance,
118 Lightning(HeadOfStormDistance),
119 Noise,
120}
121
122#[derive(Clone, Copy, Debug, Eq, PartialEq)]
123enum State {
124 Listening,
125 PoweredDown,
126 StandingBy,
127}
128
129#[derive(Default)]
130pub struct ListeningParameters {
131 pub(crate) sensor_placing: Option<SensorPlacing>,
132 pub(crate) minimum_lightning_threshold: Option<MinimumLightningThreshold>,
133 pub(crate) noise_floor_threshold: Option<NoiseFloorThreshold>,
134 pub(crate) signal_verification_threshold: Option<SignalVerificationThreshold>,
135 pub(crate) ignore_disturbances: Option<IgnoreDisturbances>,
136}
137
138impl ListeningParameters {
139 pub fn with_sensor_placing(mut self, sensor_placing: SensorPlacing) -> Self {
140 self.sensor_placing = Some(sensor_placing);
141 self
142 }
143
144 pub fn with_minimum_lightning_threshold(
145 mut self,
146 minimum_lightning_threshold: MinimumLightningThreshold,
147 ) -> Self {
148 self.minimum_lightning_threshold = Some(minimum_lightning_threshold);
149 self
150 }
151
152 pub fn with_noise_floor_threshold(
153 mut self,
154 noise_floor_threshold: NoiseFloorThreshold,
155 ) -> Self {
156 self.noise_floor_threshold = Some(noise_floor_threshold);
157 self
158 }
159
160 pub fn with_signal_verification_threshold(
161 mut self,
162 signal_verification_threshold: SignalVerificationThreshold,
163 ) -> Self {
164 self.signal_verification_threshold = Some(signal_verification_threshold);
165 self
166 }
167
168 pub fn with_ignore_disturbances(mut self, ignore_disturbances: IgnoreDisturbances) -> Self {
169 self.ignore_disturbances = Some(ignore_disturbances);
170 self
171 }
172}
173
174pub struct AS3935 {
175 interface: Arc<Mutex<Box<dyn Interface>>>,
176 irq_pin: IrqPin,
177 state: State,
178}
179
180impl AS3935 {
181 pub fn new(interface_selection: InterfaceSelection, irq_pin: IrqPin) -> Result<Self> {
182 Ok(match interface_selection {
183 InterfaceSelection::I2c(i2c, i2c_address) => Self {
184 interface: Arc::new(Mutex::new(Box::new(I2cInterface::new(i2c, i2c_address)?))),
185 irq_pin,
186 state: State::StandingBy,
187 },
188 InterfaceSelection::Spi(_, _) => unimplemented!(),
189 })
190 }
191
192 pub fn listen(&mut self, parameters: ListeningParameters) -> Result<Receiver<Event>> {
193 self.assert_state(&self.state, &[State::StandingBy, State::PoweredDown])?;
194
195 info!("starting listen sequence");
196
197 debug!("powering up");
198 self.power_up()?;
199
200 debug!("calibrating clock");
201 self.calibrate_clock()?;
202
203 debug!("resetting to defaults");
204 self.configure_defaults()?;
205
206 debug!("configuring listen parameters");
207 self.configure_listen_parameters(parameters)?;
208
209 let (sender, receiver) = channel::<Event>();
210 self.setup_irq(sender)?;
211
212 self.state = State::Listening;
213
214 Ok(receiver)
215 }
216
217 pub fn terminate(&mut self) -> Result<()> {
218 self.assert_state(&self.state, &[State::Listening])?;
219
220 self.irq_pin.clear_async_interrupt().unwrap();
221 self.power_down()?;
222
223 self.state = State::PoweredDown;
224
225 Ok(())
226 }
227
228 pub fn is_listening(&self) -> bool {
229 self.state == State::Listening
230 }
231
232 fn power_up(&mut self) -> Result<()> {
233 self.assert_state(&self.state, &[State::StandingBy, State::PoweredDown])?;
234
235 self.interface
236 .lock()
237 .unwrap()
238 .write(Box::new(PowerDown), 0b_0)?;
239 sleep(Duration::from_millis(2));
240
241 Ok(())
242 }
243
244 fn power_down(&mut self) -> Result<()> {
245 self.interface
246 .lock()
247 .unwrap()
248 .write(Box::new(PowerDown), 0b_1)?;
249
250 Ok(())
251 }
252
253 fn calibrate_clock(&mut self) -> Result<()> {
254 self.assert_state(&self.state, &[State::StandingBy, State::PoweredDown])?;
255
256 debug!("sending CALIB_RCO direct command");
257 self.interface
258 .lock()
259 .unwrap()
260 .write(Box::new(CalibrateOscillators), 0x96)?;
261 sleep(Duration::from_millis(2));
262
263 debug!("setting DISP_TRCO=1");
264 self.interface
265 .lock()
266 .unwrap()
267 .write(Box::new(DisplayTrcoOnIrqPin), 0b_1)?;
268
269 sleep(CLOCK_GENERATION_DELAY);
270
271 debug!("setting DISP_TRCO=0");
272 self.interface
273 .lock()
274 .unwrap()
275 .write(Box::new(DisplayTrcoOnIrqPin), 0)?;
276 sleep(Duration::from_millis(2));
277
278 Ok(())
279 }
280
281 fn configure_defaults(&mut self) -> Result<()> {
282 self.interface
283 .lock()
284 .unwrap()
285 .write(Box::new(PresetDefault), 0x96)?;
286
287 Ok(())
288 }
289
290 fn configure_listen_parameters(&mut self, parameters: ListeningParameters) -> Result<()> {
291 if let Some(sensor_placing) = parameters.sensor_placing {
292 debug!("configuring sensor placing");
293 self.configure_sensor_placing(&sensor_placing)?;
294 }
295
296 if let Some(minimum_lightning_threshold) = ¶meters.minimum_lightning_threshold {
297 debug!("configuring minimum lightning threshold");
298 self.configure_minimum_lightning_threshold(&minimum_lightning_threshold)?;
299 }
300
301 if let Some(noise_floor_threshold) = ¶meters.noise_floor_threshold {
302 debug!("configuring noise floor threshold");
303 self.configure_noise_floor_threshold(&noise_floor_threshold)?;
304 }
305
306 if let Some(signal_verification_threshold) = ¶meters.signal_verification_threshold {
307 debug!("configuring signal verification threshold");
308 self.configure_signal_verification_threshold(&signal_verification_threshold)?;
309 }
310
311 if let Some(ignore_disturbances) = ¶meters.ignore_disturbances {
312 debug!("configuring ignoring of disturbances");
313 self.configure_ignore_disturbances(&ignore_disturbances)?;
314 }
315
316 Ok(())
317 }
318
319 fn configure_sensor_placing(&mut self, placing: &SensorPlacing) -> Result<()> {
320 self.interface
321 .lock()
322 .unwrap()
323 .write(Box::new(AfeGainBoost), (*placing).into())?;
324
325 Ok(())
326 }
327
328 fn configure_minimum_lightning_threshold(
329 &mut self,
330 minimum_lightning_threshold: &MinimumLightningThreshold,
331 ) -> Result<()> {
332 self.interface.lock().unwrap().write(
333 Box::new(MinimumNumberOfLightning),
334 (*minimum_lightning_threshold).into(),
335 )?;
336
337 Ok(())
338 }
339
340 fn configure_noise_floor_threshold(
341 &mut self,
342 noise_floor_threshold: &NoiseFloorThreshold,
343 ) -> Result<()> {
344 self.interface
345 .lock()
346 .unwrap()
347 .write(Box::new(NoiseFloorLevel), (*noise_floor_threshold).into())?;
348
349 Ok(())
350 }
351
352 fn configure_signal_verification_threshold(
353 &mut self,
354 signal_verification_threshold: &SignalVerificationThreshold,
355 ) -> Result<()> {
356 self.interface.lock().unwrap().write(
357 Box::new(WatchdogThreshold),
358 (*signal_verification_threshold).into(),
359 )?;
360
361 Ok(())
362 }
363
364 fn configure_ignore_disturbances(
365 &mut self,
366 ignore_disturbances: &IgnoreDisturbances,
367 ) -> Result<()> {
368 self.interface
369 .lock()
370 .unwrap()
371 .write(Box::new(MaskDisturber), (*ignore_disturbances).into())?;
372
373 Ok(())
374 }
375
376 fn setup_irq(&mut self, sender: Sender<Event>) -> Result<()> {
377 let interface_mutex = self.interface.clone();
378
379 self.irq_pin
380 .set_async_interrupt(Trigger::RisingEdge, move |_level: Level| {
381 sleep(IRQ_TRIGGER_TO_READY_DELAY);
382
383 let mut interface = interface_mutex.lock().unwrap();
384
385 let irq = Irq::from(interface.read(Box::new(Interrupt)).unwrap());
386
387 let event = match irq {
388 Irq::DistanceEstimationChanged => return,
389 Irq::DisturberDetected => Event::Disturbance,
390 Irq::Lightning => {
391 sleep(LIGHTNING_CALCULATION_DELAY);
392 Event::Lightning(HeadOfStormDistance::from(
393 interface.read(Box::new(DistanceEstimation)).unwrap(),
394 ))
395 }
396 Irq::NoiseLevelTooHigh => Event::Noise,
397 };
398
399 sender.send(event).unwrap();
400 })
401 .unwrap();
402
403 Ok(())
404 }
405
406 fn assert_state(&self, state: &State, valid_states: &[State]) -> Result<()> {
407 if !valid_states.contains(state) {
408 return Err(Error::InvalidState);
409 }
410
411 Ok(())
412 }
413}