Skip to main content

embedded_batteries/
smart_battery.rs

1use bitfield_struct::bitfield;
2
3use crate::{MilliAmps, MilliAmpsSigned, MilliVolts};
4
5/// Smart Battery error.
6pub trait Error: core::fmt::Debug {
7    /// Convert error to a generic Smart Battery error kind.
8    ///
9    /// By using this method, Smart Battery errors freely defined by HAL implementations
10    /// can be converted to a set of generic Smart Battery errors upon which generic
11    /// code can act.
12    fn kind(&self) -> ErrorKind;
13}
14
15impl Error for core::convert::Infallible {
16    #[inline]
17    fn kind(&self) -> ErrorKind {
18        match *self {}
19    }
20}
21
22/// Smart Battery error kind.
23///
24/// This represents a common set of Smart Battery operation errors. HAL implementations are
25/// free to define more specific or additional error types. However, by providing
26/// a mapping to these common Smart Battery errors, generic code can still react to them.
27#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29#[non_exhaustive]
30pub enum ErrorKind {
31    /// An error occurred on the underlying peripheral supporting the sensor.
32    /// e.g. An I2C bus error occurs for an I2C enabled Smart Battery.
33    /// The original error may contain more information.
34    CommError,
35    /// An error occured and was reported by a read from the BatteryStatus (0x16) register.
36    BatteryStatus(ErrorCode),
37    /// A different error occurred. The original error may contain more information.
38    Other,
39}
40
41impl Error for ErrorKind {
42    #[inline]
43    fn kind(&self) -> ErrorKind {
44        *self
45    }
46}
47
48impl core::fmt::Display for ErrorKind {
49    #[inline]
50    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51        match self {
52            Self::CommError => write!(f, "Error communicating with Smart Battery"),
53            Self::BatteryStatus(_) => write!(
54                f,
55                "Error reported by BatteryService (0x16) register. The original error may contain more information"
56            ),
57            Self::Other => write!(
58                f,
59                "A different error occurred. The original error may contain more information"
60            ),
61        }
62    }
63}
64
65/// Smart Battery error type trait.
66///
67/// This just defines the error type, to be used by the other Smart Battery traits.
68pub trait ErrorType {
69    /// Error type.
70    type Error: Error;
71}
72
73impl<T: ErrorType + ?Sized> ErrorType for &mut T {
74    type Error = T::Error;
75}
76
77/// Depending on the value of the CapacityMode bit, the Smart Battery will use milliamps or centiwatts.
78#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80pub enum CapacityModeValue {
81    /// Unsigned Milliamp or MilliampHour representation, used when CapacityMode bit = 0.
82    MilliAmpUnsigned(u16),
83    /// Unsigned Centiwatt or CentiwattHour representation, used when CapacityMode bit = 1.
84    CentiWattUnsigned(u16),
85}
86
87/// Time is measured in minutes, where 1 minute is 1
88pub type Minutes = u16;
89
90/// Depending on the value of the CapacityMode bit, the Smart Battery will use milliamps or centiwatts.
91/// Signed to represent negative currents and capacities.
92#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
93#[cfg_attr(feature = "defmt", derive(defmt::Format))]
94pub enum CapacityModeSignedValue {
95    /// Signed Milliamp or MilliampHour representation, used when CapacityMode bit = 0.
96    MilliAmpSigned(i16),
97    /// Signed Milliamp or MilliampHour representation, used when CapacityMode bit = 1.
98    CentiWattSigned(i16),
99}
100
101/// Temperature is measured in decikelvins, where 0.1 Kelvin is 1.
102pub type DeciKelvin = u16;
103
104/// Percent, 1% is 1.
105pub type Percent = u8;
106
107/// Cycles, 1 cycle is 1.
108pub type Cycles = u16;
109
110/// Error codes that must be supported by the Smart Battery.
111#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
112#[cfg_attr(feature = "defmt", derive(defmt::Format))]
113#[repr(u8)]
114pub enum ErrorCode {
115    /// The Smart Battery processed the function code
116    /// without detecting any errors.
117    Ok = 0,
118
119    /// The Smart Battery is unable to process the function
120    /// code at this time.
121    Busy = 1,
122
123    /// The Smart Battery detected an attempt to read or
124    /// write to a function code reserved by this version of
125    /// the specification. The Smart Battery detected an
126    /// attempt to access an unsupported optional
127    /// manufacturer function code.
128    ReservedCmd = 2,
129
130    /// The Smart Battery does not support this function
131    /// code which is defined in this version of the
132    /// specification.
133    UnsupportedCmd = 3,
134
135    /// The Smart Battery detected an attempt to write to a
136    /// read only function code.
137    AccessDenied = 4,
138
139    /// The Smart Battery detected a data overflow or
140    /// under flow.
141    UnderOverFlow = 5,
142
143    /// The Smart Battery detected an attempt to write to a
144    /// function code with an incorrect size data block.
145    BadSize = 6,
146
147    /// The Smart Battery detected an unidentifiable error.
148    UnknownError = 7,
149}
150
151impl ErrorCode {
152    const fn into_bits(self) -> u8 {
153        self as _
154    }
155
156    const fn from_bits(value: u8) -> Self {
157        match value {
158            0 => Self::Ok,
159            1 => Self::Busy,
160            2 => Self::ReservedCmd,
161            3 => Self::UnsupportedCmd,
162            4 => Self::AccessDenied,
163            5 => Self::UnderOverFlow,
164            6 => Self::BadSize,
165            _ => Self::UnknownError,
166        }
167    }
168}
169
170impl From<u8> for ErrorCode {
171    fn from(value: u8) -> Self {
172        Self::from_bits(value)
173    }
174}
175
176/// Revision of SBS Spec, used in specification_info().
177#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
178#[cfg_attr(feature = "defmt", derive(defmt::Format))]
179#[repr(u8)]
180pub enum Revision {
181    /// Version 1.0 and 1.1.
182    Version1And1Dot1 = 1,
183}
184
185impl Revision {
186    const fn into_bits(self) -> u8 {
187        self as _
188    }
189
190    const fn from_bits(value: u8) -> Self {
191        match value {
192            1 => Self::Version1And1Dot1,
193            _ => unreachable!(),
194        }
195    }
196}
197
198impl TryFrom<u8> for Revision {
199    type Error = ();
200
201    fn try_from(value: u8) -> Result<Self, Self::Error> {
202        match value {
203            1 => Ok(Self::Version1And1Dot1),
204            _ => Err(()),
205        }
206    }
207}
208
209/// Version of SBS Spec, used in specification_info().
210#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
211#[cfg_attr(feature = "defmt", derive(defmt::Format))]
212#[repr(u8)]
213pub enum Version {
214    /// Reserved.
215    Reserved = 0,
216
217    /// Version 1.0.
218    Version1 = 1,
219
220    /// Version 1.1.
221    Version1Dot1 = 2,
222
223    /// Version 1.1 with optional PEC support.
224    Version1Dot1Pec = 3,
225}
226
227impl Version {
228    const fn into_bits(self) -> u8 {
229        self as _
230    }
231
232    const fn from_bits(value: u8) -> Self {
233        match value {
234            1 => Self::Version1,
235            2 => Self::Version1Dot1,
236            3 => Self::Version1Dot1Pec,
237            _ => Self::Reserved,
238        }
239    }
240}
241
242impl From<u8> for Version {
243    fn from(value: u8) -> Self {
244        Self::from_bits(value)
245    }
246}
247
248/// Return value of the manufacture_date() function (0x1b). The date is packed in the
249/// following fashion: (year-1980) * 512 + month * 32 + day.
250#[bitfield(u16, defmt = cfg(feature = "defmt"))]
251pub struct ManufactureDate {
252    /// 1 - 31 (corresponds to date).
253    #[bits(5)]
254    pub day: usize,
255
256    /// 1 - 12 (corresponds to month number).
257    #[bits(4)]
258    pub month: usize,
259
260    /// 0 - 127 (corresponds to year biased by 1980).
261    /// Add 1980 to the year to get the true year.
262    #[bits(7)]
263    pub year: usize,
264}
265
266/// Return value of the battery_mode() function (0x03). See the SBS spec for more information.
267#[bitfield(u16, defmt = cfg(feature = "defmt"))]
268pub struct BatteryModeFields {
269    /// INTERNAL_CHARGE_CONTROLLER bit set indicates that the battery pack contains its own internal
270    /// charge controller. When the bit is set, this optional function is supported and the
271    /// CHARGE_CONTROLLER_ENABLED bit will be available for activation and control of the actual
272    /// internal charger.
273    #[bits(1, access = RO)]
274    pub internal_charge_controller: bool,
275
276    /// PRIMARY_BATTERY_SUPPORT bit set indicates that the battery pack has the ability to act as either
277    /// the primary or secondary battery in a system. When the bit is set, this function is supported and the
278    /// PRIMARY_BATTERY bit will be available for activation and control of this function
279    #[bits(1, access = RO)]
280    pub primary_battery_support: bool,
281
282    #[bits(5)]
283    __: u8,
284
285    /// CONDITION_FLAG bit set indicates that the battery is requesting a conditioning cycle. A conditioning
286    /// cycle may be requested because of the characteristics of the battery chemistry and/or the electronics in
287    /// combination with the usage pattern.
288    #[bits(1, access = RO)]
289    pub condition_flag: bool,
290
291    /// CHARGE_CONTROLLER_ENABLED bit is set to enable the battery pack’s internal charge controller.
292    /// When this bit is cleared, the internal charge controller is disabled (default). This bit is active only when the
293    /// INTERNAL_CHARGE_CONTROLLER bit is set, indicating that this function is supported. The status of
294    /// a battery pack’s internal charge controller can be determined by reading this bit
295    pub charge_controller_enabled: bool,
296
297    /// PRIMARY_BATTERY bit is set to enable a battery to operate as the primary battery in a system. When
298    /// this bit is cleared, the battery operates in a secondary role (default). This bit is active only when the
299    /// PRIMARY_BATTERY_SUPPORT bit is set. The role that the battery is playing can be determined by
300    /// reading this bit.
301    pub primary_battery: bool,
302
303    #[bits(3)]
304    __: u8,
305
306    /// ALARM_MODE bit is set to disable the Smart Battery's ability to master the SMBus and send
307    /// AlarmWarning() messages to the SMBus Host and the Smart Battery Charger. When set, the Smart Battery
308    /// will NOT master the SMBus and AlarmWarning() messages will NOT be sent to the SMBus Host and the
309    /// Smart Battery Charger for a period of no more than 65 seconds and no less than 45 seconds. When
310    /// cleared (default), the Smart Battery WILL send the AlarmWarning() messages to the SMBus Host and the
311    /// Smart Battery Charger any time an alarm condition is detected. (See also Section 5.4 of the SBS spec
312    /// for a more detailed explanation of alarm conditions and operations.)
313    ///
314    /// When the ALARM_MODE bit is set, the system assumes responsibility for detecting and
315    /// responding to Smart Battery alarms by reading the BatteryStatus() to determine if any of the alarm
316    /// bit flags are set. At a minimum, this requires the system to poll the Smart Battery BatteryStatus()
317    /// every 10 seconds at all times the SMBus is active. The system is expected to take appropriate
318    /// action.
319    ///
320    /// The ALARM_MODE bit is automatically cleared by the Smart Battery electronics every 60
321    /// seconds so that any accidental activation of this mode will not be persistent. A SMBus Host which
322    /// does not want the Smart Battery to be a master on the SMBus must therefore continually set this
323    /// bit at least once per 45 seconds to keep the ALARM_MODE bit set
324    pub alarm_mode: bool,
325
326    /// CHARGER_MODE bit enables or disables the Smart Battery's transmission of ChargingCurrent() and
327    /// ChargingVoltage() messages to the Smart Battery Charger. When set, the Smart Battery will NOT transmit
328    /// ChargingCurrent() and ChargingVoltage() values to the Smart Battery Charger. When cleared, the Smart
329    /// Battery will transmit the ChargingCurrent() and ChargingVoltage() values to the Smart Battery Charger
330    /// when charging is desired. (See Section 5.3 of the SBS spec for a more detailed explanation.)
331    ///
332    /// When the CHARGER_MODE bit is set, the system assumes responsibility for safely charging the
333    /// Smart Battery. At a minimum, this requires the system to poll the Smart Battery for
334    /// ChargingVoltage() and ChargingCurrent() at the same rate the Smart Battery would normally send
335    /// these charging messages to the Smart Battery Charger (e.g. every 5 seconds to 60 seconds.)
336    /// The CHARGER_MODE bit allows a SMBus Host or Smart Battery Charger to disable the Smart
337    /// Battery's broadcast of the ChargingCurrent() and ChargingVoltage().
338    ///
339    /// The use of CHARGER_MODE does NOT affect the use of ALARM_MODE. If only
340    /// CHARGER_MODE bit is set, AlarmWarning messages relating to charging will still occur and be
341    /// broadcast the Smart Battery Charger and SMBus Host. (See ALARM_MODE bit flag definition.)
342    pub charger_mode: bool,
343
344    /// CAPACITY_MODE bit indicates if capacity information will be reported in mA/mAh or 10mW/10mWh.
345    /// When set, the capacity information will be reported in 10mW/10mWh as appropriate. When cleared, the
346    /// capacity information will be reported in mA/mAh as appropriate.
347    ///
348    /// After changing the CAPACITY_MODE bit, all related values (such as AtRate()) should be re-written while
349    /// the new mode is active. This is because changes made to the CAPACITY_MODE bit do not retroactively
350    /// affect values which may have been previously written in another mode. For example, a value written to
351    /// AtRate() while the CAPACITY_MODE bit was 0 will cause AtRate calculations to be made using the mAH
352    /// value. Changing the CAPACITY_MODE bit to 1 will not automatically cause all the AtRate calculations to
353    /// be re-calculated using the 10mWH equivalent, although this is permitted, it is not required.
354    pub capacity_mode: bool,
355}
356
357/// Return value of the battery_status() function (0x16). See the SBS spec for more information.
358#[bitfield(u16, defmt = cfg(feature = "defmt"))]
359#[derive(Eq, PartialEq, Ord, PartialOrd, Hash)]
360pub struct BatteryStatusFields {
361    /// Error codes from the Smart Battery. See ErrorCode enum fields for detailed documentation on what each
362    /// error code entails.
363    #[bits(4)]
364    pub error_code: ErrorCode,
365
366    /// FULLY_DISCHARGED bit is set when the Smart Battery determines that it has supplied all the charge it
367    /// can. Discharge should be stopped soon.
368    ///
369    /// This bit will be cleared when the RelativeStateOfCharge() is
370    /// greater than or equal to 20%. This status bit may be set prior to the
371    /// ‘TERMINATE_DISCHARGE_ALARM’ as an early or first level warning of end of battery charge.
372    pub fully_discharged: bool,
373
374    /// FULLY_CHARGED bit is set when the Smart Battery determines that has reached a full charge point.
375    ///
376    ///  This bit will be cleared when the battery may want to be charged again, which is chemistry and
377    /// manufacturer specific.
378    pub fully_charged: bool,
379
380    /// DISCHARGING bit is set when the Smart Battery determines that it is not being charged.
381    /// This bit will be cleared when the battery detects that it is being charged.
382    pub discharging: bool,
383
384    /// INITIALIZED bit is SET when the Smart Battery electronics are calibrated or configured for the first time,
385    /// typically at the time of battery pack assembly or manufacture.
386    ///
387    /// It will be cleared when the battery detects that this calibration or configuration data has been lost or
388    /// altered and a significant degradation in accuracy is possible.
389    ///
390    /// The INITIALIZED status bit is the second and more serious signal from the Smart Battery that it has
391    /// perhaps lost the ability to determine the present state-of-charge. As a result other data values required by
392    /// this specification may be inaccurate.
393    ///
394    /// (The first signal from the Smart Battery is typically the CONDITION_FLAG found in the BatteryMode()
395    /// register.)
396    pub initialized: bool,
397
398    /// REMAINING_TIME_ALARM bit is set when the Smart Battery detects that the estimated remaining
399    /// time at the present discharge rate represented by the value in AverageTimeToEmpty() is less than that set by
400    /// the RemainingTimeAlarm() function.
401    ///
402    /// This bit will be cleared when either the value set by the RemainingTimeAlarm() function is lower than the
403    /// AverageTimeToEmpty() or when the AverageTimeToEmpty() is increased by charging the Smart Battery
404    /// or decreasing the discharge rate.
405    ///
406    /// (NOTE: This Alarm bit can be disabled by writing zero to the RemainingTimeAlarm() value.)
407    pub remaining_time_alarm: bool,
408
409    /// REMAINING_CAPACITY_ALARM bit is set when the Smart Battery detects that its
410    /// RemainingCapacity() is less than that set by the RemainingCapacityAlarm() function.
411    ///
412    /// This bit will be cleared when either the value set by the RemainingCapacityAlarm() function is lower than the
413    /// RemainingCapacity() or when the RemainingCapacity() is increased by charging the Smart Battery.
414    ///
415    /// (NOTE: This Alarm bit can be disabled by writing zero to the RemainingCapacityAlarm() value.)
416    pub remaining_capacity_alarm: bool,
417
418    __: bool,
419
420    /// TERMINATE_DISCHARGE_ALARM bit is set when the Smart Battery determines that it has supplied
421    /// all the charge it can at the present discharge rate. Discharge should be stopped as soon as possible.
422    ///
423    /// This bit will be cleared when the Smart Battery detects that the discharge has stopped or that the rate
424    /// has lessened.
425    /// (Note that since this is rate dependent, it may occur at a high discharge rate and disappear when the
426    /// discharge rate has slowed such that the Smart Battery can continue to be discharged at the lower rate.)
427    pub terminate_discharge_alarm: bool,
428
429    /// OVER_TEMP_ALARM bit will be set when the Smart Battery detects that its internal temperature is
430    /// greater than a preset allowable limit. When this bit is set, charging should be stopped as soon as possible.
431    /// The Smart Battery may not yet be in a Fully Charged state.
432    /// Charging is effectively ‘suspended,’ usually temporarily. Charging may resume when the Smart Battery
433    /// detects that its internal temperature is below a preset limit to allow charging again. (This limit may be a
434    /// different value than what caused the original alarm.)
435    ///
436    /// This bit is cleared when the internal temperature has dropped below an acceptable limit, which may or may
437    /// not be the original alarm threshold (although charging may not always resume at this point.)
438    pub over_temp_alarm: bool,
439
440    __: bool,
441
442    /// TERMINATE_CHARGE_ALARM bit is set when charging should be stopped but the Smart Battery may
443    /// not yet be in a Fully Charged state. Charging is effectively ‘suspended,’ usually temporarily. Charging may
444    /// resume when the Smart Battery detects that its charging parameters are back in allowable ranges and
445    /// ChargingVoltage() and ChargingCurrent() values are both returned to non-zero values.
446    ///
447    /// This bit is cleared when the Smart Battery detects that it is no longer being charged.
448    pub terminate_charge_alarm: bool,
449
450    /// OVER_CHARGED_ALARM bit is set whenever the Smart Battery detects that it is being charged
451    /// beyond a Fully Charged state. When this bit is set, charging should be completely stopped as soon as
452    /// possible. Charging further can result in permanent damage to the battery.
453    ///
454    /// This bit will be cleared when the Smart Battery detects that it is no longer being charged. Charging should
455    /// not automatically restart.
456    pub over_charged_alarm: bool,
457}
458
459/// Return value of the specification_info() function (0x1a). See the SBS spec for more information.
460#[bitfield(u16, defmt = cfg(feature = "defmt"))]
461pub struct SpecificationInfoFields {
462    /// Revision of the SBS spec supported by this Smart Battery.
463    /// See Revision enum fields for detailed documentation.
464    #[bits(4)]
465    pub revision: Revision,
466
467    /// Version of the SBS spec supported by this Smart Battery.
468    /// See Version enum fields for detailed documentation.
469    #[bits(4)]
470    pub version: Version,
471
472    /// 0 - 3 (multiplies voltages* by 10 ^ VScale).
473    #[bits(4)]
474    pub v_scale: u8,
475
476    /// 0 - 3 (multiplies currents* and capacities by 10 ^ IPScale).
477    #[bits(4)]
478    pub ip_scale: u8,
479}
480
481/// Blocking Smart Battery methods.
482pub trait SmartBattery: ErrorType {
483    /// 0x01
484    ///
485    /// Gets the Low Capacity alarm threshold value. Whenever the RemainingCapacity() falls below the
486    /// Low Capacity value, the Smart Battery sends AlarmWarning() messages to the SMBus Host with the
487    /// REMAINING_CAPACITY_ALARM bit set. A Low Capacity value of 0 disables this alarm.
488    /// (If the ALARM_MODE bit is set in BatteryMode() then the AlarmWarning() message is disabled for a set
489    /// period of time. See the BatteryMode() function for further information.)
490    ///
491    /// The Low Capacity value is set to 10% of design capacity at time of manufacture. The Low Capacity value
492    /// will remain unchanged until altered by the RemainingCapacityAlarm() function. The Low Capacity value
493    /// may be expressed in either capacity (mAh) or power (10mWh) depending on the setting of the
494    /// BatteryMode()'s CAPACITY_MODE bit (see BatteryMode()).
495    fn remaining_capacity_alarm(&mut self) -> Result<CapacityModeValue, Self::Error>;
496
497    /// 0x01
498    ///
499    /// Sets the Low Capacity alarm threshold value. Whenever the RemainingCapacity() falls below the
500    /// Low Capacity value, the Smart Battery sends AlarmWarning() messages to the SMBus Host with the
501    /// REMAINING_CAPACITY_ALARM bit set. A Low Capacity value of 0 disables this alarm.
502    /// (If the ALARM_MODE bit is set in BatteryMode() then the AlarmWarning() message is disabled for a set
503    /// period of time. See the BatteryMode() function for further information.)
504    ///
505    /// The Low Capacity value is set to 10% of design capacity at time of manufacture. The Low Capacity value
506    /// will remain unchanged until altered by the RemainingCapacityAlarm() function. The Low Capacity value
507    /// may be expressed in either capacity (mAh) or power (10mWh) depending on the setting of the
508    /// BatteryMode()'s CAPACITY_MODE bit (see BatteryMode()).
509    fn set_remaining_capacity_alarm(&mut self, capacity: CapacityModeValue) -> Result<(), Self::Error>;
510
511    /// 0x02
512    ///
513    /// Gets the Remaining Time alarm value. Whenever the AverageTimeToEmpty() falls below the
514    /// Remaining Time value, the Smart Battery sends AlarmWarning() messages to the SMBus Host with the
515    /// REMAINING_TIME_ALARM bit set. A Remaining Time value of 0 effectively disables this alarm.
516    /// (If the ALARM_MODE bit is set in BatteryMode() then the AlarmWarning() message is disabled for a set
517    /// period of time. See the BatteryMode() function for further information.)
518    ///
519    /// The Remaining Time value is set to 10 minutes at time of manufacture. The Remaining Time value will
520    /// remain unchanged until altered by the RemainingTimeAlarm() function.
521    fn remaining_time_alarm(&mut self) -> Result<Minutes, Self::Error>;
522
523    /// 0x02
524    ///
525    /// Sets the Remaining Time alarm value. Whenever the AverageTimeToEmpty() falls below the
526    /// Remaining Time value, the Smart Battery sends AlarmWarning() messages to the SMBus Host with the
527    /// REMAINING_TIME_ALARM bit set. A Remaining Time value of 0 effectively disables this alarm.
528    /// (If the ALARM_MODE bit is set in BatteryMode() then the AlarmWarning() message is disabled for a set
529    /// period of time. See the BatteryMode() function for further information.)
530    ///
531    /// The Remaining Time value is set to 10 minutes at time of manufacture. The Remaining Time value will
532    /// remain unchanged until altered by the RemainingTimeAlarm() function.
533    fn set_remaining_time_alarm(&mut self, time: Minutes) -> Result<(), Self::Error>;
534
535    /// 0x03
536    ///
537    /// This function reads the various battery operational modes and reports the battery’s capabilities, modes,
538    /// and flags minor conditions requiring attention.
539    ///
540    /// See the SBS specification for detailed documentation.
541    fn battery_mode(&mut self) -> Result<BatteryModeFields, Self::Error>;
542
543    /// 0x03
544    ///
545    /// This function sets the various battery operational modes and reports the battery’s capabilities, modes,
546    /// and flags minor conditions requiring attention. Note that not all fields are writeable.
547    ///
548    /// See the SBS specification for detailed documentation.
549    fn set_battery_mode(&mut self, flags: BatteryModeFields) -> Result<(), Self::Error>;
550
551    /// 0x04
552    ///
553    /// The AtRate() function is the first half of a two-function call-set used to set the AtRate value used in
554    /// calculations made by the AtRateTimeToFull(), AtRateTimeToEmpty(), and AtRateOK() functions.
555    ///
556    /// The AtRate value may be expressed in either current (mA) or power (10mW) depending on the setting of the
557    /// BatteryMode()'s CAPACITY_MODE bit. (Configuration of the CAPACITY_MODE bit will alter the
558    /// calculation of AtRate functions. Changing the state of CAPACITY_MODE may require a re-write to the
559    /// AtRate() function using the appropriate units.)
560    fn at_rate(&mut self) -> Result<CapacityModeSignedValue, Self::Error>;
561
562    /// 0x04
563    ///
564    /// The AtRate() function is the first half of a two-function call-set used to set the AtRate value used in
565    /// calculations made by the AtRateTimeToFull(), AtRateTimeToEmpty(), and AtRateOK() functions.
566    ///
567    /// The AtRate value may be expressed in either current (mA) or power (10mW) depending on the setting of the
568    /// BatteryMode()'s CAPACITY_MODE bit. (Configuration of the CAPACITY_MODE bit will alter the
569    /// calculation of AtRate functions. Changing the state of CAPACITY_MODE may require a re-write to the
570    /// AtRate() function using the appropriate units.)
571    fn set_at_rate(&mut self, rate: CapacityModeSignedValue) -> Result<(), Self::Error>;
572
573    /// 0x05
574    ///
575    /// Returns the predicted remaining time to fully charge the battery at the previously written AtRate value in mA.
576    ///
577    /// Note: This function is only required to return a value when the CAPACITY_MODE bit is cleared and the
578    /// AtRate() value is written in mA units. If the CAPACITY_MODE bit is set, then AtRateTimeToFull() may
579    /// return 65535 to indicate over-range and return an error code indicating overflow. Alternately, this function
580    /// may return a remaining time to full based on a 10 mW value in AtRate().
581    fn at_rate_time_to_full(&mut self) -> Result<Minutes, Self::Error>;
582
583    /// 0x06
584    ///
585    /// Returns the predicted remaining operating time if the battery is discharged at the previously written AtRate
586    /// value. (Result will depend on the setting of CAPACITY_MODE bit.)
587    fn at_rate_time_to_empty(&mut self) -> Result<Minutes, Self::Error>;
588
589    /// 0x07
590    ///
591    /// Returns a Boolean value that indicates whether or not the battery can deliver the previously written AtRate
592    /// value of additional energy for 10 seconds (Boolean). If the AtRate value is zero or positive, the
593    /// AtRateOK() function will ALWAYS return true. Result may depend on the setting of CAPACITY_MODE
594    /// bit.
595    fn at_rate_ok(&mut self) -> Result<bool, Self::Error>;
596
597    /// 0x08
598    ///
599    /// Returns the cell-pack's internal temperature (°K). The actual operational temperature range will be defined
600    /// at a pack level by a particular manufacturer.
601    fn temperature(&mut self) -> Result<DeciKelvin, Self::Error>;
602
603    /// 0x09
604    ///
605    /// Returns the cell-pack voltage (mV).
606    fn voltage(&mut self) -> Result<MilliVolts, Self::Error>;
607
608    /// 0x0A
609    ///
610    /// Returns the current being supplied (or accepted) through the battery's terminals (mA).
611    fn current(&mut self) -> Result<MilliAmpsSigned, Self::Error>;
612
613    /// 0x0B
614    ///
615    /// Returns a one-minute rolling average based on the current being supplied (or accepted) through the battery's
616    /// terminals (mA). The AverageCurrent() function is expected to return meaningful values during the battery's
617    /// first minute of operation.
618    fn average_current(&mut self) -> Result<MilliAmpsSigned, Self::Error>;
619
620    /// 0x0C
621    ///
622    /// Returns the expected margin of error (%) in the state of charge calculation. For example, when MaxError()
623    /// returns 10% and RelativeStateOfCharge() returns 50%, the Relative StateOfCharge() is actually between 50
624    /// and 60%. The MaxError() of a battery is expected to increase until the Smart Battery identifies a condition
625    /// that will give it higher confidence in its own accuracy. For example, when a Smart Battery senses that it has
626    /// been fully charged from a fully discharged state, it may use that information to reset or partially reset
627    /// MaxError(). The Smart Battery can signal when MaxError() has become too high by setting the
628    /// CONDITION_FLAG bit in BatteryMode().
629    fn max_error(&mut self) -> Result<Percent, Self::Error>;
630
631    /// 0x0D
632    ///
633    /// Returns the predicted remaining battery capacity expressed as a percentage of FullChargeCapacity() (%).
634    fn relative_state_of_charge(&mut self) -> Result<Percent, Self::Error>;
635
636    /// 0x0E
637    ///
638    /// Returns the predicted remaining battery capacity expressed as a percentage of DesignCapacity() (%).
639    ///
640    /// Note that AbsoluteStateOfCharge() can return values greater than 100%.
641    fn absolute_state_of_charge(&mut self) -> Result<Percent, Self::Error>;
642
643    /// 0x0F
644    ///
645    /// Returns the predicted remaining battery capacity. The RemainingCapacity() capacity value is expressed in
646    /// either current (mAh at a C/5 discharge rate) or power (10mWh at a P/5 discharge rate) depending on the
647    /// setting of the BatteryMode()'s CAPACITY_MODE bit.
648    fn remaining_capacity(&mut self) -> Result<CapacityModeValue, Self::Error>;
649
650    /// 0x10
651    ///
652    /// Returns the predicted pack capacity when it is fully charged. The FullChargeCapacity() value is expressed
653    /// in either current (mAh at a C/5 discharge rate) or power (10mWh at a P/5 discharge rate) depending on the
654    /// setting of the BatteryMode()'s CAPACITY_MODE bit.
655    fn full_charge_capacity(&mut self) -> Result<CapacityModeValue, Self::Error>;
656
657    /// 0x11
658    ///
659    /// Returns the predicted remaining battery life at the present rate of discharge (minutes). The
660    /// RunTimeToEmpty() value is calculated based on either current or power depending on the setting of the
661    /// BatteryMode()'s CAPACITY_MODE bit. This is an important distinction because use of the wrong
662    /// calculation mode may result in inaccurate return values.
663    ///
664    /// 65,535 indicates battery is not being discharged.
665    fn run_time_to_empty(&mut self) -> Result<Minutes, Self::Error>;
666
667    /// 0x12
668    ///
669    /// Returns a one-minute rolling average of the predicted remaining battery life (minutes). The
670    /// AverageTimeToEmpty() value is calculated based on either current or power depending on the setting of
671    /// the BatteryMode()'s CAPACITY_MODE bit. This is an important distinction because use of the wrong
672    /// calculation mode may result in inaccurate return values.
673    ///
674    /// 65,535 indicates battery is not being discharged.
675    fn average_time_to_empty(&mut self) -> Result<Minutes, Self::Error>;
676
677    /// 0x13
678    ///
679    /// Returns a one minute rolling average of the predicted remaining time until the Smart Battery reaches full
680    /// charge (minutes).
681    ///
682    /// 65,535 indicates the battery is not being charged.
683    fn average_time_to_full(&mut self) -> Result<Minutes, Self::Error>;
684
685    /// 0x14
686    ///
687    /// The ChargingCurrent() function sets the maximum current that a Smart Battery Charger may
688    /// deliver to the Smart Battery. In combination with the ChargingVoltage() function and the
689    /// battery's internal impedance, this function determines the Smart Battery Charger's desired
690    /// operating point. Together, these functions permit a Smart Battery Charger to dynamically adjust
691    /// its charging profile (current/voltage) for optimal charge.
692    ///
693    /// The Smart Battery can turn off the Smart Battery Charger by returning a value of 0 for this function.
694    /// Smart Battery Chargers may be operated as a constant voltage source above their
695    /// maximum regulated current range by returning a ChargingCurrent() value of 65535.
696    fn charging_current(&mut self) -> Result<MilliAmps, Self::Error>;
697
698    /// 0x15
699    ///
700    /// The ChargingVoltage() function sets the maximum voltage that a Smart Battery Charger may
701    /// deliver to the Smart Battery. In combination with the ChargingCurrent() function and the
702    /// battery's internal impedance, this function determines the Smart Battery Charger's desired
703    /// operating point. Together, these functions permit a Smart Battery Charger to dynamically adjust
704    /// its charging profile (current/voltage) for optimal charge.
705    ///
706    /// The Smart Battery can turn off the Smart Battery Charger by returning a value of 0 for this function.
707    /// Smart Battery Chargers may be operated as a constant current source above their
708    /// maximum regulated voltage range by returning a ChargingVoltage() value of 65535.
709    fn charging_voltage(&mut self) -> Result<MilliVolts, Self::Error>;
710
711    /// 0x16
712    ///
713    /// Returns the Smart Battery's status word which contains Alarm and Status bit flags. Some of the
714    /// BatteryStatus() flags (REMAINING_CAPACITY_ALARM and REMAINING_TIME_ALARM) are
715    /// calculated based on either current or power depending on the setting of the BatteryMode()'s
716    /// CAPACITY_MODE bit. This is important because use of the wrong calculation mode may result in an
717    /// inaccurate alarm.
718    fn battery_status(&mut self) -> Result<BatteryStatusFields, Self::Error>;
719
720    /// 0x17
721    ///
722    /// Returns the number of cycles the battery has experienced. A cycle is defined as:
723    ///
724    /// An amount of discharge approximately equal to the value of DesignCapacity.
725    fn cycle_count(&mut self) -> Result<Cycles, Self::Error>;
726
727    /// 0x18
728    ///
729    /// Returns the theoretical capacity of a new pack. The DesignCapacity() value is expressed in either current
730    /// (mAh at a C/5 discharge rate) or power (10mWh at a P/5 discharge rate) depending on the setting of the
731    /// BatteryMode()'s CAPACITY_MODE bit.
732    fn design_capacity(&mut self) -> Result<CapacityModeValue, Self::Error>;
733
734    /// 0x19
735    ///
736    /// Returns the theoretical voltage of a new pack (mV).
737    fn design_voltage(&mut self) -> Result<MilliVolts, Self::Error>;
738
739    /// 0x1A
740    ///
741    /// Returns the version number of the Smart Battery specification the battery pack supports, as well as voltage
742    /// and current and capacity scaling information in a packed unsigned integer. Power scaling is the product of
743    /// the voltage scaling times the current scaling.
744    /// These scaling functions do NOT affect ChargingCurrent() and ChargingVoltage() values.
745    /// A Smart Battery Charger cannot be assumed to know this scaling information. (However, a ‘Level 3’
746    /// or ‘Host Controlled’ Smart Battery Charger may read this value if required for specific
747    /// applications.)
748    fn specification_info(&mut self) -> Result<SpecificationInfoFields, Self::Error>;
749
750    /// 0x1B
751    ///
752    /// This function returns the date the cell pack was manufactured.
753    fn manufacture_date(&mut self) -> Result<ManufactureDate, Self::Error>;
754
755    /// 0x1C
756    ///
757    /// This function is used to return a serial number. This number when combined with the ManufacturerName(),
758    /// the DeviceName(), and the ManufactureDate() will uniquely identify the battery (unsigned int).
759    fn serial_number(&mut self) -> Result<u16, Self::Error>;
760
761    /// 0x20
762    ///
763    /// This function accepts a mutable buffer of u8s and returns it filled with a **null-terminated** character array
764    /// containing the battery's manufacturer's name. For example, "MyBattCo\0" would identify the Smart Battery's
765    /// manufacturer as MyBattCo.
766    fn manufacturer_name(&mut self, name: &mut [u8]) -> Result<(), Self::Error>;
767
768    /// 0x21
769    ///
770    /// This function accepts a mutable buffer of u8s and returns it filled with a **null-terminated** character array
771    /// that contains the battery's name. For example, a DeviceName() of "MBC101\0" would indicate that
772    /// the battery is a model MBC101.
773    fn device_name(&mut self, name: &mut [u8]) -> Result<(), Self::Error>;
774
775    /// 0x22
776    ///
777    /// This function accepts a mutable buffer of u8s and returns it filled with a **null-terminated** character array
778    /// that contains the battery's chemistry. For example, if the DeviceChemistry() function returns "NiMH\0",
779    /// the battery pack would contain nickel metal hydride cells.
780    fn device_chemistry(&mut self, chemistry: &mut [u8]) -> Result<(), Self::Error>;
781}
782
783#[macro_export]
784/// Helper macro to implement `SmartBattery` and `ErrorType` for wrapper types that just call an inner type's SmartBattery methods.
785///
786/// This macro generates implementations of both the `SmartBattery` trait and the `ErrorType` trait
787/// for a wrapper type that contains an inner type implementing `SmartBattery`. Each trait method
788/// delegates to the corresponding inner type method, automatically converting errors from the inner
789/// type to the wrapper's error type.
790///
791/// # Requirements
792///
793/// - `From<inner::Error>` must be implemented for the wrapper error type to enable error conversion
794/// - The wrapper error type must implement the `Error` trait
795///
796/// # Parameters
797///
798/// - `$wrapper`: The wrapper type that will implement `SmartBattery` and `ErrorType`
799/// - `$inner`: The field name within the wrapper that contains the inner `SmartBattery` implementation
800/// - `$error`: The error type associated with the wrapper
801///
802/// # Example
803///
804/// ```ignore
805/// struct BatteryWrapper {
806///     driver: DriverImplingSmartBattery,
807/// }
808///
809/// impl From<DriverImplingSmartBatteryError> for WrapperError {
810///     fn from(err: DriverImplingSmartBatteryError) -> Self {
811///         WrapperError::BatteryError(err)
812///     }
813/// }
814///
815/// impl_smart_battery_for_wrapper_type!(BatteryWrapper, driver, WrapperError);
816/// ```
817macro_rules! impl_smart_battery_for_wrapper_type {
818    ($wrapper:ty, $inner:ident, $error:ty) => {
819        impl embedded_batteries::smart_battery::ErrorType for $wrapper {
820            type Error = $error;
821        }
822
823        #[allow(clippy::needless_question_mark)]
824        impl embedded_batteries::smart_battery::SmartBattery for $wrapper {
825            fn remaining_capacity_alarm(
826                &mut self,
827            ) -> Result<embedded_batteries::smart_battery::CapacityModeValue, Self::Error> {
828                Ok(self.$inner.remaining_capacity_alarm()?)
829            }
830
831            fn set_remaining_capacity_alarm(
832                &mut self,
833                capacity: embedded_batteries::smart_battery::CapacityModeValue,
834            ) -> Result<(), Self::Error> {
835                Ok(self.$inner.set_remaining_capacity_alarm(capacity)?)
836            }
837
838            fn remaining_time_alarm(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
839                Ok(self.$inner.remaining_time_alarm()?)
840            }
841
842            fn set_remaining_time_alarm(
843                &mut self,
844                time: embedded_batteries::smart_battery::Minutes,
845            ) -> Result<(), Self::Error> {
846                Ok(self.$inner.set_remaining_time_alarm(time)?)
847            }
848
849            fn battery_mode(&mut self) -> Result<embedded_batteries::smart_battery::BatteryModeFields, Self::Error> {
850                Ok(self.$inner.battery_mode()?)
851            }
852
853            fn set_battery_mode(
854                &mut self,
855                flags: embedded_batteries::smart_battery::BatteryModeFields,
856            ) -> Result<(), Self::Error> {
857                Ok(self.$inner.set_battery_mode(flags)?)
858            }
859
860            fn at_rate(&mut self) -> Result<embedded_batteries::smart_battery::CapacityModeSignedValue, Self::Error> {
861                Ok(self.$inner.at_rate()?)
862            }
863
864            fn set_at_rate(
865                &mut self,
866                rate: embedded_batteries::smart_battery::CapacityModeSignedValue,
867            ) -> Result<(), Self::Error> {
868                Ok(self.$inner.set_at_rate(rate)?)
869            }
870
871            fn at_rate_time_to_full(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
872                Ok(self.$inner.at_rate_time_to_full()?)
873            }
874
875            fn at_rate_time_to_empty(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
876                Ok(self.$inner.at_rate_time_to_empty()?)
877            }
878
879            fn at_rate_ok(&mut self) -> Result<bool, Self::Error> {
880                Ok(self.$inner.at_rate_ok()?)
881            }
882
883            fn temperature(&mut self) -> Result<embedded_batteries::smart_battery::DeciKelvin, Self::Error> {
884                Ok(self.$inner.temperature()?)
885            }
886
887            fn voltage(&mut self) -> Result<embedded_batteries::charger::MilliVolts, Self::Error> {
888                Ok(self.$inner.voltage()?)
889            }
890
891            fn current(&mut self) -> Result<embedded_batteries::smart_battery::MilliAmpsSigned, Self::Error> {
892                Ok(self.$inner.current()?)
893            }
894
895            fn average_current(&mut self) -> Result<embedded_batteries::smart_battery::MilliAmpsSigned, Self::Error> {
896                Ok(self.$inner.average_current()?)
897            }
898
899            fn max_error(&mut self) -> Result<embedded_batteries::smart_battery::Percent, Self::Error> {
900                Ok(self.$inner.max_error()?)
901            }
902
903            fn relative_state_of_charge(&mut self) -> Result<embedded_batteries::smart_battery::Percent, Self::Error> {
904                Ok(self.$inner.relative_state_of_charge()?)
905            }
906
907            fn absolute_state_of_charge(&mut self) -> Result<embedded_batteries::smart_battery::Percent, Self::Error> {
908                Ok(self.$inner.absolute_state_of_charge()?)
909            }
910
911            fn remaining_capacity(
912                &mut self,
913            ) -> Result<embedded_batteries::smart_battery::CapacityModeValue, Self::Error> {
914                Ok(self.$inner.remaining_capacity()?)
915            }
916
917            fn full_charge_capacity(
918                &mut self,
919            ) -> Result<embedded_batteries::smart_battery::CapacityModeValue, Self::Error> {
920                Ok(self.$inner.full_charge_capacity()?)
921            }
922
923            fn run_time_to_empty(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
924                Ok(self.$inner.run_time_to_empty()?)
925            }
926
927            fn average_time_to_empty(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
928                Ok(self.$inner.average_time_to_empty()?)
929            }
930
931            fn average_time_to_full(&mut self) -> Result<embedded_batteries::smart_battery::Minutes, Self::Error> {
932                Ok(self.$inner.average_time_to_full()?)
933            }
934
935            fn charging_current(&mut self) -> Result<embedded_batteries::charger::MilliAmps, Self::Error> {
936                Ok(self.$inner.charging_current()?)
937            }
938
939            fn charging_voltage(&mut self) -> Result<embedded_batteries::charger::MilliVolts, Self::Error> {
940                Ok(self.$inner.charging_voltage()?)
941            }
942
943            fn battery_status(
944                &mut self,
945            ) -> Result<embedded_batteries::smart_battery::BatteryStatusFields, Self::Error> {
946                Ok(self.$inner.battery_status()?)
947            }
948
949            fn cycle_count(&mut self) -> Result<embedded_batteries::smart_battery::Cycles, Self::Error> {
950                Ok(self.$inner.cycle_count()?)
951            }
952
953            fn design_capacity(&mut self) -> Result<embedded_batteries::smart_battery::CapacityModeValue, Self::Error> {
954                Ok(self.$inner.design_capacity()?)
955            }
956
957            fn design_voltage(&mut self) -> Result<embedded_batteries::charger::MilliVolts, Self::Error> {
958                Ok(self.$inner.design_voltage()?)
959            }
960
961            fn specification_info(
962                &mut self,
963            ) -> Result<embedded_batteries::smart_battery::SpecificationInfoFields, Self::Error> {
964                Ok(self.$inner.specification_info()?)
965            }
966
967            fn manufacture_date(&mut self) -> Result<embedded_batteries::smart_battery::ManufactureDate, Self::Error> {
968                Ok(self.$inner.manufacture_date()?)
969            }
970
971            fn serial_number(&mut self) -> Result<u16, Self::Error> {
972                Ok(self.$inner.serial_number()?)
973            }
974
975            fn manufacturer_name(&mut self, name: &mut [u8]) -> Result<(), Self::Error> {
976                Ok(self.$inner.manufacturer_name(name)?)
977            }
978
979            fn device_name(&mut self, name: &mut [u8]) -> Result<(), Self::Error> {
980                Ok(self.$inner.device_name(name)?)
981            }
982
983            fn device_chemistry(&mut self, chemistry: &mut [u8]) -> Result<(), Self::Error> {
984                Ok(self.$inner.device_chemistry(chemistry)?)
985            }
986        }
987    };
988}