Skip to main content

pamoja_sensors/
ina226.rs

1//! Texas Instruments INA226 high-side or low-side current, voltage, and power monitor.
2//!
3//! The INA226 measures the voltage across a shunt resistor and the bus voltage on
4//! common-mode voltages from 0 V to 36 V and, once its calibration register is
5//! programmed, computes current and power on the chip. It adds programmable
6//! conversion times and averaging, and an alert pin driven by a single limit
7//! register. This module builds the calibration and configuration values and decodes
8//! each register into a physical quantity, following the datasheet's equations and
9//! its worked example, so a battery-balancer or rack-power node reads amps and watts
10//! directly.
11//!
12//! Shunt voltages are returned in nanovolts, bus voltages in microvolts, and current
13//! and power in microamps and microwatts, so the 2.5 µV and 1.25 mV register LSBs
14//! convert exactly without floating point. `f32` conveniences sit beside them.
15
16use crate::SensorError;
17
18#[cfg(feature = "embedded-hal")]
19mod driver;
20#[cfg(feature = "embedded-hal")]
21pub mod sim;
22
23#[cfg(feature = "embedded-hal")]
24pub use driver::{Ina226, STATUS_POLLS};
25
26/// The INA226 register pointer addresses.
27pub mod register {
28    /// Configuration register: reset, averaging, conversion times, and operating mode.
29    pub const CONFIGURATION: u8 = 0x00;
30    /// Shunt voltage register, signed, 2.5 µV per count.
31    pub const SHUNT_VOLTAGE: u8 = 0x01;
32    /// Bus voltage register, positive only, 1.25 mV per count.
33    pub const BUS_VOLTAGE: u8 = 0x02;
34    /// Power register, scaled by the calibration register.
35    pub const POWER: u8 = 0x03;
36    /// Current register, signed, scaled by the calibration register.
37    pub const CURRENT: u8 = 0x04;
38    /// Calibration register, sets the current and power scale.
39    pub const CALIBRATION: u8 = 0x05;
40    /// Mask/Enable register: alert function selection and status flags.
41    pub const MASK_ENABLE: u8 = 0x06;
42    /// Alert limit register, compared against the selected alert function.
43    pub const ALERT_LIMIT: u8 = 0x07;
44    /// Manufacturer ID register, reads [`MANUFACTURER_ID`](super::MANUFACTURER_ID).
45    pub const MANUFACTURER_ID: u8 = 0xFE;
46    /// Die ID register: the device ID in bits 15:4 and the die revision in bits 3:0.
47    pub const DIE_ID: u8 = 0xFF;
48}
49
50/// The value the manufacturer ID register always reads (0x5449, "TI").
51pub const MANUFACTURER_ID: u16 = 0x5449;
52
53/// The 12-bit device ID carried in bits 15:4 of the die ID register.
54pub const DEVICE_ID: u16 = 0x226;
55
56/// The power-on value of the configuration register (0x4127): averaging off, 1.1 ms
57/// conversion time for both bus and shunt, and continuous shunt-and-bus conversion.
58pub const CONFIG_RESET: u16 = 0x4127;
59
60/// The shunt voltage register LSB, 2.5 µV, in nanovolts.
61pub const SHUNT_LSB_NANOVOLTS: i32 = 2_500;
62
63/// The bus voltage register LSB, 1.25 mV, in microvolts.
64pub const BUS_LSB_MICROVOLTS: u32 = 1_250;
65
66/// The fixed ratio between the power LSB and the programmed current LSB.
67pub const POWER_LSB_RATIO: u32 = 25;
68
69/// The base I2C address, selected when both address pins are tied to ground.
70pub const BASE_ADDRESS: u8 = 0x40;
71
72/// What an address pin is tied to; each of A1 and A0 takes one of four levels.
73#[derive(Clone, Copy, Debug, PartialEq, Eq)]
74#[repr(u8)]
75pub enum AddressPin {
76    /// Tied to GND.
77    Ground = 0,
78    /// Tied to VS.
79    Supply = 1,
80    /// Tied to SDA.
81    Sda = 2,
82    /// Tied to SCL.
83    Scl = 3,
84}
85
86/// Returns the 7-bit I2C address selected by the A1 and A0 pins.
87///
88/// The address is `1 0 0 A1 A0` where each pin contributes two bits in the order
89/// GND, VS, SDA, SCL, giving the sixteen addresses 0x40 through 0x4F.
90///
91/// # Arguments
92///
93/// * `a1` - what the A1 pin is tied to.
94/// * `a0` - what the A0 pin is tied to.
95///
96/// # Returns
97///
98/// The 7-bit target address, before the read/write bit is appended.
99pub fn address(a1: AddressPin, a0: AddressPin) -> u8 {
100    BASE_ADDRESS | ((a1 as u8) << 2) | a0 as u8
101}
102
103/// The number of samples the ADC averages before updating the result registers.
104#[derive(Clone, Copy, Debug, PartialEq, Eq)]
105#[repr(u8)]
106pub enum Averaging {
107    /// No averaging, every conversion is reported.
108    Samples1 = 0,
109    /// Average of 4 samples.
110    Samples4 = 1,
111    /// Average of 16 samples.
112    Samples16 = 2,
113    /// Average of 64 samples.
114    Samples64 = 3,
115    /// Average of 128 samples.
116    Samples128 = 4,
117    /// Average of 256 samples.
118    Samples256 = 5,
119    /// Average of 512 samples.
120    Samples512 = 6,
121    /// Average of 1024 samples.
122    Samples1024 = 7,
123}
124
125impl Averaging {
126    fn from_bits(bits: u16) -> Self {
127        match bits & 0x07 {
128            0 => Self::Samples1,
129            1 => Self::Samples4,
130            2 => Self::Samples16,
131            3 => Self::Samples64,
132            4 => Self::Samples128,
133            5 => Self::Samples256,
134            6 => Self::Samples512,
135            _ => Self::Samples1024,
136        }
137    }
138
139    /// Returns the number of samples this setting averages.
140    ///
141    /// # Returns
142    ///
143    /// The sample count, from 1 to 1024.
144    pub fn samples(self) -> u16 {
145        match self {
146            Self::Samples1 => 1,
147            Self::Samples4 => 4,
148            Self::Samples16 => 16,
149            Self::Samples64 => 64,
150            Self::Samples128 => 128,
151            Self::Samples256 => 256,
152            Self::Samples512 => 512,
153            Self::Samples1024 => 1024,
154        }
155    }
156}
157
158/// The ADC conversion time for one shunt or bus voltage measurement.
159#[derive(Clone, Copy, Debug, PartialEq, Eq)]
160#[repr(u8)]
161pub enum ConversionTime {
162    /// 140 µs.
163    Us140 = 0,
164    /// 204 µs.
165    Us204 = 1,
166    /// 332 µs.
167    Us332 = 2,
168    /// 588 µs.
169    Us588 = 3,
170    /// 1.1 ms.
171    Us1100 = 4,
172    /// 2.116 ms.
173    Us2116 = 5,
174    /// 4.156 ms.
175    Us4156 = 6,
176    /// 8.244 ms.
177    Us8244 = 7,
178}
179
180impl ConversionTime {
181    fn from_bits(bits: u16) -> Self {
182        match bits & 0x07 {
183            0 => Self::Us140,
184            1 => Self::Us204,
185            2 => Self::Us332,
186            3 => Self::Us588,
187            4 => Self::Us1100,
188            5 => Self::Us2116,
189            6 => Self::Us4156,
190            _ => Self::Us8244,
191        }
192    }
193
194    /// Returns the typical conversion time this setting selects.
195    ///
196    /// # Returns
197    ///
198    /// The conversion time in microseconds.
199    pub fn microseconds(self) -> u32 {
200        match self {
201            Self::Us140 => 140,
202            Self::Us204 => 204,
203            Self::Us332 => 332,
204            Self::Us588 => 588,
205            Self::Us1100 => 1_100,
206            Self::Us2116 => 2_116,
207            Self::Us4156 => 4_156,
208            Self::Us8244 => 8_244,
209        }
210    }
211}
212
213/// The operating mode: which inputs are converted, and whether once or continuously.
214///
215/// Both `000` and `100` select power-down; this type reads either as
216/// [`Mode::PowerDown`] and writes it back as `000`.
217#[derive(Clone, Copy, Debug, PartialEq, Eq)]
218#[repr(u8)]
219pub enum Mode {
220    /// Power-down (shutdown); registers stay readable and writable.
221    PowerDown = 0,
222    /// One shunt voltage conversion, then idle.
223    ShuntTriggered = 1,
224    /// One bus voltage conversion, then idle.
225    BusTriggered = 2,
226    /// One shunt and one bus voltage conversion, then idle.
227    ShuntAndBusTriggered = 3,
228    /// Shunt voltage conversions back to back.
229    ShuntContinuous = 5,
230    /// Bus voltage conversions back to back.
231    BusContinuous = 6,
232    /// Shunt and bus voltage conversions back to back, the power-on mode.
233    ShuntAndBusContinuous = 7,
234}
235
236impl Mode {
237    fn from_bits(bits: u16) -> Self {
238        match bits & 0x07 {
239            1 => Self::ShuntTriggered,
240            2 => Self::BusTriggered,
241            3 => Self::ShuntAndBusTriggered,
242            5 => Self::ShuntContinuous,
243            6 => Self::BusContinuous,
244            7 => Self::ShuntAndBusContinuous,
245            _ => Self::PowerDown,
246        }
247    }
248
249    /// Returns whether this mode converts the shunt voltage.
250    ///
251    /// # Returns
252    ///
253    /// `true` for the shunt-only and shunt-and-bus modes.
254    pub fn measures_shunt(self) -> bool {
255        self as u8 & 0x01 != 0
256    }
257
258    /// Returns whether this mode converts the bus voltage.
259    ///
260    /// # Returns
261    ///
262    /// `true` for the bus-only and shunt-and-bus modes.
263    pub fn measures_bus(self) -> bool {
264        self as u8 & 0x02 != 0
265    }
266
267    /// Returns whether this mode keeps converting after the first result.
268    ///
269    /// # Returns
270    ///
271    /// `true` for the three continuous modes.
272    pub fn is_continuous(self) -> bool {
273        matches!(
274            self,
275            Self::ShuntContinuous | Self::BusContinuous | Self::ShuntAndBusContinuous
276        )
277    }
278}
279
280/// The configuration register (0x00), decoded into its fields.
281///
282/// Bit 14 is reserved and reads as `1` after reset; [`Configuration::to_register`]
283/// writes it that way so the reset value round-trips unchanged.
284#[derive(Clone, Copy, Debug, PartialEq, Eq)]
285pub struct Configuration {
286    /// Set to trigger a system reset equivalent to power-on; the bit self-clears.
287    pub reset: bool,
288    /// How many samples are averaged before the result registers update.
289    pub averaging: Averaging,
290    /// The conversion time for each bus voltage measurement.
291    pub bus_conversion_time: ConversionTime,
292    /// The conversion time for each shunt voltage measurement.
293    pub shunt_conversion_time: ConversionTime,
294    /// Which inputs are converted, and whether once or continuously.
295    pub mode: Mode,
296}
297
298impl Configuration {
299    /// The power-on configuration, the decoded form of [`CONFIG_RESET`].
300    pub const RESET: Self = Self {
301        reset: false,
302        averaging: Averaging::Samples1,
303        bus_conversion_time: ConversionTime::Us1100,
304        shunt_conversion_time: ConversionTime::Us1100,
305        mode: Mode::ShuntAndBusContinuous,
306    };
307
308    /// Decodes a configuration register value.
309    ///
310    /// # Arguments
311    ///
312    /// * `raw` - the 16-bit configuration register.
313    ///
314    /// # Returns
315    ///
316    /// The decoded fields; reserved bits are ignored.
317    pub fn from_register(raw: u16) -> Self {
318        Self {
319            reset: raw & 0x8000 != 0,
320            averaging: Averaging::from_bits(raw >> 9),
321            bus_conversion_time: ConversionTime::from_bits(raw >> 6),
322            shunt_conversion_time: ConversionTime::from_bits(raw >> 3),
323            mode: Mode::from_bits(raw),
324        }
325    }
326
327    /// Encodes the fields as a configuration register value.
328    ///
329    /// # Returns
330    ///
331    /// The 16-bit register to write, with reserved bit 14 set as at reset.
332    pub fn to_register(self) -> u16 {
333        (if self.reset { 0x8000 } else { 0 })
334            | 0x4000
335            | ((self.averaging as u16) << 9)
336            | ((self.bus_conversion_time as u16) << 6)
337            | ((self.shunt_conversion_time as u16) << 3)
338            | self.mode as u16
339    }
340
341    /// Returns how often the result registers update with these settings.
342    ///
343    /// One update takes the averaged sample count times the sum of the conversion
344    /// times of the inputs the mode measures, as the datasheet's timing examples
345    /// work it.
346    ///
347    /// # Returns
348    ///
349    /// The update interval in microseconds, or `0` in power-down.
350    pub fn update_microseconds(self) -> u32 {
351        let shunt = if self.mode.measures_shunt() {
352            self.shunt_conversion_time.microseconds()
353        } else {
354            0
355        };
356        let bus = if self.mode.measures_bus() {
357            self.bus_conversion_time.microseconds()
358        } else {
359            0
360        };
361        u32::from(self.averaging.samples()) * (shunt + bus)
362    }
363}
364
365impl Default for Configuration {
366    fn default() -> Self {
367        Self::RESET
368    }
369}
370
371/// The five limit comparisons the alert pin can be assigned to.
372#[derive(Clone, Copy, Debug, PartialEq, Eq)]
373pub enum AlertFunction {
374    /// Shunt voltage above the alert limit (SOL, bit 15).
375    ShuntOverLimit,
376    /// Shunt voltage below the alert limit (SUL, bit 14).
377    ShuntUnderLimit,
378    /// Bus voltage above the alert limit (BOL, bit 13).
379    BusOverLimit,
380    /// Bus voltage below the alert limit (BUL, bit 12).
381    BusUnderLimit,
382    /// Power above the alert limit (POL, bit 11).
383    PowerOverLimit,
384}
385
386/// The Mask/Enable register (0x06): which alert function drives the pin, how the
387/// pin behaves, and the status flags the chip reports back.
388///
389/// The alert limit register is compared in the units of the selected function, so
390/// build it with [`shunt_register`], [`bus_register`], or [`power_register`].
391#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
392pub struct MaskEnable {
393    /// Assert the alert pin when the shunt voltage exceeds the limit (SOL).
394    pub shunt_over_limit: bool,
395    /// Assert the alert pin when the shunt voltage drops below the limit (SUL).
396    pub shunt_under_limit: bool,
397    /// Assert the alert pin when the bus voltage exceeds the limit (BOL).
398    pub bus_over_limit: bool,
399    /// Assert the alert pin when the bus voltage drops below the limit (BUL).
400    pub bus_under_limit: bool,
401    /// Assert the alert pin when the power exceeds the limit (POL).
402    pub power_over_limit: bool,
403    /// Also assert the alert pin when a conversion completes (CNVR).
404    pub conversion_ready: bool,
405    /// Status: the selected alert function, not conversion-ready, caused the last
406    /// alert (AFF).
407    pub alert_function_flag: bool,
408    /// Status: all conversions, averaging, and multiplications are complete (CVRF).
409    pub conversion_ready_flag: bool,
410    /// Status: an arithmetic overflow occurred and current and power may be invalid
411    /// (OVF).
412    pub math_overflow: bool,
413    /// Alert pin polarity: `true` for inverted (active-high), `false` for the default
414    /// active-low (APOL).
415    pub alert_active_high: bool,
416    /// Latch the alert pin and flag until this register is read, rather than clearing
417    /// when the fault clears (LEN).
418    pub alert_latch: bool,
419}
420
421impl MaskEnable {
422    /// Decodes a Mask/Enable register value.
423    ///
424    /// # Arguments
425    ///
426    /// * `raw` - the 16-bit Mask/Enable register.
427    ///
428    /// # Returns
429    ///
430    /// The decoded enables and flags; reserved bits are ignored.
431    pub fn from_register(raw: u16) -> Self {
432        Self {
433            shunt_over_limit: raw & 0x8000 != 0,
434            shunt_under_limit: raw & 0x4000 != 0,
435            bus_over_limit: raw & 0x2000 != 0,
436            bus_under_limit: raw & 0x1000 != 0,
437            power_over_limit: raw & 0x0800 != 0,
438            conversion_ready: raw & 0x0400 != 0,
439            alert_function_flag: raw & 0x0010 != 0,
440            conversion_ready_flag: raw & 0x0008 != 0,
441            math_overflow: raw & 0x0004 != 0,
442            alert_active_high: raw & 0x0002 != 0,
443            alert_latch: raw & 0x0001 != 0,
444        }
445    }
446
447    /// Encodes the enables and flags as a Mask/Enable register value.
448    ///
449    /// # Returns
450    ///
451    /// The 16-bit register to write.
452    pub fn to_register(self) -> u16 {
453        let mut raw = 0;
454        for (set, bit) in [
455            (self.shunt_over_limit, 0x8000),
456            (self.shunt_under_limit, 0x4000),
457            (self.bus_over_limit, 0x2000),
458            (self.bus_under_limit, 0x1000),
459            (self.power_over_limit, 0x0800),
460            (self.conversion_ready, 0x0400),
461            (self.alert_function_flag, 0x0010),
462            (self.conversion_ready_flag, 0x0008),
463            (self.math_overflow, 0x0004),
464            (self.alert_active_high, 0x0002),
465            (self.alert_latch, 0x0001),
466        ] {
467            if set {
468                raw |= bit;
469            }
470        }
471        raw
472    }
473
474    /// Returns the alert function the pin actually responds to.
475    ///
476    /// Only one limit function can drive the pin at a time; when several are
477    /// enabled the chip honors the most significant bit.
478    ///
479    /// # Returns
480    ///
481    /// The highest-priority enabled function, or `None` if no limit function is
482    /// enabled.
483    pub fn active_alert_function(self) -> Option<AlertFunction> {
484        if self.shunt_over_limit {
485            Some(AlertFunction::ShuntOverLimit)
486        } else if self.shunt_under_limit {
487            Some(AlertFunction::ShuntUnderLimit)
488        } else if self.bus_over_limit {
489            Some(AlertFunction::BusOverLimit)
490        } else if self.bus_under_limit {
491            Some(AlertFunction::BusUnderLimit)
492        } else if self.power_over_limit {
493            Some(AlertFunction::PowerOverLimit)
494        } else {
495            None
496        }
497    }
498}
499
500/// The die ID register (0xFF), split into its device and revision fields.
501#[derive(Clone, Copy, Debug, PartialEq, Eq)]
502pub struct DieId {
503    /// The 12-bit device identifier, [`DEVICE_ID`] for an INA226.
504    pub device: u16,
505    /// The 4-bit die revision.
506    pub revision: u8,
507}
508
509impl DieId {
510    /// Splits a die ID register value into its fields.
511    ///
512    /// # Arguments
513    ///
514    /// * `raw` - the 16-bit die ID register.
515    ///
516    /// # Returns
517    ///
518    /// The device ID from bits 15:4 and the revision from bits 3:0.
519    pub fn from_register(raw: u16) -> Self {
520        Self {
521            device: raw >> 4,
522            revision: (raw & 0x0F) as u8,
523        }
524    }
525}
526
527/// Checks that the identification registers belong to an INA226.
528///
529/// A node reads both registers at start-up so a wrong part on the address, or a bus
530/// that reads all ones, is caught before its readings are trusted.
531///
532/// # Arguments
533///
534/// * `manufacturer_id` - the manufacturer ID register (0xFE).
535/// * `die_id` - the die ID register (0xFF).
536///
537/// # Returns
538///
539/// The decoded die ID when both registers match.
540///
541/// # Errors
542///
543/// [`SensorError::Identity`] if the manufacturer ID is not [`MANUFACTURER_ID`] or
544/// the device field of the die ID is not [`DEVICE_ID`].
545pub fn identify(manufacturer_id: u16, die_id: u16) -> Result<DieId, SensorError> {
546    let die = DieId::from_register(die_id);
547    if manufacturer_id != MANUFACTURER_ID || die.device != DEVICE_ID {
548        return Err(SensorError::Identity);
549    }
550    Ok(die)
551}
552
553/// Computes the calibration register value for a chosen current resolution and shunt.
554///
555/// This is the datasheet's calibration equation, `CAL = 0.00512 / (Current_LSB *
556/// R_SHUNT)`, expressed in integer micro-units: with the current LSB in microamps
557/// and the shunt in milliohms, the fixed `0.00512` becomes `5_120_000`.
558///
559/// # Arguments
560///
561/// * `current_lsb_microamps` - the amps-per-count the current register should carry.
562/// * `shunt_milliohms` - the shunt resistor value, in milliohms.
563///
564/// # Returns
565///
566/// The value to program into the calibration register, truncated as the datasheet
567/// does and capped at the register's 15-bit width. Returns `0` if either argument
568/// is `0`, which is the chip's own uncalibrated state.
569pub fn calibration(current_lsb_microamps: u32, shunt_milliohms: u32) -> u16 {
570    let denominator = current_lsb_microamps.saturating_mul(shunt_milliohms);
571    if denominator == 0 {
572        return 0;
573    }
574    (5_120_000 / denominator).min(0x7FFF) as u16
575}
576
577/// Returns the smallest current LSB, in microamps, that still spans a full-scale
578/// current.
579///
580/// The current register is 15 bits of magnitude, so the minimum resolution is the
581/// maximum expected current divided by 2^15, rounded up to the next whole microamp.
582/// The datasheet then rounds this up further to a convenient round number.
583///
584/// # Arguments
585///
586/// * `max_expected_microamps` - the largest current the application will measure.
587///
588/// # Returns
589///
590/// The minimum current LSB in microamps.
591pub fn minimum_current_lsb_microamps(max_expected_microamps: u32) -> u32 {
592    max_expected_microamps.div_ceil(32_768)
593}
594
595/// Decodes the shunt voltage register to nanovolts.
596///
597/// # Arguments
598///
599/// * `raw` - the signed shunt voltage register.
600///
601/// # Returns
602///
603/// The shunt voltage in nanovolts, at 2.5 µV per count.
604pub fn shunt_nanovolts(raw: i16) -> i32 {
605    i32::from(raw) * SHUNT_LSB_NANOVOLTS
606}
607
608/// Decodes the shunt voltage register to millivolts as a float.
609///
610/// # Arguments
611///
612/// * `raw` - the signed shunt voltage register.
613///
614/// # Returns
615///
616/// The shunt voltage in millivolts.
617pub fn shunt_millivolts_f32(raw: i16) -> f32 {
618    f32::from(raw) * 0.0025
619}
620
621/// Decodes the bus voltage register to microvolts.
622///
623/// Bit 15 is always zero on the chip, since the bus voltage is positive only, and
624/// is ignored here.
625///
626/// # Arguments
627///
628/// * `raw` - the bus voltage register.
629///
630/// # Returns
631///
632/// The bus voltage in microvolts, at 1.25 mV per count.
633pub fn bus_microvolts(raw: u16) -> u32 {
634    u32::from(raw & 0x7FFF) * BUS_LSB_MICROVOLTS
635}
636
637/// Decodes the bus voltage register to volts as a float.
638///
639/// # Arguments
640///
641/// * `raw` - the bus voltage register.
642///
643/// # Returns
644///
645/// The bus voltage in volts.
646pub fn bus_volts_f32(raw: u16) -> f32 {
647    f32::from(raw & 0x7FFF) * 0.00125
648}
649
650/// Decodes the current register to microamps for a given current LSB.
651///
652/// # Arguments
653///
654/// * `raw` - the signed current register.
655/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
656///
657/// # Returns
658///
659/// The current in microamps.
660pub fn current_microamps(raw: i16, current_lsb_microamps: u32) -> i32 {
661    i32::from(raw) * current_lsb_microamps as i32
662}
663
664/// Decodes the current register to amps as a float.
665///
666/// # Arguments
667///
668/// * `raw` - the signed current register.
669/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
670///
671/// # Returns
672///
673/// The current in amps.
674pub fn current_amps_f32(raw: i16, current_lsb_microamps: u32) -> f32 {
675    current_microamps(raw, current_lsb_microamps) as f32 * 1e-6
676}
677
678/// Decodes the power register to microwatts for a given current LSB.
679///
680/// The power LSB is fixed by the datasheet at twenty-five times the current LSB.
681///
682/// # Arguments
683///
684/// * `raw` - the power register.
685/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
686///
687/// # Returns
688///
689/// The power in microwatts.
690pub fn power_microwatts(raw: u16, current_lsb_microamps: u32) -> u32 {
691    u32::from(raw) * (POWER_LSB_RATIO * current_lsb_microamps)
692}
693
694/// Decodes the power register to watts as a float.
695///
696/// # Arguments
697///
698/// * `raw` - the power register.
699/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
700///
701/// # Returns
702///
703/// The power in watts.
704pub fn power_watts_f32(raw: u16, current_lsb_microamps: u32) -> f32 {
705    power_microwatts(raw, current_lsb_microamps) as f32 * 1e-6
706}
707
708/// Builds the shunt voltage register a monitor reports for a shunt voltage.
709///
710/// The inverse of [`shunt_nanovolts`], so a node can be written and tested against
711/// what a monitor sends without one attached. The same value serves as the alert
712/// limit for the shunt over- and under-limit functions.
713///
714/// # Arguments
715///
716/// * `nanovolts` - the shunt voltage in nanovolts.
717///
718/// # Returns
719///
720/// The signed shunt voltage register, at 2.5 µV per count.
721pub fn shunt_register(nanovolts: i32) -> i16 {
722    (nanovolts / SHUNT_LSB_NANOVOLTS) as i16
723}
724
725/// Builds the bus voltage register a monitor reports for a bus voltage.
726///
727/// The inverse of [`bus_microvolts`]. The same value serves as the alert limit for
728/// the bus over- and under-limit functions.
729///
730/// # Arguments
731///
732/// * `microvolts` - the bus voltage in microvolts.
733///
734/// # Returns
735///
736/// The bus voltage register, at 1.25 mV per count.
737pub fn bus_register(microvolts: u32) -> u16 {
738    (microvolts / BUS_LSB_MICROVOLTS) as u16
739}
740
741/// Builds the current register a monitor reports for a current.
742///
743/// The inverse of [`current_microamps`].
744///
745/// # Arguments
746///
747/// * `microamps` - the current in microamps.
748/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
749///
750/// # Returns
751///
752/// The signed current register, or zero if `current_lsb_microamps` is zero.
753pub fn current_register(microamps: i32, current_lsb_microamps: u32) -> i16 {
754    if current_lsb_microamps == 0 {
755        return 0;
756    }
757    (microamps / current_lsb_microamps as i32) as i16
758}
759
760/// Builds the power register a monitor reports for a power.
761///
762/// The inverse of [`power_microwatts`]. The same value serves as the alert limit for
763/// the power over-limit function.
764///
765/// # Arguments
766///
767/// * `microwatts` - the power in microwatts.
768/// * `current_lsb_microamps` - the current LSB the calibration register was set for.
769///
770/// # Returns
771///
772/// The power register, or zero if `current_lsb_microamps` is zero.
773pub fn power_register(microwatts: u32, current_lsb_microamps: u32) -> u16 {
774    if current_lsb_microamps == 0 {
775        return 0;
776    }
777    (microwatts / (POWER_LSB_RATIO * current_lsb_microamps)) as u16
778}
779
780/// Reproduces the chip's current calculation from a shunt reading and calibration.
781///
782/// This is the datasheet's `Current = ShuntVoltage * CalibrationRegister / 2048`,
783/// so a simulator can fill the current register the way the chip would.
784///
785/// # Arguments
786///
787/// * `shunt` - the signed shunt voltage register.
788/// * `calibration` - the programmed calibration register.
789///
790/// # Returns
791///
792/// The signed current register the chip would hold.
793pub fn current_register_from_shunt(shunt: i16, calibration: u16) -> i16 {
794    (i32::from(shunt) * i32::from(calibration) / 2048) as i16
795}
796
797/// Reproduces the chip's power calculation from the current and bus registers.
798///
799/// This is the datasheet's `Power = Current * BusVoltage / 20000`. The power
800/// register is unsigned, so the magnitude of the current is used.
801///
802/// # Arguments
803///
804/// * `current` - the signed current register.
805/// * `bus` - the bus voltage register.
806///
807/// # Returns
808///
809/// The power register the chip would hold.
810pub fn power_register_from_current(current: i16, bus: u16) -> u16 {
811    (u32::from(current.unsigned_abs()) * u32::from(bus & 0x7FFF) / 20_000) as u16
812}
813
814/// One set of results, with the current resolution they were taken at.
815///
816/// The four data registers are kept as read; the methods apply the datasheet's
817/// scaling. The overflow flag is the one the Mask/Enable register carried when the
818/// conversion finished.
819#[derive(Clone, Copy, Debug, PartialEq, Eq)]
820pub struct Reading {
821    /// The Shunt Voltage register.
822    pub shunt: i16,
823    /// The Bus Voltage register.
824    pub bus: u16,
825    /// The Current register.
826    pub current: i16,
827    /// The Power register.
828    pub power: u16,
829    /// The programmed current resolution, in microamps per count.
830    pub current_lsb_microamps: u32,
831    /// The math overflow flag: the current and power may be invalid.
832    pub math_overflow: bool,
833}
834
835impl Reading {
836    /// Returns the shunt voltage in nanovolts.
837    pub fn shunt_nanovolts(&self) -> i32 {
838        shunt_nanovolts(self.shunt)
839    }
840
841    /// Returns the shunt voltage in millivolts.
842    pub fn shunt_millivolts(&self) -> f32 {
843        shunt_millivolts_f32(self.shunt)
844    }
845
846    /// Returns the bus voltage in microvolts.
847    pub fn bus_microvolts(&self) -> u32 {
848        bus_microvolts(self.bus)
849    }
850
851    /// Returns the bus voltage in volts.
852    pub fn bus_volts(&self) -> f32 {
853        bus_volts_f32(self.bus)
854    }
855
856    /// Returns the current in microamps.
857    pub fn current_microamps(&self) -> i32 {
858        current_microamps(self.current, self.current_lsb_microamps)
859    }
860
861    /// Returns the current in amps.
862    pub fn current_amps(&self) -> f32 {
863        current_amps_f32(self.current, self.current_lsb_microamps)
864    }
865
866    /// Returns the power in microwatts.
867    pub fn power_microwatts(&self) -> u32 {
868        power_microwatts(self.power, self.current_lsb_microamps)
869    }
870
871    /// Returns the power in watts.
872    pub fn power_watts(&self) -> f32 {
873        power_watts_f32(self.power, self.current_lsb_microamps)
874    }
875}
876
877#[cfg(test)]
878mod driver_support_tests {
879    use super::*;
880
881    #[test]
882    fn a_reading_scales_its_registers_like_the_free_functions() {
883        let reading = Reading {
884            shunt: shunt_register(50_000_000),
885            bus: bus_register(12_000_000),
886            current: current_register(1_000_000, 100),
887            power: power_register(12_000_000, 100),
888            current_lsb_microamps: 100,
889            math_overflow: false,
890        };
891        assert_eq!(reading.shunt_nanovolts(), 50_000_000);
892        assert!((reading.shunt_millivolts() - 50.0).abs() < 1e-3);
893        assert_eq!(reading.bus_microvolts(), 12_000_000);
894        assert!((reading.bus_volts() - 12.0).abs() < 1e-3);
895        assert_eq!(reading.current_microamps(), 1_000_000);
896        assert!((reading.current_amps() - 1.0).abs() < 1e-3);
897        assert_eq!(reading.power_microwatts(), 12_000_000);
898        assert!((reading.power_watts() - 12.0).abs() < 1e-3);
899    }
900}
901
902#[cfg(test)]
903mod tests {
904    use super::*;
905
906    // The datasheet's worked example (section 6.5.1, Table 6-1): a 10 A load across
907    // a 2 mΩ shunt, 12 V common mode, current LSB rounded to 1 mA/bit.
908    const CURRENT_LSB: u32 = 1_000; // 1 mA in microamps
909
910    #[test]
911    fn every_register_survives_a_round_trip_through_its_builder() {
912        // Table 6-1: 20 mV shunt, 11.98 V bus, 10 A, 119.8 W.
913        assert_eq!(shunt_register(20_000_000), 0x1F40);
914        assert_eq!(shunt_nanovolts(shunt_register(20_000_000)), 20_000_000);
915        assert_eq!(shunt_nanovolts(shunt_register(-80_000_000)), -80_000_000);
916        assert_eq!(bus_register(11_980_000), 0x2570);
917        assert_eq!(bus_microvolts(bus_register(11_980_000)), 11_980_000);
918        assert_eq!(current_register(10_000_000, CURRENT_LSB), 0x2710);
919        assert_eq!(
920            current_microamps(current_register(10_000_000, CURRENT_LSB), CURRENT_LSB),
921            10_000_000
922        );
923        assert_eq!(current_register(-2_500_000, CURRENT_LSB), -2_500);
924        assert_eq!(power_register(119_800_000, CURRENT_LSB), 0x12B8);
925        assert_eq!(
926            power_microwatts(power_register(119_800_000, CURRENT_LSB), CURRENT_LSB),
927            119_800_000
928        );
929        assert_eq!(current_register(1, 0), 0);
930        assert_eq!(power_register(1, 0), 0);
931    }
932
933    #[test]
934    fn calibration_matches_the_datasheet_example() {
935        // Equation 1 with Current_LSB = 1 mA/bit and R_SHUNT = 2 mΩ: 2560 = A00h.
936        assert_eq!(calibration(CURRENT_LSB, 2), 2_560);
937        assert_eq!(calibration(CURRENT_LSB, 2), 0xA00);
938    }
939
940    #[test]
941    fn calibration_is_capped_at_the_register_width() {
942        // Table 7-11: the calibration value occupies FS14..FS0.
943        assert_eq!(calibration(1, 1), 0x7FFF);
944    }
945
946    #[test]
947    fn minimum_current_lsb_matches_the_datasheet_example() {
948        // Equation 2, section 6.5.1: 15 A / 2^15 = 457.7 µA/bit, up to the next
949        // whole microamp.
950        assert_eq!(minimum_current_lsb_microamps(15_000_000), 458);
951    }
952
953    #[test]
954    fn shunt_register_decodes_per_the_datasheet() {
955        // Table 6-1: 1F40h = 8000 at 2.5 µV per count is 20 mV.
956        assert_eq!(shunt_nanovolts(0x1F40), 20_000_000);
957        // Section 7.1.2 worked two's complement: -80 mV is 8300h.
958        assert_eq!(
959            shunt_nanovolts(i16::from_be_bytes([0x83, 0x00])),
960            -80_000_000
961        );
962        // Section 7.1.2: full scale 7FFFh is 81.92 mV (81.9175 mV exactly, per the
963        // electrical characteristics input range).
964        assert_eq!(shunt_nanovolts(0x7FFF), 81_917_500);
965        assert!((shunt_millivolts_f32(0x1F40) - 20.0).abs() < 1e-4);
966    }
967
968    #[test]
969    fn bus_register_decodes_per_the_datasheet() {
970        // Table 6-1: 2570h = 9584 at 1.25 mV per count is 11.98 V.
971        assert_eq!(bus_microvolts(0x2570), 11_980_000);
972        // Section 7.1.3: full scale 7FFFh is 40.96 V.
973        assert_eq!(bus_microvolts(0x7FFF), 40_958_750);
974        // Table 7-8: D15 is always zero, so it carries no value if it ever reads set.
975        assert_eq!(bus_microvolts(0xA570), bus_microvolts(0x2570));
976        assert!((bus_volts_f32(0x2570) - 11.98).abs() < 1e-4);
977    }
978
979    #[test]
980    fn current_register_decodes_to_the_example_load() {
981        // Table 6-1: 2710h = 10000 at 1 mA per count is 10 A.
982        assert_eq!(current_microamps(0x2710, CURRENT_LSB), 10_000_000);
983        assert!((current_amps_f32(0x2710, CURRENT_LSB) - 10.0).abs() < 1e-5);
984    }
985
986    #[test]
987    fn power_register_decodes_to_the_example_load() {
988        // Table 6-1: 12B8h = 4792 at 25 mW per count (25 times the 1 mA current
989        // LSB) is 119.8 W; the table prints the figure as 119.82 W.
990        assert_eq!(power_microwatts(0x12B8, CURRENT_LSB), 119_800_000);
991        assert!((power_watts_f32(0x12B8, CURRENT_LSB) - 119.8).abs() < 1e-3);
992    }
993
994    #[test]
995    fn chip_arithmetic_reproduces_the_datasheet_example() {
996        // Equation 3: 8000 * 2560 / 2048 = 10000 = 2710h.
997        assert_eq!(current_register_from_shunt(0x1F40, 0xA00), 0x2710);
998        // Equation 4: 10000 * 9584 / 20000 = 4792 = 12B8h.
999        assert_eq!(power_register_from_current(0x2710, 0x2570), 0x12B8);
1000        // A reversed current gives the same power magnitude.
1001        assert_eq!(current_register_from_shunt(-0x1F40, 0xA00), -0x2710);
1002        assert_eq!(power_register_from_current(-0x2710, 0x2570), 0x12B8);
1003        // Nothing is computed until the calibration register is programmed
1004        // (Table 7-1, note 2).
1005        assert_eq!(current_register_from_shunt(0x1F40, 0), 0);
1006    }
1007
1008    #[test]
1009    fn configuration_reset_value_matches_the_datasheet() {
1010        // Table 7-1 / Table 7-2: power-on reset 4127h, averaging 1, 1.1 ms for both
1011        // conversions, shunt and bus continuous. Table 6-1 step 1 writes the same.
1012        let config = Configuration::from_register(CONFIG_RESET);
1013        assert_eq!(config, Configuration::RESET);
1014        assert_eq!(config, Configuration::default());
1015        assert!(!config.reset);
1016        assert_eq!(config.averaging, Averaging::Samples1);
1017        assert_eq!(config.bus_conversion_time, ConversionTime::Us1100);
1018        assert_eq!(config.shunt_conversion_time, ConversionTime::Us1100);
1019        assert_eq!(config.mode, Mode::ShuntAndBusContinuous);
1020        assert_eq!(config.to_register(), 0x4127);
1021    }
1022
1023    #[test]
1024    fn configuration_fields_land_on_their_datasheet_bits() {
1025        // Table 7-2: RST in D15, AVG in D11:9, VBUSCT in D8:6, VSHCT in D5:3, MODE
1026        // in D2:0.
1027        let config = Configuration {
1028            reset: true,
1029            averaging: Averaging::Samples1024,
1030            bus_conversion_time: ConversionTime::Us8244,
1031            shunt_conversion_time: ConversionTime::Us8244,
1032            mode: Mode::ShuntAndBusContinuous,
1033        };
1034        assert_eq!(
1035            config.to_register(),
1036            0x8000 | 0x4000 | 0x0E00 | 0x01C0 | 0x0038 | 0x0007
1037        );
1038        assert_eq!(Configuration::from_register(config.to_register()), config);
1039
1040        let config = Configuration {
1041            reset: false,
1042            averaging: Averaging::Samples16,
1043            bus_conversion_time: ConversionTime::Us140,
1044            shunt_conversion_time: ConversionTime::Us588,
1045            mode: Mode::ShuntTriggered,
1046        };
1047        assert_eq!(config.to_register(), 0x4000 | 0x0400 | 0x0018 | 0x0001);
1048        assert_eq!(Configuration::from_register(config.to_register()), config);
1049
1050        // Table 7-6: both 000 and 100 are power-down.
1051        assert_eq!(Configuration::from_register(0x4120).mode, Mode::PowerDown);
1052        assert_eq!(Configuration::from_register(0x4124).mode, Mode::PowerDown);
1053    }
1054
1055    #[test]
1056    fn averaging_table_decodes_per_the_datasheet() {
1057        // Table 7-3.
1058        let table = [1, 4, 16, 64, 128, 256, 512, 1024];
1059        for (bits, samples) in table.into_iter().enumerate() {
1060            let averaging = Averaging::from_bits(bits as u16);
1061            assert_eq!(averaging as u16, bits as u16);
1062            assert_eq!(averaging.samples(), samples, "AVG = {bits:03b}");
1063        }
1064    }
1065
1066    #[test]
1067    fn conversion_time_table_decodes_per_the_datasheet() {
1068        // Tables 7-4 and 7-5, the same eight settings for bus and shunt.
1069        let table = [140, 204, 332, 588, 1_100, 2_116, 4_156, 8_244];
1070        for (bits, microseconds) in table.into_iter().enumerate() {
1071            let time = ConversionTime::from_bits(bits as u16);
1072            assert_eq!(time as u16, bits as u16);
1073            assert_eq!(time.microseconds(), microseconds, "CT = {bits:03b}");
1074        }
1075    }
1076
1077    #[test]
1078    fn mode_table_decodes_per_the_datasheet() {
1079        // Table 7-6.
1080        assert_eq!(Mode::from_bits(0b000), Mode::PowerDown);
1081        assert_eq!(Mode::from_bits(0b001), Mode::ShuntTriggered);
1082        assert_eq!(Mode::from_bits(0b010), Mode::BusTriggered);
1083        assert_eq!(Mode::from_bits(0b011), Mode::ShuntAndBusTriggered);
1084        assert_eq!(Mode::from_bits(0b100), Mode::PowerDown);
1085        assert_eq!(Mode::from_bits(0b101), Mode::ShuntContinuous);
1086        assert_eq!(Mode::from_bits(0b110), Mode::BusContinuous);
1087        assert_eq!(Mode::from_bits(0b111), Mode::ShuntAndBusContinuous);
1088        assert!(Mode::ShuntContinuous.measures_shunt());
1089        assert!(!Mode::ShuntContinuous.measures_bus());
1090        assert!(Mode::BusTriggered.measures_bus());
1091        assert!(!Mode::BusTriggered.is_continuous());
1092        assert!(Mode::ShuntAndBusContinuous.is_continuous());
1093        assert!(!Mode::PowerDown.measures_shunt());
1094        assert!(!Mode::PowerDown.measures_bus());
1095    }
1096
1097    #[test]
1098    fn update_interval_matches_the_datasheet_timing_examples() {
1099        // Section 6.4.1: 588 µs for both conversions averaged over 4 samples updates
1100        // about every 4.7 ms, as does 4.156 ms shunt with 588 µs bus and no averaging.
1101        let config = Configuration {
1102            averaging: Averaging::Samples4,
1103            bus_conversion_time: ConversionTime::Us588,
1104            shunt_conversion_time: ConversionTime::Us588,
1105            ..Configuration::RESET
1106        };
1107        assert_eq!(config.update_microseconds(), 4_704);
1108        let config = Configuration {
1109            averaging: Averaging::Samples1,
1110            bus_conversion_time: ConversionTime::Us588,
1111            shunt_conversion_time: ConversionTime::Us4156,
1112            ..Configuration::RESET
1113        };
1114        assert_eq!(config.update_microseconds(), 4_744);
1115        assert_eq!(Configuration::RESET.update_microseconds(), 2_200);
1116        let config = Configuration {
1117            mode: Mode::ShuntContinuous,
1118            ..config
1119        };
1120        assert_eq!(config.update_microseconds(), 4_156);
1121        let config = Configuration {
1122            mode: Mode::PowerDown,
1123            ..config
1124        };
1125        assert_eq!(config.update_microseconds(), 0);
1126    }
1127
1128    #[test]
1129    fn address_table_matches_the_datasheet() {
1130        // Table 6-2, in its row order GND, VS, SDA, SCL for each pin.
1131        use AddressPin::*;
1132        let pins = [Ground, Supply, Sda, Scl];
1133        let mut expected = 0x40;
1134        for a1 in pins {
1135            for a0 in pins {
1136                assert_eq!(address(a1, a0), expected, "A1 = {a1:?}, A0 = {a0:?}");
1137                expected += 1;
1138            }
1139        }
1140        assert_eq!(address(Ground, Ground), 0b1000000);
1141        assert_eq!(address(Supply, Ground), 0b1000100);
1142        assert_eq!(address(Sda, Scl), 0b1001011);
1143        assert_eq!(address(Scl, Scl), 0b1001111);
1144    }
1145
1146    #[test]
1147    fn identification_registers_match_the_datasheet() {
1148        // Table 7-1: manufacturer ID 5449h; die ID 2260h or 2261h (note 3).
1149        assert_eq!(MANUFACTURER_ID, 0x5449);
1150        assert_eq!(
1151            identify(0x5449, 0x2260),
1152            Ok(DieId {
1153                device: 0x226,
1154                revision: 0
1155            })
1156        );
1157        assert_eq!(
1158            identify(0x5449, 0x2261),
1159            Ok(DieId {
1160                device: 0x226,
1161                revision: 1
1162            })
1163        );
1164        // An unpowered or absent part reads all ones.
1165        assert_eq!(identify(0xFFFF, 0xFFFF), Err(SensorError::Identity));
1166        // Another TI part on the same address.
1167        assert_eq!(identify(0x5449, 0x2280), Err(SensorError::Identity));
1168        assert_eq!(identify(0x0000, 0x2260), Err(SensorError::Identity));
1169    }
1170
1171    #[test]
1172    fn mask_enable_decodes_the_alert_bits() {
1173        // Table 7-12: SOL D15, SUL D14, BOL D13, BUL D12, POL D11, CNVR D10, AFF D4,
1174        // CVRF D3, OVF D2, APOL D1, LEN D0.
1175        let mask = MaskEnable::from_register(0x8001);
1176        assert!(mask.shunt_over_limit);
1177        assert!(mask.alert_latch);
1178        assert_eq!(
1179            mask.active_alert_function(),
1180            Some(AlertFunction::ShuntOverLimit)
1181        );
1182        assert_eq!(mask.to_register(), 0x8001);
1183
1184        let mask = MaskEnable::from_register(0x0418);
1185        assert!(mask.conversion_ready);
1186        assert!(mask.alert_function_flag);
1187        assert!(mask.conversion_ready_flag);
1188        assert!(!mask.math_overflow);
1189        assert_eq!(mask.active_alert_function(), None);
1190        assert_eq!(mask.to_register(), 0x0418);
1191
1192        assert!(MaskEnable::from_register(0x0004).math_overflow);
1193        assert!(MaskEnable::from_register(0x0002).alert_active_high);
1194        assert_eq!(MaskEnable::from_register(0x0000), MaskEnable::default());
1195        assert_eq!(MaskEnable::default().to_register(), 0x0000);
1196
1197        for bit in 0..16 {
1198            let raw = 1u16 << bit;
1199            let reserved = (5..=9).contains(&bit);
1200            assert_eq!(
1201                MaskEnable::from_register(raw).to_register(),
1202                if reserved { 0 } else { raw },
1203                "bit {bit}"
1204            );
1205        }
1206    }
1207
1208    #[test]
1209    fn the_highest_alert_function_bit_takes_priority() {
1210        // Section 7.1.7: with several functions enabled, the most significant wins.
1211        assert_eq!(
1212            MaskEnable::from_register(0xF800).active_alert_function(),
1213            Some(AlertFunction::ShuntOverLimit)
1214        );
1215        assert_eq!(
1216            MaskEnable::from_register(0x7800).active_alert_function(),
1217            Some(AlertFunction::ShuntUnderLimit)
1218        );
1219        assert_eq!(
1220            MaskEnable::from_register(0x3800).active_alert_function(),
1221            Some(AlertFunction::BusOverLimit)
1222        );
1223        assert_eq!(
1224            MaskEnable::from_register(0x1800).active_alert_function(),
1225            Some(AlertFunction::BusUnderLimit)
1226        );
1227        assert_eq!(
1228            MaskEnable::from_register(0x0800).active_alert_function(),
1229            Some(AlertFunction::PowerOverLimit)
1230        );
1231        assert_eq!(
1232            MaskEnable::from_register(0x0400).active_alert_function(),
1233            None
1234        );
1235    }
1236
1237    #[test]
1238    fn integer_conversions_track_the_floating_point_reference() {
1239        // Equation 1 in its floating-point form, CAL = 0.00512 / (Current_LSB *
1240        // R_SHUNT), swept over current LSBs and shunts a design would choose.
1241        for &lsb in &[50u32, 100, 250, 458, 500, 1_000, 2_000, 5_000, 10_000] {
1242            for &shunt in &[1u32, 2, 5, 10, 25, 100, 500, 1_000] {
1243                let reference = 0.00512 / (f64::from(lsb) * 1e-6 * f64::from(shunt) * 1e-3);
1244                let expected = reference.trunc().min(32_767.0);
1245                let actual = f64::from(calibration(lsb, shunt));
1246                assert!(
1247                    (actual - expected).abs() <= 1.0,
1248                    "lsb {lsb} µA, shunt {shunt} mΩ: {actual} vs {expected}"
1249                );
1250            }
1251        }
1252
1253        // The 2.5 µV, 1.25 mV, and 25 x Current_LSB scalings against their float
1254        // forms across the register range.
1255        for raw in (-32_768..=32_767).step_by(997) {
1256            let shunt = f64::from(shunt_nanovolts(raw as i16)) * 1e-9;
1257            assert!((shunt - f64::from(raw) * 2.5e-6).abs() < 1e-12);
1258            let current = f64::from(current_microamps(raw as i16, 458)) * 1e-6;
1259            assert!((current - f64::from(raw) * 458e-6).abs() < 1e-9);
1260        }
1261        for raw in (0..=0x7FFF).step_by(499) {
1262            let bus = f64::from(bus_microvolts(raw as u16)) * 1e-6;
1263            assert!((bus - f64::from(raw) * 1.25e-3).abs() < 1e-9);
1264            let power = f64::from(power_microwatts(raw as u16, 458)) * 1e-6;
1265            assert!((power - f64::from(raw) * 25.0 * 458e-6).abs() < 1e-9);
1266        }
1267    }
1268
1269    #[test]
1270    fn an_uncalibrated_request_returns_zero() {
1271        assert_eq!(calibration(0, 2), 0);
1272        assert_eq!(calibration(CURRENT_LSB, 0), 0);
1273    }
1274}