pub const IMPROV_HEADER: [u8; 6] = [ 'I' as u8, 'M' as u8, 'P' as u8, 'R' as u8, 'O' as u8, 'V' as u8, ]; pub const IMPROV_VERSION: u8 = 0x01; #[derive(Clone, PartialEq)] #[repr(u8)] pub enum PacketType { CurrentState = 0x01, ErrorState = 0x02, RPCCommand = 0x03, RPCResult = 0x04, } impl TryFrom<&u8> for PacketType { type Error= &'static str; fn try_from(b: &u8) -> Result { match b { 0x01 => Ok(Self::CurrentState), 0x02 => Ok(Self::ErrorState), 0x03 => Ok(Self::RPCCommand), 0x04 => Ok(Self::RPCResult), _ => Err("Cannot convert to packet type"), } } } impl std::fmt::Display for PacketType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::CurrentState => write!(f, "Current State"), Self::ErrorState => write!(f, "Error State"), Self::RPCCommand => write!(f, "RPC Command"), Self::RPCResult => write!(f, "RPC Result"), } } } #[derive(Clone)] #[repr(u8)] pub enum CurrentState { Ready = 0x02, Provisioning = 0x03, Provisioned = 0x04, } impl TryFrom<&u8> for CurrentState { type Error= &'static str; fn try_from(b: &u8) -> Result { match b { 0x02 => Ok(Self::Ready), 0x03 => Ok(Self::Provisioning), 0x04 => Ok(Self::Provisioned), _ => Err("Cannot convert to current state"), } } } impl std::fmt::Display for CurrentState { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Ready => write!(f, "Ready"), Self::Provisioning => write!(f, "Provisioning"), Self::Provisioned => write!(f, "Provisioned"), } } } #[derive(Clone)] #[repr(u8)] pub enum ErrorState { NoError = 0x00, InvalidRPCPacket = 0x01, UnknownRPCCommand = 0x02, UnableToConnect = 0x03, UnknownError = 0xFF, } #[derive(Clone)] #[repr(u8)] pub enum RPCCommand { SendWifiSettings = 0x01, RequestCurrentState = 0x02, } pub fn calculate_checksum(data: &Vec) -> u8 { // Pass data as full packet, with header, but without checksum byte let mut checksum: u8 = 0x00; for e in data { checksum = checksum.wrapping_add(e.clone()); } return checksum; } pub struct ImprovPacket { pub version: u8, pub r#type: PacketType, pub data: Vec, } impl ImprovPacket { pub fn try_from_bytes(bytes: &Vec) -> Result { if bytes.len() < 11 { return Err("Packet too small"); } for i in 0..5 { if bytes[i] != IMPROV_HEADER[i] { return Err("Improv header not found"); } } let data: Vec = Vec::new(); let length: usize = bytes[8].into(); if bytes.len() != length + 10 { return Err("Packet with invalid length"); } return Ok(Self { version: bytes[6], r#type: PacketType::try_from(&bytes[7])?, data: bytes[9..(bytes.len()-1)].to_vec(), }); } }