use crate::bmap::{
enums::{status, FunctionBlock, Operator},
packet::{BmapPacket, PacketError},
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BatteryInfo {
pub percentage: u8,
pub remaining_minutes: Option<u16>,
pub component_id: u8,
}
pub fn query() -> BmapPacket {
BmapPacket::new(FunctionBlock::Status, status::BATTERY_LEVEL, Operator::Get, vec![])
}
pub fn parse_response(packet: &BmapPacket) -> Result<Vec<BatteryInfo>, PacketError> {
if packet.function_block != FunctionBlock::Status || packet.function != status::BATTERY_LEVEL {
return Err(PacketError::InvalidFunctionBlock(packet.function_block.into()));
}
let payload = &packet.payload;
if payload.is_empty() {
return Ok(vec![]);
}
let mut results = Vec::new();
if payload.len() < 4 {
results.push(BatteryInfo {
percentage: payload[0],
remaining_minutes: None,
component_id: payload.get(3).copied().unwrap_or(0),
});
} else {
let mut offset = 0;
while offset + 4 <= payload.len() {
let percentage = payload[offset];
let remaining_raw =
((payload[offset + 1] as u16) << 8) | (payload[offset + 2] as u16);
let remaining_minutes = if remaining_raw == 0xFFFF {
None
} else {
Some(remaining_raw)
};
let component_id = payload[offset + 3];
results.push(BatteryInfo {
percentage,
remaining_minutes,
component_id,
});
offset += 4;
}
}
Ok(results)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn query_packet() {
let pkt = query();
assert_eq!(pkt.to_bytes(), vec![0x02, 0x02, 0x01, 0x00]);
}
#[test]
fn parse_single_battery() {
let pkt = BmapPacket::new(
FunctionBlock::Status,
status::BATTERY_LEVEL,
Operator::Status,
vec![85, 0x01, 0x2C, 0x00], );
let info = parse_response(&pkt).unwrap();
assert_eq!(info.len(), 1);
assert_eq!(info[0].percentage, 85);
assert_eq!(info[0].remaining_minutes, Some(300));
assert_eq!(info[0].component_id, 0);
}
#[test]
fn parse_two_batteries() {
let pkt = BmapPacket::new(
FunctionBlock::Status,
status::BATTERY_LEVEL,
Operator::Status,
vec![
85, 0x01, 0x2C, 0x00, 50, 0xFF, 0xFF, 0x01, ],
);
let info = parse_response(&pkt).unwrap();
assert_eq!(info.len(), 2);
assert_eq!(info[0].percentage, 85);
assert_eq!(info[1].percentage, 50);
assert_eq!(info[1].remaining_minutes, None);
assert_eq!(info[1].component_id, 1);
}
}