use crate::fat_error::{FatError, FatResult}; use crate::hal::Box; use async_trait::async_trait; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use esp_hal::i2c::master::I2c; use esp_hal::Blocking; use lib_bms_protocol::{ BatteryState as bstate, BmsReadable, Config, FirmwareVersion, ProtocolVersion, }; use serde::Serialize; #[async_trait(?Send)] pub trait BatteryInteraction { async fn get_state(&mut self) -> FatResult; async fn get_firmware(&mut self) -> FatResult; async fn get_protocol(&mut self) -> FatResult; async fn reset(&mut self) -> FatResult<()>; } #[derive(Debug, Serialize, Copy, Clone)] pub struct BatteryInfo { pub voltage_milli_volt: u32, pub average_current_milli_ampere: i32, pub design_milli_ampere_hour: u32, pub remaining_milli_ampere_hour: u32, pub state_of_charge: u8, pub state_of_health: u32, pub temperature: i32, } #[derive(Debug, Serialize)] pub enum BatteryState { Unknown, Info(BatteryInfo), } /// If no battery monitor is installed this implementation will be used pub struct NoBatteryMonitor {} #[async_trait(?Send)] impl BatteryInteraction for NoBatteryMonitor { async fn get_state(&mut self) -> FatResult { Ok(BatteryState::Unknown) } async fn get_firmware(&mut self) -> FatResult { Err(FatError::NoBatteryMonitor) } async fn get_protocol(&mut self) -> FatResult { Err(FatError::NoBatteryMonitor) } async fn reset(&mut self) -> FatResult<()> { Err(FatError::NoBatteryMonitor) } } //TODO implement this battery monitor kind once controller is complete #[allow(dead_code)] pub struct WchI2cSlave {} pub struct WCHI2CSlave<'a> { pub(crate) i2c: I2cDevice<'a, CriticalSectionRawMutex, I2c<'a, Blocking>>, } #[async_trait(?Send)] impl BatteryInteraction for WCHI2CSlave<'_> { async fn get_state(&mut self) -> FatResult { let state = bstate::read_from_i2c(&mut self.i2c)?; let config = Config::read_from_i2c(&mut self.i2c)?; let state_of_charge = (state.remaining_capacity_mah * 100 / state.lifetime_capacity_mah) as u8; let state_of_health = state.lifetime_capacity_mah / config.capacity_mah * 100; Ok(BatteryState::Info(BatteryInfo { voltage_milli_volt: state.current_mv, average_current_milli_ampere: 1337, design_milli_ampere_hour: config.capacity_mah, remaining_milli_ampere_hour: state.remaining_capacity_mah, state_of_charge, state_of_health, temperature: state.temperature_celcius, })) } async fn get_firmware(&mut self) -> FatResult { todo!() } async fn get_protocol(&mut self) -> FatResult { todo!() } async fn reset(&mut self) -> FatResult<()> { todo!() } }