Skip to content

Commit

Permalink
adding function parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
maebli committed Nov 17, 2023
1 parent ef38ed7 commit cc29e9e
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 30 deletions.
10 changes: 8 additions & 2 deletions examples/example.rs
Original file line number Diff line number Diff line change
@@ -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);

}
123 changes: 95 additions & 28 deletions src/frames/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
}

Expand All @@ -31,20 +31,20 @@ pub enum Function{


impl Function {
fn from(byte: u8) -> Function {
fn from(byte: u8) -> Result<Function,FrameError> {
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}),
}
}
}
Expand Down Expand Up @@ -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<ControlInformation,FrameError> {
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<Self, FrameError>
where
Expand Down Expand Up @@ -129,14 +198,14 @@ pub fn parse_frame(data: &[u8]) -> Result<FrameType, FrameError> {
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],
}),
}
Expand All @@ -145,7 +214,7 @@ pub fn parse_frame(data: &[u8]) -> Result<FrameType, FrameError> {
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 {
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down

0 comments on commit cc29e9e

Please sign in to comment.