use core::fmt;
use nonmax::NonMaxU8;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum EventData2Type {
Unspecified,
TriggerReading(NonMaxU8),
OemCode(NonMaxU8),
SensorSpecific(NonMaxU8),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum EventData3Type {
Unspecified,
TriggerThreshold(NonMaxU8),
OemCode(NonMaxU8),
SensorSpecific(NonMaxU8),
}
impl EventData2Type {
pub fn is_unspecified(&self) -> bool {
matches!(self, Self::Unspecified)
}
fn parse(kind: u8, value: u8) -> Self {
let Some(value) = NonMaxU8::new(value) else {
return Self::Unspecified;
};
match kind {
0b01 => Self::TriggerReading(value),
0b10 => Self::OemCode(value),
0b11 => Self::SensorSpecific(value),
_ => Self::Unspecified,
}
}
}
impl fmt::Display for EventData2Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::TriggerReading(value) => write!(f, "reading={}", value.get()),
Self::OemCode(value) => write!(f, "oem2=0x{:02X}", value.get()),
Self::SensorSpecific(value) => write!(f, "ext2=0x{:02X}", value.get()),
Self::Unspecified => Ok(()),
}
}
}
impl EventData3Type {
pub fn is_unspecified(&self) -> bool {
matches!(self, Self::Unspecified)
}
fn parse(kind: u8, value: u8) -> Self {
let Some(value) = NonMaxU8::new(value) else {
return Self::Unspecified;
};
match kind {
0b01 => Self::TriggerThreshold(value),
0b10 => Self::OemCode(value),
0b11 => Self::SensorSpecific(value),
_ => Self::Unspecified,
}
}
}
impl fmt::Display for EventData3Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::TriggerThreshold(value) => write!(f, "threshold={}", value.get()),
Self::OemCode(value) => write!(f, "oem3=0x{:02X}", value.get()),
Self::SensorSpecific(value) => write!(f, "ext3=0x{:02X}", value.get()),
Self::Unspecified => Ok(()),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct EventData {
pub offset: u8,
pub data2_type: EventData2Type,
pub data3_type: EventData3Type,
}
impl EventData {
pub fn parse(data: &[u8; 3]) -> Self {
let offset = data[0] & 0x0F;
let data2_type = EventData2Type::parse((data[0] >> 4) & 0x03, data[1]);
let data3_type = EventData3Type::parse((data[0] >> 6) & 0x03, data[2]);
Self {
offset,
data2_type,
data3_type,
}
}
}
impl fmt::Display for EventData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut parts = Vec::new();
if !self.data2_type.is_unspecified() {
parts.push(self.data2_type.to_string());
}
if !self.data3_type.is_unspecified() {
parts.push(self.data3_type.to_string());
}
write!(f, "{}", parts.join(", "))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_event_data() {
let data = EventData::parse(&[0x59, 0x42, 0x50]); assert_eq!(data.offset, 0x09);
assert_eq!(
data.data2_type,
EventData2Type::TriggerReading(NonMaxU8::new(0x42).unwrap())
);
assert_eq!(
data.data3_type,
EventData3Type::TriggerThreshold(NonMaxU8::new(0x50).unwrap())
);
}
#[test]
fn test_format_trigger_data() {
let data = EventData::parse(&[0x59, 0x42, 0x50]);
assert_eq!(data.to_string(), "reading=66, threshold=80");
}
#[test]
fn test_unspecified_data() {
let data = EventData::parse(&[0x00, 0xFF, 0xFF]);
assert_eq!(data.to_string(), "");
}
}