Files
shturman/crates/core/shturman-power/src/protocol.rs
T
2026-06-25 15:44:10 +03:00

84 lines
2.4 KiB
Rust

//! Типы сообщений 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<u8> {
match self {
SocToMcu::ShutdownImminent { budget } => vec![*budget],
_ => vec![],
}
}
pub fn from_wire(t: u8, p: &[u8]) -> Option<Self> {
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<u8> {
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<Self> {
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,
}
}
}