use self::address::Address;
use embedded_devices_derive::{forward_register_fns, sensor};
use embedded_interfaces::TransportError;
use uom::si::electric_current::ampere;
use uom::si::electrical_resistance::ohm;
use uom::si::f64::{ElectricCurrent, ElectricPotential, ElectricalResistance, Power};
pub mod address;
pub mod registers;
#[derive(Debug, thiserror::Error)]
pub enum MeasurementError<BusError> {
#[error("transport error")]
Transport(#[from] TransportError<(), BusError>),
#[error("conversion timeout")]
Timeout,
#[error("overflow in measurement")]
Overflow(Measurement),
}
#[derive(Debug, thiserror::Error)]
pub enum ContinuousMeasurementError<BusError> {
#[error("transport error")]
Transport(#[from] TransportError<(), BusError>),
#[error("overflow in measurement")]
Overflow(Measurement),
}
#[derive(Debug, embedded_devices_derive::Measurement)]
pub struct Measurement {
pub shunt_voltage: ElectricPotential,
#[measurement(Voltage)]
pub bus_voltage: ElectricPotential,
#[measurement(Current)]
pub current: ElectricCurrent,
#[measurement(Power)]
pub power: Power,
}
#[maybe_async_cfg::maybe(
idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), RegisterInterface),
sync(feature = "sync"),
async(feature = "async")
)]
pub struct INA219<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> {
delay: D,
interface: I,
shunt_resistance: ElectricalResistance,
max_expected_current: ElectricCurrent,
current_lsb_na: u32,
}
pub trait INA219Register {}
#[maybe_async_cfg::maybe(
idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), I2cDevice),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D, I> INA219<D, embedded_interfaces::i2c::I2cDevice<I, hal::i2c::SevenBitAddress>>
where
I: hal::i2c::I2c<hal::i2c::SevenBitAddress> + hal::i2c::ErrorType,
D: hal::delay::DelayNs,
{
#[inline]
pub fn new_i2c(delay: D, interface: I, address: Address) -> Self {
Self {
delay,
interface: embedded_interfaces::i2c::I2cDevice::new(interface, address.into()),
shunt_resistance: Default::default(),
max_expected_current: Default::default(),
current_lsb_na: 1,
}
}
}
#[forward_register_fns]
#[sensor(Voltage, Current, Power)]
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
ResettableDevice
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> INA219<D, I> {
pub async fn init(
&mut self,
shunt_resistance: ElectricalResistance,
max_expected_current: ElectricCurrent,
) -> Result<(), TransportError<(), I::BusError>> {
use crate::device::ResettableDevice;
self.reset().await?;
self.calibrate(shunt_resistance, max_expected_current).await?;
Ok(())
}
pub async fn calibrate(
&mut self,
shunt_resistance: ElectricalResistance,
max_expected_current: ElectricCurrent,
) -> Result<(), TransportError<(), I::BusError>> {
self.shunt_resistance = shunt_resistance;
self.max_expected_current = max_expected_current;
let shunt_resistance = shunt_resistance.get::<ohm>();
let max_expected_current = max_expected_current.get::<ampere>();
self.current_lsb_na = ((1_000_000_000f64 / (1 << 15) as f64) * max_expected_current) as u32;
let shunt_resistance_mohm = (1_000.0 * shunt_resistance) as u32;
let cal = 4_096_000_000 / (self.current_lsb_na * shunt_resistance_mohm / 10);
self.write_register(self::registers::Calibration::default().with_raw_value(cal as u16))
.await?;
Ok(())
}
pub async fn read_measurements(&mut self) -> Result<Measurement, MeasurementError<I::BusError>> {
let bus_voltage = self.read_register::<self::registers::BusVoltage>().await?;
let shunt_voltage = self.read_register::<self::registers::ShuntVoltage>().await?;
let current = self.read_register::<self::registers::Current>().await?;
let power = self.read_register::<self::registers::Power>().await?;
let measurement = Measurement {
shunt_voltage: shunt_voltage.read_value(),
bus_voltage: bus_voltage.read_value(),
current: current.read_current(self.current_lsb_na),
power: power.read_power(self.current_lsb_na),
};
if bus_voltage.read_overflow() {
Err(MeasurementError::Overflow(measurement))
} else {
Ok(measurement)
}
}
}
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
ResettableDevice
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::device::ResettableDevice
for INA219<D, I>
{
type Error = TransportError<(), I::BusError>;
async fn reset(&mut self) -> Result<(), Self::Error> {
self.write_register(self::registers::Configuration::default().with_reset(true))
.await?;
Ok(())
}
}
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
OneshotSensor
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::sensor::OneshotSensor
for INA219<D, I>
{
type Error = MeasurementError<I::BusError>;
type Measurement = Measurement;
async fn measure(&mut self) -> Result<Self::Measurement, Self::Error> {
let reg_conf = self.read_register::<self::registers::Configuration>().await?;
self.write_register(reg_conf.with_operating_mode(self::registers::OperatingMode::ShuntAndBusTriggered))
.await?;
let measurement_time_us = reg_conf.read_bus_adc_resolution().conversion_time_us()
+ reg_conf.read_shunt_adc_resolution().conversion_time_us();
self.delay.delay_us(1000 + measurement_time_us).await;
const TRIES: u8 = 5;
for _ in 0..TRIES {
let bus_voltage = self.read_register::<self::registers::BusVoltage>().await?;
if bus_voltage.read_conversion_ready() {
let shunt_voltage = self.read_register::<self::registers::ShuntVoltage>().await?;
let current = self.read_register::<self::registers::Current>().await?;
let power = self.read_register::<self::registers::Power>().await?;
let measurement = Measurement {
shunt_voltage: shunt_voltage.read_value(),
bus_voltage: bus_voltage.read_value(),
current: current.read_current(self.current_lsb_na),
power: power.read_power(self.current_lsb_na),
};
if bus_voltage.read_overflow() {
return Err(MeasurementError::Overflow(measurement));
} else {
return Ok(measurement);
}
}
self.delay.delay_us(1000).await;
}
Err(MeasurementError::Timeout)
}
}
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
ContinuousSensor
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::sensor::ContinuousSensor
for INA219<D, I>
{
type Error = ContinuousMeasurementError<I::BusError>;
type Measurement = Measurement;
async fn start_measuring(&mut self) -> Result<(), Self::Error> {
let reg_conf = self.read_register::<self::registers::Configuration>().await?;
self.write_register(reg_conf.with_operating_mode(self::registers::OperatingMode::ShuntAndBusContinuous))
.await?;
Ok(())
}
async fn stop_measuring(&mut self) -> Result<(), Self::Error> {
let reg_conf = self.read_register::<self::registers::Configuration>().await?;
self.write_register(reg_conf.with_operating_mode(self::registers::OperatingMode::PowerDown))
.await?;
Ok(())
}
async fn measurement_interval_us(&mut self) -> Result<u32, Self::Error> {
let reg_conf = self.read_register::<self::registers::Configuration>().await?;
let measurement_time_us = reg_conf.read_bus_adc_resolution().conversion_time_us()
+ reg_conf.read_shunt_adc_resolution().conversion_time_us();
Ok(measurement_time_us)
}
async fn current_measurement(&mut self) -> Result<Option<Self::Measurement>, Self::Error> {
let bus_voltage = self.read_register::<self::registers::BusVoltage>().await?;
let shunt_voltage = self.read_register::<self::registers::ShuntVoltage>().await?;
let current = self.read_register::<self::registers::Current>().await?;
let power = self.read_register::<self::registers::Power>().await?;
let measurement = Measurement {
shunt_voltage: shunt_voltage.read_value(),
bus_voltage: bus_voltage.read_value(),
current: current.read_current(self.current_lsb_na),
power: power.read_power(self.current_lsb_na),
};
if bus_voltage.read_overflow() {
Err(ContinuousMeasurementError::Overflow(measurement))
} else {
Ok(Some(measurement))
}
}
async fn is_measurement_ready(&mut self) -> Result<bool, Self::Error> {
let bus_voltage = self.read_register::<self::registers::BusVoltage>().await?;
Ok(bus_voltage.read_conversion_ready())
}
async fn next_measurement(&mut self) -> Result<Self::Measurement, Self::Error> {
loop {
let bus_voltage = self.read_register::<self::registers::BusVoltage>().await?;
if bus_voltage.read_conversion_ready() {
let shunt_voltage = self.read_register::<self::registers::ShuntVoltage>().await?;
let current = self.read_register::<self::registers::Current>().await?;
let power = self.read_register::<self::registers::Power>().await?;
let measurement = Measurement {
shunt_voltage: shunt_voltage.read_value(),
bus_voltage: bus_voltage.read_value(),
current: current.read_current(self.current_lsb_na),
power: power.read_power(self.current_lsb_na),
};
if bus_voltage.read_overflow() {
return Err(ContinuousMeasurementError::Overflow(measurement));
} else {
return Ok(measurement);
}
}
self.delay.delay_us(100).await;
}
}
}