use embedded_hal_async::delay::DelayNs;
use embedded_hal_async::spi::SpiDevice;
use crate::config::Config;
use crate::error::{Error, InitStage};
use crate::proto::{self, build_init_sequence};
use crate::readings::PhaseReadings;
use crate::registers::*;
use crate::status::PhaseStatus;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Phase {
A,
B,
C,
}
impl Phase {
#[inline]
fn index(self) -> usize {
match self {
Phase::A => 0,
Phase::B => 1,
Phase::C => 2,
}
}
}
pub struct Atm90e32<SPI, D> {
spi: SPI,
delay: D,
}
impl<SPI, D> Atm90e32<SPI, D>
where
SPI: SpiDevice,
D: DelayNs,
{
pub fn new(spi: SPI, delay: D) -> Self {
Self { spi, delay }
}
pub fn release(self) -> (SPI, D) {
(self.spi, self.delay)
}
pub async fn read_register(&mut self, addr: u16) -> Result<u16, Error<SPI::Error>> {
let tx = proto::build_read_frame(addr);
let mut rx = [0u8; 4];
self.spi.transfer(&mut rx, &tx).await.map_err(Error::Spi)?;
Ok(proto::parse_read_response(&rx))
}
pub async fn write_register(&mut self, addr: u16, value: u16) -> Result<(), Error<SPI::Error>> {
let tx = proto::build_write_frame(addr, value);
self.spi.write(&tx).await.map_err(Error::Spi)
}
pub async fn probe(&mut self) -> Result<u16, Error<SPI::Error>> {
let status = self.read_register(REG_SYSSTATUS0).await?;
if status == 0x0000 || status == 0xFFFF {
Err(Error::NotPresent)
} else {
Ok(status)
}
}
pub async fn init(&mut self, config: &Config) -> Result<(), Error<SPI::Error>> {
self.write_register(REG_SOFTRESET, 0x789A)
.await
.map_err(|_| Error::InitFailed(InitStage::SoftReset))?;
self.delay.delay_ms(config.post_reset_delay_ms).await;
for step in build_init_sequence(config).iter() {
self.write_register(step.addr, step.value)
.await
.map_err(|_| Error::InitFailed(step.stage))?;
}
Ok(())
}
pub async fn read_all_phases(&mut self) -> Result<PhaseReadings, Error<SPI::Error>> {
let ua = self.read_register(REG_URMS_A).await?;
let ub = self.read_register(REG_URMS_B).await?;
let uc = self.read_register(REG_URMS_C).await?;
let ia = self.read_register(REG_IRMS_A).await?;
let ib = self.read_register(REG_IRMS_B).await?;
let ic = self.read_register(REG_IRMS_C).await?;
let pa_h = self.read_register(REG_PMEAN_A).await?;
let pa_l = self.read_register(REG_PMEAN_A_LSB).await?;
let pb_h = self.read_register(REG_PMEAN_B).await?;
let pb_l = self.read_register(REG_PMEAN_B_LSB).await?;
let pc_h = self.read_register(REG_PMEAN_C).await?;
let pc_l = self.read_register(REG_PMEAN_C_LSB).await?;
let qa_h = self.read_register(REG_QMEAN_A).await?;
let qa_l = self.read_register(REG_QMEAN_A_LSB).await?;
let qb_h = self.read_register(REG_QMEAN_B).await?;
let qb_l = self.read_register(REG_QMEAN_B_LSB).await?;
let qc_h = self.read_register(REG_QMEAN_C).await?;
let qc_l = self.read_register(REG_QMEAN_C_LSB).await?;
let pfa = self.read_register(REG_PFMEAN_A).await?;
let pfb = self.read_register(REG_PFMEAN_B).await?;
let pfc = self.read_register(REG_PFMEAN_C).await?;
let freq = self.read_register(REG_FREQ).await?;
let ang_a = self.read_register(REG_PANGLE_A).await?;
let ang_b = self.read_register(REG_PANGLE_B).await?;
let ang_c = self.read_register(REG_PANGLE_C).await?;
Ok(PhaseReadings {
voltage: [ua, ub, uc],
current: [ia, ib, ic],
power: [
proto::combine_power_words(pa_h, pa_l),
proto::combine_power_words(pb_h, pb_l),
proto::combine_power_words(pc_h, pc_l),
],
reactive: [
proto::combine_power_words(qa_h, qa_l),
proto::combine_power_words(qb_h, qb_l),
proto::combine_power_words(qc_h, qc_l),
],
pf: [pfa as i16, pfb as i16, pfc as i16],
frequency: freq,
phase_angle: [ang_a, ang_b, ang_c],
})
}
pub async fn read_voltage(&mut self, phase: Phase) -> Result<u16, Error<SPI::Error>> {
const REGS: [u16; 3] = [REG_URMS_A, REG_URMS_B, REG_URMS_C];
self.read_register(REGS[phase.index()]).await
}
pub async fn read_current(&mut self, phase: Phase) -> Result<u16, Error<SPI::Error>> {
const REGS: [u16; 3] = [REG_IRMS_A, REG_IRMS_B, REG_IRMS_C];
self.read_register(REGS[phase.index()]).await
}
pub async fn read_active_power(&mut self, phase: Phase) -> Result<i32, Error<SPI::Error>> {
const HI: [u16; 3] = [REG_PMEAN_A, REG_PMEAN_B, REG_PMEAN_C];
const LO: [u16; 3] = [REG_PMEAN_A_LSB, REG_PMEAN_B_LSB, REG_PMEAN_C_LSB];
let idx = phase.index();
let hi = self.read_register(HI[idx]).await?;
let lo = self.read_register(LO[idx]).await?;
Ok(proto::combine_power_words(hi, lo))
}
pub async fn read_reactive_power(&mut self, phase: Phase) -> Result<i32, Error<SPI::Error>> {
const HI: [u16; 3] = [REG_QMEAN_A, REG_QMEAN_B, REG_QMEAN_C];
const LO: [u16; 3] = [REG_QMEAN_A_LSB, REG_QMEAN_B_LSB, REG_QMEAN_C_LSB];
let idx = phase.index();
let hi = self.read_register(HI[idx]).await?;
let lo = self.read_register(LO[idx]).await?;
Ok(proto::combine_power_words(hi, lo))
}
pub async fn read_power_factor(&mut self, phase: Phase) -> Result<i16, Error<SPI::Error>> {
const REGS: [u16; 3] = [REG_PFMEAN_A, REG_PFMEAN_B, REG_PFMEAN_C];
let raw = self.read_register(REGS[phase.index()]).await?;
Ok(raw as i16)
}
pub async fn read_frequency(&mut self) -> Result<u16, Error<SPI::Error>> {
self.read_register(REG_FREQ).await
}
pub async fn read_phase_angle(&mut self, phase: Phase) -> Result<u16, Error<SPI::Error>> {
const REGS: [u16; 3] = [REG_PANGLE_A, REG_PANGLE_B, REG_PANGLE_C];
self.read_register(REGS[phase.index()]).await
}
pub async fn read_chip_temperature(&mut self) -> Result<u16, Error<SPI::Error>> {
self.read_register(REG_TEMP).await
}
pub async fn read_status(&mut self) -> Result<PhaseStatus, Error<SPI::Error>> {
let s0 = self.read_register(REG_EMMSTATE0).await?;
let s1 = self.read_register(REG_EMMSTATE1).await?;
Ok(PhaseStatus::from_emm(s0, s1))
}
}