diff options
author | Yves Fischer <yvesf+git@xapek.org> | 2021-10-13 23:22:16 +0200 |
---|---|---|
committer | Yves Fischer <yvesf+git@xapek.org> | 2021-12-31 23:57:06 +0100 |
commit | 76f8611ee3345268e2091a9d2e81b53a8b05889c (patch) | |
tree | 833dacff2aae89ec54a7fee827e75f93fba63669 /ebus-rust/src/layer7/mod.rs | |
parent | caae83f445935c06cd6aef36f283a4688675278a (diff) | |
download | ebus-76f8611ee3345268e2091a9d2e81b53a8b05889c.tar.gz ebus-76f8611ee3345268e2091a9d2e81b53a8b05889c.zip |
ebus parser in rust
Diffstat (limited to 'ebus-rust/src/layer7/mod.rs')
-rw-r--r-- | ebus-rust/src/layer7/mod.rs | 129 |
1 files changed, 129 insertions, 0 deletions
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<types::Value>, + pub name: String, + pub field: model::PacketField, +} + +pub fn decode_fields(p: &layer2::Packet, fields: &[model::PacketField]) -> Vec<DecodedField> { + fields + .iter() + .map(|f| { + let r = |decoder: &dyn Fn(&[u8]) -> Option<types::Value>, + 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<DecodedField>) -> String { + values + .iter() + .map(|df| { + df.name.clone() + + "=" + + &df + .v + .as_ref() + .map(|v2| v2.convert()) + .unwrap_or(String::from("<None>")) + }) + .collect::<Vec<String>>() + .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=<None>,kesselTemperatur=39,ruecklaufTemperatur=<None>,boilerTemperatur=53,aussenTemperatur=11", tostring(values)); + } + + #[test] + fn test() { + let conf = model::read_config(EBUS_XML).unwrap(); + + let data: Vec<u8> = 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) + ); + } +} |