Skip to main content

dumb_ina219/
lib.rs

1extern crate i2cdev;
2use i2cdev::core::*;
3#[cfg(any(target_os = "linux"))]
4use i2cdev::linux::{LinuxI2CDevice, LinuxI2CError};
5use std::{thread::sleep, time::Duration};
6
7#[cfg(not(any(target_os = "linux")))]
8mod stub;
9#[cfg(not(any(target_os = "linux")))]
10use crate::stub::{LinuxI2CDevice, LinuxI2CError};
11
12pub mod units;
13use crate::units::*;
14
15enum RegAddrs {
16    Cfg          = 0x00,
17    ShuntVoltage = 0x01,
18    BusVoltage   = 0x02,
19    Power        = 0x03,
20    Current      = 0x04,
21    Calibration  = 0x05,
22}
23
24pub struct Ina219 {
25    shunt_resistance: ResistanceUnit,
26    max_expected_current: CurrentUnit,
27    current_lsb: CurrentUnit,
28    power_lsb: PowerUnit,
29    i2c_address: u8,
30    device: LinuxI2CDevice,
31}
32
33impl Ina219 {
34    /// You **must** init after creating a new INA219 instance.
35    pub fn new(
36        shunt_resistance: ResistanceUnit,
37        max_expected_current: CurrentUnit,
38        address: u8,
39    ) -> Result<Self, LinuxI2CError> {
40        Ok(
41            Self {
42                shunt_resistance: shunt_resistance,
43                max_expected_current: max_expected_current,
44                current_lsb: CurrentUnit::milliamps(0.0),
45                power_lsb: PowerUnit::milliwatts(0.0),
46                i2c_address: address,
47                device: LinuxI2CDevice::new("/dev/i2c-1", address as u16)?
48            }
49        )
50    }
51
52    /// This **must** be called before calling methods to read voltage/current/power measurements.
53    pub fn init(&mut self) -> Result<(), LinuxI2CError> {
54        sleep(Duration::from_millis(650)); // slight delay after bus init
55        let current_lsb_val = self.max_expected_current.get_val() / 32768.0;
56        self.current_lsb.set_val(current_lsb_val);
57
58        let power_lsb_val = 20.0 * current_lsb_val;
59        self.power_lsb.set_val(power_lsb_val);
60        self.device.write(&[RegAddrs::Cfg as u8, 0x1F as u8, 0xFF as u8])?; // Default config
61        Ok(())
62    }
63
64    fn calibrate(&mut self) -> Result<(), LinuxI2CError> {
65        let cal = (0.04096 / (self.current_lsb.get_val() * self.shunt_resistance.get_val())).trunc() as u16;
66        self.device.write(
67            &[RegAddrs::Calibration as u8, (cal >> 8) as u8, cal as u8]
68        )?;
69        Ok(())
70    }
71
72    pub fn shunt_voltage(&mut self) -> Result<VoltageUnit, LinuxI2CError> {
73        let mut buf: [u8; 2] = [0; 2];
74        self.calibrate()?;
75        self.device.write(&[RegAddrs::ShuntVoltage as u8])?;
76        self.device.read(&mut buf)?;
77        let val = (i16::from_be_bytes(buf)) as f64;
78        Ok(VoltageUnit::volts(val*0.00001)) // 10uV step size: 10uV * (1V / 10^6 uV)
79    }
80
81    pub fn bus_voltage(&mut self) -> Result<VoltageUnit, LinuxI2CError> {
82        let mut buf: [u8; 2] = [0; 2];
83        self.calibrate()?;
84        self.device.write(&[RegAddrs::BusVoltage as u8])?;
85        self.device.read(&mut buf)?;
86        let val = (i16::from_be_bytes(buf) >> 3) as f64;
87        Ok(VoltageUnit::volts(val*0.004)) // 4mV step size: 4mV * (1V / 1000 mV)
88    }
89
90    pub fn power(&mut self) -> Result<PowerUnit, LinuxI2CError> {
91        let mut buf: [u8; 2] = [0; 2];
92        self.calibrate()?;
93        self.device.write(&[RegAddrs::Power as u8])?;
94        self.device.read(&mut buf)?;
95        let val = (i16::from_be_bytes(buf)) as f64;
96        Ok(PowerUnit::watts(val * self.power_lsb.get_val()))
97    }
98
99    pub fn load_current(&mut self) -> Result<CurrentUnit, LinuxI2CError> {
100        let mut buf: [u8; 2] = [0; 2];
101        self.calibrate()?;
102        self.device.write(&[RegAddrs::Current as u8])?;
103        self.device.read(&mut buf)?;
104        let val = ((i16::from_be_bytes(buf)) as f64)  * self.current_lsb.get_val();
105        Ok(CurrentUnit::amps(val))
106    }
107}