From 76f8611ee3345268e2091a9d2e81b53a8b05889c Mon Sep 17 00:00:00 2001 From: Yves Fischer Date: Wed, 13 Oct 2021 23:22:16 +0200 Subject: ebus parser in rust --- ebus-rust/src/layer7/mod.rs | 129 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 ebus-rust/src/layer7/mod.rs (limited to 'ebus-rust/src/layer7/mod.rs') diff --git a/ebus-rust/src/layer7/mod.rs b/ebus-rust/src/layer7/mod.rs new file mode 100644 index 0000000..7f22478 --- /dev/null +++ b/ebus-rust/src/layer7/mod.rs @@ -0,0 +1,129 @@ +pub mod types; +use crate::layer2; +use crate::model; + +pub struct DecodedField { + pub v: Option, + pub name: String, + pub field: model::PacketField, +} + +pub fn decode_fields(p: &layer2::Packet, fields: &[model::PacketField]) -> Vec { + fields + .iter() + .map(|f| { + let r = |decoder: &dyn Fn(&[u8]) -> Option, + offset: &u8, + name: &String| DecodedField { + v: decoder( + p.payload_decoded() + .get((*offset as usize)..) + .unwrap_or(&[0; 0]), + ), + name: name.clone(), + field: f.clone(), + }; + match f { + model::PacketField::Byte { offset, name } => r(&types::byte, offset, name), + model::PacketField::Data1b { offset, name } => r(&types::data1b, offset, name), + model::PacketField::Data1c { offset, name } => r(&types::data1c, offset, name), + model::PacketField::Data2b { offset, name } => r(&types::data2b, offset, name), + model::PacketField::Data2c { offset, name } => r(&types::data2c, offset, name), + model::PacketField::ByteEnum { + offset, + name, + options, + } => r(&(move |data| types::byteenum(data, options)), offset, name), + model::PacketField::Bcd { offset, name } => r(&types::bcd, offset, name), + model::PacketField::Bit { offset, name } => r(&types::bit, offset, name), + model::PacketField::Word { offset, name } => r(&types::word, offset, name), + model::PacketField::String { + offset, + name, + length, + } => r( + &(move |data| types::string(data, *length as usize)), + offset, + name, + ), + } + }) + .collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + static EBUS_XML: &[u8] = include_bytes!("../../../ebus-xml/ebus.xml"); + + fn tostring(values: Vec) -> String { + values + .iter() + .map(|df| { + df.name.clone() + + "=" + + &df + .v + .as_ref() + .map(|v2| v2.convert()) + .unwrap_or(String::from("")) + }) + .collect::>() + .join(",") + } + + #[test] + fn test1() { + let conf = model::read_config(EBUS_XML).unwrap(); + let data = [ + 0xf1, 0xfe, 0x5, 0x3, 0x08, 0x01, 0x01, 0x10, 0xff, 0x4e, 0xff, 0x35, 0x0b, 0x92, 0x00, + 0xaa, + ]; + + let l2p = layer2::parse(&data[..]).unwrap(); + let pack = conf.packets.get(l2p.primary, l2p.secondary).unwrap(); + let values = decode_fields(&l2p, pack.fields.fields.as_ref().unwrap()); + assert_eq!("stellgradKesselleistung=,kesselTemperatur=39,ruecklaufTemperatur=,boilerTemperatur=53,aussenTemperatur=11", tostring(values)); + } + + #[test] + fn test() { + let conf = model::read_config(EBUS_XML).unwrap(); + + let data: Vec = vec![ + 170, // Syn + 170, // Syn + 003, // Source + 241, // Destination + 008, // primaryCommand + 000, // secondaryCommand + 008, // payloadLength + 128, // p1 + 040, // p2 + 230, // p3 + 002, // p4 + 000, // p5 + 002, // p6 + 000, // p7 + 010, // p8 + 128, // CRC + 000, // ACK + 170, // SYN + 170, + ]; + + let res = layer2::parse(&data).unwrap(); + assert_eq!( + res.payload_decoded(), + vec![128, 040, 230, 002, 000, 002, 000, 010] + ); + + let pack = conf.packets.get(res.primary, res.secondary).unwrap(); + let values = decode_fields(&res, pack.fields.fields.as_ref().unwrap()); + assert_eq!( + "TK_soll=40.5,TA_ist=2.8984375,L_zwang=0,Status=false,TB_soll=10", + tostring(values) + ); + } +} -- cgit v1.2.1