pamoja_sensors/ads1115/sim.rs
1//! An ADS1115 that is not there.
2//!
3//! A conversion comes back as a count of the full-scale range the gain selects, so
4//! [`reporting`] takes the same gain a driver is given with
5//! [`with_gain`](super::Ads1115::with_gain), and holds the count that voltage converts to. The
6//! part keeps whatever configuration a driver writes, so a conversion a driver starts reads as
7//! finished. [`part`] reads 1.65 V, half a 3.3 V supply, at the gain a driver starts with.
8
9use pamoja_hal::sim::WordPart;
10
11use super::{register, Config, Pga};
12
13/// The voltage [`part`] reports.
14pub const VOLTS: f32 = 1.65;
15
16/// An ADS1115 answering at an address, reading [`VOLTS`] at the gain a driver starts with.
17///
18/// # Arguments
19///
20/// * `address` - the address its ADDR pin selects.
21///
22/// # Returns
23///
24/// The part.
25#[must_use]
26pub fn part(address: u8) -> WordPart {
27 reporting(address, Config::default().pga, VOLTS)
28}
29
30/// An ADS1115 that reads what it is asked to.
31///
32/// # Arguments
33///
34/// * `address` - the address it answers to.
35/// * `pga` - the gain the driver converts at.
36/// * `volts` - the voltage it reports, held to the gain's full-scale range.
37///
38/// # Returns
39///
40/// The part. Its reading lands on the nearest of the 32768 steps either side of zero the gain
41/// divides its range into.
42///
43/// # Examples
44///
45/// ```
46/// use pamoja_hal::script::DelayLog;
47/// use pamoja_sensors::ads1115::{address, sim, Ads1115, Pga};
48///
49/// let mut adc = Ads1115::new(sim::reporting(address::GND, Pga::Fsr4_096, 3.0), address::GND, DelayLog::new())
50/// .with_gain(Pga::Fsr4_096);
51/// let sample = adc.sample().expect("the part answers");
52/// assert!((sample.volts() - 3.0).abs() < 0.001);
53/// ```
54#[must_use]
55pub fn reporting(address: u8, pga: Pga, volts: f32) -> WordPart {
56 let full_scale = pga.full_scale_microvolts() as f32;
57 let counts = volts * 1_000_000.0 / full_scale * 32_768.0;
58 let raw = if counts >= 0.0 {
59 (counts + 0.5).min(f32::from(i16::MAX))
60 } else {
61 (counts - 0.5).max(f32::from(i16::MIN))
62 } as i16;
63 WordPart::new(address)
64 .holding(register::CONFIG, Config::default().bits())
65 .holding(register::CONVERSION, raw as u16)
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use crate::ads1115::{address, Ads1115};
72 use pamoja_hal::script::DelayLog;
73
74 #[test]
75 fn a_driver_at_the_same_gain_reads_the_voltage() {
76 let mut adc = Ads1115::new(part(address::VDD), address::VDD, DelayLog::new());
77 let sample = adc.sample().expect("a sample");
78 assert!((sample.volts() - VOLTS).abs() < 0.001);
79
80 let mut adc = Ads1115::new(
81 reporting(address::SDA, Pga::Fsr0_256, -0.1),
82 address::SDA,
83 DelayLog::new(),
84 )
85 .with_gain(Pga::Fsr0_256);
86 let sample = adc.sample().expect("a sample");
87 assert!((sample.volts() + 0.1).abs() < 0.0001);
88 }
89}