//! Типы сообщений SoC↔MCU (B08, спека v0.4 §6.1). seq — поле кадра (codec), не сообщения. pub mod wire { pub const HEARTBEAT: u8 = 0x01; pub const SHUTDOWN_IMMINENT: u8 = 0x02; pub const SAFE_TO_CUT: u8 = 0x03; pub const ACK: u8 = 0x81; pub const ACC: u8 = 0x82; pub const VOLTAGE: u8 = 0x83; pub const CUT_WARNING: u8 = 0x84; } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SocToMcu { Heartbeat, ShutdownImminent { budget: u8 }, SafeToCut, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum McuToSoc { Ack, Acc { on: bool }, Voltage { mv: u16 }, CutWarning, } impl SocToMcu { pub fn wire_type(&self) -> u8 { match self { SocToMcu::Heartbeat => wire::HEARTBEAT, SocToMcu::ShutdownImminent { .. } => wire::SHUTDOWN_IMMINENT, SocToMcu::SafeToCut => wire::SAFE_TO_CUT, } } pub fn payload(&self) -> Vec { match self { SocToMcu::ShutdownImminent { budget } => vec![*budget], _ => vec![], } } pub fn from_wire(t: u8, p: &[u8]) -> Option { match t { wire::HEARTBEAT => Some(SocToMcu::Heartbeat), wire::SHUTDOWN_IMMINENT => Some(SocToMcu::ShutdownImminent { budget: *p.first()?, }), wire::SAFE_TO_CUT => Some(SocToMcu::SafeToCut), _ => None, } } } impl McuToSoc { pub fn wire_type(&self) -> u8 { match self { McuToSoc::Ack => wire::ACK, McuToSoc::Acc { .. } => wire::ACC, McuToSoc::Voltage { .. } => wire::VOLTAGE, McuToSoc::CutWarning => wire::CUT_WARNING, } } pub fn payload(&self) -> Vec { match self { McuToSoc::Acc { on } => vec![*on as u8], McuToSoc::Voltage { mv } => mv.to_be_bytes().to_vec(), _ => vec![], } } pub fn from_wire(t: u8, p: &[u8]) -> Option { match t { wire::ACK => Some(McuToSoc::Ack), wire::ACC => Some(McuToSoc::Acc { on: *p.first()? != 0, }), wire::VOLTAGE => Some(McuToSoc::Voltage { mv: u16::from_be_bytes([*p.first()?, *p.get(1)?]), }), wire::CUT_WARNING => Some(McuToSoc::CutWarning), _ => None, } } }