use crate::std::{self, fmt};
use crate::{impl_default, tuple_struct_ser};
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum ProtocolVersion {
One = 0x01,
Two = 0x02,
Three = 0x03,
Four = 0x04,
Five = 0x05,
Six = 0x06,
Seven = 0x07,
Eight = 0x08,
Reserved = 0xff,
}
impl ProtocolVersion {
pub const fn new() -> Self {
Self::Six
}
pub const fn from_u8(val: u8) -> Self {
match val {
0x01 => Self::One,
0x02 => Self::Two,
0x03 => Self::Three,
0x04 => Self::Four,
0x05 => Self::Five,
0x06 => Self::Six,
0x07 => Self::Seven,
0x08 => Self::Eight,
_ => Self::Reserved,
}
}
pub const fn to_u8(&self) -> u8 {
match self {
ProtocolVersion::One => 0x01,
ProtocolVersion::Two => 0x02,
ProtocolVersion::Three => 0x03,
ProtocolVersion::Four => 0x04,
ProtocolVersion::Five => 0x05,
ProtocolVersion::Six => 0x06,
ProtocolVersion::Seven => 0x07,
ProtocolVersion::Eight => 0x08,
ProtocolVersion::Reserved => 0xff,
}
}
}
impl From<u8> for ProtocolVersion {
fn from(val: u8) -> Self {
Self::from_u8(val)
}
}
impl From<ProtocolVersion> for u8 {
fn from(val: ProtocolVersion) -> Self {
val.to_u8()
}
}
impl From<&ProtocolVersion> for u8 {
fn from(val: &ProtocolVersion) -> Self {
(*val).into()
}
}
impl From<ProtocolVersion> for &'static str {
fn from(val: ProtocolVersion) -> Self {
match val {
ProtocolVersion::One => "1",
ProtocolVersion::Two => "2",
ProtocolVersion::Three => "3",
ProtocolVersion::Four => "4",
ProtocolVersion::Five => "5",
ProtocolVersion::Six => "6",
ProtocolVersion::Seven => "7",
ProtocolVersion::Eight => "8",
ProtocolVersion::Reserved => "255",
}
}
}
impl From<&ProtocolVersion> for &'static str {
fn from(val: &ProtocolVersion) -> Self {
(*val).into()
}
}
impl fmt::Display for ProtocolVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", <&'static str>::from(self))
}
}
impl_default!(ProtocolVersion);
tuple_struct_ser!(
FirmwareVersion,
u32,
"ASCII-encoded firmware version for the device."
);
impl From<&[u8]> for FirmwareVersion {
fn from(val: &[u8]) -> Self {
let version = std::str::from_utf8(val)
.unwrap_or("0000")
.trim_start_matches(['0', '\0'])
.parse::<u32>()
.unwrap_or(0);
Self(version)
}
}
impl<const N: usize> From<[u8; N]> for FirmwareVersion {
fn from(val: [u8; N]) -> Self {
val.as_ref().into()
}
}
impl<const N: usize> From<&[u8; N]> for FirmwareVersion {
fn from(val: &[u8; N]) -> Self {
val.as_ref().into()
}
}
impl fmt::Display for FirmwareVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:.02}", self.0 as f32 / 100.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(not(feature = "std"))]
use alloc::format;
#[test]
fn test_firmware_version() {
let version_bytes = [0x00, 0x33, 0x33, 0x33];
let exp_version = 333;
let exp_version_str = "3.33";
let version = FirmwareVersion::from(version_bytes);
assert_eq!(FirmwareVersion::from_inner(exp_version), version);
assert_eq!(FirmwareVersion::from(b"0333"), version);
assert_eq!(version.as_inner(), exp_version);
assert_eq!(format!("{version}").as_str(), exp_version_str);
assert_eq!(
FirmwareVersion::from([0x00, 0x00, 0x00, 0x00]),
FirmwareVersion::from(0)
);
}
}