use core::fmt;
use crate::{Error, Result};
pub const LOAD_STICK_FIRMWARE_VERSION_COMMAND: [u8; 7] = [0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00];
pub const LOAD_HOLDER_FIRMWARE_VERSION_COMMAND: [u8; 7] =
[0x00, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FirmwareKind {
Stick = 0xC0,
Holder = 0x08,
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct FirmwareVersion {
pub major: u8,
pub minor: u8,
pub patch: u8,
pub year: u8,
}
impl FirmwareVersion {
pub fn from_response(bytes: &[u8], kind: FirmwareKind) -> Result<Self> {
if bytes.len() < 10 {
return Err(Error::ProtocolDecode(
"invalid firmware response: frame too short".to_string(),
));
}
if bytes[0] != 0x00 || bytes[1] != kind as u8 || bytes[2] != 0x88 || bytes[3] != 0x00 {
return Err(Error::ProtocolDecode(
"invalid firmware response: header mismatch".to_string(),
));
}
Ok(Self { major: bytes[6], minor: bytes[7], patch: bytes[8], year: bytes[9] })
}
}
impl fmt::Display for FirmwareVersion {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "v{}.{}.{}.{}", self.major, self.minor, self.patch, self.year)
}
}
#[cfg(test)]
mod tests {
use super::{
FirmwareKind, FirmwareVersion, LOAD_HOLDER_FIRMWARE_VERSION_COMMAND,
LOAD_STICK_FIRMWARE_VERSION_COMMAND,
};
#[test]
fn parses_stick_firmware_response() {
let version = FirmwareVersion::from_response(
&[0x00, 0xC0, 0x88, 0x00, 0x00, 0x00, 0x02, 0x05, 0x07, 0x18],
FirmwareKind::Stick,
)
.unwrap();
assert_eq!(version, FirmwareVersion { major: 2, minor: 5, patch: 7, year: 24 });
}
#[test]
fn parses_holder_firmware_response() {
let version = FirmwareVersion::from_response(
&[0x00, 0x08, 0x88, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x19],
FirmwareKind::Holder,
)
.unwrap();
assert_eq!(version.to_string(), "v1.2.3.25");
}
#[test]
fn rejects_invalid_firmware_header() {
let result = FirmwareVersion::from_response(
&[0x00, 0xC9, 0x88, 0x00, 0x00, 0x00, 0x02, 0x05, 0x07, 0x18],
FirmwareKind::Stick,
);
assert!(result.is_err());
}
#[test]
fn rejects_short_firmware_response() {
let result = FirmwareVersion::from_response(&[0x00, 0xC0, 0x88, 0x00], FirmwareKind::Stick);
assert!(result.is_err());
}
#[test]
fn keeps_firmware_commands_stable() {
assert_eq!(LOAD_STICK_FIRMWARE_VERSION_COMMAND, [0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00]);
assert_eq!(
LOAD_HOLDER_FIRMWARE_VERSION_COMMAND,
[0x00, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00]
);
}
}