Skip to main content

as3935_generic/
lib.rs

1#![no_std]
2#![allow(dead_code)]
3#![allow(unused_variables)]
4
5
6//#![feature(inherent_associated_types)]
7pub mod error;
8
9use crate::error::Error;
10
11pub mod data;
12use crate::data::{ AFE_GAIN, INTReg, INTType, LightningReg, Location, LocationMask, MinStrikes, Oscillator, StormFrontDistance, THRESHOLDS };
13
14pub mod constants;
15
16use crate::constants::DeviceAddress::{AD1_1_AD0_1, AD1_0_AD0_1, AD1_1_AD0_0, };
17use crate::constants::{ AS3935_POWER_MASK, AS3935_REG0x00, AS3935_REG0x01, AS3935_REG0x02, AS3935_REG0x03, AS3935_REG0x3A, 
18    AS3935_REG0x3B, AS3935_REG0x3C, AS3935_REG0x3D, AS3935_REG0x04, AS3935_REG0x05, AS3935_REG0x06, AS3935_REG0x07, 
19    AS3935_REG0x08, AS3953_DIRECT_COMMAND };
20
21
22#[cfg(not(feature = "async"))]
23use embedded_hal::{i2c::I2c, delay::DelayNs};
24#[cfg(feature = "async")]
25use embedded_hal_async::{i2c::I2c as AsyncI2c, delay::DelayNs as AsyncDelayNs};
26
27use log::{debug, info};
28use libm::{pow, truncf};
29
30
31/// the AS3935 device
32pub struct AS3935<I2C, D> {
33    /// I²C interface
34    i2c: I2C,
35    /// I²C device address
36    address: u8,
37    delayer: D,
38
39}
40
41#[cfg(not(feature = "async"))]
42impl<I2C, D, E> AS3935<I2C, D>
43where  
44    I2C: I2c<Error = E>,
45    D: DelayNs,
46{
47    
48
49    /// create new AS3935 driver with address and delay given
50    /// the datasheet states the max speed is 400 kHz with just AS3935 on the bus and external 10 k pull ups
51    /// otherwise use 4k7 pulls up and max speed is 100 kHz.  
52    /// Best to use 100 kHz.
53    /// use constant::DeviceAddress::default() with AD1 and AD0 pins high 
54    pub fn new(i2c: I2C, address: u8, delayer: D) -> Self {
55        log::debug!("new called");
56        Self {
57            i2c,
58            address: address,
59            delayer,
60        }
61    }
62
63
64    /// give back the I2C interface
65    pub fn release(self) -> I2C {
66        self.i2c
67    }
68
69}
70
71#[cfg(feature = "async")]
72impl<I2C, D, E> AS3935<I2C, D>
73where  
74    I2C: AsyncI2c<Error = E>,
75    D: AsyncDelayNs,
76{
77    /// create new AS3935 driver with address and delay given
78    /// the datasheet states the max speed is 400 kHz with just AS3935 on the bus and external 10 k pull ups
79    /// otherwise use 4k7 pulls up and max speed is 100 kHz.  
80    /// Best to use 100 kHz.
81    /// use constant::DeviceAddress::default() with AD1 and AD0 pins high  
82    pub fn new(i2c: I2C, address: u8, delayer: D) -> Self {
83        debug!("new called");
84        Self {
85            i2c,
86            address: address,
87            delayer,
88        }
89    }
90
91    /// give back the I2C interface
92    pub fn release(self) -> I2C {
93        self.i2c.release;
94    }
95
96}
97
98#[maybe_async_cfg::maybe(
99    sync(
100        cfg(not(feature = "async")),
101        self = "AS3935",
102        idents(AsyncI2c(sync = "I2c"), AsyncDelayNs(sync = "DelayNs"))
103    ),
104    async(feature = "async", keep_self)
105)]
106
107impl<I2C, D, E> AS3935<I2C, D>
108where  
109    I2C: AsyncI2c<Error = E>,
110    D: AsyncDelayNs,
111{
112
113    // command_buf is an u8 array that starts with command byte followed by command data byte(s)
114    async fn write_command<const N: usize>(&mut self, command_buf: [u8; N] ) -> Result<(), Error<E>> {
115        // debug!("write_command : {:#?}", command_buf);
116        self.i2c
117            .write(self.address, &command_buf).await
118            .map_err(Error::I2c)?;
119        Ok(())
120    }
121
122    async fn read_register( &mut self, register_address: u8, buffer: &mut [u8] ) -> Result<(), Error<E>> {
123        let mut command_buffer = [0u8; 1];
124        command_buffer[0] = register_address;
125        // let mut result_buffer = [0u8; N];
126        self.i2c
127            .write_read(self.address, &command_buffer, buffer).await
128            .map_err(Error::I2c)?;
129        Ok(())
130    }
131
132    
133
134    /// calibrate both internal oscillators, first tune your antenna
135    pub async fn calibrate_osc(&mut self) -> Result<(), Error<E>> {
136        debug!("in calibrate_osc");
137        self.write_command([AS3935_REG0x3D, AS3953_DIRECT_COMMAND]).await?;
138        self.display_oscillator(true, Oscillator::TRCO);
139        self.delayer.delay_ms(2).await;
140        self.display_oscillator(false, Oscillator::TRCO);
141
142        // check if osc started
143        let mut result_buf: [u8; 1] = [0; 1];
144        self.read_register(AS3935_REG0x3B, &mut result_buf).await?;
145        let srco: bool = ((result_buf[0] & 0x40) >> 6) != 0;  // 1 = success, do not care about bit 5 
146        self.read_register(AS3935_REG0x3A, &mut result_buf).await?;
147        let trco: bool = ((result_buf[0] & 0x40) >> 6) != 0;  // 1 = success, do not care about bit 5
148        if (srco || trco) {
149            return Err(Error::OscFailedCalibration);
150        } else {
151            return Ok(());
152        }
153    }
154
155        
156    /// reset all settings to defaults
157    pub async fn reset_settings(&mut self) -> Result<(), Error<E>> {
158        debug!("in reset_settings");
159        self.write_command([AS3935_REG0x3C, AS3953_DIRECT_COMMAND]).await?;
160        Ok(())
161    }
162
163    /// read lightning energy (unit-less as per datasheet)
164    pub async fn get_lightning_energy(&mut self) -> Result<u32, Error<E>> {
165        debug!("in get_lightning_energy");
166        let mut result_buf: [u8; 1] = [0; 1];
167        self.read_register(AS3935_REG0x06, &mut result_buf).await?;
168        let mmsb: u8 = (result_buf[0] & 0x3f);
169        self.read_register(AS3935_REG0x05, &mut result_buf).await?;
170        let msb: u8 = result_buf[0];
171        self.read_register(AS3935_REG0x04, &mut result_buf).await?;
172        let lsb: u8 = result_buf[0];
173        let bytes: [u8; 4] = [0x00, mmsb, msb, lsb];
174        let value: u32 = u32::from_be_bytes(bytes);
175        return Ok(value);
176
177    }
178
179    /// display oscillator on IRQ pin
180    /// state = true to turn on, false to turn off
181    /// use a logic analyzer or oscilloscope to see the clock signal.
182    pub async fn display_oscillator(&mut self, state: bool, osc: Oscillator) -> Result<(), Error<E>> {
183        debug!("in display_oscillator");
184        let mut result_buf: [u8; 1] = [0; 1];
185        self.read_register(AS3935_REG0x08, &mut result_buf).await?;
186        let mut value : u8 = result_buf[0] | (osc as u8); 
187        if (state)  { //  turn on display
188            self.write_command([AS3935_REG0x08,  value]).await?;
189        } else { // turn off
190            value = result_buf[0] & !(osc as u8);
191            self.write_command([AS3935_REG0x08, value]).await?;
192        }
193        Ok(())
194    }
195
196
197    /// get distance to storm front in km.  > 40 km == OutOfRange
198    pub async fn get_distance_to_storm(&mut self) -> Result<StormFrontDistance, Error<E>> {
199        debug!("in get_distance_to_storm");
200        let mut result_buf: [u8; 1] = [0; 1];
201        self.read_register(AS3935_REG0x07, &mut result_buf).await?;
202        let distance: u8 = result_buf[0] & 0x3f;
203        let mut storm_front_distance: StormFrontDistance = StormFrontDistance::OutOfRange;
204        if (distance == 0x3f) {
205            storm_front_distance = StormFrontDistance::OutOfRange;
206        } else if (distance == 0x01) {
207            storm_front_distance = StormFrontDistance::Overhead;
208        } else {
209            storm_front_distance = StormFrontDistance::Range_km(distance);
210        }
211        Ok(storm_front_distance)
212    }
213
214    /// power_down
215    /// note:  the TRCO oscillator must then be recalibrated after power_down() call which is built into wakeup()
216    pub async fn power_down(&mut self) -> Result<(), Error<E>> {
217        debug!("in power_down");
218        self.write_command([AS3935_REG0x00, AS3935_POWER_MASK ]).await?;
219        Ok(())
220    } 
221
222    /// set indoor-outdoor location of sensor
223    pub async fn set_indoor_outdoor(&mut self, location:  Location) -> Result<(), Error<E>> {
224        debug!("in set_indoor_outdoor({:?})", location);
225        let mut location_mask = LocationMask::Indoor;
226        info!("  location is {:?} hex = {:02x}", location, location as u8);
227    
228        if (location == Location::Indoor) {
229            location_mask = LocationMask::Indoor;
230        } else {
231            location_mask = LocationMask::Outdoor;
232        }
233
234        debug!("  location_mask = {:02x}", location_mask as u8);
235        let mut afe_gain: AFE_GAIN = AFE_GAIN(0x00);
236        afe_gain.set_location_mask(location_mask as u8);
237        debug!("  afe_gain is {:02x}", afe_gain.0);
238        self.write_command([AS3935_REG0x00, (afe_gain.0 as u8)]).await?;
239        Ok(()) 
240    }
241
242    /// get indoor-outdoor location from sensor
243    pub async fn get_indoor_outdoor(&mut self) -> Result<Location, Error<E>> {
244        debug!("in get_indoor_outdoor");
245        let mut result_buf: [u8; 1] = [0; 1];
246        self.read_register(AS3935_REG0x00, &mut result_buf).await?;
247        debug!("  reg0x00 = {:02x}", result_buf[0]);
248        let afe_gain: AFE_GAIN = AFE_GAIN(result_buf[0]);
249        debug!("  afe_gain in hex = {:02x}", afe_gain.0);
250        debug!("  afe_gain = {:?}", afe_gain);
251        let mut where_is_it = Location::Indoor;
252        if (afe_gain.get_location_mask() == LocationMask::Indoor) {
253            where_is_it = Location::Indoor;
254        } else if (afe_gain.get_location_mask() == LocationMask::Outdoor) {
255            where_is_it = Location::Outdoor;
256        } else {
257            return Err(Error::ResponseError);
258        }
259        return Ok(where_is_it);
260    }
261
262    /// get interrupt register:  useful to see what the AS3935 detected
263    pub async fn get_interrupt_register(&mut self) -> Result<INTType, Error<E>> {
264        debug!("in get_interrupt_register");
265        let mut result_buf: [u8; 1] = [0; 1];
266        self.read_register(AS3935_REG0x03, &mut result_buf).await?;
267        let int_reg: INTReg = INTReg(result_buf[0]);
268        let int_type: INTType = int_reg.get_int_type();
269        Ok(int_type)
270    }
271
272    //  /// read_interrupt_register, first delay 2msec as per datasheet
273    // pub async fn read_interrupt_register(&mut self) -> Result<INTType, Error<E>>  {
274    //     debug!("in read_interrupt_register";)
275    //     let mut result_buf: [u8; 1] = [0; 1];
276    //     self.delayer.delay_ms(2).await;
277    //     self.read_register(AS3935_REG0x03, &mut result_buf).await?;
278    //     let int_reg: INTReg = INTReg(result_buf[0]);
279    //     Ok(int_reg.get_int_type())
280    // }
281
282    /// wakup, and then calibrate the oscillators
283    pub async fn wakeup(&mut self) -> Result<(), Error<E>> {
284        debug!("in wakeup");
285        let mut result_buf: [u8; 1] = [0; 1];
286        self.read_register(AS3935_REG0x3A, &mut result_buf).await?;
287        let mut afe_gain: AFE_GAIN = AFE_GAIN(result_buf[0]);
288        afe_gain.set_powerdown(false);  // false is == 0 to power up
289        self.write_command([AS3935_REG0x3A, afe_gain.0]).await?;
290        self.calibrate_osc().await?;
291        Ok(())
292
293    }
294
295    /// set watchdog threshold, threshold < 11
296    pub async fn set_watchdog_threshold(&mut self, threshold: u8 ) -> Result<(), Error<E>> {
297        debug!("in set_watchdog_threshold");
298        if (threshold > 10) {
299            return Err(Error::ValueLimit);
300        }
301        let mut result_buf: [u8; 1] = [0; 1];
302        self.read_register(AS3935_REG0x01, &mut result_buf).await?;
303        let mut threshold_reg: THRESHOLDS = THRESHOLDS(result_buf[0]);
304        threshold_reg.set_wd_threshold(threshold as u8);
305        self.write_command([AS3935_REG0x01, threshold_reg.0]).await?;
306        Ok(())
307    }
308
309    /// get watchdog threshold
310    pub async fn get_watchdog_threshold(&mut self) -> Result<u8, Error<E>> {
311        debug!("in get_watchdog_threshold");
312        let mut result_buf: [u8; 1] = [0; 1];
313        self.read_register(AS3935_REG0x01, &mut result_buf).await?;
314        let threshold_reg: THRESHOLDS = THRESHOLDS(result_buf[0]);
315        let threshold = threshold_reg.get_wd_threshold();
316        Ok(threshold)
317    }
318
319    /// set noise floor level, level < 8
320    pub async fn set_noise_level(&mut self, level: u8 ) -> Result<(), Error<E>> {
321        debug!("in set_noise_level");
322        if (level > 7) {
323            return Err(Error::ValueLimit);
324        }
325        let mut result_buf: [u8; 1] = [0; 1];
326        self.read_register(AS3935_REG0x01, &mut result_buf).await?;
327        let mut threshold_reg: THRESHOLDS = THRESHOLDS(result_buf[0]);
328        threshold_reg.set_noise_floor(level);
329        self.write_command([AS3935_REG0x01, threshold_reg.0]).await?;
330        Ok(())
331    }
332
333    /// get noise floor level
334    pub async fn get_noise_level(&mut self) -> Result<u8, Error<E>> {
335        debug!("in get_noise_level");
336        let mut result_buf: [u8; 1] = [0; 1];
337        self.read_register(AS3935_REG0x01, &mut result_buf).await?;
338        let threshold_reg: THRESHOLDS = THRESHOLDS(result_buf[0]);
339        let level = threshold_reg.get_noise_floor();
340        Ok(level)
341    }
342
343    /// set lightning threshold (minimum number of lightning strikes)
344    pub async fn set_lightning_threshold(&mut self, threshold: MinStrikes ) -> Result<(), Error<E>> {
345        debug!("in set_lightning_threshold");
346        let mut result_buf: [u8; 1] = [0; 1];
347        self.read_register(AS3935_REG0x02, &mut result_buf).await?;
348        let mut lightning_reg: LightningReg = LightningReg(result_buf[0]);
349        lightning_reg.set_min_strikes(threshold as u8);
350        self.write_command([AS3935_REG0x02, lightning_reg.0]).await?;
351        Ok(())
352    }
353
354    /// get lightning threshold (minimum number of lightning strikes)
355    pub async fn get_lightning_threshold(&mut self) -> Result<MinStrikes, Error<E>> {
356        debug!("in get_lightning_threshold");
357        let mut result_buf: [u8; 1] = [0; 1];
358        self.read_register(AS3935_REG0x02, &mut result_buf).await?;
359        let lightning_reg: LightningReg = LightningReg(result_buf[0]);
360        let min_strikes: MinStrikes = lightning_reg.get_min_strikes();
361        Ok(min_strikes)
362    }
363
364    /// clear statistics :  clears the number of lightning strikes detected in last 15 minutes
365    pub async fn clear_statistics(&mut self) -> Result<(), Error<E>> {
366        debug!("in clear_statistics");
367        let mut result_buf: [u8; 1] = [0; 1];
368        self.read_register(AS3935_REG0x02, &mut result_buf).await?;
369        let mut lightning_reg: LightningReg = LightningReg(result_buf[0]);
370        lightning_reg.set_clear_stats(true);
371        debug!("  writing lightning_reg = {:?}", lightning_reg);
372        self.write_command([AS3935_REG0x02, lightning_reg.0]).await?;
373        Ok(())
374    }
375
376    /// set mask disturber:  defines if "disturbers" trigger interrupts, default is false == not masked
377    pub async fn set_mask_disturber(&mut self, enable: bool) -> Result<(), Error<E>> {
378        debug!("in set_mask_disturber");
379        let mut result_buf: [u8; 1] = [0; 1];
380        self.read_register(AS3935_REG0x03, &mut result_buf).await?;
381        let mut int_reg: INTReg = INTReg(result_buf[0]);
382        int_reg.set_mask_dist(enable);
383        self.write_command([AS3935_REG0x03, int_reg.0]).await?;
384        Ok(())
385    }
386
387    /// get mask disturber: whether disturbers triggers interrupts
388    pub async fn get_mask_disturber(&mut self) -> Result<bool, Error<E>> {
389        debug!("in get_mask_disturber");
390        let mut result_buf: [u8; 1] = [0; 1];
391        self.read_register(AS3935_REG0x03, &mut result_buf).await?;
392        let int_reg: INTReg = INTReg(result_buf[0]);
393        Ok(int_reg.get_mask_dist())
394    }
395
396    /// set spike rejection sensitivity  < 16
397    pub async fn set_spike_rejection(&mut self, sensitivity: u8) -> Result<(), Error<E>> {
398        debug!("in set_spike_rejection");
399        if (sensitivity > 15) {
400            return Err(Error::ValueLimit);
401        }
402        let mut result_buf: [u8; 1] = [0; 1];
403        self.read_register(AS3935_REG0x02, &mut result_buf).await?;
404        let mut lightning_reg: LightningReg = LightningReg(result_buf[0]);
405        lightning_reg.set_spike_reject(sensitivity);
406        self.write_command([AS3935_REG0x02, lightning_reg.0]).await?;
407        Ok(())
408    }
409
410    /// get spike rejection sensitivity
411    pub async fn get_spike_rejection(&mut self) -> Result<u8, Error<E>> {
412        debug!("in get_spike_rejection");
413        let mut result_buf: [u8; 1] = [0; 1];
414        let mut result_buf: [u8; 1] = [0; 1];
415        self.read_register(AS3935_REG0x02, &mut result_buf).await?;
416        let mut lightning_reg: LightningReg = LightningReg(result_buf[0]);
417        let sensitivity = lightning_reg.get_spike_reject();
418        Ok(sensitivity)
419    }
420
421    /// set antenna frequency division ratio for antenna tuning
422    /// ratios are:  16, 32, 64 or 128
423    pub async fn set_antenna_div_ratio(&mut self, ratio: u8) -> Result<(), Error<E>> {
424        debug!("in set_antenna_div_ratio ( {} )", ratio);
425        let mut value: u8 = 0;
426        if (ratio == 16) {
427            value = 0;
428        } else if (ratio == 32) {
429            value = 1;
430        } else if { ratio == 64} {
431            value = 2;
432        } else if (ratio == 128) {
433            value = 3;
434        } else {
435            return Err(Error::ValueLimit);
436        }
437
438        let mut result_buf: [u8; 1] = [0; 1];
439        self.read_register(AS3935_REG0x03, &mut result_buf).await?;
440        let mut int_reg: INTReg = INTReg(result_buf[0]);
441        int_reg.set_freq_div(value);
442        //info!("  writing value {:02x} and int_reg = {:?}", value, int_reg);
443        self.write_command([AS3935_REG0x03, int_reg.0]).await?;
444        Ok(())
445    }
446
447    /// get antenna frequency division ratio for antenna tuning
448    pub async fn get_antenna_div_ratio(&mut self) -> Result<u8, Error<E>> {
449        debug!("in get_antenna_div_ratio");
450        let mut result_buf: [u8; 1] = [0; 1];
451        self.read_register(AS3935_REG0x03, &mut result_buf).await?;
452        let mut int_reg: INTReg = INTReg(result_buf[0]);
453        let value = int_reg.get_freq_div();
454        let return_value: u8 = (1 << (value + 4));
455        Ok((return_value))
456    }
457
458    /// set tuning cap for antenna
459    /// farads must be <= 128 and modulo 8,  specifically from 0 to 120 pF in steps of 8 pF (modulo 8) 
460    pub async fn set_tuning_cap(&mut self, p_farads: u8) -> Result<(), Error<E>> {
461        debug!("in set_tuning_cap( {:02x} )", p_farads);
462        if (p_farads > 128) {
463            return Err(Error::ValueLimit);
464        } else if ((p_farads % 8) != 0) {
465            debug!("  bummer, not modulo 8");
466            return Err(Error::ValueLimit);
467        }
468        let mut result_buf: [u8; 1] = [0; 1];
469        self.read_register(AS3935_REG0x08, &mut result_buf).await?;
470        let mut new_value: u8 = (result_buf[0]) | ((p_farads >> 3) & 0x17);
471        //info!("  new tuning cap value to write is {:02x}", new_value);
472        self.write_command([AS3935_REG0x08, new_value]).await?;
473
474        Ok(())
475    }
476
477    /// get tuning cap (internal) for antenna in pF, manufacturer default is 0 pF if not changed
478    pub async fn get_tuning_cap(&mut self) -> Result<u8, Error<E>> {
479        debug!("in get_tuning_cap");
480        let mut result_buf: [u8; 1] = [0; 1];
481        self.read_register(AS3935_REG0x08, &mut result_buf).await?;
482        let p_farads: u8 = (result_buf[0] & 0x1f) << 3;  // bit [3:0] in steps of 8 pF 
483        Ok(p_farads)
484    }
485
486
487}