use embedded_hal_async::{delay::DelayNs, i2c::I2c as AsyncI2c};
use crate::{
configuration::Configuration, constants::DEFAULT_I2C_ADDRESS, error::Error, register::Register,
status::Status,
};
#[derive(Debug, PartialEq, Eq)]
pub struct As5600<I2C> {
address: u8,
bus: I2C,
}
impl<I, E> As5600<I>
where
I: AsyncI2c<Error = E>,
{
pub fn new(bus: I) -> Self {
Self::with_address(DEFAULT_I2C_ADDRESS, bus)
}
pub fn with_address(address: u8, bus: I) -> Self {
Self { address, bus }
}
pub fn release(self) -> I {
self.bus
}
pub async fn raw_angle(&mut self) -> Result<u16, Error<E>> {
Ok(self.read_u16(Register::RawAngle).await? & 0x0FFF)
}
pub async fn angle(&mut self) -> Result<u16, Error<E>> {
Ok(self.read_u16(Register::Angle).await? & 0x0FFF)
}
pub async fn zmco(&mut self) -> Result<u8, Error<E>> {
let mut buffer = [0u8; 1];
self.bus
.write_read(self.address, &[Register::Zmco.into()], &mut buffer)
.await
.map_err(Error::Communication)?;
Ok(buffer[0] & 0b0000_0011)
}
pub async fn magnet_status(&mut self) -> Result<Status, Error<E>> {
let mut buffer = [0u8; 1];
self.bus
.write_read(self.address, &[Register::Status.into()], &mut buffer)
.await
.map_err(Error::Communication)?;
Status::try_from(buffer).map_err(Error::Status)
}
pub async fn zero_position(&mut self) -> Result<u16, Error<E>> {
Ok(self.read_u16(Register::Zpos).await? & 0x0FFF)
}
pub async fn set_zero_position(&mut self, bytes: u16) -> Result<(), Error<E>> {
self.write_u16(Register::Zpos, bytes & 0x0FFF).await
}
pub async fn maximum_position(&mut self) -> Result<u16, Error<E>> {
Ok(self.read_u16(Register::Mpos).await? & 0x0FFF)
}
pub async fn set_maximum_position(&mut self, bytes: u16) -> Result<(), Error<E>> {
self.write_u16(Register::Mpos, bytes & 0x0FFF).await
}
pub async fn maximum_angle(&mut self) -> Result<u16, Error<E>> {
Ok(self.read_u16(Register::Mang).await? & 0x0FFF)
}
pub async fn set_maximum_angle(&mut self, bytes: u16) -> Result<(), Error<E>> {
self.write_u16(Register::Mang, bytes & 0x0FFF).await
}
pub async fn config(&mut self) -> Result<Configuration, Error<E>> {
let bytes = self.read_u16(Register::Conf).await?;
Configuration::try_from(bytes).map_err(Error::Configuration)
}
pub async fn set_config(&mut self, config: Configuration) -> Result<(), Error<E>> {
let current_config = self.read_u16(Register::Conf).await?;
let blank_fields = current_config & 0b1100_0000_0000_0000;
let mut bytes = u16::from(config);
bytes |= blank_fields;
self.write_u16(Register::Conf, bytes).await
}
pub async fn automatic_gain_control(&mut self) -> Result<u8, Error<E>> {
let mut buffer = [0u8; 1];
self.bus
.write_read(self.address, &[0x1a], &mut buffer)
.await
.map_err(Error::Communication)?;
Ok(buffer[0])
}
pub async fn magnitude(&mut self) -> Result<u16, Error<E>> {
Ok(self.read_u16(Register::Magnitude).await? & 0x0FFF)
}
pub async fn persist_maximum_angle_and_config_settings<D>(
&mut self,
delay: &mut D,
) -> Result<(), Error<E>>
where
D: DelayNs,
{
let zmco = self.zmco().await?;
if zmco != 0 {
return Err(Error::MangConfigPersistenceExhausted);
}
self.bus
.write(self.address, &[Register::Burn.into(), 0x40])
.await
.map_err(Error::Communication)?;
delay.delay_ms(1).await;
Ok(())
}
pub async fn persist_position_settings<D>(&mut self, delay: &mut D) -> Result<(), Error<E>>
where
D: DelayNs,
{
let zmco = self.zmco().await?;
if zmco >= 3 {
return Err(Error::MaximumPositionPersistsReached);
}
if self.magnet_status().await? != Status::MagnetDetected {
return Err(Error::MagnetRequired);
}
self.bus
.write(self.address, &[Register::Burn.into(), 0x80])
.await
.map_err(Error::Communication)?;
delay.delay_ms(1).await;
Ok(())
}
async fn read_u16(&mut self, command: Register) -> Result<u16, Error<E>> {
let mut buffer = [0u8; 2];
self.bus
.write_read(self.address, &[command.into()], &mut buffer)
.await
.map_err(Error::Communication)?;
Ok(u16::from_be_bytes(buffer))
}
async fn write_u16(&mut self, command: Register, bytes: u16) -> Result<(), Error<E>> {
let bytes: [u8; 2] = bytes.to_be_bytes();
let buffer = [u8::from(command), bytes[0], bytes[1]];
self.bus
.write(self.address, &buffer)
.await
.map_err(Error::Communication)
}
}