From cc29e9e8a0a5f3ec6b4034380884d780947d97b7 Mon Sep 17 00:00:00 2001 From: heroichornet Date: Fri, 17 Nov 2023 23:42:45 +0100 Subject: [PATCH] adding function parsing --- examples/example.rs | 10 +++- src/frames/mod.rs | 123 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 103 insertions(+), 30 deletions(-) diff --git a/examples/example.rs b/examples/example.rs index 470b050..50c4022 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -1,8 +1,14 @@ use m_bus_parser::parse_frame; fn main() { - let data = [0x68, 0x04, 0x04, 0x68, 0x53, 0x01, 0x00, 0x00, 0x54, 0x16]; - let frame = parse_frame(&data).unwrap(); + let example = vec![ 0x68, 0x4D, 0x4D, 0x68, 0x08, 0x01, 0x72, 0x01, 0x00, 0x00, 0x00, 0x96, 0x15, 0x01, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x78, 0x56, 0x00, 0x00, 0x00, 0x01, 0xFD, 0x1B, + 0x00, 0x02, 0xFC, 0x03, 0x48, 0x52, 0x25, 0x74, 0x44, 0x0D, 0x22, 0xFC, 0x03, 0x48, + 0x52, 0x25, 0x74, 0xF1, 0x0C, 0x12, 0xFC, 0x03, 0x48, 0x52, 0x25, 0x74, 0x63, 0x11, + 0x02, 0x65, 0xB4, 0x09, 0x22, 0x65, 0x86, 0x09, 0x12, 0x65, 0xB7, 0x09, 0x01, 0x72, + 0x00, 0x72, 0x65, 0x00, 0x00, 0xB2, 0x01, 0x65, 0x00, 0x00, 0x1F, 0xB3, 0x16, + ]; + let frame = parse_frame(&example).unwrap(); println!("{:?}", frame); } \ No newline at end of file diff --git a/src/frames/mod.rs b/src/frames/mod.rs index b400c69..70f5578 100644 --- a/src/frames/mod.rs +++ b/src/frames/mod.rs @@ -10,12 +10,12 @@ pub enum FrameType<'a> { LongFrame{ function: Function, address: Address, - control_information: u8, + control_information: ControlInformation, data: &'a [u8]}, ControlFrame{ function: Function, address: Address, - control_information: u8 + control_information: ControlInformation, }, } @@ -31,20 +31,20 @@ pub enum Function{ impl Function { - fn from(byte: u8) -> Function { + fn from(byte: u8) -> Result { match byte { - 0x40 => Function::SND_NK, - 0x53 => Function::SND_UD{FCB: false}, - 0x73 => Function::SND_UD{FCB: true}, - 0x5B => Function::REQ_UD2{FCB: false}, - 0x7B => Function::REQ_UD2{FCB: true}, - 0x5A => Function::REQ_UD1{FCB: false}, - 0x7A => Function::REQ_UD1{FCB: true}, - 0x08 => Function::RSP_UD{ACD: false, DFC: false}, - 0x18 => Function::RSP_UD{ACD: false, DFC: true}, - 0x28 => Function::RSP_UD{ACD: true, DFC: false}, - 0x38 => Function::RSP_UD{ACD: true, DFC: true}, - _ => panic!("Invalid function byte: {}", byte), + 0x40 => Ok(Function::SND_NK), + 0x53 => Ok(Function::SND_UD{FCB: false}), + 0x73 => Ok(Function::SND_UD{FCB: true}), + 0x5B => Ok(Function::REQ_UD2{FCB: false}), + 0x7B => Ok(Function::REQ_UD2{FCB: true}), + 0x5A => Ok(Function::REQ_UD1{FCB: false}), + 0x7A => Ok(Function::REQ_UD1{FCB: true}), + 0x08 => Ok(Function::RSP_UD{ACD: false, DFC: false}), + 0x18 => Ok(Function::RSP_UD{ACD: false, DFC: true}), + 0x28 => Ok(Function::RSP_UD{ACD: true, DFC: false}), + 0x38 => Ok(Function::RSP_UD{ACD: true, DFC: true}), + _ => Err(FrameError::InvalidFunction{byte: byte}), } } } @@ -82,8 +82,77 @@ pub enum FrameError { expected: u8, actual: u8, }, + InvalidControlInformation{ + byte: u8, + }, + InvalidFunction{ + byte: u8, + }, +} +#[derive(Debug, PartialEq)] +enum Direction { + SlaveToMaster, + MasterToSlave, +} + +#[derive(Debug, PartialEq)] +enum ControlInformation { + SendData(Direction), + SelectSlave(Direction), + ResetAtApplicationLevel(Direction), + SynchronizeSlave(Direction), + SetBaudRate300(Direction), + SetBaudRate600(Direction), + SetBaudRate1200(Direction), + SetBaudRate2400(Direction), + SetBaudRate4800(Direction), + SetBaudRate9600(Direction), + SetBaudRate19200(Direction), + SetBaudRate38400(Direction), + OutputRAMContent(Direction), + WriteRAMContent(Direction), + StartCalibrationTestMode(Direction), + ReadEEPROM(Direction), + StartSoftwareTest(Direction), + HashProcedure(u8, Direction), + SendErrorStatus(Direction), + SendAlarmStatus(Direction), + ResponseWithVariableDataStructure(Direction), + ResponseWithFixedDataStructure(Direction), +} + +impl ControlInformation { + fn from(byte: u8) -> Result { + match byte { + 0x51 => Ok(ControlInformation::SendData(Direction::MasterToSlave)), + 0x52 => Ok(ControlInformation::SelectSlave(Direction::MasterToSlave)), + 0x50 => Ok(ControlInformation::ResetAtApplicationLevel(Direction::MasterToSlave)), + 0x54 => Ok(ControlInformation::SynchronizeSlave(Direction::MasterToSlave)), + 0xB8 => Ok(ControlInformation::SetBaudRate300(Direction::MasterToSlave)), + 0xB9 => Ok(ControlInformation::SetBaudRate600(Direction::MasterToSlave)), + 0xBA => Ok(ControlInformation::SetBaudRate1200(Direction::MasterToSlave)), + 0xBB => Ok(ControlInformation::SetBaudRate2400(Direction::MasterToSlave)), + 0xBC => Ok(ControlInformation::SetBaudRate4800(Direction::MasterToSlave)), + 0xBD => Ok(ControlInformation::SetBaudRate9600(Direction::MasterToSlave)), + 0xBE => Ok(ControlInformation::SetBaudRate19200(Direction::MasterToSlave)), + 0xBF => Ok(ControlInformation::SetBaudRate38400(Direction::MasterToSlave)), + 0xB1 => Ok(ControlInformation::OutputRAMContent(Direction::MasterToSlave)), + 0xB2 => Ok(ControlInformation::WriteRAMContent(Direction::MasterToSlave)), + 0xB3 => Ok(ControlInformation::StartCalibrationTestMode(Direction::MasterToSlave)), + 0xB4 => Ok(ControlInformation::ReadEEPROM(Direction::MasterToSlave)), + 0xB6 => Ok(ControlInformation::StartSoftwareTest(Direction::MasterToSlave)), + 0x90..=0x97 => Ok(ControlInformation::HashProcedure(byte - 0x90, Direction::MasterToSlave)), + 0x70 => Ok(ControlInformation::SendErrorStatus(Direction::SlaveToMaster)), + 0x71 => Ok(ControlInformation::SendAlarmStatus(Direction::SlaveToMaster)), + 0x72 | 0x76 => Ok(ControlInformation::ResponseWithVariableDataStructure(Direction::SlaveToMaster)), + 0x73 | 0x77 => Ok(ControlInformation::ResponseWithFixedDataStructure(Direction::SlaveToMaster)), + _ => Err(FrameError::InvalidControlInformation{byte: byte}), + } + } } + + pub trait Frame { fn from(data: &[u8]) -> Result where @@ -129,14 +198,14 @@ pub fn parse_frame(data: &[u8]) -> Result { let control_field = data[4]; match control_field { 0x53 => Ok(FrameType::ControlFrame{ - function: Function::from(data[4]), + function: Function::from(data[4])?, address: Address::from(data[5]), - control_information: data[6] + control_information: ControlInformation::from(data[6])? }), _ => Ok(FrameType::LongFrame{ - function: Function::from(data[4]), + function: Function::from(data[4])?, address: Address::from(data[5]), - control_information: data[6], + control_information: ControlInformation::from(data[6])?, data: &data[7..data.len() - 2], }), } @@ -145,7 +214,7 @@ pub fn parse_frame(data: &[u8]) -> Result { validate_checksum(&data[1..])?; if data.len() == 5 && data[4] == 0x16 { Ok(FrameType::ShortFrame{ - function: Function::from(data[1]), + function: Function::from(data[1])?, address: Address::from(data[2]), }) } else { @@ -187,7 +256,7 @@ mod tests { let single_character_frame = vec![0xE5]; let short_frame = vec![0x10, 0x7B, 0x8b, 0x06,0x16]; - let control_frame = vec![0x68, 0x03, 0x03, 0x68, 0x53, 0x01, 0x00, 0x54, 0x16]; + let control_frame = vec![0x68, 0x03, 0x03, 0x68, 0x53, 0x01, 0x51, 0x54, 0x16]; let example = vec![ 0x68, 0x4D, 0x4D, 0x68, 0x08, 0x01, 0x72, 0x01, 0x00, 0x00, 0x00, 0x96, 0x15, 0x01, @@ -197,21 +266,19 @@ mod tests { 0x02, 0x65, 0xB4, 0x09, 0x22, 0x65, 0x86, 0x09, 0x12, 0x65, 0xB7, 0x09, 0x01, 0x72, 0x00, 0x72, 0x65, 0x00, 0x00, 0xB2, 0x01, 0x65, 0x00, 0x00, 0x1F, 0xB3, 0x16, ]; - - assert_eq!(parse_frame(&single_character_frame), Ok(FrameType::SingleCharacter{character: 0xE5})); - assert_eq!(parse_frame(&short_frame), Ok(FrameType::ShortFrame{function: Function::from(0x7B), address: Address::from(0x8B)})); + assert_eq!(parse_frame(&short_frame), Ok(FrameType::ShortFrame{function: Function::from(0x7B).unwrap(), address: Address::from(0x8B)})); assert_eq!(parse_frame(&control_frame), Ok(FrameType::ControlFrame { - function: Function::from(0x53), + function: Function::from(0x53).unwrap(), address: Address::from(0x01), - control_information: 0x00, + control_information: ControlInformation::from(0x51).unwrap(), })); assert_eq!(parse_frame(&example),Ok(FrameType::LongFrame { - function: Function::from(8), + function: Function::from(8).unwrap(), address: Address::from(1), - control_information: 114, + control_information: ControlInformation::from(114).unwrap(), data: &[ 1, 0, 0, 0, 150, 21, 1, 0, 24, 0, 0, 0, 12, 120, 86, 0, 0, 0, 1, 253,