use super::{
Display, Event, Frame, OneOrMany,
OneOrMany::{Many, One},
ParseError,
};
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(PartialEq, Debug, Clone, Copy)]
pub struct MPH(pub(crate) u16);
impl MPH {
pub const fn raw(self) -> u16 {
self.0
}
}
impl From<u8> for MPH {
fn from(byte: u8) -> Self {
Self(u16::from(byte) * 200)
}
}
impl From<MPH> for f32 {
fn from(mph: MPH) -> Self {
f32::from(mph.0) / 200.0
}
}
impl std::fmt::Display for MPH {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let value: f32 = self.clone().into();
f.write_fmt(format_args!("MPH({:.2})", value))
}
}
impl TryFrom<Frame> for MPH {
type Error = ParseError;
fn try_from(frame: Frame) -> Result<Self, Self::Error> {
if let Some(&value) = frame.data().get(7) {
Ok(Self(value.into()))
} else {
Err(ParseError::Len { frame, expected: 8 })
}
}
}
pub struct KPH(pub(crate) MPH);
impl KPH {
pub const fn raw(self) -> u16 {
self.0.raw()
}
}
impl From<MPH> for KPH {
fn from(mph: MPH) -> Self {
KPH(mph)
}
}
impl From<KPH> for f32 {
fn from(kph: KPH) -> Self {
f32::from(kph.0) * 1.60934
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(PartialEq, Debug, Clone, Copy)]
pub struct RPMs(pub(crate) u16);
impl RPMs {
#[inline]
pub const fn raw(self) -> u16 {
self.0
}
#[inline]
pub const fn engine_is_on(self) -> bool {
self.raw() != 0xffff
}
#[inline]
pub const fn engine_is_off(self) -> bool {
!self.engine_is_on()
}
#[inline]
pub const fn get(self) -> Option<u16> {
if self.engine_is_on() {
Some(self.0)
} else {
None
}
}
}
impl std::fmt::Display for RPMs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.get() {
Some(rpms) => f.write_fmt(format_args!("RPMs(Some({rpms}))")),
None => f.write_str("RPMs(None)"),
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(PartialEq, Debug, Display, Clone)]
#[repr(align(8))]
pub enum Engine {
RPMs(RPMs),
ApproxMPH(MPH),
MPH(MPH),
}
impl TryFrom<Frame> for OneOrMany<Engine> {
type Error = ParseError;
fn try_from(frame: Frame) -> Result<Self, Self::Error> {
match frame.id() {
0x340 => Ok(One(Engine::MPH(MPH::try_from(frame)?))),
0x322 => {
const LEN: usize = 8;
let mut engines = Vec::new();
let data: [u8; LEN] = match frame.data().try_into() {
Ok(data) => data,
Err(_) => {
return Err(ParseError::Len {
frame,
expected: LEN,
})
}
};
let rpms = RPMs(u16::from_be_bytes([data[0], data[1]]));
engines.push(Engine::RPMs(rpms));
let mph = MPH(u16::from_be_bytes([data[2], data[3]]));
engines.push(Engine::ApproxMPH(mph));
Ok(Many(engines))
}
_ => Err(ParseError::Id { frame }),
}
}
}
impl From<OneOrMany<Engine>> for OneOrMany<Event> {
fn from(engine_or_engines: OneOrMany<Engine>) -> Self {
match engine_or_engines {
One(engine) => One(Event::Engine(engine)),
Many(engines) => Many(
engines
.into_iter()
.map(|engine| Event::Engine(engine))
.collect(),
),
}
}
}