use bon::Builder;
#[cfg(feature = "async")]
use embedded_hal_async::i2c::I2c;
#[cfg(not(feature = "async"))]
use embedded_hal::i2c::I2c;
use super::{Acs37800, Acs37800EepromRegister, Acs37800ReadError};
pub const I2C_ADDRESS_MEASURED_BASE: u8 = 0x60;
pub const I2C_ADDRESS_PROGRAMMED_DEFAULT: u8 = 0x7F;
#[derive(Builder)]
pub struct Acs37800I2c<I2C: I2c> {
i2c: I2C,
#[builder(default = 0x60)]
address: u8,
}
impl<I2C: I2c> Acs37800 for Acs37800I2c<I2C> {
#[cfg(feature = "async")]
fn read_reg32(
&mut self,
reg: Acs37800EepromRegister,
) -> impl Future<Output = Result<u32, Acs37800ReadError>> {
async move {
let mut buf = [0u8; 4];
let result = self
.i2c
.write_read(self.address, &[reg as u8], &mut buf)
.await;
#[cfg(feature = "std")]
{
result.map_err(|cause| Acs37800ReadError::Io(format!("{cause:?}")))?;
}
#[cfg(not(feature = "std"))]
{
result.map_err(|_| Acs37800ReadError::Io)?;
}
Ok(u32::from_le_bytes(buf))
}
}
#[cfg(not(feature = "async"))]
fn read_reg32(&mut self, reg: Acs37800EepromRegister) -> Result<u32, Acs37800ReadError> {
let mut buf = [0u8; 4];
let result = self.i2c.write_read(self.address, &[reg as u8], &mut buf);
#[cfg(feature = "std")]
{
result.map_err(|cause| Acs37800ReadError::Io(format!("{cause:?}")))?;
}
#[cfg(not(feature = "std"))]
{
result.map_err(|_| Acs37800ReadError::Io)?;
}
Ok(u32::from_le_bytes(buf))
}
}
#[cfg(all(test, not(feature = "async")))]
mod tests {
use embedded_hal::i2c::ErrorKind;
use embedded_hal_mock::eh1::i2c::{Mock as I2cMock, Transaction as I2cTransaction};
use crate::test::assert_is_bus_error;
use super::*;
fn new_driver(expectations: &[I2cTransaction]) -> Acs37800I2c<I2cMock> {
let i2c = I2cMock::new(expectations);
Acs37800I2c::builder().i2c(i2c).address(0x60).build()
}
#[test]
fn read_reg32_returns_le_word() {
let expectations = [I2cTransaction::write_read(
0x60,
vec![Acs37800EepromRegister::R0C as u8],
vec![0x78, 0x56, 0x34, 0x12],
)];
let mut driver = new_driver(&expectations);
let value = driver
.read_reg32(Acs37800EepromRegister::R0C)
.expect("read value");
assert_eq!(value, 0x1234_5678);
driver.i2c.done();
}
#[test]
fn read_reg32_maps_bus_errors() {
let expectations =
[
I2cTransaction::write_read(
0x60,
vec![Acs37800EepromRegister::R0B as u8],
vec![0; 4],
)
.with_error(ErrorKind::Other),
];
let mut driver = new_driver(&expectations);
let err = driver
.read_reg32(Acs37800EepromRegister::R0B)
.expect_err("should propagate error");
assert_is_bus_error(&err);
driver.i2c.done();
}
}
#[cfg(all(test, feature = "async"))]
mod async_tests {
use embedded_hal::i2c::ErrorKind;
use embedded_hal_mock::eh1::i2c::{Mock as I2cMock, Transaction as I2cTransaction};
use crate::test::assert_is_bus_error;
use super::*;
fn new_driver(expectations: &[I2cTransaction]) -> Acs37800I2c<I2cMock> {
let i2c = I2cMock::new(expectations);
Acs37800I2c::builder().i2c(i2c).address(0x60).build()
}
#[tokio::test]
async fn read_reg32_returns_le_word_async() {
let expectations = [I2cTransaction::write_read(
0x60,
vec![Acs37800EepromRegister::R0C as u8],
vec![0x78, 0x56, 0x34, 0x12],
)];
let mut driver = new_driver(&expectations);
let value = driver
.read_reg32(Acs37800EepromRegister::R0C)
.await
.expect("read value");
assert_eq!(value, 0x1234_5678);
driver.i2c.done();
}
#[tokio::test]
async fn read_reg32_maps_bus_errors_async() {
let expectations =
[
I2cTransaction::write_read(
0x60,
vec![Acs37800EepromRegister::R0B as u8],
vec![0; 4],
)
.with_error(ErrorKind::Other),
];
let mut driver = new_driver(&expectations);
let err = driver
.read_reg32(Acs37800EepromRegister::R0B)
.await
.expect_err("should propagate error");
assert_is_bus_error(&err);
driver.i2c.done();
}
}