use embedded_hal::i2c::{I2c, SevenBitAddress};
use uom::si::{
electric_current::{microampere, milliampere},
f32::ElectricCurrent,
};
use crate::{
device::AFE4404,
errors::AfeError,
modes::{LedMode, ThreeLedsMode, TwoLedsMode},
register_structs::R22h,
};
impl<I2C, MODE> AFE4404<I2C, MODE>
where
I2C: I2c<SevenBitAddress>,
MODE: LedMode,
{
fn scale_current(reg_value: u8, prev_2x: bool, curr_2x: bool) -> u8 {
if prev_2x == curr_2x {
reg_value
} else if curr_2x {
reg_value / 2
} else {
reg_value * 2
}
}
pub fn set_led1_current(
&mut self,
current: ElectricCurrent,
) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r22h_prev = self.registers.r22h.read()?;
let r23h_prev = self.registers.r23h.read()?;
let high_current = current.get::<milliampere>() > 50.0
|| (r23h_prev.iled_2x() && (r22h_prev.iled2() > 31 || r22h_prev.iled3() > 31));
let range = if high_current {
ElectricCurrent::new::<milliampere>(100.0)
} else {
ElectricCurrent::new::<milliampere>(50.0)
};
let quantisation = range / 63.0;
if current > range || current.get::<milliampere>() < 0.0 {
return Err(AfeError::LedCurrentOutsideAllowedRange);
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let values = [
(current / quantisation).value.round() as u8,
Self::scale_current(r22h_prev.iled2(), r23h_prev.iled_2x(), high_current),
Self::scale_current(r22h_prev.iled3(), r23h_prev.iled_2x(), high_current),
];
self.registers.r22h.write(
R22h::new()
.with_iled1(values[0])
.with_iled2(values[1])
.with_iled3(values[2]),
)?;
self.registers
.r23h
.write(r23h_prev.with_iled_2x(high_current))?;
Ok(f32::from(values[0]) * quantisation)
}
pub fn set_led2_current(
&mut self,
current: ElectricCurrent,
) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r22h_prev = self.registers.r22h.read()?;
let r23h_prev = self.registers.r23h.read()?;
let high_current = current.get::<milliampere>() > 50.0
|| (r23h_prev.iled_2x() && (r22h_prev.iled1() > 31 || r22h_prev.iled3() > 31));
let range = if high_current {
ElectricCurrent::new::<milliampere>(100.0)
} else {
ElectricCurrent::new::<milliampere>(50.0)
};
let quantisation = range / 63.0;
if current > range || current.get::<milliampere>() < 0.0 {
return Err(AfeError::LedCurrentOutsideAllowedRange);
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let values = [
Self::scale_current(r22h_prev.iled1(), r23h_prev.iled_2x(), high_current),
(current / quantisation).value.round() as u8,
Self::scale_current(r22h_prev.iled3(), r23h_prev.iled_2x(), high_current),
];
self.registers.r22h.write(
R22h::new()
.with_iled1(values[0])
.with_iled2(values[1])
.with_iled3(values[2]),
)?;
self.registers
.r23h
.write(r23h_prev.with_iled_2x(high_current))?;
Ok(f32::from(values[1]) * quantisation)
}
pub fn get_led1_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r22h_prev = self.registers.r22h.read()?;
let r23h_prev = self.registers.r23h.read()?;
let range = if r23h_prev.iled_2x() {
ElectricCurrent::new::<milliampere>(100.0)
} else {
ElectricCurrent::new::<milliampere>(50.0)
};
let quantisation = range / 63.0;
Ok(f32::from(r22h_prev.iled1()) * quantisation)
}
pub fn get_led2_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r22h_prev = self.registers.r22h.read()?;
let r23h_prev = self.registers.r23h.read()?;
let range = if r23h_prev.iled_2x() {
ElectricCurrent::new::<milliampere>(100.0)
} else {
ElectricCurrent::new::<milliampere>(50.0)
};
let quantisation = range / 63.0;
Ok(f32::from(r22h_prev.iled2()) * quantisation)
}
pub fn set_offset_led1_current(
&mut self,
offset: ElectricCurrent,
) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
if offset > range || offset < -range {
return Err(AfeError::OffsetCurrentOutsideAllowedRange);
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let value = (
(offset.abs() / quantisation).value.round() as u8,
offset.get::<microampere>() < 0.0,
);
self.registers.r3Ah.write(
r3ah_prev
.with_i_offdac_led1(value.0)
.with_pol_offdac_led1(value.1),
)?;
Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
}
pub fn set_offset_led2_current(
&mut self,
offset: ElectricCurrent,
) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
if offset > range || offset < -range {
return Err(AfeError::OffsetCurrentOutsideAllowedRange);
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let value = (
(offset.abs() / quantisation).value.round() as u8,
offset.get::<microampere>() < 0.0,
);
self.registers.r3Ah.write(
r3ah_prev
.with_i_offdac_led2(value.0)
.with_pol_offdac_led2(value.1),
)?;
Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
}
pub fn get_offset_led1_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
Ok(f32::from(r3ah_prev.i_offdac_led1())
* quantisation
* if r3ah_prev.pol_offdac_led1() {
-1.0
} else {
1.0
})
}
pub fn get_offset_led2_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
Ok(f32::from(r3ah_prev.i_offdac_led2())
* quantisation
* if r3ah_prev.pol_offdac_led2() {
-1.0
} else {
1.0
})
}
}
impl<I2C> AFE4404<I2C, ThreeLedsMode>
where
I2C: I2c<SevenBitAddress>,
{
pub fn set_led3_current(
&mut self,
current: ElectricCurrent,
) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r22h_prev = self.registers.r22h.read()?;
let r23h_prev = self.registers.r23h.read()?;
let high_current = current.get::<milliampere>() > 50.0
|| (r23h_prev.iled_2x() && (r22h_prev.iled1() > 31 || r22h_prev.iled2() > 31));
let range = if high_current {
ElectricCurrent::new::<milliampere>(100.0)
} else {
ElectricCurrent::new::<milliampere>(50.0)
};
let quantisation = range / 63.0;
if current > range || current.get::<milliampere>() < 0.0 {
return Err(AfeError::LedCurrentOutsideAllowedRange);
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let values = [
Self::scale_current(r22h_prev.iled1(), r23h_prev.iled_2x(), high_current),
Self::scale_current(r22h_prev.iled2(), r23h_prev.iled_2x(), high_current),
(current / quantisation).value.round() as u8,
];
self.registers.r22h.write(
R22h::new()
.with_iled1(values[0])
.with_iled2(values[1])
.with_iled3(values[2]),
)?;
self.registers
.r23h
.write(r23h_prev.with_iled_2x(high_current))?;
Ok(f32::from(values[2]) * quantisation)
}
pub fn get_led3_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r22h_prev = self.registers.r22h.read()?;
let r23h_prev = self.registers.r23h.read()?;
let range = if r23h_prev.iled_2x() {
ElectricCurrent::new::<milliampere>(100.0)
} else {
ElectricCurrent::new::<milliampere>(50.0)
};
let quantisation = range / 63.0;
Ok(f32::from(r22h_prev.iled3()) * quantisation)
}
pub fn set_offset_led3_current(
&mut self,
offset: ElectricCurrent,
) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
if offset > range || offset < -range {
return Err(AfeError::OffsetCurrentOutsideAllowedRange);
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let value = (
(offset.abs() / quantisation).value.round() as u8,
offset.get::<microampere>() < 0.0,
);
self.registers.r3Ah.write(
r3ah_prev
.with_i_offdac_amb2_or_i_offdac_led3(value.0)
.with_pol_offdac_amb2_or_pol_offdac_led3(value.1),
)?;
Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
}
pub fn set_offset_amb_current(
&mut self,
offset: ElectricCurrent,
) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
if offset > range || offset < -range {
return Err(AfeError::OffsetCurrentOutsideAllowedRange);
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let value = (
(offset.abs() / quantisation).value.round() as u8,
offset.get::<microampere>() < 0.0,
);
self.registers.r3Ah.write(
r3ah_prev
.with_i_offdac_amb1(value.0)
.with_pol_offdac_amb1(value.1),
)?;
Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
}
pub fn get_offset_led3_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
Ok(f32::from(r3ah_prev.i_offdac_amb2_or_i_offdac_led3())
* quantisation
* if r3ah_prev.pol_offdac_amb2_or_pol_offdac_led3() {
-1.0
} else {
1.0
})
}
pub fn get_offset_amb_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
Ok(f32::from(r3ah_prev.i_offdac_amb1())
* quantisation
* if r3ah_prev.pol_offdac_amb1() {
-1.0
} else {
1.0
})
}
}
impl<I2C> AFE4404<I2C, TwoLedsMode>
where
I2C: I2c<SevenBitAddress>,
{
pub fn set_offset_amb1_current(
&mut self,
offset: ElectricCurrent,
) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
if offset > range || offset < -range {
return Err(AfeError::OffsetCurrentOutsideAllowedRange);
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let value = (
(offset.abs() / quantisation).value.round() as u8,
offset.get::<microampere>() < 0.0,
);
self.registers.r3Ah.write(
r3ah_prev
.with_i_offdac_amb1(value.0)
.with_pol_offdac_amb1(value.1),
)?;
Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
}
pub fn set_offset_amb2_current(
&mut self,
offset: ElectricCurrent,
) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
if offset > range || offset < -range {
return Err(AfeError::OffsetCurrentOutsideAllowedRange);
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let value = (
(offset.abs() / quantisation).value.round() as u8,
offset.get::<microampere>() < 0.0,
);
self.registers.r3Ah.write(
r3ah_prev
.with_i_offdac_amb2_or_i_offdac_led3(value.0)
.with_pol_offdac_amb2_or_pol_offdac_led3(value.1),
)?;
Ok(f32::from(value.0) * quantisation * if value.1 { -1.0 } else { 1.0 })
}
pub fn get_offset_amb1_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
Ok(f32::from(r3ah_prev.i_offdac_amb1())
* quantisation
* if r3ah_prev.pol_offdac_amb1() {
-1.0
} else {
1.0
})
}
pub fn get_offset_amb2_current(&mut self) -> Result<ElectricCurrent, AfeError<I2C::Error>> {
let r3ah_prev = self.registers.r3Ah.read()?;
let range = ElectricCurrent::new::<microampere>(7.0);
let quantisation = range / 15.0;
Ok(f32::from(r3ah_prev.i_offdac_amb2_or_i_offdac_led3())
* quantisation
* if r3ah_prev.pol_offdac_amb2_or_pol_offdac_led3() {
-1.0
} else {
1.0
})
}
}