#![cfg_attr(not(test), no_std)]
pub mod regs;
use embedded_hal::blocking::i2c;
use packed_struct::prelude::*;
use paste::paste;
use regs::*;
#[repr(u8)]
#[derive(Debug, Copy, Clone)]
pub enum AddrSelect {
GND = 0b10000,
_499 = 0b10001,
_806 = 0b10010,
_1270 = 0b10011,
_2050 = 0b10100,
_3240 = 0b10101,
_5230 = 0b10110,
_8450 = 0b10111,
_13300 = 0b11000,
_21500 = 0b11001,
_34000 = 0b11010,
_54900 = 0b11011,
_88700 = 0b11100,
_140000 = 0b11101,
_226000 = 0b11110,
VDD = 0b11111,
}
#[derive(Debug, Copy, Clone)]
pub enum ProductId {
PAC1941_1,
PAC1942_1,
PAC1943_1,
PAC1944_1,
PAC1941_2,
PAC1942_2,
}
pub struct PAC194X<I>
where
I: i2c::Read + i2c::Write + i2c::WriteRead,
{
i2c: I,
address: u8,
}
#[derive(Debug, PartialEq)]
pub enum Error<E> {
I2c(E),
Internal,
}
macro_rules! read_fn {
($var:ident: $type:ty) => {
paste! {
#[doc = stringify!(Reads the $type register and deserializes into the appropriate struct)]
pub fn [<read_ $var>](&mut self) -> Result<$type, Error<E>> {
Ok($type::unpack(&self.block_read($type::addr())?).unwrap())
}
}
};
}
macro_rules! read_n_fn {
($var:ident: $type:ty) => {
paste! {
#[doc = stringify!(Reads the $type register and deserializes into the appropriate struct)]
pub fn [<read_ $var>](&mut self, n: u8) -> Result<$type, Error<E>> {
assert!((1..=4).contains(&n),"Channel n must be between 1 and 4");
Ok($type::unpack(&self.block_read_n($type::addr(),n)?).unwrap())
}
}
};
}
macro_rules! write_fn {
($var:ident: $type:ty) => {
paste! {
#[doc = stringify!(Writes out the $type register)]
pub fn [<write_ $var>](&mut self, $var: $type) -> Result<(), Error<E>> {
const PACKED_SIZE_WITH_ADDR: usize = core::mem::size_of::<<$type as PackedStruct>::ByteArray>() + 1;
let mut bytes = [0u8; PACKED_SIZE_WITH_ADDR];
bytes[0] = $type::addr() as u8;
$var.pack_to_slice(&mut bytes[1..]).unwrap();
self.block_write(&bytes)?;
Ok(())
}
}
};
}
macro_rules! write_n_fn {
($var:ident: $type:ty) => {
paste! {
#[doc = stringify!(Writes out the $type register)]
pub fn [<write_ $var>](&mut self, $var: $type, n: u8) -> Result<(), Error<E>> {
assert!((1..=4).contains(&n),"Channel n must be between 1 and 4");
const PACKED_SIZE_WITH_ADDR: usize = core::mem::size_of::<<$type as PackedStruct>::ByteArray>() + 1;
let mut bytes = [0u8; PACKED_SIZE_WITH_ADDR];
bytes[0] = ($type::addr() as u8) + n - 1;
$var.pack_to_slice(&mut bytes[1..]).unwrap();
self.block_write(&bytes)?;
Ok(())
}
}
};
}
macro_rules! read_write {
($var:ident: $type:ty) => {
write_fn!($var: $type);
read_fn!($var: $type);
};
}
macro_rules! read_write_n {
($var:ident: $type:ty) => {
write_n_fn!($var: $type);
read_n_fn!($var: $type);
};
}
fn vbus_to_real(raw: u16, fsr: VBusFSR) -> f32 {
9.0 * match fsr {
VBusFSR::Unipolar => (raw as f32) / 65536.0,
VBusFSR::BipolarHV => (i16::from_ne_bytes(raw.to_le_bytes()) as f32) / 65536.0,
VBusFSR::BipolarLV => (i16::from_ne_bytes(raw.to_le_bytes()) as f32) / 32768.0,
}
}
fn vsense_to_real(raw: u16, fsr: VSenseFSR) -> f32 {
0.1 * match fsr {
VSenseFSR::Unipolar => (raw as f32) / 65536.0,
VSenseFSR::BipolarHV => (i16::from_ne_bytes(raw.to_le_bytes()) as f32) / 65536.0,
VSenseFSR::BipolarLV => (i16::from_ne_bytes(raw.to_le_bytes()) as f32) / 32768.0,
}
}
impl<E, I> PAC194X<I>
where
I: i2c::Read<Error = E> + i2c::Write<Error = E> + i2c::WriteRead<Error = E>,
{
pub fn new(i2c: I, addr_sel: AddrSelect) -> Self {
Self {
i2c,
address: addr_sel as u8,
}
}
fn send_byte(&mut self, addr: Address) -> Result<(), Error<E>> {
self.i2c
.write(self.address, &[addr as u8])
.map_err(Error::I2c)?;
Ok(())
}
fn receive_byte(&mut self) -> Result<u8, Error<E>> {
let mut buf = [0u8; 1];
self.i2c.read(self.address, &mut buf).map_err(Error::I2c)?;
Ok(buf[0])
}
fn block_write(&mut self, bytes: &[u8]) -> Result<(), Error<E>> {
self.i2c.write(self.address, bytes).map_err(Error::I2c)?;
Ok(())
}
fn block_read<const N: usize>(&mut self, addr: Address) -> Result<[u8; N], Error<E>> {
let mut buf = [0u8; N];
self.i2c
.write_read(self.address, &[addr as u8], &mut buf)
.map_err(Error::I2c)?;
Ok(buf)
}
fn block_read_n<const N: usize>(&mut self, addr: Address, n: u8) -> Result<[u8; N], Error<E>> {
let mut buf = [0u8; N];
self.i2c
.write_read(self.address, &[(addr as u8) + (n - 1)], &mut buf)
.map_err(Error::I2c)?;
Ok(buf)
}
pub fn refresh(&mut self) -> Result<(), Error<E>> {
self.send_byte(Address::Refresh)
}
pub fn refresh_v(&mut self) -> Result<(), Error<E>> {
self.send_byte(Address::RefreshV)
}
pub fn regresh_g(&mut self) -> Result<(), Error<E>> {
self.i2c
.write(0u8, &[Address::RefreshG as u8])
.map_err(Error::I2c)?;
Ok(())
}
pub fn product_id(&mut self) -> Result<ProductId, Error<E>> {
self.send_byte(regs::Address::ProductId)?;
Ok(match self.receive_byte()? {
0b0110_1000 => ProductId::PAC1941_1,
0b0110_1001 => ProductId::PAC1942_1,
0b0110_1010 => ProductId::PAC1943_1,
0b0110_1011 => ProductId::PAC1944_1,
0b0110_1100 => ProductId::PAC1941_2,
0b0110_1101 => ProductId::PAC1942_2,
_ => unreachable!(),
})
}
pub fn manufacturer_id(&mut self) -> Result<u8, Error<E>> {
self.send_byte(regs::Address::ManufacturerId)?;
self.receive_byte()
}
pub fn revision_id(&mut self) -> Result<u8, Error<E>> {
self.send_byte(regs::Address::RevisionId)?;
self.receive_byte()
}
pub fn read_bus_voltage_n(&mut self, n: u8) -> Result<f32, Error<E>> {
assert!((1..=4).contains(&n), "Channel n must be between 1 and 4");
let fsr_reg = self.read_neg_pwr_fsr_lat()?;
let fsr = match n {
1 => fsr_reg.cfg_vb1,
2 => fsr_reg.cfg_vb2,
3 => fsr_reg.cfg_vb3,
4 => fsr_reg.cfg_vb4,
_ => unreachable!(),
};
Ok(vbus_to_real(self.read_vbusn(n)?.voltage, fsr))
}
pub fn read_sense_voltage_n(&mut self, n: u8) -> Result<f32, Error<E>> {
assert!((1..=4).contains(&n), "Channel n must be between 1 and 4");
let fsr_reg = self.read_neg_pwr_fsr_lat()?;
let fsr = match n {
1 => fsr_reg.cfg_vs1,
2 => fsr_reg.cfg_vs2,
3 => fsr_reg.cfg_vs3,
4 => fsr_reg.cfg_vs4,
_ => unreachable!(),
};
Ok(vsense_to_real(self.read_vsensen(n)?.voltage, fsr))
}
pub fn read_avg_bus_voltage_n(&mut self, n: u8) -> Result<f32, Error<E>> {
assert!((1..=4).contains(&n), "Channel n must be between 1 and 4");
let fsr_reg = self.read_neg_pwr_fsr_lat()?;
let fsr = match n {
1 => fsr_reg.cfg_vb1,
2 => fsr_reg.cfg_vb2,
3 => fsr_reg.cfg_vb3,
4 => fsr_reg.cfg_vb4,
_ => unreachable!(),
};
Ok(vbus_to_real(self.read_vbusn_avg(n)?.voltage, fsr))
}
pub fn read_avg_sense_voltage_n(&mut self, n: u8) -> Result<f32, Error<E>> {
assert!((1..=4).contains(&n), "Channel n must be between 1 and 4");
let fsr_reg = self.read_neg_pwr_fsr_lat()?;
let fsr = match n {
1 => fsr_reg.cfg_vs1,
2 => fsr_reg.cfg_vs2,
3 => fsr_reg.cfg_vs3,
4 => fsr_reg.cfg_vs4,
_ => unreachable!(),
};
Ok(vsense_to_real(self.read_vsensen(n)?.voltage, fsr))
}
read_write!(ctrl: Ctrl);
read_write!(acc_count: AccCount);
read_n_fn!(vaccn: Vaccn);
read_n_fn!(vbusn: Vbusn);
read_n_fn!(vsensen: Vsensen);
read_n_fn!(vbusn_avg: VbusnAvg);
read_n_fn!(vsensen_avg: VsensenAvg);
read_n_fn!(vpowern: Vpowern);
read_write!(smub_settings: SmbusSettings);
read_write!(neg_pwr_fsr: NegPwrFsr);
read_fn!(slow: Slow);
read_fn!(ctrl_act: CtrlAct);
read_write!(neg_pwr_fsr_act: NegPwrFsrAct);
read_fn!(ctrl_lat: CtrlLat);
read_write!(neg_pwr_fsr_lat: NegPwrFsrLat);
read_write!(accum_config: AccumConfig);
read_fn!(alert_statuc: AlertStatus);
read_write!(slow_alert1: SlowAlert1);
read_write!(gpio_alert2: GpioAlert2);
read_write!(acc_fullness_limits: AccFullnessLimits);
read_write_n!(oc_limitn: OcLimitn);
read_write_n!(uc_limitn: UcLimitn);
read_write_n!(op_limitn: OpLimitn);
read_write_n!(ov_limitn: OvLimitn);
read_write_n!(uv_limitn: UvLimitn);
read_write!(oc_limit_n_samples: OcLimitNSamples);
read_write!(uc_limit_n_samples: UcLimitNSamples);
read_write!(op_limit_n_samples: OpLimitNSamples);
read_write!(ov_limit_n_samples: OvLimitNSamples);
read_write!(uv_limit_n_samples: UvLimitNSamples);
read_write!(alert_enable: AlertEnable);
read_write!(accum_config_act: AccumConfigAct);
read_write!(accum_config_lat: AccumConfigLat);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn addr_values() {
assert_eq!(Address::AlertEnable as u8, 0x49);
assert_eq!(Address::RevisionId as u8, 0xFF);
}
}