summaryrefslogtreecommitdiff
path: root/ebus-rust/src/layer7/mod.rs
diff options
context:
space:
mode:
authorYves Fischer <yvesf+git@xapek.org>2021-10-13 23:22:16 +0200
committerYves Fischer <yvesf+git@xapek.org>2021-12-31 23:57:06 +0100
commit76f8611ee3345268e2091a9d2e81b53a8b05889c (patch)
tree833dacff2aae89ec54a7fee827e75f93fba63669 /ebus-rust/src/layer7/mod.rs
parentcaae83f445935c06cd6aef36f283a4688675278a (diff)
downloadebus-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.rs129
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)
+ );
+ }
+}