use crate::{Protocol300Message, message}; use thiserror::Error; #[cfg(feature = "defmt")] use defmt::{error}; #[cfg(feature = "log")] use log::{error}; extern crate alloc; use alloc::vec; use alloc::vec::Vec; use alloc::borrow::ToOwned; #[derive(Debug, PartialEq, Eq)] pub enum Protocol300Transmission { /// 0x06 - ACK, used by all clients as acknowledgement Ack, /// 0x05 - Gets sent periodically to indicate idle/not initialized connection by the heater Enq, /// 0x04 - Resets the connection to a known state Eot, /// 0x16 0x00 0x00 - Initializes the connection, sent by the client Init, /// 0x15 - Negative Acknowledgement, indicates an error in the last message Nack, /// A valid decoded message Message(Protocol300Message) } impl Protocol300Transmission { /// Try to convert bytes to a Protocol 300 Transmission /// /// # Errors /// Returns a `FromBytesError` if the conversion fails in some way pub fn try_from_bytes(bytes: &[u8]) -> Result { match bytes { [0x06] => Ok(Self::Ack), [0x05] => Ok(Self::Enq), [0x04] => Ok(Self::Eot), [0x15] => Ok(Self::Nack), [0x16, 0x00, 0x00] => Ok(Self::Init), [0x41, ..] => Ok(Self::Message(Protocol300Message::try_from_bytes(bytes)?)), b => { error!("Failed to parse Protocol300 transmission: invalid byte sequence (length: {}, first byte: 0x{:02X})", bytes.len(), bytes.first().unwrap_or(&0x00)); Err(FromBytesError::InvalidBytes(b.to_owned())) }, } } #[must_use] pub fn to_bytes(&self) -> Vec { match self { Self::Ack => vec![0x06], Self::Enq => vec![0x05], Self::Eot => vec![0x04], Self::Init => vec![0x16, 0x00, 0x00], Self::Nack => vec![0x15], Self::Message(protocol300_message) => protocol300_message.to_bytes(), } } /// Returns the length in bytes of the transmission #[must_use] pub fn length_in_bytes(&self) -> usize { match self { Self::Ack | Self::Enq | Self::Eot | Self::Nack => 1, Self::Init => 3, Self::Message(protocol300_message) => (protocol300_message.telegram_length + 3).into(), } } } /// Errors that can occur when getting a Protocol 300 Transmission from bytes #[derive(Error, Debug, PartialEq, Eq)] pub enum FromBytesError{ #[error("Failed to parse message")] MessageParsing(#[from] message::MessageDecodingError), #[error("Invalid bytes in vec")] InvalidBytes(Vec) } #[cfg(test)] mod tests { use crate::{FunctionCode, MessageIdentifier, Protocol300Message, transmission::Protocol300Transmission}; #[test] fn from_bytes_ack() { assert_eq!(Protocol300Transmission::Ack, Protocol300Transmission::try_from_bytes(&[0x06]).unwrap()); } #[test] fn from_bytes_nack() { assert_eq!(Protocol300Transmission::Nack, Protocol300Transmission::try_from_bytes(&[0x15]).unwrap()); } #[test] fn from_bytes_eot() { assert_eq!(Protocol300Transmission::Eot, Protocol300Transmission::try_from_bytes(&[0x04]).unwrap()); } #[test] fn from_bytes_enq() { assert_eq!(Protocol300Transmission::Enq, Protocol300Transmission::try_from_bytes(&[0x05]).unwrap()); } #[test] fn from_bytes_init() { assert_eq!(Protocol300Transmission::Init, Protocol300Transmission::try_from_bytes(&[0x16, 0x00, 0x00]).unwrap()); } #[test] fn from_bytes_message() { let message = Protocol300Message{ data_address: 0x5525, telegram_length: 0x09, function_code: FunctionCode::VirtualREAD, message_identifier: MessageIdentifier::Response, data_length: 0x04, data: vec![0x07, 0x01, 0x27, 0x11], checksum: 0xC9 }; let bytes = vec![0x41, 0x09, 0x01, 0x01, 0x55, 0x25, 0x04, 0x07, 0x01, 0x27, 0x11, 0xC9]; assert_eq!(Protocol300Transmission::Message(message), Protocol300Transmission::try_from_bytes(&bytes).unwrap()); } #[test] fn to_bytes_ack() { assert_eq!(Protocol300Transmission::Ack.to_bytes(), &[0x06]); } #[test] fn to_bytes_eot() { assert_eq!(Protocol300Transmission::Eot.to_bytes(), &[0x04]); } #[test] fn to_bytes_nack() { assert_eq!(Protocol300Transmission::Nack.to_bytes(), &[0x15]); } #[test] fn to_bytes_enq() { assert_eq!(Protocol300Transmission::Enq.to_bytes(), &[0x05]); } #[test] fn to_bytes_init() { assert_eq!(Protocol300Transmission::Init.to_bytes(), &[0x16, 0x00, 0x00]); } #[test] fn to_bytes_message() { let message = Protocol300Message{ data_address: 0x5525, telegram_length: 0x09, function_code: FunctionCode::VirtualREAD, message_identifier: MessageIdentifier::Response, data_length: 0x04, data: vec![0x07, 0x01, 0x27, 0x11], checksum: 0xC9 }; assert_eq!(Protocol300Transmission::Message(message).to_bytes(), &[0x41, 0x09, 0x01, 0x01, 0x55, 0x25, 0x04, 0x07, 0x01, 0x27, 0x11, 0xC9]); } #[test] fn length_in_bytes_ack() { assert_eq!(Protocol300Transmission::Ack.length_in_bytes(), 1); } #[test] fn length_in_bytes_enq() { assert_eq!(Protocol300Transmission::Enq.length_in_bytes(), 1); } #[test] fn length_in_bytes_eot() { assert_eq!(Protocol300Transmission::Eot.length_in_bytes(), 1); } #[test] fn length_in_bytes_nack() { assert_eq!(Protocol300Transmission::Nack.length_in_bytes(), 1); } #[test] fn length_in_bytes_init() { assert_eq!(Protocol300Transmission::Init.length_in_bytes(), 3); } #[test] fn length_in_bytes_message() { let message = Protocol300Message{ data_address: 0x5525, telegram_length: 0x09, function_code: FunctionCode::VirtualREAD, message_identifier: MessageIdentifier::Response, data_length: 0x04, data: vec![0x07, 0x01, 0x27, 0x11], checksum: 0xC9 }; // telegram_length is 0x09, so expected length is 0x09 + 3 = 12 assert_eq!(Protocol300Transmission::Message(message).length_in_bytes(), 12); } }