use super::ChecksumError;
use embedded_devices_derive::forward_register_fns;
use embedded_devices_derive::sensor;
use embedded_interfaces::TransportError;
use uom::si::electrical_resistance::ohm;
use uom::si::f64::{ElectricCurrent, ElectricPotential, ElectricalResistance, Energy, Frequency, Power};
pub mod registers;
pub const V_REF: f64 = 1.218;
pub const V_RMS_COEFF: f64 = V_REF / (73989.0 * 1000.0);
pub const I_RMS_COEFF: f64 = V_REF / (305978.0 * 1000.0);
pub const I_FAST_RMS_FACTOR: f64 = 0.363;
pub const P_COEFF: f64 = V_REF * V_REF / (3537.0 * 1_000_000.0);
pub const E_COEFF: f64 = 1638.4 * 256.0 / 3600.0;
#[derive(Debug, embedded_devices_derive::Measurement)]
pub struct Measurement {
#[measurement(Voltage)]
pub voltage: ElectricPotential,
#[measurement(Current)]
pub current: ElectricCurrent,
#[measurement(Power)]
pub power: Power,
#[measurement(Energy)]
pub energy: Energy,
#[measurement(Frequency)]
pub frequency: Frequency,
}
#[maybe_async_cfg::maybe(
idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), RegisterInterface),
sync(feature = "sync"),
async(feature = "async")
)]
pub struct BL0942<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> {
delay: D,
interface: I,
pub shunt_resistance: ElectricalResistance,
pub voltage_divider_coeff: f64,
pub i_lsb: f64,
pub v_lsb: f64,
pub p_lsb: f64,
pub e_lsb: f64,
}
pub trait BL0942Register {}
#[maybe_async_cfg::maybe(
idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), SpiDevice),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D, I> BL0942<D, embedded_interfaces::spi::SpiDevice<I>>
where
I: hal::spi::r#SpiDevice,
D: hal::delay::DelayNs,
{
#[inline]
pub fn new_spi(
delay: D,
interface: I,
shunt_resistance: ElectricalResistance,
voltage_divider_r1: ElectricalResistance,
voltage_divider_r2: ElectricalResistance,
) -> Self {
let r1 = voltage_divider_r1.get::<ohm>();
let r2 = voltage_divider_r2.get::<ohm>();
let voltage_divider_coeff = (r1 + r2) / r1;
let p_lsb = P_COEFF * voltage_divider_coeff / shunt_resistance.get::<ohm>();
Self {
delay,
interface: embedded_interfaces::spi::SpiDevice::new(interface),
shunt_resistance,
voltage_divider_coeff,
i_lsb: I_RMS_COEFF / shunt_resistance.get::<ohm>(),
v_lsb: V_RMS_COEFF * voltage_divider_coeff,
p_lsb,
e_lsb: E_COEFF * p_lsb,
}
}
}
#[forward_register_fns]
#[sensor(Voltage, Current, Power, Energy)]
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
ResettableDevice
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> BL0942<D, I> {
pub async fn init(&mut self) -> Result<(), TransportError<ChecksumError, I::BusError>> {
use crate::device::ResettableDevice;
self.reset().await?;
self.delay.delay_ms(1).await;
Ok(())
}
}
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
ResettableDevice
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::device::ResettableDevice
for BL0942<D, I>
{
type Error = TransportError<ChecksumError, I::BusError>;
async fn reset(&mut self) -> Result<(), Self::Error> {
self.write_register(self::registers::WriteProtection::default().with_key(registers::ProtectionKey::Unlocked))
.await?;
self.write_register(self::registers::SoftReset::default().with_magic(registers::ResetMagic::Reset))
.await?;
Ok(())
}
}
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
OneshotSensor
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::sensor::OneshotSensor
for BL0942<D, I>
{
type Error = TransportError<ChecksumError, I::BusError>;
type Measurement = Measurement;
async fn measure(&mut self) -> Result<Self::Measurement, Self::Error> {
use uom::si::{electric_current::ampere, electric_potential::volt, energy::watt_hour, power::watt};
let i_rms = self.read_register::<self::registers::CurrentRms>().await?.read_value() as f64 * self.i_lsb;
let v_rms = self.read_register::<self::registers::VoltageRms>().await?.read_value() as f64 * self.v_lsb;
let power = self.read_register::<self::registers::ActivePower>().await?.read_value() as f64 * self.p_lsb;
let energy = self
.read_register::<self::registers::EnergyCounter>()
.await?
.read_value() as f64
* self.e_lsb;
let frequency = self
.read_register::<self::registers::Frequency>()
.await?
.read_frequency();
let measurement = Measurement {
voltage: ElectricPotential::new::<volt>(v_rms),
current: ElectricCurrent::new::<ampere>(i_rms),
power: Power::new::<watt>(power),
energy: Energy::new::<watt_hour>(energy),
frequency,
};
Ok(measurement)
}
}
#[maybe_async_cfg::maybe(
idents(
hal(sync = "embedded_hal", async = "embedded_hal_async"),
RegisterInterface,
OneshotSensor,
ContinuousSensor
),
sync(feature = "sync"),
async(feature = "async")
)]
impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::sensor::ContinuousSensor
for BL0942<D, I>
{
type Error = TransportError<ChecksumError, I::BusError>;
type Measurement = Measurement;
async fn start_measuring(&mut self) -> Result<(), Self::Error> {
Ok(())
}
async fn stop_measuring(&mut self) -> Result<(), Self::Error> {
Ok(())
}
async fn measurement_interval_us(&mut self) -> Result<u32, Self::Error> {
Ok(self
.read_register::<self::registers::UserMode>()
.await?
.read_rms_update_rate()
.as_us())
}
async fn current_measurement(&mut self) -> Result<Option<Self::Measurement>, Self::Error> {
use crate::sensor::OneshotSensor;
Ok(Some(self.measure().await?))
}
async fn is_measurement_ready(&mut self) -> Result<bool, Self::Error> {
Ok(true)
}
async fn next_measurement(&mut self) -> Result<Self::Measurement, Self::Error> {
use crate::sensor::OneshotSensor;
let interval = self.measurement_interval_us().await?;
self.delay.delay_us(interval).await;
self.measure().await
}
}