use bitflags::bitflags;
use zerocopy::{FromBytes, Immutable, IntoBytes};
#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct BstReturn {
pub battery_state: BatteryState,
pub battery_present_rate: u32,
pub battery_remaining_capacity: u32,
pub battery_present_voltage: u32,
}
pub const BST_RETURN_SIZE_BYTES: usize = 16;
#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct BatteryState(u32);
bitflags! {
impl BatteryState: u32 {
const DISCHARGING = 1 << 0;
const CHARGING = 1 << 1;
const CRITICAL = 1 << 2;
const CHARGE_LIMITING = 1 << 3;
}
}
#[repr(C)]
#[derive(Default, PartialEq, Eq, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct BixReturn<'a> {
pub revision: u32,
pub power_unit: PowerUnit,
pub design_capacity: u32,
pub last_full_charge_capacity: u32,
pub battery_technology: BatteryTechnology,
pub design_voltage: u32,
pub design_cap_of_warning: u32,
pub design_cap_of_low: u32,
pub cycle_count: u32,
pub measurement_accuracy: u32,
pub max_sampling_time: u32,
pub min_sampling_time: u32,
pub max_averaging_interval: u32,
pub min_averaging_interval: u32,
pub battery_capacity_granularity_1: u32,
pub battery_capacity_granularity_2: u32,
pub model_number: &'a [u8],
pub serial_number: &'a [u8],
pub battery_type: &'a [u8],
pub oem_info: &'a [u8],
pub battery_swapping_capability: BatterySwapCapability,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BixReturnSerializeErr {
StringSizeMismatch,
InputSliceTooSmall,
}
impl<'a> BixReturn<'a> {
pub fn to_bytes(
self,
dst_slice: &mut [u8],
model_num_size: usize,
serial_num_size: usize,
battery_type_size: usize,
oem_info_size: usize,
) -> Result<(), BixReturnSerializeErr> {
const MODEL_NUM_START_IDX: usize = 64;
let model_num_end_idx: usize = MODEL_NUM_START_IDX + model_num_size;
let serial_num_start_idx = model_num_end_idx;
let serial_num_end_idx = serial_num_start_idx + serial_num_size;
let battery_type_start_idx = serial_num_end_idx;
let battery_type_end_idx = battery_type_start_idx + battery_type_size;
let oem_info_start_idx = battery_type_end_idx;
let oem_info_end_idx = oem_info_start_idx + oem_info_size;
if dst_slice.len() < oem_info_end_idx {
return Err(BixReturnSerializeErr::InputSliceTooSmall);
}
if self.model_number.len() != model_num_size
|| self.serial_number.len() != serial_num_size
|| self.battery_type.len() != battery_type_size
|| self.oem_info.len() != oem_info_size
{
return Err(BixReturnSerializeErr::StringSizeMismatch);
}
dst_slice[..4].copy_from_slice(&u32::to_le_bytes(self.revision));
dst_slice[4..8].copy_from_slice(&u32::to_le_bytes(self.power_unit.into()));
dst_slice[8..12].copy_from_slice(&u32::to_le_bytes(self.design_capacity));
dst_slice[12..16].copy_from_slice(&u32::to_le_bytes(self.last_full_charge_capacity));
dst_slice[16..20].copy_from_slice(&u32::to_le_bytes(self.battery_technology.into()));
dst_slice[20..24].copy_from_slice(&u32::to_le_bytes(self.design_voltage));
dst_slice[24..28].copy_from_slice(&u32::to_le_bytes(self.design_cap_of_warning));
dst_slice[28..32].copy_from_slice(&u32::to_le_bytes(self.design_cap_of_low));
dst_slice[32..36].copy_from_slice(&u32::to_le_bytes(self.cycle_count));
dst_slice[36..40].copy_from_slice(&u32::to_le_bytes(self.measurement_accuracy));
dst_slice[40..44].copy_from_slice(&u32::to_le_bytes(self.max_sampling_time));
dst_slice[44..48].copy_from_slice(&u32::to_le_bytes(self.min_sampling_time));
dst_slice[48..52].copy_from_slice(&u32::to_le_bytes(self.max_averaging_interval));
dst_slice[52..56].copy_from_slice(&u32::to_le_bytes(self.min_averaging_interval));
dst_slice[56..60].copy_from_slice(&u32::to_le_bytes(self.battery_capacity_granularity_1));
dst_slice[60..64].copy_from_slice(&u32::to_le_bytes(self.battery_capacity_granularity_2));
dst_slice[MODEL_NUM_START_IDX..model_num_end_idx].copy_from_slice(self.model_number);
dst_slice[serial_num_start_idx..serial_num_end_idx].copy_from_slice(self.serial_number);
dst_slice[battery_type_start_idx..battery_type_end_idx].copy_from_slice(self.battery_type);
dst_slice[oem_info_start_idx..oem_info_end_idx].copy_from_slice(self.oem_info);
dst_slice[oem_info_end_idx..oem_info_end_idx + 4]
.copy_from_slice(&u32::to_le_bytes(self.battery_swapping_capability.into()));
Ok(())
}
}
#[repr(u32)]
#[derive(Default, Copy, Clone, PartialEq, Eq, Immutable, IntoBytes)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PowerUnit {
MilliWatts = 0,
#[default]
MilliAmps = 1,
}
impl From<PowerUnit> for u32 {
fn from(value: PowerUnit) -> Self {
match value {
PowerUnit::MilliWatts => 0,
PowerUnit::MilliAmps => 1,
}
}
}
impl TryFrom<u32> for PowerUnit {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::MilliWatts),
1 => Ok(Self::MilliAmps),
_ => Err(()),
}
}
}
#[repr(u32)]
#[derive(Default, Copy, Clone, PartialEq, Eq, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BatteryTechnology {
Primary = 0,
#[default]
Secondary = 1,
}
impl From<BatteryTechnology> for u32 {
fn from(value: BatteryTechnology) -> Self {
match value {
BatteryTechnology::Primary => 0,
BatteryTechnology::Secondary => 1,
}
}
}
impl TryFrom<u32> for BatteryTechnology {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Primary),
1 => Ok(Self::Secondary),
_ => Err(()),
}
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq, IntoBytes, Immutable)]
#[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BatterySwapCapability {
#[default]
NonSwappable = 0,
ColdSwappable = 1,
HotSwappable = 2,
}
impl From<BatterySwapCapability> for u32 {
fn from(value: BatterySwapCapability) -> Self {
match value {
BatterySwapCapability::NonSwappable => 0,
BatterySwapCapability::ColdSwappable => 1,
BatterySwapCapability::HotSwappable => 2,
}
}
}
impl TryFrom<u32> for BatterySwapCapability {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::NonSwappable),
1 => Ok(Self::ColdSwappable),
2 => Ok(Self::HotSwappable),
_ => Err(()),
}
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq, Immutable, IntoBytes)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PsrReturn {
pub power_source: PowerSource,
}
pub const PSR_RETURN_SIZE_BYTES: usize = 4;
#[repr(u32)]
#[derive(Default, Copy, Clone, PartialEq, Eq, Immutable, IntoBytes)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PowerSource {
#[default]
Offline = 0,
Online = 1,
}
impl From<PowerSource> for u32 {
fn from(value: PowerSource) -> Self {
match value {
PowerSource::Offline => 0,
PowerSource::Online => 1,
}
}
}
impl TryFrom<u32> for PowerSource {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Offline),
1 => Ok(Self::Online),
_ => Err(()),
}
}
}
#[repr(C)]
#[derive(Default, PartialEq, Eq, FromBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Pif<'a> {
pub power_source_state: PowerSourceState,
pub max_output_power: u32,
pub max_input_power: u32,
pub model_number: &'a [u8],
pub serial_number: &'a [u8],
pub oem_info: &'a [u8],
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PifSerializeErr {
StringSizeMismatch,
InputSliceTooSmall,
}
impl<'a> Pif<'a> {
pub fn to_bytes(
self,
dst_slice: &mut [u8],
model_num_size: usize,
serial_num_size: usize,
oem_info_size: usize,
) -> Result<(), PifSerializeErr> {
const MODEL_NUM_START_IDX: usize = 12;
let model_num_end_idx: usize = MODEL_NUM_START_IDX + model_num_size;
let serial_num_start_idx = model_num_end_idx;
let serial_num_end_idx = serial_num_start_idx + serial_num_size;
let oem_info_start_idx = serial_num_end_idx;
let oem_info_end_idx = oem_info_start_idx + oem_info_size;
if dst_slice.len() < oem_info_end_idx {
return Err(PifSerializeErr::InputSliceTooSmall);
}
if self.model_number.len() != model_num_size
|| self.serial_number.len() != serial_num_size
|| self.oem_info.len() != oem_info_size
{
return Err(PifSerializeErr::StringSizeMismatch);
}
dst_slice[..4].copy_from_slice(&u32::to_le_bytes(self.power_source_state.bits()));
dst_slice[4..8].copy_from_slice(&u32::to_le_bytes(self.max_output_power));
dst_slice[8..12].copy_from_slice(&u32::to_le_bytes(self.max_input_power));
dst_slice[MODEL_NUM_START_IDX..model_num_end_idx].copy_from_slice(self.model_number);
dst_slice[serial_num_start_idx..serial_num_end_idx].copy_from_slice(self.serial_number);
dst_slice[oem_info_start_idx..oem_info_end_idx].copy_from_slice(self.oem_info);
Ok(())
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PowerSourceState(u32);
bitflags! {
impl PowerSourceState: u32 {
const REDUNDANT = 1 << 0;
const SHARED = 1 << 1;
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Bps {
pub revision: u32,
pub instantaneous_peak_power_level: u32,
pub instantaneous_peak_power_period: u32,
pub sustainable_peak_power_level: u32,
pub sustainable_peak_power_period: u32,
}
pub const BPS_RETURN_SIZE_BYTES: usize = 20;
#[derive(Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Btp {
pub trip_point: u32,
}
#[derive(Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Bpt {
pub revision: u32,
pub threshold_id: ThresholdId,
pub threshold_value: u32,
}
#[repr(u32)]
#[derive(Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ThresholdId {
#[default]
ClearAll = 0,
InstantaneousPeakPower = 1,
SustainablePeakPower = 2,
}
impl TryFrom<u32> for ThresholdId {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::ClearAll),
1 => Ok(Self::InstantaneousPeakPower),
2 => Ok(Self::SustainablePeakPower),
_ => Err(()),
}
}
}
#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BptReturnStatus {
Success = 0x00000000,
InvalidThresholdValue = 0x00000001,
HardwareTimeout = 0x00000002,
UnknownHardwareError = 0x00000003,
UnsupportedThresholdType = 0x00000004,
UnsupportedRevision = 0x00000005,
}
#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Bpc {
pub revision: u32,
pub power_threshold_support: PowerThresholdSupport,
pub max_instantaneous_peak_power_threshold: u32,
pub max_sustainable_peak_power_threshold: u32,
}
pub const BPC_RETURN_SIZE_BYTES: usize = 16;
#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PowerThresholdSupport(u32);
bitflags! {
impl PowerThresholdSupport: u32 {
const INSTANTANEOUS = 1 << 0;
const SUSTAINABLE = 1 << 1;
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Bmc {
pub maintenance_control_flags: BmcControlFlags,
}
#[derive(Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct BmcControlFlags(u32);
bitflags! {
impl BmcControlFlags: u32 {
const CALIBRATION_CYCLE = 1 << 0;
const DISABLE_CHARGING = 1 << 1;
const ALLOW_DISCHARGE_ON_AC = 1 << 2;
const SUSPEND_CHARGE_LIMITING = 1 << 3;
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Bmd {
pub status_flags: BmdStatusFlags,
pub capability_flags: BmdCapabilityFlags,
pub recalibrate_count: u32,
pub quick_recalibrate_time: u32,
pub slow_recalibrate_time: u32,
}
pub const BMD_RETURN_SIZE_BYTES: usize = 20;
#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct BmdStatusFlags(u32);
bitflags! {
impl BmdStatusFlags: u32 {
const AML_CALIBRATION_ACTIVE = 1 << 0;
const CHARGING_DISABLED = 1 << 1;
const DISCHARGE_ON_AC = 1 << 2;
const RECALIBRATION_NEEDED = 1 << 3;
const STANDBY_RECOMMENDED = 1 << 4;
const CHARGE_LIMIT_THERMAL_LOCK = 1 << 5;
const CHARGE_LIMIT_PROTECTION_LOCK = 1 << 6;
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct BmdCapabilityFlags(u32);
bitflags! {
impl BmdCapabilityFlags: u32 {
const AML_CALIBRATION_SUPPORTED = 1 << 0;
const CHARGER_DISABLE_SUPPORTED = 1 << 1;
const DISCHARGE_ON_AC_SUPPORTED = 1 << 2;
const GLOBAL_CONTROL = 1 << 3;
const FULL_CHARGE_BEFORE_CALIBRATION = 1 << 4;
const CHARGE_LIMIT_SUSPEND_SUPPORTED = 1 << 5;
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Bct {
pub charge_level_percent: u32,
}
#[repr(u32)]
#[derive(Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BctReturnResult {
InvalidTarget = 0x00000000,
EstimatedTime(u32),
#[default]
Unknown = 0xFFFFFFFF,
}
pub const BCT_RETURN_SIZE_BYTES: usize = 4;
impl From<u32> for BctReturnResult {
fn from(value: u32) -> Self {
match value {
0x00000000 => BctReturnResult::InvalidTarget,
0xFFFFFFFF => BctReturnResult::Unknown,
seconds => BctReturnResult::EstimatedTime(seconds),
}
}
}
impl From<BctReturnResult> for u32 {
fn from(value: BctReturnResult) -> Self {
match value {
BctReturnResult::InvalidTarget => 0x00000000,
BctReturnResult::Unknown => 0xFFFFFFFF,
BctReturnResult::EstimatedTime(seconds) => seconds,
}
}
}
impl From<BctReturnResult> for [u8; BCT_RETURN_SIZE_BYTES] {
fn from(value: BctReturnResult) -> Self {
u32::to_le_bytes(u32::from(value))
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Btm {
pub discharge_rate: u32,
}
#[repr(u32)]
#[derive(Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BtmReturnResult {
RateTooHighOrBatteryCritical = 0x00000000,
EstimatedRuntime(u32),
#[default]
Unknown = 0xFFFFFFFF,
}
pub const BTM_RETURN_SIZE_BYTES: usize = 4;
impl From<u32> for BtmReturnResult {
fn from(value: u32) -> Self {
match value {
0x00000000 => BtmReturnResult::RateTooHighOrBatteryCritical,
0xFFFFFFFF => BtmReturnResult::Unknown,
seconds => BtmReturnResult::EstimatedRuntime(seconds),
}
}
}
impl From<BtmReturnResult> for u32 {
fn from(value: BtmReturnResult) -> Self {
match value {
BtmReturnResult::RateTooHighOrBatteryCritical => 0x00000000,
BtmReturnResult::Unknown => 0xFFFFFFFF,
BtmReturnResult::EstimatedRuntime(seconds) => seconds,
}
}
}
impl From<BtmReturnResult> for [u8; BTM_RETURN_SIZE_BYTES] {
fn from(value: BtmReturnResult) -> Self {
u32::to_le_bytes(u32::from(value))
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Bms {
pub sampling_time_ms: u32,
}
#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BmsReturnResult {
Success = 0,
OutOfRange = 1,
}
impl From<BmsReturnResult> for u32 {
fn from(value: BmsReturnResult) -> Self {
match value {
BmsReturnResult::Success => 0,
BmsReturnResult::OutOfRange => 1,
}
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Bma {
pub averaging_interval_ms: u32,
}
#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BmaReturnResult {
Success = 0,
OutOfRange = 1,
}
impl From<BmaReturnResult> for u32 {
fn from(value: BmaReturnResult) -> Self {
match value {
BmaReturnResult::Success => 0,
BmaReturnResult::OutOfRange => 1,
}
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StaReturn(u32);
bitflags! {
impl StaReturn: u32 {
const DEVICE_PRESENT = 1 << 0;
const DEVICE_ENABLED = 1 << 1;
const DEVICE_SHOULD_SHOWN_UI = 1 << 2;
const DEVICE_FUNCTIONING = 1 << 3;
const BATTERY_PRESENT = 1 << 4;
}
}
pub const STA_RETURN_SIZE_BYTES: usize = 4;