#![no_std]
use embedded_hal as hal;
use core::mem;
use crate::hal::blocking::i2c::{Write, WriteRead};
use cast::{i32, u16, u32};
#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
pub enum Register {
CONFIG = 0x00,
CURRENT = 0x01,
VOLTAGE = 0x02,
POWER = 0x03,
MASK_ENABLE = 0x06,
ALERT_LIMIT = 0x07,
MANUFACTURER_ID = 0xFE,
DIE_ID = 0xFF,
}
impl Register {
#[inline(always)]
pub fn addr(self) -> u8 {
self as u8
}
}
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum Averaging {
AVG1 = 0b0000_0000_0000_0000,
AVG4 = 0b0000_0010_0000_0000,
AVG16 = 0b0000_0100_0000_0000,
AVG64 = 0b0000_0110_0000_0000,
AVG128 = 0b0000_1000_0000_0000,
AVG256 = 0b0000_1010_0000_0000,
AVG512 = 0b0000_1100_0000_0000,
AVG1024 = 0b0000_1110_0000_0000,
}
impl Averaging {
#[inline(always)]
pub fn bits(self) -> u16 {
self as u16
}
}
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum BVConvTime {
US140 = 0b0000_0000_0000_0000,
US204 = 0b0000_0000_0100_0000,
US332 = 0b0000_0000_1000_0000,
US588 = 0b0000_0000_1100_0000,
MS1_1 = 0b0000_0001_0000_0000,
MS2_116 = 0b0000_0001_0100_0000,
MS4_156 = 0b0000_0001_1000_0000,
MS8_244 = 0b0000_0001_1100_0000,
}
impl BVConvTime {
#[inline(always)]
pub fn bits(self) -> u16 {
self as u16
}
}
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum SCConvTime {
US140 = 0b0000_0000_0000_0000,
US204 = 0b0000_0000_0000_1000,
US332 = 0b0000_0000_0001_0000,
US588 = 0b0000_0000_0001_1000,
MS1_1 = 0b0000_0000_0010_0000,
MS2_116 = 0b0000_0000_0010_1000,
MS4_156 = 0b0000_0000_0011_0000,
MS8_244 = 0b0000_0000_0011_1000,
}
impl SCConvTime {
#[inline(always)]
pub fn bits(self) -> u16 {
self as u16
}
}
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum OperMode {
SHUTDOWN = 0b0000_0000_0000_0000,
SCT = 0b0000_0000_0000_0001,
BVT = 0b0000_0000_0000_0010,
SCBVT = 0b0000_0000_0000_0011,
SCC = 0b0000_0000_0000_0101,
BVC = 0b0000_0000_0000_0110,
SCBVC = 0b0000_0000_0000_0111,
}
impl OperMode {
#[inline(always)]
pub fn bits(self) -> u16 {
self as u16
}
}
#[inline(always)]
fn write_register<I2C>(
i2c: &mut I2C,
address: u8,
reg: Register,
data: u16,
) -> Result<(), I2C::Error>
where
I2C: Write,
{
i2c.write(
address,
&[reg.addr(), (data >> 8) as u8, (data & 255) as u8],
)
}
pub struct INA260NonOwned<I2C> {
address: u8,
state: u16,
_marker: core::marker::PhantomData<I2C>,
}
impl<I2C, E> INA260NonOwned<I2C>
where
I2C: WriteRead<Error = E> + Write<Error = E>,
{
#[inline(always)]
pub fn new(i2c: &mut I2C, address: u8) -> Result<Self, E> {
let ina260 = Self {
_marker: core::marker::PhantomData,
address,
state: OperMode::SCBVC.bits()
| Averaging::AVG1.bits()
| SCConvTime::MS1_1.bits()
| BVConvTime::MS1_1.bits(),
};
write_register(i2c, address, Register::CONFIG, 0x8000)?;
Ok(ina260)
}
#[inline(always)]
pub fn set_averaging_mode(&mut self, i2c: &mut I2C, a: Averaging) -> Result<(), E> {
let bits = a.bits();
let state = (self.state & !Averaging::AVG1024.bits()) | bits;
write_register(i2c, self.address, Register::CONFIG, state)?;
self.state = state;
Ok(())
}
#[inline(always)]
pub fn set_operating_mode(&mut self, i2c: &mut I2C, o: OperMode) -> Result<(), E> {
let bits = o.bits();
let state = (self.state & !OperMode::SCBVC.bits()) | bits;
write_register(i2c, self.address, Register::CONFIG, state)?;
self.state = state;
Ok(())
}
#[inline(always)]
pub fn set_scconvtime_mode(&mut self, i2c: &mut I2C, s: SCConvTime) -> Result<(), E> {
let bits = s.bits();
let state = (self.state & !SCConvTime::MS8_244.bits()) | bits;
write_register(i2c, self.address, Register::CONFIG, state)?;
self.state = state;
Ok(())
}
#[inline(always)]
pub fn set_bvconvtime_mode(&mut self, i2c: &mut I2C, b: BVConvTime) -> Result<(), E> {
let bits = b.bits();
let state = (self.state & !BVConvTime::MS8_244.bits()) | bits;
write_register(i2c, self.address, Register::CONFIG, state)?;
self.state = state;
Ok(())
}
#[inline(always)]
pub fn did(&mut self, i2c: &mut I2C) -> Result<u16, E> {
let mut buffer: [u8; 2] = unsafe { mem::uninitialized() };
i2c.write_read(self.address, &[Register::DIE_ID.addr()], &mut buffer)?;
Ok((u16(buffer[0]) << 8 | u16(buffer[1])) >> 4)
}
#[inline(always)]
pub fn rid(&mut self, i2c: &mut I2C) -> Result<u16, E> {
let mut buffer: [u8; 2] = unsafe { mem::uninitialized() };
i2c.write_read(self.address, &[Register::DIE_ID.addr()], &mut buffer)?;
Ok(u16(buffer[1]) & 0b1111)
}
#[inline(always)]
pub fn current_raw(&mut self, i2c: &mut I2C) -> Result<i16, E> {
let mut buffer: [u8; 2] = unsafe { mem::uninitialized() };
i2c.write_read(self.address, &[Register::CURRENT.addr()], &mut buffer)?;
Ok((u16(buffer[0]) << 8 | u16(buffer[1])) as i16)
}
#[inline(always)]
pub fn current(&mut self, i2c: &mut I2C) -> Result<i32, E> {
let raw = self.current_raw(i2c)?;
Ok(i32(raw) * 1250)
}
#[inline(always)]
pub fn current_split(&mut self, i2c: &mut I2C) -> Result<(i8, u32), E> {
let raw = i32::from(self.current_raw(i2c)?);
if raw >= 0 {
let full = (0..=raw).step_by(800).skip(1).count() as i32;
let rest = (raw - (full * 800)) * 125;
Ok((full as i8, rest as u32))
} else {
let full = -((raw..=0).step_by(800).skip(1).count() as i32);
let rest = -(raw - (full * 800)) * 125;
Ok((full as i8, rest as u32))
}
}
#[inline(always)]
pub fn voltage_raw(&mut self, i2c: &mut I2C) -> Result<u16, E> {
let mut buffer: [u8; 2] = unsafe { mem::uninitialized() };
i2c.write_read(self.address, &[Register::VOLTAGE.addr()], &mut buffer)?;
Ok(u16(buffer[0]) << 8 | u16(buffer[1]))
}
#[inline(always)]
pub fn voltage(&mut self, i2c: &mut I2C) -> Result<u32, E> {
let raw = self.voltage_raw(i2c)?;
Ok(u32(raw) * 1250)
}
#[inline(always)]
pub fn voltage_split(&mut self, i2c: &mut I2C) -> Result<(u8, u32), E> {
let raw = u32::from(self.voltage_raw(i2c)?);
let full = (0..=raw).step_by(800).skip(1).count() as u32;
let rest = (raw - (full * 800)) * 125;
Ok((full as u8, rest))
}
#[inline(always)]
pub fn power_raw(&mut self, i2c: &mut I2C) -> Result<u16, E> {
let mut buffer: [u8; 2] = unsafe { mem::uninitialized() };
i2c.write_read(self.address, &[Register::POWER.addr()], &mut buffer)?;
Ok(u16(buffer[0]) << 8 | u16(buffer[1]))
}
#[inline(always)]
pub fn power(&mut self, i2c: &mut I2C) -> Result<u32, E> {
let raw = self.power_raw(i2c)?;
Ok(u32(raw) * 10)
}
#[inline(always)]
pub fn power_split(&mut self, i2c: &mut I2C) -> Result<(u8, u32), E> {
let raw = u32::from(self.power_raw(i2c)?);
let full = (0..=raw).step_by(100).skip(1).count() as u32;
let rest = (raw - (full * 100)) * 1000;
Ok((full as u8, rest))
}
}
pub struct INA260<I2C>(I2C, INA260NonOwned<I2C>);
impl<I2C, E> INA260<I2C>
where
I2C: WriteRead<Error = E> + Write<Error = E>,
{
#[inline(always)]
pub fn new(mut i2c: I2C, address: u8) -> Result<Self, E> {
let ina260 = INA260NonOwned::new(&mut i2c, address)?;
Ok(Self(i2c, ina260))
}
#[inline(always)]
pub fn release(mut self) -> I2C {
let _ = self.set_operating_mode(OperMode::SHUTDOWN);
self.0
}
#[inline(always)]
pub fn set_averaging_mode(&mut self, a: Averaging) -> Result<(), E> {
self.1.set_averaging_mode(&mut self.0, a)
}
#[inline(always)]
pub fn set_operating_mode(&mut self, o: OperMode) -> Result<(), E> {
self.1.set_operating_mode(&mut self.0, o)
}
#[inline(always)]
pub fn set_scconvtime_mode(&mut self, s: SCConvTime) -> Result<(), E> {
self.1.set_scconvtime_mode(&mut self.0, s)
}
#[inline(always)]
pub fn set_bvconvtime_mode(&mut self, b: BVConvTime) -> Result<(), E> {
self.1.set_bvconvtime_mode(&mut self.0, b)
}
#[inline(always)]
pub fn did(&mut self) -> Result<u16, E> {
self.1.did(&mut self.0)
}
#[inline(always)]
pub fn rid(&mut self) -> Result<u16, E> {
self.1.rid(&mut self.0)
}
#[inline(always)]
pub fn current_raw(&mut self) -> Result<i16, E> {
self.1.current_raw(&mut self.0)
}
#[inline(always)]
pub fn current(&mut self) -> Result<i32, E> {
self.1.current(&mut self.0)
}
#[inline(always)]
pub fn current_split(&mut self) -> Result<(i8, u32), E> {
self.1.current_split(&mut self.0)
}
#[inline(always)]
pub fn voltage_raw(&mut self) -> Result<u16, E> {
self.1.voltage_raw(&mut self.0)
}
#[inline(always)]
pub fn voltage(&mut self) -> Result<u32, E> {
self.1.voltage(&mut self.0)
}
#[inline(always)]
pub fn voltage_split(&mut self) -> Result<(u8, u32), E> {
self.1.voltage_split(&mut self.0)
}
#[inline(always)]
pub fn power_raw(&mut self) -> Result<u16, E> {
self.1.power_raw(&mut self.0)
}
#[inline(always)]
pub fn power(&mut self) -> Result<u32, E> {
self.1.power(&mut self.0)
}
#[inline(always)]
pub fn power_split(&mut self) -> Result<(u8, u32), E> {
self.1.power_split(&mut self.0)
}
}