Skip to main content

embedded_batteries/
acpi.rs

1use bitflags::bitflags;
2use zerocopy::{FromBytes, Immutable, IntoBytes};
3
4/// BST: Battery Status.
5#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7pub struct BstReturn {
8    /// Battery state flags indicating charging/discharging/critical status.
9    pub battery_state: BatteryState,
10    /// Present rate of power or current flow (in mW or mA).
11    ///
12    /// - `0x00000000..=0x7FFFFFFF`: Valid rate.
13    /// - `0xFFFFFFFF`: Unknown rate.
14    pub battery_present_rate: u32,
15    /// Estimated remaining battery capacity (in mWh or mAh).
16    ///
17    /// - `0x00000000..=0x7FFFFFFF`: Valid capacity.
18    /// - `0xFFFFFFFF`: Unknown capacity.
19    pub battery_remaining_capacity: u32,
20    /// Present voltage across the battery terminals (in mV).
21    ///
22    /// - `0x00000000..=0x7FFFFFFF`: Valid voltage.
23    /// - `0xFFFFFFFF`: Unknown voltage (only for primary batteries).
24    pub battery_present_voltage: u32,
25}
26
27/// Size of BstReturn in bytes
28pub const BST_RETURN_SIZE_BYTES: usize = 16;
29
30/// Battery State (BST).
31#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
33pub struct BatteryState(u32);
34bitflags! {
35    impl BatteryState: u32 {
36        /// Battery is discharging.
37        const DISCHARGING = 1 << 0;
38
39        /// Battery is charging.
40        const CHARGING = 1 << 1;
41
42        /// Battery is in a critical energy state.
43        const CRITICAL = 1 << 2;
44
45        /// Battery is in Battery Charge Limiting state.
46        const CHARGE_LIMITING = 1 << 3;
47    }
48}
49
50/// BIX: Battery Information Extended.
51///
52/// Represents static battery information that remains constant until the battery is replaced.
53/// Supersedes `_BIF` and includes additional fields introduced in ACPI 4.0.
54#[repr(C)]
55#[derive(Default, PartialEq, Eq, Immutable)]
56#[cfg_attr(feature = "defmt", derive(defmt::Format))]
57pub struct BixReturn<'a> {
58    /// Revision of the BIX structure. Current revision is 1.
59    pub revision: u32,
60    /// Unit used for capacity and rate values.
61    pub power_unit: PowerUnit,
62    /// Design capacity of the battery (in mWh or mAh).
63    pub design_capacity: u32,
64    /// Last full charge capacity (in mWh or mAh).
65    pub last_full_charge_capacity: u32,
66    /// Battery technology type.
67    pub battery_technology: BatteryTechnology,
68    /// Design voltage (in mV).
69    pub design_voltage: u32,
70    /// Warning capacity threshold (in mWh or mAh).
71    pub design_cap_of_warning: u32,
72    /// Low capacity threshold (in mWh or mAh).
73    pub design_cap_of_low: u32,
74    /// Number of charge/discharge cycles.
75    pub cycle_count: u32,
76    /// Measurement accuracy in thousandths of a percent (e.g., 80000 = 80.000%).
77    pub measurement_accuracy: u32,
78    /// Maximum supported sampling time (in ms).
79    pub max_sampling_time: u32,
80    /// Minimum supported sampling time (in ms).
81    pub min_sampling_time: u32,
82    /// Maximum supported averaging interval (in ms).
83    pub max_averaging_interval: u32,
84    /// Minimum supported averaging interval (in ms).
85    pub min_averaging_interval: u32,
86    /// Capacity granularity between low and warning (in mWh or mAh).
87    pub battery_capacity_granularity_1: u32,
88    /// Capacity granularity between warning and full (in mWh or mAh).
89    pub battery_capacity_granularity_2: u32,
90    /// OEM-specific model number (ASCIIZ).
91    pub model_number: &'a [u8],
92    /// OEM-specific serial number (ASCIIZ).
93    pub serial_number: &'a [u8],
94    /// OEM-specific battery type (ASCIIZ).
95    pub battery_type: &'a [u8],
96    /// OEM-specific information (ASCIIZ).
97    pub oem_info: &'a [u8],
98    /// Battery swapping capability.
99    pub battery_swapping_capability: BatterySwapCapability,
100}
101
102#[derive(Clone, Copy, PartialEq, Eq)]
103#[cfg_attr(feature = "defmt", derive(defmt::Format))]
104/// Error type when serializing BixReturn.
105pub enum BixReturnSerializeErr {
106    /// An incorrect size for a string was passed in.
107    StringSizeMismatch,
108    /// Input slice is too small to encapsulate all the fields.
109    InputSliceTooSmall,
110}
111
112impl<'a> BixReturn<'a> {
113    /// Serialize BIX return value, needed because BixReturn doesn't support zerocopy::IntoBytes derive.
114    ///
115    /// `dst_slice` should be at least 64 + model_num_size + serial_num_size + battery_type_size + oem_info_size bytes large.
116    pub fn to_bytes(
117        self,
118        dst_slice: &mut [u8],
119        model_num_size: usize,
120        serial_num_size: usize,
121        battery_type_size: usize,
122        oem_info_size: usize,
123    ) -> Result<(), BixReturnSerializeErr> {
124        const MODEL_NUM_START_IDX: usize = 64;
125        let model_num_end_idx: usize = MODEL_NUM_START_IDX + model_num_size;
126        let serial_num_start_idx = model_num_end_idx;
127        let serial_num_end_idx = serial_num_start_idx + serial_num_size;
128        let battery_type_start_idx = serial_num_end_idx;
129        let battery_type_end_idx = battery_type_start_idx + battery_type_size;
130        let oem_info_start_idx = battery_type_end_idx;
131        let oem_info_end_idx = oem_info_start_idx + oem_info_size;
132
133        if dst_slice.len() < oem_info_end_idx {
134            return Err(BixReturnSerializeErr::InputSliceTooSmall);
135        }
136
137        if self.model_number.len() != model_num_size
138            || self.serial_number.len() != serial_num_size
139            || self.battery_type.len() != battery_type_size
140            || self.oem_info.len() != oem_info_size
141        {
142            return Err(BixReturnSerializeErr::StringSizeMismatch);
143        }
144
145        dst_slice[..4].copy_from_slice(&u32::to_le_bytes(self.revision));
146        dst_slice[4..8].copy_from_slice(&u32::to_le_bytes(self.power_unit.into()));
147        dst_slice[8..12].copy_from_slice(&u32::to_le_bytes(self.design_capacity));
148        dst_slice[12..16].copy_from_slice(&u32::to_le_bytes(self.last_full_charge_capacity));
149        dst_slice[16..20].copy_from_slice(&u32::to_le_bytes(self.battery_technology.into()));
150        dst_slice[20..24].copy_from_slice(&u32::to_le_bytes(self.design_voltage));
151        dst_slice[24..28].copy_from_slice(&u32::to_le_bytes(self.design_cap_of_warning));
152        dst_slice[28..32].copy_from_slice(&u32::to_le_bytes(self.design_cap_of_low));
153        dst_slice[32..36].copy_from_slice(&u32::to_le_bytes(self.cycle_count));
154        dst_slice[36..40].copy_from_slice(&u32::to_le_bytes(self.measurement_accuracy));
155        dst_slice[40..44].copy_from_slice(&u32::to_le_bytes(self.max_sampling_time));
156        dst_slice[44..48].copy_from_slice(&u32::to_le_bytes(self.min_sampling_time));
157        dst_slice[48..52].copy_from_slice(&u32::to_le_bytes(self.max_averaging_interval));
158        dst_slice[52..56].copy_from_slice(&u32::to_le_bytes(self.min_averaging_interval));
159        dst_slice[56..60].copy_from_slice(&u32::to_le_bytes(self.battery_capacity_granularity_1));
160        dst_slice[60..64].copy_from_slice(&u32::to_le_bytes(self.battery_capacity_granularity_2));
161        dst_slice[MODEL_NUM_START_IDX..model_num_end_idx].copy_from_slice(self.model_number);
162        dst_slice[serial_num_start_idx..serial_num_end_idx].copy_from_slice(self.serial_number);
163        dst_slice[battery_type_start_idx..battery_type_end_idx].copy_from_slice(self.battery_type);
164        dst_slice[oem_info_start_idx..oem_info_end_idx].copy_from_slice(self.oem_info);
165        dst_slice[oem_info_end_idx..oem_info_end_idx + 4]
166            .copy_from_slice(&u32::to_le_bytes(self.battery_swapping_capability.into()));
167        Ok(())
168    }
169}
170
171/// Power Unit.
172#[repr(u32)]
173#[derive(Default, Copy, Clone, PartialEq, Eq, Immutable, IntoBytes)]
174#[cfg_attr(feature = "defmt", derive(defmt::Format))]
175pub enum PowerUnit {
176    /// Capacity in mWh, rate in mW.
177    MilliWatts = 0,
178    /// Capacity in mAh, rate in mA.
179    #[default]
180    MilliAmps = 1,
181}
182
183impl From<PowerUnit> for u32 {
184    fn from(value: PowerUnit) -> Self {
185        match value {
186            PowerUnit::MilliWatts => 0,
187            PowerUnit::MilliAmps => 1,
188        }
189    }
190}
191
192impl TryFrom<u32> for PowerUnit {
193    type Error = ();
194    fn try_from(value: u32) -> Result<Self, Self::Error> {
195        match value {
196            0 => Ok(Self::MilliWatts),
197            1 => Ok(Self::MilliAmps),
198            _ => Err(()),
199        }
200    }
201}
202
203/// Battery Technology.
204#[repr(u32)]
205#[derive(Default, Copy, Clone, PartialEq, Eq, IntoBytes, Immutable)]
206#[cfg_attr(feature = "defmt", derive(defmt::Format))]
207pub enum BatteryTechnology {
208    /// Primary (non-rechargeable).
209    Primary = 0,
210    /// Secondary (rechargeable).
211    #[default]
212    Secondary = 1,
213}
214
215impl From<BatteryTechnology> for u32 {
216    fn from(value: BatteryTechnology) -> Self {
217        match value {
218            BatteryTechnology::Primary => 0,
219            BatteryTechnology::Secondary => 1,
220        }
221    }
222}
223
224impl TryFrom<u32> for BatteryTechnology {
225    type Error = ();
226    fn try_from(value: u32) -> Result<Self, Self::Error> {
227        match value {
228            0 => Ok(Self::Primary),
229            1 => Ok(Self::Secondary),
230            _ => Err(()),
231        }
232    }
233}
234
235/// Battery Swapping Capability.
236#[derive(Default, Copy, Clone, PartialEq, Eq, IntoBytes, Immutable)]
237#[repr(u32)]
238#[cfg_attr(feature = "defmt", derive(defmt::Format))]
239pub enum BatterySwapCapability {
240    /// Non-swappable battery.
241    #[default]
242    NonSwappable = 0,
243    /// Cold-swappable battery.
244    ColdSwappable = 1,
245    /// Hot-swappable battery.
246    HotSwappable = 2,
247}
248
249impl From<BatterySwapCapability> for u32 {
250    fn from(value: BatterySwapCapability) -> Self {
251        match value {
252            BatterySwapCapability::NonSwappable => 0,
253            BatterySwapCapability::ColdSwappable => 1,
254            BatterySwapCapability::HotSwappable => 2,
255        }
256    }
257}
258
259impl TryFrom<u32> for BatterySwapCapability {
260    type Error = ();
261    fn try_from(value: u32) -> Result<Self, Self::Error> {
262        match value {
263            0 => Ok(Self::NonSwappable),
264            1 => Ok(Self::ColdSwappable),
265            2 => Ok(Self::HotSwappable),
266            _ => Err(()),
267        }
268    }
269}
270
271/// PSR: Power Source Status.
272///
273/// Represents whether a power source (e.g., AC adapter) is currently online or offline.
274/// This is used to determine if the system is running on this power source.
275#[derive(Default, Copy, Clone, PartialEq, Eq, Immutable, IntoBytes)]
276#[cfg_attr(feature = "defmt", derive(defmt::Format))]
277pub struct PsrReturn {
278    /// The current power source status.
279    pub power_source: PowerSource,
280}
281
282/// Size of PsrReturn in bytes
283pub const PSR_RETURN_SIZE_BYTES: usize = 4;
284
285/// Result of a _PSR query.
286///
287/// Indicates whether the power source is currently supplying power to the system
288#[repr(u32)]
289#[derive(Default, Copy, Clone, PartialEq, Eq, Immutable, IntoBytes)]
290#[cfg_attr(feature = "defmt", derive(defmt::Format))]
291pub enum PowerSource {
292    /// Power source is offline (not supplying power).
293    #[default]
294    Offline = 0,
295
296    /// Power source is online (supplying power).
297    Online = 1,
298}
299
300impl From<PowerSource> for u32 {
301    fn from(value: PowerSource) -> Self {
302        match value {
303            PowerSource::Offline => 0,
304            PowerSource::Online => 1,
305        }
306    }
307}
308
309impl TryFrom<u32> for PowerSource {
310    type Error = ();
311    fn try_from(value: u32) -> Result<Self, Self::Error> {
312        match value {
313            0 => Ok(Self::Offline),
314            1 => Ok(Self::Online),
315            _ => Err(()),
316        }
317    }
318}
319
320/// PIF: Power Source Information.
321///
322/// Represents static information about a power source device. This information
323/// remains constant until the power source is changed.
324#[repr(C)]
325#[derive(Default, PartialEq, Eq, FromBytes, Immutable)]
326#[cfg_attr(feature = "defmt", derive(defmt::Format))]
327pub struct Pif<'a> {
328    /// Bitfield describing the state and characteristics of the power source.
329    pub power_source_state: PowerSourceState,
330    /// Maximum rated output power in milliwatts (mW).
331    ///
332    /// 0xFFFFFFFF indicates the value is unavailable.
333    pub max_output_power: u32,
334    /// Maximum rated input power in milliwatts (mW).
335    ///
336    /// 0xFFFFFFFF indicates the value is unavailable.
337    pub max_input_power: u32,
338    /// OEM-specific model number (ASCIIZ). Empty string if not supported.
339    pub model_number: &'a [u8],
340    /// OEM-specific serial number (ASCIIZ). Empty string if not supported.
341    pub serial_number: &'a [u8],
342    /// OEM-specific information (ASCIIZ). Empty string if not supported.
343    pub oem_info: &'a [u8],
344}
345
346#[derive(Clone, Copy, PartialEq, Eq)]
347#[cfg_attr(feature = "defmt", derive(defmt::Format))]
348/// Error type when serializing Pif.
349pub enum PifSerializeErr {
350    /// An incorrect size for a string was passed in.
351    StringSizeMismatch,
352    /// Input slice is too small to encapsulate all the fields.
353    InputSliceTooSmall,
354}
355
356impl<'a> Pif<'a> {
357    /// Serialize PIF return value, needed because Pif doesn't support zerocopy::IntoBytes derive.
358    ///
359    /// `dst_slice` should be at least 12 + model_num_size + serial_num_size + oem_info_size bytes large.
360    pub fn to_bytes(
361        self,
362        dst_slice: &mut [u8],
363        model_num_size: usize,
364        serial_num_size: usize,
365        oem_info_size: usize,
366    ) -> Result<(), PifSerializeErr> {
367        const MODEL_NUM_START_IDX: usize = 12;
368        let model_num_end_idx: usize = MODEL_NUM_START_IDX + model_num_size;
369        let serial_num_start_idx = model_num_end_idx;
370        let serial_num_end_idx = serial_num_start_idx + serial_num_size;
371        let oem_info_start_idx = serial_num_end_idx;
372        let oem_info_end_idx = oem_info_start_idx + oem_info_size;
373
374        if dst_slice.len() < oem_info_end_idx {
375            return Err(PifSerializeErr::InputSliceTooSmall);
376        }
377
378        if self.model_number.len() != model_num_size
379            || self.serial_number.len() != serial_num_size
380            || self.oem_info.len() != oem_info_size
381        {
382            return Err(PifSerializeErr::StringSizeMismatch);
383        }
384
385        dst_slice[..4].copy_from_slice(&u32::to_le_bytes(self.power_source_state.bits()));
386        dst_slice[4..8].copy_from_slice(&u32::to_le_bytes(self.max_output_power));
387        dst_slice[8..12].copy_from_slice(&u32::to_le_bytes(self.max_input_power));
388        dst_slice[MODEL_NUM_START_IDX..model_num_end_idx].copy_from_slice(self.model_number);
389        dst_slice[serial_num_start_idx..serial_num_end_idx].copy_from_slice(self.serial_number);
390        dst_slice[oem_info_start_idx..oem_info_end_idx].copy_from_slice(self.oem_info);
391        Ok(())
392    }
393}
394
395/// Power Source State.
396#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
397#[cfg_attr(feature = "defmt", derive(defmt::Format))]
398pub struct PowerSourceState(u32);
399bitflags! {
400    impl PowerSourceState: u32 {
401        /// Indicates the power source is redundant.
402        const REDUNDANT = 1 << 0;
403
404        /// Indicates the power source is shared across multiple machines.
405        const SHARED = 1 << 1;
406    }
407}
408
409/// BPS: Battery Power Source Information.
410#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
411#[cfg_attr(feature = "defmt", derive(defmt::Format))]
412pub struct Bps {
413    /// Current revision of the BPS structure.
414    ///
415    /// The current revision is 1.
416    pub revision: u32,
417
418    /// Instantaneous Peak Power Level in mW or mA.
419    ///
420    /// Represents the instantaneous peak output power of the battery, based on the Power Unit
421    /// value returned by `_BIX`. The time period is specified in the `instantaneous_peak_power_period`.
422    /// This value accounts for battery resistances and the minimum system voltage.
423    /// If unsupported, this field should be zero.
424    pub instantaneous_peak_power_level: u32,
425
426    /// Instantaneous Peak Power Period in milliseconds.
427    ///
428    /// The duration for which the battery can supply the `instantaneous_peak_power_level`.
429    /// If unsupported, this field should be zero.
430    pub instantaneous_peak_power_period: u32,
431
432    /// Sustainable Peak Power Level in mW or mA.
433    ///
434    /// Represents the sustainable peak output power of the battery, based on the Power Unit
435    /// value returned by `_BIX`. The time period is specified in the `sustainable_peak_power_period`.
436    /// This value accounts for battery resistances and the minimum system voltage.
437    /// If unsupported, this field should be zero.
438    pub sustainable_peak_power_level: u32,
439
440    /// Sustainable Peak Power Period in milliseconds.
441    ///
442    /// The duration for which the battery can supply the `sustainable_peak_power_level`.
443    /// If unsupported, this field should be zero.
444    pub sustainable_peak_power_period: u32,
445}
446
447/// Size of BpsReturn in bytes
448pub const BPS_RETURN_SIZE_BYTES: usize = 20;
449
450/// BTP: Battery Trip Point.
451#[derive(Default, Copy, Clone, PartialEq, Eq)]
452#[cfg_attr(feature = "defmt", derive(defmt::Format))]
453pub struct Btp {
454    /// 0 - Clear the trip point.
455    /// 1 - 0x7FFFFFFF - New trip point, in units of mWh or mAh depending on the Power Units value
456    pub trip_point: u32,
457}
458
459/// BPT: Battery Power Threshold Configuration.
460///
461/// Represents a request to set or clear battery power delivery capability thresholds.
462/// Used by the OS Power Management (OSPM) to configure notifications for changes
463/// in battery power delivery capabilities.
464#[derive(Default, Copy, Clone, PartialEq, Eq)]
465#[cfg_attr(feature = "defmt", derive(defmt::Format))]
466pub struct Bpt {
467    /// Revision of the BPT structure.
468    ///
469    /// For this version of the specification, the revision must be set to 1.
470    pub revision: u32,
471
472    /// Type of threshold to set or clear.
473    pub threshold_id: ThresholdId,
474
475    /// Threshold value in mW or mA.
476    ///
477    /// This value is based on the Power Unit field returned by `_BIX`.
478    /// A value of `0` disables the selected threshold.
479    /// The value must not exceed the maximum values reported by `_BPC`.
480    pub threshold_value: u32,
481}
482
483/// Enum representing the threshold type for battery power delivery capability.
484#[repr(u32)]
485#[derive(Default, Copy, Clone, PartialEq, Eq)]
486#[cfg_attr(feature = "defmt", derive(defmt::Format))]
487pub enum ThresholdId {
488    #[default]
489    /// Clear all threshold trip points.
490    ClearAll = 0,
491
492    /// Set Instantaneous Peak Power Threshold.
493    InstantaneousPeakPower = 1,
494
495    /// Set Sustainable Peak Power Threshold.
496    SustainablePeakPower = 2,
497}
498
499impl TryFrom<u32> for ThresholdId {
500    type Error = ();
501    fn try_from(value: u32) -> Result<Self, Self::Error> {
502        match value {
503            0 => Ok(Self::ClearAll),
504            1 => Ok(Self::InstantaneousPeakPower),
505            2 => Ok(Self::SustainablePeakPower),
506            _ => Err(()),
507        }
508    }
509}
510
511/// Return codes for BPT operations.
512#[repr(u32)]
513#[derive(Copy, Clone, PartialEq, Eq)]
514#[cfg_attr(feature = "defmt", derive(defmt::Format))]
515pub enum BptReturnStatus {
516    /// Operation completed successfully.
517    Success = 0x00000000,
518
519    /// Failure due to an invalid threshold value.
520    InvalidThresholdValue = 0x00000001,
521
522    /// Failure due to hardware timeout.
523    HardwareTimeout = 0x00000002,
524
525    /// Failure due to an unknown hardware error.
526    UnknownHardwareError = 0x00000003,
527
528    /// Failure due to unsupported threshold type.
529    UnsupportedThresholdType = 0x00000004,
530
531    /// Failure due to unsupported revision.
532    UnsupportedRevision = 0x00000005,
533}
534
535/// BPC: Battery Power Characteristics.
536///
537/// Represents static values returned by the platform firmware that describe
538/// the battery's power delivery capabilities and threshold support.
539#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
540#[cfg_attr(feature = "defmt", derive(defmt::Format))]
541pub struct Bpc {
542    /// Revision of the BPC structure.
543    ///
544    /// For this version of the specification, the revision must be set to 1.
545    pub revision: u32,
546
547    /// Power threshold support capability of the platform firmware.
548    ///
549    /// This is a bitfield indicating which types of power thresholds are supported.
550    pub power_threshold_support: PowerThresholdSupport,
551
552    /// Maximum supported threshold for instantaneous peak power (in mW or mA).
553    ///
554    /// This value defines the upper bound for the instantaneous peak power threshold
555    /// that can be set using `_BPT`.
556    pub max_instantaneous_peak_power_threshold: u32,
557
558    /// Maximum supported threshold for sustainable peak power (in mW or mA).
559    ///
560    /// This value defines the upper bound for the sustainable peak power threshold
561    /// that can be set using `_BPT`.
562    pub max_sustainable_peak_power_threshold: u32,
563}
564
565/// Size of BpcReturn in bytes
566pub const BPC_RETURN_SIZE_BYTES: usize = 16;
567
568/// Bitflags representing the power threshold support capabilities of the platform firmware.
569///
570/// These values are encoded in the lower two bits of the `Power Threshold Support` field.
571#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
572#[cfg_attr(feature = "defmt", derive(defmt::Format))]
573pub struct PowerThresholdSupport(u32);
574bitflags! {
575    impl PowerThresholdSupport: u32 {
576        /// Supports Instantaneous Peak Power Threshold.
577        const INSTANTANEOUS = 1 << 0;
578        /// Supports Sustainable Peak Power Threshold.
579        const SUSTAINABLE = 1 << 1;
580    }
581}
582
583/// BMC: Batery Maintenance Control
584#[derive(Default, Copy, Clone, PartialEq, Eq)]
585#[cfg_attr(feature = "defmt", derive(defmt::Format))]
586pub struct Bmc {
587    /// Feature control flags used to configure battery maintenance behavior.
588    pub maintenance_control_flags: BmcControlFlags,
589}
590
591/// Bitflags representing the power threshold support capabilities of the platform firmware.
592///
593/// These values are encoded in the lower two bits of the `Power Threshold Support` field.
594#[derive(Default, Copy, Clone, PartialEq, Eq)]
595#[cfg_attr(feature = "defmt", derive(defmt::Format))]
596pub struct BmcControlFlags(u32);
597bitflags! {
598    impl BmcControlFlags: u32 {
599        /// Set to initiate an AML-controlled calibration cycle. Clear to end it.
600        const CALIBRATION_CYCLE = 1 << 0;
601
602        /// Set to disable charging. Clear to enable charging.
603        const DISABLE_CHARGING = 1 << 1;
604
605        /// Set to allow discharging while AC power is available.
606        const ALLOW_DISCHARGE_ON_AC = 1 << 2;
607
608        /// Set to request suspension of Battery Charge Limiting mode.
609        const SUSPEND_CHARGE_LIMITING = 1 << 3;
610    }
611}
612
613/// BMD: Battery Maintenance Data.
614///
615/// Contains information about the battery’s capabilities and current state
616/// related to calibration and charger control features.
617#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
618#[cfg_attr(feature = "defmt", derive(defmt::Format))]
619pub struct Bmd {
620    /// Current status flags indicating battery maintenance state.
621    pub status_flags: BmdStatusFlags,
622
623    /// Capability flags indicating supported battery maintenance features.
624    pub capability_flags: BmdCapabilityFlags,
625
626    /// Recommended recalibration count.
627    ///
628    /// - `0x00000000`: Only calibrate when Status Flag bit [3] is set.
629    /// - `0x00000001..=0xFFFFFFFF`: Calibrate after this many battery cycles.
630    pub recalibrate_count: u32,
631
632    /// Estimated time (in seconds) to recalibrate the battery if the system enters standby.
633    ///
634    /// - `0x00000000`: Standby not supported.
635    /// - `0x00000001..=0xFFFFFFFE`: Estimated time in seconds.
636    /// - `0xFFFFFFFF`: Time unknown.
637    pub quick_recalibrate_time: u32,
638
639    /// Estimated time (in seconds) to recalibrate the battery without standby.
640    ///
641    /// - `0x00000000`: Calibration may not be successful.
642    /// - `0x00000001..=0xFFFFFFFE`: Estimated time in seconds.
643    /// - `0xFFFFFFFF`: Time unknown.
644    pub slow_recalibrate_time: u32,
645}
646
647/// Size of BmdReturn in bytes
648pub const BMD_RETURN_SIZE_BYTES: usize = 20;
649
650/// Status Flags returned by _BMD.
651///
652/// These indicate the current state of battery maintenance operations.
653#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
654#[cfg_attr(feature = "defmt", derive(defmt::Format))]
655pub struct BmdStatusFlags(u32);
656bitflags! {
657    impl BmdStatusFlags: u32 {
658        /// Battery is running an AML-controlled calibration cycle.
659        const AML_CALIBRATION_ACTIVE = 1 << 0;
660
661        /// Charging has been disabled.
662        const CHARGING_DISABLED = 1 << 1;
663
664        /// Battery is allowed to discharge while AC is available.
665        const DISCHARGE_ON_AC = 1 << 2;
666
667        /// Battery should be recalibrated.
668        const RECALIBRATION_NEEDED = 1 << 3;
669
670        /// OS should enter standby to speed up calibration.
671        const STANDBY_RECOMMENDED = 1 << 4;
672
673        /// Battery Charge Limiting cannot be suspended due to thermal conditions.
674        const CHARGE_LIMIT_THERMAL_LOCK = 1 << 5;
675
676        /// Battery Charge Limiting cannot be suspended for protection reasons.
677        const CHARGE_LIMIT_PROTECTION_LOCK = 1 << 6;
678    }
679}
680
681/// Capability Flags returned by _BMD.
682///
683/// These indicate which battery maintenance features are supported.
684#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
685#[cfg_attr(feature = "defmt", derive(defmt::Format))]
686pub struct BmdCapabilityFlags(u32);
687bitflags! {
688    impl BmdCapabilityFlags: u32 {
689        /// AML-controlled calibration cycle is supported.
690        const AML_CALIBRATION_SUPPORTED = 1 << 0;
691
692        /// Disabling the charger is supported.
693        const CHARGER_DISABLE_SUPPORTED = 1 << 1;
694
695        /// Discharging while on AC is supported.
696        const DISCHARGE_ON_AC_SUPPORTED = 1 << 2;
697
698        /// _BMC affects all batteries in the system.
699        const GLOBAL_CONTROL = 1 << 3;
700
701        /// Calibration must start with a full charge.
702        const FULL_CHARGE_BEFORE_CALIBRATION = 1 << 4;
703
704        /// Battery Charge Limiting suspension is supported.
705        const CHARGE_LIMIT_SUSPEND_SUPPORTED = 1 << 5;
706    }
707}
708
709/// BCT: Battery Charge Time.
710///
711/// Represents a request to estimate the time required to charge the battery
712/// to a specified percentage of its Last Full Charge Capacity.
713#[derive(Default, Copy, Clone, PartialEq, Eq)]
714#[cfg_attr(feature = "defmt", derive(defmt::Format))]
715pub struct Bct {
716    /// Target charge level as a percentage of Last Full Charge Capacity (1–100).
717    ///
718    /// For example, `96` means 96% of full charge.
719    pub charge_level_percent: u32,
720}
721
722/// Result of a _BCT query.
723///
724/// This enum represents the possible return values from the `_BCT` method.
725#[repr(u32)]
726#[derive(Default, Copy, Clone, PartialEq, Eq)]
727#[cfg_attr(feature = "defmt", derive(defmt::Format))]
728pub enum BctReturnResult {
729    /// The requested charge level is invalid (less than current or greater than 100%).
730    InvalidTarget = 0x00000000,
731
732    /// Estimated time in seconds to reach the target charge level.
733    EstimatedTime(u32),
734
735    /// Charging time is unknown.
736    #[default]
737    Unknown = 0xFFFFFFFF,
738}
739
740/// Size of BctReturnResult in bytes
741pub const BCT_RETURN_SIZE_BYTES: usize = 4;
742
743impl From<u32> for BctReturnResult {
744    fn from(value: u32) -> Self {
745        match value {
746            0x00000000 => BctReturnResult::InvalidTarget,
747            0xFFFFFFFF => BctReturnResult::Unknown,
748            seconds => BctReturnResult::EstimatedTime(seconds),
749        }
750    }
751}
752
753impl From<BctReturnResult> for u32 {
754    fn from(value: BctReturnResult) -> Self {
755        match value {
756            BctReturnResult::InvalidTarget => 0x00000000,
757            BctReturnResult::Unknown => 0xFFFFFFFF,
758            BctReturnResult::EstimatedTime(seconds) => seconds,
759        }
760    }
761}
762
763impl From<BctReturnResult> for [u8; BCT_RETURN_SIZE_BYTES] {
764    fn from(value: BctReturnResult) -> Self {
765        u32::to_le_bytes(u32::from(value))
766    }
767}
768
769/// BTM: Battery Time.
770///
771/// Represents a request to estimate the remaining runtime of the battery
772/// while it is discharging at a specified rate.
773#[derive(Default, Copy, Clone, PartialEq, Eq)]
774#[cfg_attr(feature = "defmt", derive(defmt::Format))]
775pub struct Btm {
776    /// Discharge rate in mA or mW.
777    ///
778    /// - `0`: Use the current average discharge rate.
779    /// - `1..=0x7FFFFFFF`: Specific discharge rate to evaluate.
780    pub discharge_rate: u32,
781}
782
783/// Result of a _BTM query.
784///
785/// This enum represents the possible return values from the `_BTM` method.
786#[repr(u32)]
787#[derive(Default, Copy, Clone, PartialEq, Eq)]
788#[cfg_attr(feature = "defmt", derive(defmt::Format))]
789pub enum BtmReturnResult {
790    /// The discharge rate is too high, or the battery is critical (if input was 0).
791    RateTooHighOrBatteryCritical = 0x00000000,
792
793    /// Estimated runtime in seconds.
794    EstimatedRuntime(u32),
795
796    /// Runtime is unknown.
797    #[default]
798    Unknown = 0xFFFFFFFF,
799}
800
801/// Size of BtmReturnResult in bytes
802pub const BTM_RETURN_SIZE_BYTES: usize = 4;
803
804impl From<u32> for BtmReturnResult {
805    fn from(value: u32) -> Self {
806        match value {
807            0x00000000 => BtmReturnResult::RateTooHighOrBatteryCritical,
808            0xFFFFFFFF => BtmReturnResult::Unknown,
809            seconds => BtmReturnResult::EstimatedRuntime(seconds),
810        }
811    }
812}
813
814impl From<BtmReturnResult> for u32 {
815    fn from(value: BtmReturnResult) -> Self {
816        match value {
817            BtmReturnResult::RateTooHighOrBatteryCritical => 0x00000000,
818            BtmReturnResult::Unknown => 0xFFFFFFFF,
819            BtmReturnResult::EstimatedRuntime(seconds) => seconds,
820        }
821    }
822}
823
824impl From<BtmReturnResult> for [u8; BTM_RETURN_SIZE_BYTES] {
825    fn from(value: BtmReturnResult) -> Self {
826        u32::to_le_bytes(u32::from(value))
827    }
828}
829
830/// BMS: Battery Measurement Sampling Time.
831///
832/// Used to set the sampling interval (in milliseconds) for battery capacity measurements
833/// such as present rate and remaining capacity reported by `_BST`.
834#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
835#[cfg_attr(feature = "defmt", derive(defmt::Format))]
836pub struct Bms {
837    /// Desired sampling time in milliseconds.
838    ///
839    /// Valid range: `0x00000001` to `0xFFFFFFFF`.
840    pub sampling_time_ms: u32,
841}
842
843/// Result of a _BMS operation.
844///
845/// Represents the possible return values from the `_BMS` method.
846#[repr(u32)]
847#[derive(Copy, Clone, PartialEq, Eq)]
848#[cfg_attr(feature = "defmt", derive(defmt::Format))]
849pub enum BmsReturnResult {
850    /// Sampling time was successfully set.
851    Success = 0,
852
853    /// Sampling time is outside the battery's supported range.
854    OutOfRange = 1,
855}
856
857impl From<BmsReturnResult> for u32 {
858    fn from(value: BmsReturnResult) -> Self {
859        match value {
860            BmsReturnResult::Success => 0,
861            BmsReturnResult::OutOfRange => 1,
862        }
863    }
864}
865
866/// BMA: Battery Measurement Averaging Interval.
867///
868/// Used to set the averaging interval (in milliseconds) for battery capacity measurements
869/// such as remaining capacity and present rate reported by `_BST`.
870#[derive(Default, Copy, Clone, PartialEq, Eq)]
871#[cfg_attr(feature = "defmt", derive(defmt::Format))]
872pub struct Bma {
873    /// Desired averaging interval in milliseconds.
874    ///
875    /// Valid range: `0x00000001` to `0xFFFFFFFF`.
876    pub averaging_interval_ms: u32,
877}
878
879/// Result of a _BMA operation.
880///
881/// Represents the possible return values from the `_BMA` method.
882#[repr(u32)]
883#[derive(Copy, Clone, PartialEq, Eq)]
884#[cfg_attr(feature = "defmt", derive(defmt::Format))]
885pub enum BmaReturnResult {
886    /// Averaging interval was successfully set.
887    Success = 0,
888
889    /// Averaging interval is outside the battery's supported range.
890    OutOfRange = 1,
891}
892
893impl From<BmaReturnResult> for u32 {
894    fn from(value: BmaReturnResult) -> Self {
895        match value {
896            BmaReturnResult::Success => 0,
897            BmaReturnResult::OutOfRange => 1,
898        }
899    }
900}
901
902/// Result of a _STA operation.
903///
904/// This object returns the current status of a device, which can be one of the following: enabled, disabled, or removed.
905#[derive(Default, Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, Immutable)]
906#[cfg_attr(feature = "defmt", derive(defmt::Format))]
907pub struct StaReturn(u32);
908bitflags! {
909    impl StaReturn: u32 {
910        /// Set if the device is present.
911        const DEVICE_PRESENT = 1 << 0;
912
913        /// Set if the device is enabled and decoding its resources.
914        const DEVICE_ENABLED = 1 << 1;
915
916        /// Set if the device should be shown in the UI.
917        const DEVICE_SHOULD_SHOWN_UI = 1 << 2;
918
919        /// Set if the device is functioning properly (cleared if device failed its diagnostics).
920        const DEVICE_FUNCTIONING = 1 << 3;
921
922        /// Set if the battery is present.
923        const BATTERY_PRESENT = 1 << 4;
924    }
925}
926
927/// Size of StaReturn in bytes
928pub const STA_RETURN_SIZE_BYTES: usize = 4;