use bitfield_struct::bitfield;
use crate::{MilliAmps, MilliAmpsSigned, MilliVolts};
pub trait Error: core::fmt::Debug {
fn kind(&self) -> ErrorKind;
}
impl Error for core::convert::Infallible {
#[inline]
fn kind(&self) -> ErrorKind {
match *self {}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum ErrorKind {
CommError,
BatteryStatus(ErrorCode),
Other,
}
impl Error for ErrorKind {
#[inline]
fn kind(&self) -> ErrorKind {
*self
}
}
impl core::fmt::Display for ErrorKind {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::CommError => write!(f, "Error communicating with Smart Battery"),
Self::BatteryStatus(_) => write!(
f,
"Error reported by BatteryService (0x16) register. The original error may contain more information"
),
Self::Other => write!(
f,
"A different error occurred. The original error may contain more information"
),
}
}
}
pub trait ErrorType {
type Error: Error;
}
impl<T: ErrorType + ?Sized> ErrorType for &mut T {
type Error = T::Error;
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CapacityModeValue {
MilliAmpUnsigned(u16),
CentiWattUnsigned(u16),
}
pub type Minutes = u16;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CapacityModeSignedValue {
MilliAmpSigned(i16),
CentiWattSigned(i16),
}
pub type DeciKelvin = u16;
pub type Percent = u8;
pub type Cycles = u16;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum ErrorCode {
Ok = 0,
Busy = 1,
ReservedCmd = 2,
UnsupportedCmd = 3,
AccessDenied = 4,
UnderOverFlow = 5,
BadSize = 6,
UnknownError = 7,
}
impl ErrorCode {
const fn into_bits(self) -> u8 {
self as _
}
const fn from_bits(value: u8) -> Self {
match value {
0 => Self::Ok,
1 => Self::Busy,
2 => Self::ReservedCmd,
3 => Self::UnsupportedCmd,
4 => Self::AccessDenied,
5 => Self::UnderOverFlow,
6 => Self::BadSize,
_ => Self::UnknownError,
}
}
}
impl From<u8> for ErrorCode {
fn from(value: u8) -> Self {
Self::from_bits(value)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum Revision {
Version1And1Dot1 = 1,
}
impl Revision {
const fn into_bits(self) -> u8 {
self as _
}
const fn from_bits(value: u8) -> Self {
match value {
1 => Self::Version1And1Dot1,
_ => unreachable!(),
}
}
}
impl TryFrom<u8> for Revision {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::Version1And1Dot1),
_ => Err(()),
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum Version {
Reserved = 0,
Version1 = 1,
Version1Dot1 = 2,
Version1Dot1Pec = 3,
}
impl Version {
const fn into_bits(self) -> u8 {
self as _
}
const fn from_bits(value: u8) -> Self {
match value {
1 => Self::Version1,
2 => Self::Version1Dot1,
3 => Self::Version1Dot1Pec,
_ => Self::Reserved,
}
}
}
impl From<u8> for Version {
fn from(value: u8) -> Self {
Self::from_bits(value)
}
}
#[bitfield(u16, defmt = cfg(feature = "defmt"))]
pub struct ManufactureDate {
#[bits(5)]
pub day: usize,
#[bits(4)]
pub month: usize,
#[bits(7)]
pub year: usize,
}
#[bitfield(u16, defmt = cfg(feature = "defmt"))]
pub struct BatteryModeFields {
#[bits(1, access = RO)]
pub internal_charge_controller: bool,
#[bits(1, access = RO)]
pub primary_battery_support: bool,
#[bits(5)]
__: u8,
#[bits(1, access = RO)]
pub condition_flag: bool,
pub charge_controller_enabled: bool,
pub primary_battery: bool,
#[bits(3)]
__: u8,
pub alarm_mode: bool,
pub charger_mode: bool,
pub capacity_mode: bool,
}
#[bitfield(u16, defmt = cfg(feature = "defmt"))]
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct BatteryStatusFields {
#[bits(4)]
pub error_code: ErrorCode,
pub fully_discharged: bool,
pub fully_charged: bool,
pub discharging: bool,
pub initialized: bool,
pub remaining_time_alarm: bool,
pub remaining_capacity_alarm: bool,
__: bool,
pub terminate_discharge_alarm: bool,
pub over_temp_alarm: bool,
__: bool,
pub terminate_charge_alarm: bool,
pub over_charged_alarm: bool,
}
#[bitfield(u16, defmt = cfg(feature = "defmt"))]
pub struct SpecificationInfoFields {
#[bits(4)]
pub revision: Revision,
#[bits(4)]
pub version: Version,
#[bits(4)]
pub v_scale: u8,
#[bits(4)]
pub ip_scale: u8,
}
pub trait SmartBattery: ErrorType {
fn remaining_capacity_alarm(&mut self) -> Result<CapacityModeValue, Self::Error>;
fn set_remaining_capacity_alarm(&mut self, capacity: CapacityModeValue) -> Result<(), Self::Error>;
fn remaining_time_alarm(&mut self) -> Result<Minutes, Self::Error>;
fn set_remaining_time_alarm(&mut self, time: Minutes) -> Result<(), Self::Error>;
fn battery_mode(&mut self) -> Result<BatteryModeFields, Self::Error>;
fn set_battery_mode(&mut self, flags: BatteryModeFields) -> Result<(), Self::Error>;
fn at_rate(&mut self) -> Result<CapacityModeSignedValue, Self::Error>;
fn set_at_rate(&mut self, rate: CapacityModeSignedValue) -> Result<(), Self::Error>;
fn at_rate_time_to_full(&mut self) -> Result<Minutes, Self::Error>;
fn at_rate_time_to_empty(&mut self) -> Result<Minutes, Self::Error>;
fn at_rate_ok(&mut self) -> Result<bool, Self::Error>;
fn temperature(&mut self) -> Result<DeciKelvin, Self::Error>;
fn voltage(&mut self) -> Result<MilliVolts, Self::Error>;
fn current(&mut self) -> Result<MilliAmpsSigned, Self::Error>;
fn average_current(&mut self) -> Result<MilliAmpsSigned, Self::Error>;
fn max_error(&mut self) -> Result<Percent, Self::Error>;
fn relative_state_of_charge(&mut self) -> Result<Percent, Self::Error>;
fn absolute_state_of_charge(&mut self) -> Result<Percent, Self::Error>;
fn remaining_capacity(&mut self) -> Result<CapacityModeValue, Self::Error>;
fn full_charge_capacity(&mut self) -> Result<CapacityModeValue, Self::Error>;
fn run_time_to_empty(&mut self) -> Result<Minutes, Self::Error>;
fn average_time_to_empty(&mut self) -> Result<Minutes, Self::Error>;
fn average_time_to_full(&mut self) -> Result<Minutes, Self::Error>;
fn charging_current(&mut self) -> Result<MilliAmps, Self::Error>;
fn charging_voltage(&mut self) -> Result<MilliVolts, Self::Error>;
fn battery_status(&mut self) -> Result<BatteryStatusFields, Self::Error>;
fn cycle_count(&mut self) -> Result<Cycles, Self::Error>;
fn design_capacity(&mut self) -> Result<CapacityModeValue, Self::Error>;
fn design_voltage(&mut self) -> Result<MilliVolts, Self::Error>;
fn specification_info(&mut self) -> Result<SpecificationInfoFields, Self::Error>;
fn manufacture_date(&mut self) -> Result<ManufactureDate, Self::Error>;
fn serial_number(&mut self) -> Result<u16, Self::Error>;
fn manufacturer_name(&mut self, name: &mut [u8]) -> Result<(), Self::Error>;
fn device_name(&mut self, name: &mut [u8]) -> Result<(), Self::Error>;
fn device_chemistry(&mut self, chemistry: &mut [u8]) -> Result<(), Self::Error>;
}
#[macro_export]
macro_rules! impl_smart_battery_for_wrapper_type {
($wrapper:ty, $inner:ident, $error:ty) => {
impl embedded_batteries::smart_battery::ErrorType for $wrapper {
type Error = $error;
}
impl embedded_batteries::smart_battery::SmartBattery for $wrapper {
fn remaining_capacity_alarm(
&mut self,
) -> Result<embedded_batteries::smart_battery::CapacityModeValue, Self::Error> {
self.$inner.remaining_capacity_alarm()
}
fn set_remaining_capacity_alarm(
&mut self,
capacity: embedded_batteries::smart_battery::CapacityModeValue,
) -> Result<(), Self::Error> {
self.$inner.set_remaining_capacity_alarm(capacity)
}
fn remaining_time_alarm(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
self.$inner.remaining_time_alarm()
}
fn set_remaining_time_alarm(
&mut self,
time: embedded_batteries::smart_battery::Minutes,
) -> Result<(), Self::Error> {
self.$inner.set_remaining_time_alarm(time)
}
fn battery_mode(&mut self) -> Result<embedded_batteries::smart_battery::BatteryModeFields, Self::Error> {
self.$inner.battery_mode()
}
fn set_battery_mode(
&mut self,
flags: embedded_batteries::smart_battery::BatteryModeFields,
) -> Result<(), Self::Error> {
self.$inner.set_battery_mode(flags)
}
fn at_rate(&mut self) -> Result<embedded_batteries::smart_battery::CapacityModeSignedValue, Self::Error> {
self.$inner.at_rate()
}
fn set_at_rate(
&mut self,
rate: embedded_batteries::smart_battery::CapacityModeSignedValue,
) -> Result<(), Self::Error> {
self.$inner.set_at_rate(rate)
}
fn at_rate_time_to_full(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
self.$inner.at_rate_time_to_full()
}
fn at_rate_time_to_empty(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
self.$inner.at_rate_time_to_empty()
}
fn at_rate_ok(&mut self) -> Result<bool, Self::Error> {
self.$inner.at_rate_ok()
}
fn temperature(&mut self) -> Result<embedded_batteries::smart_battery::DeciKelvin, Self::Error> {
self.$inner.temperature()
}
fn voltage(&mut self) -> Result<embedded_batteries::charger::MilliVolts, Self::Error> {
self.$inner.voltage()
}
fn current(&mut self) -> Result<embedded_batteries::smart_battery::MilliAmpsSigned, Self::Error> {
self.$inner.current()
}
fn average_current(&mut self) -> Result<embedded_batteries::smart_battery::MilliAmpsSigned, Self::Error> {
self.$inner.average_current()
}
fn max_error(&mut self) -> Result<embedded_batteries::smart_battery::Percent, Self::Error> {
self.$inner.max_error()
}
fn relative_state_of_charge(&mut self) -> Result<embedded_batteries::smart_battery::Percent, Self::Error> {
self.$inner.relative_state_of_charge()
}
fn absolute_state_of_charge(&mut self) -> Result<embedded_batteries::smart_battery::Percent, Self::Error> {
self.$inner.absolute_state_of_charge()
}
fn remaining_capacity(
&mut self,
) -> Result<embedded_batteries::smart_battery::CapacityModeValue, Self::Error> {
self.$inner.remaining_capacity()
}
fn full_charge_capacity(
&mut self,
) -> Result<embedded_batteries::smart_battery::CapacityModeValue, Self::Error> {
self.$inner.full_charge_capacity()
}
fn run_time_to_empty(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
self.$inner.run_time_to_empty()
}
fn average_time_to_empty(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
self.$inner.average_time_to_empty()
}
fn average_time_to_full(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
self.$inner.average_time_to_full()
}
fn charging_current(&mut self) -> Result<embedded_batteries::charger::MilliAmps, Self::Error> {
self.$inner.charging_current()
}
fn charging_voltage(&mut self) -> Result<embedded_batteries::charger::MilliVolts, Self::Error> {
self.$inner.charging_voltage()
}
fn battery_status(
&mut self,
) -> Result<embedded_batteries::smart_battery::BatteryStatusFields, Self::Error> {
self.$inner.battery_status()
}
fn cycle_count(&mut self) -> Result<embedded_batteries::smart_battery::Cycles, Self::Error> {
self.$inner.cycle_count()
}
fn design_capacity(&mut self) -> Result<embedded_batteries::smart_battery::CapacityModeValue, Self::Error> {
self.$inner.design_capacity()
}
fn design_voltage(&mut self) -> Result<embedded_batteries::charger::MilliVolts, Self::Error> {
self.$inner.design_voltage()
}
fn specification_info(
&mut self,
) -> Result<embedded_batteries::smart_battery::SpecificationInfoFields, Self::Error> {
self.$inner.specification_info()
}
fn manufacture_date(&mut self) -> Result<embedded_batteries::smart_battery::ManufactureDate, Self::Error> {
self.$inner.manufacture_date()
}
fn serial_number(&mut self) -> Result<u16, Self::Error> {
self.$inner.serial_number()
}
fn manufacturer_name(&mut self, name: &mut [u8]) -> Result<(), Self::Error> {
self.$inner.manufacturer_name(name)
}
fn device_name(&mut self, name: &mut [u8]) -> Result<(), Self::Error> {
self.$inner.device_name(name)
}
fn device_chemistry(&mut self, chemistry: &mut [u8]) -> Result<(), Self::Error> {
self.$inner.device_chemistry(chemistry)
}
}
};
}