From 47002fd721428869b40fdb5e43207c802acd8dda Mon Sep 17 00:00:00 2001 From: "Michael P. Jung" Date: Mon, 30 Mar 2026 10:11:28 +0200 Subject: [PATCH 1/3] Add support for nested and repeating groups --- CHANGELOG.md | 6 + Cargo.lock | 11 + Cargo.toml | 7 +- examples/model712/Cargo.toml | 14 + examples/model712/README.md | 10 + examples/model712/src/main.rs | 71 ++++ src/client/async.rs | 2 +- src/group.rs | 4 + src/lib.rs | 2 + src/model.rs | 8 +- src/models/model1.rs | 44 ++- src/models/model10.rs | 37 +- src/models/model101.rs | 122 +++--- src/models/model102.rs | 122 +++--- src/models/model103.rs | 122 +++--- src/models/model11.rs | 45 ++- src/models/model111.rs | 98 +++-- src/models/model112.rs | 98 +++-- src/models/model113.rs | 98 +++-- src/models/model12.rs | 61 +-- src/models/model120.rs | 86 +++-- src/models/model121.rs | 96 +++-- src/models/model122.rs | 76 ++-- src/models/model123.rs | 84 +++-- src/models/model124.rs | 84 +++-- src/models/model125.rs | 50 ++- src/models/model126.rs | 464 ++++++++++++++++++++++- src/models/model127.rs | 54 ++- src/models/model128.rs | 62 +-- src/models/model129.rs | 396 ++++++++++++++++++- src/models/model13.rs | 61 +-- src/models/model130.rs | 396 ++++++++++++++++++- src/models/model131.rs | 416 +++++++++++++++++++- src/models/model132.rs | 462 ++++++++++++++++++++++- src/models/model133.rs | 442 +++++++++++++++++++++- src/models/model134.rs | 477 ++++++++++++++++++++++- src/models/model135.rs | 396 ++++++++++++++++++- src/models/model136.rs | 396 ++++++++++++++++++- src/models/model137.rs | 396 ++++++++++++++++++- src/models/model138.rs | 396 ++++++++++++++++++- src/models/model139.rs | 398 ++++++++++++++++++- src/models/model14.rs | 47 ++- src/models/model140.rs | 398 ++++++++++++++++++- src/models/model141.rs | 396 ++++++++++++++++++- src/models/model142.rs | 396 ++++++++++++++++++- src/models/model143.rs | 398 ++++++++++++++++++- src/models/model144.rs | 398 ++++++++++++++++++- src/models/model145.rs | 48 ++- src/models/model15.rs | 49 ++- src/models/model16.rs | 51 ++- src/models/model160.rs | 234 +++++++++++- src/models/model17.rs | 47 ++- src/models/model18.rs | 35 +- src/models/model19.rs | 49 ++- src/models/model2.rs | 56 ++- src/models/model201.rs | 180 +++++---- src/models/model202.rs | 180 +++++---- src/models/model203.rs | 180 +++++---- src/models/model204.rs | 180 +++++---- src/models/model211.rs | 160 ++++---- src/models/model212.rs | 160 ++++---- src/models/model213.rs | 160 ++++---- src/models/model214.rs | 160 ++++---- src/models/model220.rs | 146 +++++-- src/models/model3.rs | 195 ++++++---- src/models/model302.rs | 106 +++++- src/models/model303.rs | 80 +++- src/models/model304.rs | 92 ++++- src/models/model305.rs | 44 ++- src/models/model306.rs | 40 +- src/models/model307.rs | 54 ++- src/models/model308.rs | 40 +- src/models/model4.rs | 199 ++++++---- src/models/model401.rs | 208 +++++++++- src/models/model402.rs | 247 ++++++++++-- src/models/model403.rs | 212 +++++++++-- src/models/model404.rs | 258 +++++++++++-- src/models/model5.rs | 255 ++++++++----- src/models/model501.rs | 70 ++-- src/models/model502.rs | 78 ++-- src/models/model6.rs | 257 ++++++++----- src/models/model601.rs | 231 +++++++++++- src/models/model63001.rs | 237 +++++++++--- src/models/model63002.rs | 87 ++++- src/models/model64001.rs | 101 ++--- src/models/model64020.rs | 145 +++++-- src/models/model64101.rs | 39 +- src/models/model64111.rs | 77 ++-- src/models/model64112.rs | 167 ++++---- src/models/model64410.rs | 283 +++++++++++--- src/models/model64411.rs | 296 ++++++++++++--- src/models/model64412.rs | 124 +++--- src/models/model64413.rs | 100 ++++- src/models/model64414.rs | 50 ++- src/models/model64415.rs | 42 ++- src/models/model7.rs | 97 ++++- src/models/model701.rs | 176 +++++---- src/models/model702.rs | 134 ++++--- src/models/model703.rs | 58 ++- src/models/model704.rs | 542 +++++++++++++++++++++++--- src/models/model705.rs | 413 +++++++++++++++++++- src/models/model706.rs | 286 +++++++++++++- src/models/model707.rs | 394 ++++++++++++++++++- src/models/model708.rs | 394 ++++++++++++++++++- src/models/model709.rs | 394 ++++++++++++++++++- src/models/model710.rs | 394 ++++++++++++++++++- src/models/model711.rs | 194 +++++++++- src/models/model712.rs | 332 +++++++++++++++- src/models/model713.rs | 50 ++- src/models/model714.rs | 303 ++++++++++++++- src/models/model715.rs | 46 ++- src/models/model8.rs | 85 ++++- src/models/model801.rs | 34 +- src/models/model802.rs | 150 ++++---- src/models/model803.rs | 692 ++++++++++++++++++++++++++++++++-- src/models/model804.rs | 233 +++++++++--- src/models/model805.rs | 180 +++++++-- src/models/model806.rs | 82 +++- src/models/model807.rs | 607 +++++++++++++++++++++++++++-- src/models/model808.rs | 82 +++- src/models/model809.rs | 82 +++- src/models/model9.rs | 261 ++++++++----- src/point.rs | 16 +- sunspec-gen/src/gen.rs | 291 ++++++++++++-- sunspec-gen/src/json.rs | 2 +- sunspec-gen/src/main.rs | 4 +- tests/test_model712.rs | 73 ++++ 127 files changed, 18756 insertions(+), 3517 deletions(-) create mode 100644 examples/model712/Cargo.toml create mode 100644 examples/model712/README.md create mode 100644 examples/model712/src/main.rs create mode 100644 src/group.rs create mode 100644 tests/test_model712.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b88979..2e2b028 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ + # Changelog All notable changes to this project will be documented in this file. @@ -7,6 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add support for nested and repeating groups +- Add `examples/model712` showing how to read model 712 from a device + ### Changed - Update `strum` to version `0.27` diff --git a/Cargo.lock b/Cargo.lock index 0830b8e..ae90485 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -459,6 +459,17 @@ dependencies = [ "tokio-modbus", ] +[[package]] +name = "sunspec-example-model712" +version = "0.1.0" +dependencies = [ + "clap", + "itertools", + "sunspec", + "tokio", + "tokio-modbus", +] + [[package]] name = "sunspec-example-readme" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index cc9a1c8..326516c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,4 +29,9 @@ tokio-modbus = { version = "0.16", optional = true } serde_json = "1.0.114" [workspace] -members = ["sunspec-gen", "examples/readme", "examples/model103"] +members = [ + "sunspec-gen", + "examples/readme", + "examples/model103", + "examples/model712", +] diff --git a/examples/model712/Cargo.toml b/examples/model712/Cargo.toml new file mode 100644 index 0000000..b3af3bb --- /dev/null +++ b/examples/model712/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "sunspec-example-model712" +version = "0.1.0" +edition = "2021" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tokio = { version = "1.33.0", features = ["rt-multi-thread", "macros", "time"] } +tokio-modbus = { version = "0.16", features = ["tcp"] } +sunspec = { path = "../../" } +clap = { version = "4.4.7", features = ["derive"] } +itertools = "0.14.0" diff --git a/examples/model712/README.md b/examples/model712/README.md new file mode 100644 index 0000000..163d5bc --- /dev/null +++ b/examples/model712/README.md @@ -0,0 +1,10 @@ +# Model 712 example + +This code connects to a device that supports sunspec via modbus TCP and +outputs the contents of model 1 and then proceeds reading model 712. + +Usage example: + +``` +$ cargo run 192.168.178.38:1502 1 +``` diff --git a/examples/model712/src/main.rs b/examples/model712/src/main.rs new file mode 100644 index 0000000..54f2b71 --- /dev/null +++ b/examples/model712/src/main.rs @@ -0,0 +1,71 @@ +use std::{error::Error, net::SocketAddr, time::Duration}; + +use clap::Parser; +use itertools::Itertools; +use sunspec::{ + client::{AsyncClient, Config}, + models::{model1::Model1, model712::Model712}, + DEFAULT_DISCOVERY_ADDRESSES, +}; +use tokio_modbus::{client::tcp::connect_slave, Slave}; + +#[derive(Parser)] +struct Args { + addr: SocketAddr, + device_id: u8, + #[arg( + long, + short='d', + help = "Discovery addresses", + name = "ADDRESS", + default_values_t = DEFAULT_DISCOVERY_ADDRESSES + )] + discovery_addresses: Vec, + #[arg( + long, + short = 't', + help = "Read timeout in seconds", + name = "SECONDS", + default_value_t = 1.0 + )] + read_timeout: f32, +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let args = Args::parse(); + + let client = AsyncClient::new( + connect_slave(args.addr, Slave(args.device_id)).await?, + Config { + discovery_addresses: args.discovery_addresses, + read_timeout: (args.read_timeout != 0.0) + .then(|| Duration::from_secs_f32(args.read_timeout)), + ..Default::default() + }, + ); + + let device = client.device(args.device_id).await?; + + let m1: Model1 = device.read_model().await?; + + println!("Manufacturer: {}", m1.mn); + println!("Model: {}", m1.md); + println!("Version: {}", m1.vr.as_deref().unwrap_or("(unspecified)")); + println!("Serial Number: {}", m1.sn); + + println!( + "Supported models: {}", + device + .models + .supported_model_ids() + .iter() + .map(|id| id.to_string()) + .join(", ") + ); + + let m712: Model712 = device.read_model().await?; + println!("{:?}", m712); + + Ok(()) +} diff --git a/src/client/async.rs b/src/client/async.rs index 8e4ea0e..901619c 100644 --- a/src/client/async.rs +++ b/src/client/async.rs @@ -289,7 +289,7 @@ async fn read_model( } data }; - Ok(M::from_data(&data)?) + Ok(M::parse(&data)?) } /// Read data for a single point. Please note that diff --git a/src/group.rs b/src/group.rs new file mode 100644 index 0000000..96fe8e4 --- /dev/null +++ b/src/group.rs @@ -0,0 +1,4 @@ +pub trait Group: Sized { + /// Group length (without nested and repeating groups) + const LEN: u16; +} diff --git a/src/lib.rs b/src/lib.rs index bcd2eb8..765d825 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ )] pub use constants::{DEFAULT_DISCOVERY_ADDRESSES, SUNS_IDENTIFIER}; +pub use group::Group; pub use model::{Model, ModelAddr}; pub use models::Models; pub use point::Point; @@ -29,6 +30,7 @@ pub use value::{DecodeError, FixedSize, Value}; /// This module contains all client specific code. pub mod client; mod constants; +mod group; mod model; /// This module contains all the genererated SunSpec models. pub mod models; diff --git a/src/model.rs b/src/model.rs index b873ec1..5d65451 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,16 +1,16 @@ use std::marker::PhantomData; -use crate::{DecodeError, Models}; +use crate::{DecodeError, Group, Models}; /// Every model implements this trait which contains methods /// for accessing -pub trait Model: Sized { +pub trait Model: Sized + Group { /// Model ID const ID: u16; - /// Parse model points from a given u16 slice - fn from_data(data: &[u16]) -> Result; /// Get model address from discovered models struct fn addr(models: &Models) -> ModelAddr; + /// Parse model data from a given u16 slice + fn parse(data: &[u16]) -> Result; } /// This structure is used to store the address of diff --git a/src/models/model1.rs b/src/models/model1.rs index dea7df7..04003f0 100644 --- a/src/models/model1.rs +++ b/src/models/model1.rs @@ -1,10 +1,11 @@ //! Common +pub type Model1 = Common; /// Common /// /// All SunSpec compliant devices must include this as the first model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model1 { +pub struct Common { /// Manufacturer /// /// Well known value registered with SunSpec for compliance @@ -33,7 +34,7 @@ pub struct Model1 { pub da: Option, } #[allow(missing_docs)] -impl Model1 { +impl Common { pub const MN: crate::Point = crate::Point::new(0, 16, false); pub const MD: crate::Point = crate::Point::new(16, 16, false); pub const OPT: crate::Point> = crate::Point::new(32, 8, false); @@ -41,19 +42,36 @@ impl Model1 { pub const SN: crate::Point = crate::Point::new(48, 16, false); pub const DA: crate::Point> = crate::Point::new(64, 1, true); } -impl crate::Model for Model1 { - const ID: u16 = 1; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - mn: Self::MN.from_data(data)?, - md: Self::MD.from_data(data)?, - opt: Self::OPT.from_data(data)?, - vr: Self::VR.from_data(data)?, - sn: Self::SN.from_data(data)?, - da: Self::DA.from_data(data)?, - }) +impl crate::Group for Common { + const LEN: u16 = 66; +} +impl Common { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + mn: Self::MN.from_data(data)?, + md: Self::MD.from_data(data)?, + opt: Self::OPT.from_data(data)?, + vr: Self::VR.from_data(data)?, + sn: Self::SN.from_data(data)?, + da: Self::DA.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } +} +impl crate::Model for Common { + const ID: u16 = 1; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m1 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model10.rs b/src/models/model10.rs index 880edcd..d803a4b 100644 --- a/src/models/model10.rs +++ b/src/models/model10.rs @@ -24,17 +24,24 @@ impl Model10 { pub const CTL: crate::Point> = crate::Point::new(1, 1, true); pub const TYP: crate::Point> = crate::Point::new(2, 1, false); } -impl crate::Model for Model10 { - const ID: u16 = 10; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - st: Self::ST.from_data(data)?, - ctl: Self::CTL.from_data(data)?, - typ: Self::TYP.from_data(data)?, - }) +impl crate::Group for Model10 { + const LEN: u16 = 4; +} +impl Model10 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + st: Self::ST.from_data(data)?, + ctl: Self::CTL.from_data(data)?, + typ: Self::TYP.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m10 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Interface Status @@ -125,3 +132,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Model10 { + const ID: u16 = 10; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m10 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model101.rs b/src/models/model101.rs index 6a0a2f4..84f541d 100644 --- a/src/models/model101.rs +++ b/src/models/model101.rs @@ -1,10 +1,11 @@ //! Inverter (Single Phase) +pub type Model101 = InverterSinglePhase; /// Inverter (Single Phase) /// /// Include this model for single phase inverter monitoring #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model101 { +pub struct InverterSinglePhase { /// Amps /// /// AC Current @@ -157,7 +158,7 @@ pub struct Model101 { pub evt_vnd4: Option, } #[allow(missing_docs)] -impl Model101 { +impl InverterSinglePhase { pub const A: crate::Point = crate::Point::new(0, 1, false); pub const APH_A: crate::Point = crate::Point::new(1, 1, false); pub const APH_B: crate::Point> = crate::Point::new(2, 1, false); @@ -202,57 +203,64 @@ impl Model101 { pub const EVT_VND3: crate::Point> = crate::Point::new(46, 2, false); pub const EVT_VND4: crate::Point> = crate::Point::new(48, 2, false); } -impl crate::Model for Model101 { - const ID: u16 = 101; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, - pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, - pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - w: Self::W.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - hz: Self::HZ.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - va: Self::VA.from_data(data)?, - va_sf: Self::VA_SF.from_data(data)?, - v_ar: Self::V_AR.from_data(data)?, - v_ar_sf: Self::V_AR_SF.from_data(data)?, - pf: Self::PF.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - wh: Self::WH.from_data(data)?, - wh_sf: Self::WH_SF.from_data(data)?, - dca: Self::DCA.from_data(data)?, - dca_sf: Self::DCA_SF.from_data(data)?, - dcv: Self::DCV.from_data(data)?, - dcv_sf: Self::DCV_SF.from_data(data)?, - dcw: Self::DCW.from_data(data)?, - dcw_sf: Self::DCW_SF.from_data(data)?, - tmp_cab: Self::TMP_CAB.from_data(data)?, - tmp_snk: Self::TMP_SNK.from_data(data)?, - tmp_trns: Self::TMP_TRNS.from_data(data)?, - tmp_ot: Self::TMP_OT.from_data(data)?, - tmp_sf: Self::TMP_SF.from_data(data)?, - st: Self::ST.from_data(data)?, - st_vnd: Self::ST_VND.from_data(data)?, - evt1: Self::EVT1.from_data(data)?, - evt2: Self::EVT2.from_data(data)?, - evt_vnd1: Self::EVT_VND1.from_data(data)?, - evt_vnd2: Self::EVT_VND2.from_data(data)?, - evt_vnd3: Self::EVT_VND3.from_data(data)?, - evt_vnd4: Self::EVT_VND4.from_data(data)?, - }) +impl crate::Group for InverterSinglePhase { + const LEN: u16 = 50; +} +impl InverterSinglePhase { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, + pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, + pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + w: Self::W.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + hz: Self::HZ.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + va: Self::VA.from_data(data)?, + va_sf: Self::VA_SF.from_data(data)?, + v_ar: Self::V_AR.from_data(data)?, + v_ar_sf: Self::V_AR_SF.from_data(data)?, + pf: Self::PF.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + wh: Self::WH.from_data(data)?, + wh_sf: Self::WH_SF.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dca_sf: Self::DCA_SF.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + dcv_sf: Self::DCV_SF.from_data(data)?, + dcw: Self::DCW.from_data(data)?, + dcw_sf: Self::DCW_SF.from_data(data)?, + tmp_cab: Self::TMP_CAB.from_data(data)?, + tmp_snk: Self::TMP_SNK.from_data(data)?, + tmp_trns: Self::TMP_TRNS.from_data(data)?, + tmp_ot: Self::TMP_OT.from_data(data)?, + tmp_sf: Self::TMP_SF.from_data(data)?, + st: Self::ST.from_data(data)?, + st_vnd: Self::ST_VND.from_data(data)?, + evt1: Self::EVT1.from_data(data)?, + evt2: Self::EVT2.from_data(data)?, + evt_vnd1: Self::EVT_VND1.from_data(data)?, + evt_vnd2: Self::EVT_VND2.from_data(data)?, + evt_vnd3: Self::EVT_VND3.from_data(data)?, + evt_vnd4: Self::EVT_VND4.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m101 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Operating State @@ -504,3 +512,13 @@ impl crate::Value for Option { } } } +impl crate::Model for InverterSinglePhase { + const ID: u16 = 101; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m101 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model102.rs b/src/models/model102.rs index 6c03ed7..47bbaec 100644 --- a/src/models/model102.rs +++ b/src/models/model102.rs @@ -1,10 +1,11 @@ //! Inverter (Split-Phase) +pub type Model102 = InverterSplitPhase; /// Inverter (Split-Phase) /// /// Include this model for split phase inverter monitoring #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model102 { +pub struct InverterSplitPhase { /// Amps /// /// AC Current @@ -161,7 +162,7 @@ pub struct Model102 { pub evt_vnd4: Option, } #[allow(missing_docs)] -impl Model102 { +impl InverterSplitPhase { pub const A: crate::Point = crate::Point::new(0, 1, false); pub const APH_A: crate::Point = crate::Point::new(1, 1, false); pub const APH_B: crate::Point = crate::Point::new(2, 1, false); @@ -206,57 +207,64 @@ impl Model102 { pub const EVT_VND3: crate::Point> = crate::Point::new(46, 2, false); pub const EVT_VND4: crate::Point> = crate::Point::new(48, 2, false); } -impl crate::Model for Model102 { - const ID: u16 = 102; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, - pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, - pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - w: Self::W.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - hz: Self::HZ.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - va: Self::VA.from_data(data)?, - va_sf: Self::VA_SF.from_data(data)?, - v_ar: Self::V_AR.from_data(data)?, - v_ar_sf: Self::V_AR_SF.from_data(data)?, - pf: Self::PF.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - wh: Self::WH.from_data(data)?, - wh_sf: Self::WH_SF.from_data(data)?, - dca: Self::DCA.from_data(data)?, - dca_sf: Self::DCA_SF.from_data(data)?, - dcv: Self::DCV.from_data(data)?, - dcv_sf: Self::DCV_SF.from_data(data)?, - dcw: Self::DCW.from_data(data)?, - dcw_sf: Self::DCW_SF.from_data(data)?, - tmp_cab: Self::TMP_CAB.from_data(data)?, - tmp_snk: Self::TMP_SNK.from_data(data)?, - tmp_trns: Self::TMP_TRNS.from_data(data)?, - tmp_ot: Self::TMP_OT.from_data(data)?, - tmp_sf: Self::TMP_SF.from_data(data)?, - st: Self::ST.from_data(data)?, - st_vnd: Self::ST_VND.from_data(data)?, - evt1: Self::EVT1.from_data(data)?, - evt2: Self::EVT2.from_data(data)?, - evt_vnd1: Self::EVT_VND1.from_data(data)?, - evt_vnd2: Self::EVT_VND2.from_data(data)?, - evt_vnd3: Self::EVT_VND3.from_data(data)?, - evt_vnd4: Self::EVT_VND4.from_data(data)?, - }) +impl crate::Group for InverterSplitPhase { + const LEN: u16 = 50; +} +impl InverterSplitPhase { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, + pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, + pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + w: Self::W.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + hz: Self::HZ.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + va: Self::VA.from_data(data)?, + va_sf: Self::VA_SF.from_data(data)?, + v_ar: Self::V_AR.from_data(data)?, + v_ar_sf: Self::V_AR_SF.from_data(data)?, + pf: Self::PF.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + wh: Self::WH.from_data(data)?, + wh_sf: Self::WH_SF.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dca_sf: Self::DCA_SF.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + dcv_sf: Self::DCV_SF.from_data(data)?, + dcw: Self::DCW.from_data(data)?, + dcw_sf: Self::DCW_SF.from_data(data)?, + tmp_cab: Self::TMP_CAB.from_data(data)?, + tmp_snk: Self::TMP_SNK.from_data(data)?, + tmp_trns: Self::TMP_TRNS.from_data(data)?, + tmp_ot: Self::TMP_OT.from_data(data)?, + tmp_sf: Self::TMP_SF.from_data(data)?, + st: Self::ST.from_data(data)?, + st_vnd: Self::ST_VND.from_data(data)?, + evt1: Self::EVT1.from_data(data)?, + evt2: Self::EVT2.from_data(data)?, + evt_vnd1: Self::EVT_VND1.from_data(data)?, + evt_vnd2: Self::EVT_VND2.from_data(data)?, + evt_vnd3: Self::EVT_VND3.from_data(data)?, + evt_vnd4: Self::EVT_VND4.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m102 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Operating State @@ -508,3 +516,13 @@ impl crate::Value for Option { } } } +impl crate::Model for InverterSplitPhase { + const ID: u16 = 102; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m102 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model103.rs b/src/models/model103.rs index 6fb8c25..2dc99ab 100644 --- a/src/models/model103.rs +++ b/src/models/model103.rs @@ -1,10 +1,11 @@ //! Inverter (Three Phase) +pub type Model103 = InverterThreePhase; /// Inverter (Three Phase) /// /// Include this model for three phase inverter monitoring #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model103 { +pub struct InverterThreePhase { /// Amps /// /// AC Current @@ -163,7 +164,7 @@ pub struct Model103 { pub evt_vnd4: Option, } #[allow(missing_docs)] -impl Model103 { +impl InverterThreePhase { pub const A: crate::Point = crate::Point::new(0, 1, false); pub const APH_A: crate::Point = crate::Point::new(1, 1, false); pub const APH_B: crate::Point = crate::Point::new(2, 1, false); @@ -208,57 +209,64 @@ impl Model103 { pub const EVT_VND3: crate::Point> = crate::Point::new(46, 2, false); pub const EVT_VND4: crate::Point> = crate::Point::new(48, 2, false); } -impl crate::Model for Model103 { - const ID: u16 = 103; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, - pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, - pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - w: Self::W.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - hz: Self::HZ.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - va: Self::VA.from_data(data)?, - va_sf: Self::VA_SF.from_data(data)?, - v_ar: Self::V_AR.from_data(data)?, - v_ar_sf: Self::V_AR_SF.from_data(data)?, - pf: Self::PF.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - wh: Self::WH.from_data(data)?, - wh_sf: Self::WH_SF.from_data(data)?, - dca: Self::DCA.from_data(data)?, - dca_sf: Self::DCA_SF.from_data(data)?, - dcv: Self::DCV.from_data(data)?, - dcv_sf: Self::DCV_SF.from_data(data)?, - dcw: Self::DCW.from_data(data)?, - dcw_sf: Self::DCW_SF.from_data(data)?, - tmp_cab: Self::TMP_CAB.from_data(data)?, - tmp_snk: Self::TMP_SNK.from_data(data)?, - tmp_trns: Self::TMP_TRNS.from_data(data)?, - tmp_ot: Self::TMP_OT.from_data(data)?, - tmp_sf: Self::TMP_SF.from_data(data)?, - st: Self::ST.from_data(data)?, - st_vnd: Self::ST_VND.from_data(data)?, - evt1: Self::EVT1.from_data(data)?, - evt2: Self::EVT2.from_data(data)?, - evt_vnd1: Self::EVT_VND1.from_data(data)?, - evt_vnd2: Self::EVT_VND2.from_data(data)?, - evt_vnd3: Self::EVT_VND3.from_data(data)?, - evt_vnd4: Self::EVT_VND4.from_data(data)?, - }) +impl crate::Group for InverterThreePhase { + const LEN: u16 = 50; +} +impl InverterThreePhase { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, + pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, + pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + w: Self::W.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + hz: Self::HZ.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + va: Self::VA.from_data(data)?, + va_sf: Self::VA_SF.from_data(data)?, + v_ar: Self::V_AR.from_data(data)?, + v_ar_sf: Self::V_AR_SF.from_data(data)?, + pf: Self::PF.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + wh: Self::WH.from_data(data)?, + wh_sf: Self::WH_SF.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dca_sf: Self::DCA_SF.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + dcv_sf: Self::DCV_SF.from_data(data)?, + dcw: Self::DCW.from_data(data)?, + dcw_sf: Self::DCW_SF.from_data(data)?, + tmp_cab: Self::TMP_CAB.from_data(data)?, + tmp_snk: Self::TMP_SNK.from_data(data)?, + tmp_trns: Self::TMP_TRNS.from_data(data)?, + tmp_ot: Self::TMP_OT.from_data(data)?, + tmp_sf: Self::TMP_SF.from_data(data)?, + st: Self::ST.from_data(data)?, + st_vnd: Self::ST_VND.from_data(data)?, + evt1: Self::EVT1.from_data(data)?, + evt2: Self::EVT2.from_data(data)?, + evt_vnd1: Self::EVT_VND1.from_data(data)?, + evt_vnd2: Self::EVT_VND2.from_data(data)?, + evt_vnd3: Self::EVT_VND3.from_data(data)?, + evt_vnd4: Self::EVT_VND4.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m103 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Operating State @@ -510,3 +518,13 @@ impl crate::Value for Option { } } } +impl crate::Model for InverterThreePhase { + const ID: u16 = 103; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m103 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model11.rs b/src/models/model11.rs index 0ebbb78..ccd7607 100644 --- a/src/models/model11.rs +++ b/src/models/model11.rs @@ -44,21 +44,28 @@ impl Model11 { pub const CTL: crate::Point> = crate::Point::new(11, 1, true); pub const FRC_SPD: crate::Point> = crate::Point::new(12, 1, true); } -impl crate::Model for Model11 { - const ID: u16 = 11; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - spd: Self::SPD.from_data(data)?, - cfg_st: Self::CFG_ST.from_data(data)?, - st: Self::ST.from_data(data)?, - mac: Self::MAC.from_data(data)?, - nam: Self::NAM.from_data(data)?, - ctl: Self::CTL.from_data(data)?, - frc_spd: Self::FRC_SPD.from_data(data)?, - }) +impl crate::Group for Model11 { + const LEN: u16 = 13; +} +impl Model11 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + spd: Self::SPD.from_data(data)?, + cfg_st: Self::CFG_ST.from_data(data)?, + st: Self::ST.from_data(data)?, + mac: Self::MAC.from_data(data)?, + nam: Self::NAM.from_data(data)?, + ctl: Self::CTL.from_data(data)?, + frc_spd: Self::FRC_SPD.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m11 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -173,3 +180,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Model11 { + const ID: u16 = 11; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m11 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model111.rs b/src/models/model111.rs index 75f2a5b..5e00200 100644 --- a/src/models/model111.rs +++ b/src/models/model111.rs @@ -1,10 +1,11 @@ //! Inverter (Single Phase) FLOAT +pub type Model111 = InverterSinglePhaseFloat; /// Inverter (Single Phase) FLOAT /// /// Include this model for single phase inverter monitoring using float values #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model111 { +pub struct InverterSinglePhaseFloat { /// Amps /// /// AC Current @@ -133,7 +134,7 @@ pub struct Model111 { pub evt_vnd4: Option, } #[allow(missing_docs)] -impl Model111 { +impl InverterSinglePhaseFloat { pub const A: crate::Point = crate::Point::new(0, 2, false); pub const APH_A: crate::Point = crate::Point::new(2, 2, false); pub const APH_B: crate::Point> = crate::Point::new(4, 2, false); @@ -166,45 +167,52 @@ impl Model111 { pub const EVT_VND3: crate::Point> = crate::Point::new(56, 2, false); pub const EVT_VND4: crate::Point> = crate::Point::new(58, 2, false); } -impl crate::Model for Model111 { - const ID: u16 = 111; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, - pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, - pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - w: Self::W.from_data(data)?, - hz: Self::HZ.from_data(data)?, - va: Self::VA.from_data(data)?, - v_ar: Self::V_AR.from_data(data)?, - pf: Self::PF.from_data(data)?, - wh: Self::WH.from_data(data)?, - dca: Self::DCA.from_data(data)?, - dcv: Self::DCV.from_data(data)?, - dcw: Self::DCW.from_data(data)?, - tmp_cab: Self::TMP_CAB.from_data(data)?, - tmp_snk: Self::TMP_SNK.from_data(data)?, - tmp_trns: Self::TMP_TRNS.from_data(data)?, - tmp_ot: Self::TMP_OT.from_data(data)?, - st: Self::ST.from_data(data)?, - st_vnd: Self::ST_VND.from_data(data)?, - evt1: Self::EVT1.from_data(data)?, - evt2: Self::EVT2.from_data(data)?, - evt_vnd1: Self::EVT_VND1.from_data(data)?, - evt_vnd2: Self::EVT_VND2.from_data(data)?, - evt_vnd3: Self::EVT_VND3.from_data(data)?, - evt_vnd4: Self::EVT_VND4.from_data(data)?, - }) +impl crate::Group for InverterSinglePhaseFloat { + const LEN: u16 = 60; +} +impl InverterSinglePhaseFloat { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, + pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, + pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + w: Self::W.from_data(data)?, + hz: Self::HZ.from_data(data)?, + va: Self::VA.from_data(data)?, + v_ar: Self::V_AR.from_data(data)?, + pf: Self::PF.from_data(data)?, + wh: Self::WH.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + dcw: Self::DCW.from_data(data)?, + tmp_cab: Self::TMP_CAB.from_data(data)?, + tmp_snk: Self::TMP_SNK.from_data(data)?, + tmp_trns: Self::TMP_TRNS.from_data(data)?, + tmp_ot: Self::TMP_OT.from_data(data)?, + st: Self::ST.from_data(data)?, + st_vnd: Self::ST_VND.from_data(data)?, + evt1: Self::EVT1.from_data(data)?, + evt2: Self::EVT2.from_data(data)?, + evt_vnd1: Self::EVT_VND1.from_data(data)?, + evt_vnd2: Self::EVT_VND2.from_data(data)?, + evt_vnd3: Self::EVT_VND3.from_data(data)?, + evt_vnd4: Self::EVT_VND4.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m111 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Operating State @@ -456,3 +464,13 @@ impl crate::Value for Option { } } } +impl crate::Model for InverterSinglePhaseFloat { + const ID: u16 = 111; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m111 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model112.rs b/src/models/model112.rs index 11d3083..dbfb297 100644 --- a/src/models/model112.rs +++ b/src/models/model112.rs @@ -1,10 +1,11 @@ //! Inverter (Split Phase) FLOAT +pub type Model112 = InverterSplitPhaseFloat; /// Inverter (Split Phase) FLOAT /// /// Include this model for split phase inverter monitoring using float values #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model112 { +pub struct InverterSplitPhaseFloat { /// Amps /// /// AC Current @@ -135,7 +136,7 @@ pub struct Model112 { pub evt_vnd4: Option, } #[allow(missing_docs)] -impl Model112 { +impl InverterSplitPhaseFloat { pub const A: crate::Point = crate::Point::new(0, 2, false); pub const APH_A: crate::Point = crate::Point::new(2, 2, false); pub const APH_B: crate::Point = crate::Point::new(4, 2, false); @@ -168,45 +169,52 @@ impl Model112 { pub const EVT_VND3: crate::Point> = crate::Point::new(56, 2, false); pub const EVT_VND4: crate::Point> = crate::Point::new(58, 2, false); } -impl crate::Model for Model112 { - const ID: u16 = 112; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, - pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, - pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - w: Self::W.from_data(data)?, - hz: Self::HZ.from_data(data)?, - va: Self::VA.from_data(data)?, - v_ar: Self::V_AR.from_data(data)?, - pf: Self::PF.from_data(data)?, - wh: Self::WH.from_data(data)?, - dca: Self::DCA.from_data(data)?, - dcv: Self::DCV.from_data(data)?, - dcw: Self::DCW.from_data(data)?, - tmp_cab: Self::TMP_CAB.from_data(data)?, - tmp_snk: Self::TMP_SNK.from_data(data)?, - tmp_trns: Self::TMP_TRNS.from_data(data)?, - tmp_ot: Self::TMP_OT.from_data(data)?, - st: Self::ST.from_data(data)?, - st_vnd: Self::ST_VND.from_data(data)?, - evt1: Self::EVT1.from_data(data)?, - evt2: Self::EVT2.from_data(data)?, - evt_vnd1: Self::EVT_VND1.from_data(data)?, - evt_vnd2: Self::EVT_VND2.from_data(data)?, - evt_vnd3: Self::EVT_VND3.from_data(data)?, - evt_vnd4: Self::EVT_VND4.from_data(data)?, - }) +impl crate::Group for InverterSplitPhaseFloat { + const LEN: u16 = 60; +} +impl InverterSplitPhaseFloat { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, + pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, + pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + w: Self::W.from_data(data)?, + hz: Self::HZ.from_data(data)?, + va: Self::VA.from_data(data)?, + v_ar: Self::V_AR.from_data(data)?, + pf: Self::PF.from_data(data)?, + wh: Self::WH.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + dcw: Self::DCW.from_data(data)?, + tmp_cab: Self::TMP_CAB.from_data(data)?, + tmp_snk: Self::TMP_SNK.from_data(data)?, + tmp_trns: Self::TMP_TRNS.from_data(data)?, + tmp_ot: Self::TMP_OT.from_data(data)?, + st: Self::ST.from_data(data)?, + st_vnd: Self::ST_VND.from_data(data)?, + evt1: Self::EVT1.from_data(data)?, + evt2: Self::EVT2.from_data(data)?, + evt_vnd1: Self::EVT_VND1.from_data(data)?, + evt_vnd2: Self::EVT_VND2.from_data(data)?, + evt_vnd3: Self::EVT_VND3.from_data(data)?, + evt_vnd4: Self::EVT_VND4.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m112 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Operating State @@ -458,3 +466,13 @@ impl crate::Value for Option { } } } +impl crate::Model for InverterSplitPhaseFloat { + const ID: u16 = 112; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m112 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model113.rs b/src/models/model113.rs index b4f8d3d..073dd73 100644 --- a/src/models/model113.rs +++ b/src/models/model113.rs @@ -1,10 +1,11 @@ //! Inverter (Three Phase) FLOAT +pub type Model113 = InverterThreePhaseFloat; /// Inverter (Three Phase) FLOAT /// /// Include this model for three phase inverter monitoring using float values #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model113 { +pub struct InverterThreePhaseFloat { /// Amps /// /// AC Current @@ -139,7 +140,7 @@ pub struct Model113 { pub evt_vnd4: Option, } #[allow(missing_docs)] -impl Model113 { +impl InverterThreePhaseFloat { pub const A: crate::Point = crate::Point::new(0, 2, false); pub const APH_A: crate::Point = crate::Point::new(2, 2, false); pub const APH_B: crate::Point = crate::Point::new(4, 2, false); @@ -172,45 +173,52 @@ impl Model113 { pub const EVT_VND3: crate::Point> = crate::Point::new(56, 2, false); pub const EVT_VND4: crate::Point> = crate::Point::new(58, 2, false); } -impl crate::Model for Model113 { - const ID: u16 = 113; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, - pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, - pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - w: Self::W.from_data(data)?, - hz: Self::HZ.from_data(data)?, - va: Self::VA.from_data(data)?, - v_ar: Self::V_AR.from_data(data)?, - pf: Self::PF.from_data(data)?, - wh: Self::WH.from_data(data)?, - dca: Self::DCA.from_data(data)?, - dcv: Self::DCV.from_data(data)?, - dcw: Self::DCW.from_data(data)?, - tmp_cab: Self::TMP_CAB.from_data(data)?, - tmp_snk: Self::TMP_SNK.from_data(data)?, - tmp_trns: Self::TMP_TRNS.from_data(data)?, - tmp_ot: Self::TMP_OT.from_data(data)?, - st: Self::ST.from_data(data)?, - st_vnd: Self::ST_VND.from_data(data)?, - evt1: Self::EVT1.from_data(data)?, - evt2: Self::EVT2.from_data(data)?, - evt_vnd1: Self::EVT_VND1.from_data(data)?, - evt_vnd2: Self::EVT_VND2.from_data(data)?, - evt_vnd3: Self::EVT_VND3.from_data(data)?, - evt_vnd4: Self::EVT_VND4.from_data(data)?, - }) +impl crate::Group for InverterThreePhaseFloat { + const LEN: u16 = 60; +} +impl InverterThreePhaseFloat { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, + pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, + pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + w: Self::W.from_data(data)?, + hz: Self::HZ.from_data(data)?, + va: Self::VA.from_data(data)?, + v_ar: Self::V_AR.from_data(data)?, + pf: Self::PF.from_data(data)?, + wh: Self::WH.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + dcw: Self::DCW.from_data(data)?, + tmp_cab: Self::TMP_CAB.from_data(data)?, + tmp_snk: Self::TMP_SNK.from_data(data)?, + tmp_trns: Self::TMP_TRNS.from_data(data)?, + tmp_ot: Self::TMP_OT.from_data(data)?, + st: Self::ST.from_data(data)?, + st_vnd: Self::ST_VND.from_data(data)?, + evt1: Self::EVT1.from_data(data)?, + evt2: Self::EVT2.from_data(data)?, + evt_vnd1: Self::EVT_VND1.from_data(data)?, + evt_vnd2: Self::EVT_VND2.from_data(data)?, + evt_vnd3: Self::EVT_VND3.from_data(data)?, + evt_vnd4: Self::EVT_VND4.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m113 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Operating State @@ -462,3 +470,13 @@ impl crate::Value for Option { } } } +impl crate::Model for InverterThreePhaseFloat { + const ID: u16 = 113; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m113 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model12.rs b/src/models/model12.rs index f5725f1..141d8bf 100644 --- a/src/models/model12.rs +++ b/src/models/model12.rs @@ -84,29 +84,36 @@ impl Model12 { pub const DOM_NAM: crate::Point> = crate::Point::new(73, 12, true); pub const HOST_NAM: crate::Point> = crate::Point::new(85, 12, true); } -impl crate::Model for Model12 { - const ID: u16 = 12; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - nam: Self::NAM.from_data(data)?, - cfg_st: Self::CFG_ST.from_data(data)?, - chg_st: Self::CHG_ST.from_data(data)?, - cap: Self::CAP.from_data(data)?, - cfg: Self::CFG.from_data(data)?, - ctl: Self::CTL.from_data(data)?, - addr: Self::ADDR.from_data(data)?, - msk: Self::MSK.from_data(data)?, - gw: Self::GW.from_data(data)?, - dns1: Self::DNS1.from_data(data)?, - dns2: Self::DNS2.from_data(data)?, - ntp1: Self::NTP1.from_data(data)?, - ntp2: Self::NTP2.from_data(data)?, - dom_nam: Self::DOM_NAM.from_data(data)?, - host_nam: Self::HOST_NAM.from_data(data)?, - }) +impl crate::Group for Model12 { + const LEN: u16 = 98; +} +impl Model12 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + nam: Self::NAM.from_data(data)?, + cfg_st: Self::CFG_ST.from_data(data)?, + chg_st: Self::CHG_ST.from_data(data)?, + cap: Self::CAP.from_data(data)?, + cfg: Self::CFG.from_data(data)?, + ctl: Self::CTL.from_data(data)?, + addr: Self::ADDR.from_data(data)?, + msk: Self::MSK.from_data(data)?, + gw: Self::GW.from_data(data)?, + dns1: Self::DNS1.from_data(data)?, + dns2: Self::DNS2.from_data(data)?, + ntp1: Self::NTP1.from_data(data)?, + ntp2: Self::NTP2.from_data(data)?, + dom_nam: Self::DOM_NAM.from_data(data)?, + host_nam: Self::HOST_NAM.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m12 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Config Status @@ -304,3 +311,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Model12 { + const ID: u16 = 12; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m12 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model120.rs b/src/models/model120.rs index 0bac3d5..f71e1e6 100644 --- a/src/models/model120.rs +++ b/src/models/model120.rs @@ -1,4 +1,5 @@ //! Nameplate +pub type Model120 = Nameplate; /// Nameplate /// /// Inverter Controls Nameplate Ratings @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.14.3.2, Ref 4: 17 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model120 { +pub struct Nameplate { /// DERTyp /// /// Type of DER device. Default value is 4 to indicate PV device. @@ -119,7 +120,7 @@ pub struct Model120 { pub max_dis_cha_rte_sf: Option, } #[allow(missing_docs)] -impl Model120 { +impl Nameplate { pub const DER_TYP: crate::Point = crate::Point::new(0, 1, false); pub const W_RTG: crate::Point = crate::Point::new(1, 1, false); pub const W_RTG_SF: crate::Point = crate::Point::new(2, 1, false); @@ -146,39 +147,46 @@ impl Model120 { pub const MAX_DIS_CHA_RTE: crate::Point> = crate::Point::new(23, 1, false); pub const MAX_DIS_CHA_RTE_SF: crate::Point> = crate::Point::new(24, 1, false); } -impl crate::Model for Model120 { - const ID: u16 = 120; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - der_typ: Self::DER_TYP.from_data(data)?, - w_rtg: Self::W_RTG.from_data(data)?, - w_rtg_sf: Self::W_RTG_SF.from_data(data)?, - va_rtg: Self::VA_RTG.from_data(data)?, - va_rtg_sf: Self::VA_RTG_SF.from_data(data)?, - v_ar_rtg_q1: Self::V_AR_RTG_Q1.from_data(data)?, - v_ar_rtg_q2: Self::V_AR_RTG_Q2.from_data(data)?, - v_ar_rtg_q3: Self::V_AR_RTG_Q3.from_data(data)?, - v_ar_rtg_q4: Self::V_AR_RTG_Q4.from_data(data)?, - v_ar_rtg_sf: Self::V_AR_RTG_SF.from_data(data)?, - a_rtg: Self::A_RTG.from_data(data)?, - a_rtg_sf: Self::A_RTG_SF.from_data(data)?, - pf_rtg_q1: Self::PF_RTG_Q1.from_data(data)?, - pf_rtg_q2: Self::PF_RTG_Q2.from_data(data)?, - pf_rtg_q3: Self::PF_RTG_Q3.from_data(data)?, - pf_rtg_q4: Self::PF_RTG_Q4.from_data(data)?, - pf_rtg_sf: Self::PF_RTG_SF.from_data(data)?, - wh_rtg: Self::WH_RTG.from_data(data)?, - wh_rtg_sf: Self::WH_RTG_SF.from_data(data)?, - ahr_rtg: Self::AHR_RTG.from_data(data)?, - ahr_rtg_sf: Self::AHR_RTG_SF.from_data(data)?, - max_cha_rte: Self::MAX_CHA_RTE.from_data(data)?, - max_cha_rte_sf: Self::MAX_CHA_RTE_SF.from_data(data)?, - max_dis_cha_rte: Self::MAX_DIS_CHA_RTE.from_data(data)?, - max_dis_cha_rte_sf: Self::MAX_DIS_CHA_RTE_SF.from_data(data)?, - }) +impl crate::Group for Nameplate { + const LEN: u16 = 26; +} +impl Nameplate { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + der_typ: Self::DER_TYP.from_data(data)?, + w_rtg: Self::W_RTG.from_data(data)?, + w_rtg_sf: Self::W_RTG_SF.from_data(data)?, + va_rtg: Self::VA_RTG.from_data(data)?, + va_rtg_sf: Self::VA_RTG_SF.from_data(data)?, + v_ar_rtg_q1: Self::V_AR_RTG_Q1.from_data(data)?, + v_ar_rtg_q2: Self::V_AR_RTG_Q2.from_data(data)?, + v_ar_rtg_q3: Self::V_AR_RTG_Q3.from_data(data)?, + v_ar_rtg_q4: Self::V_AR_RTG_Q4.from_data(data)?, + v_ar_rtg_sf: Self::V_AR_RTG_SF.from_data(data)?, + a_rtg: Self::A_RTG.from_data(data)?, + a_rtg_sf: Self::A_RTG_SF.from_data(data)?, + pf_rtg_q1: Self::PF_RTG_Q1.from_data(data)?, + pf_rtg_q2: Self::PF_RTG_Q2.from_data(data)?, + pf_rtg_q3: Self::PF_RTG_Q3.from_data(data)?, + pf_rtg_q4: Self::PF_RTG_Q4.from_data(data)?, + pf_rtg_sf: Self::PF_RTG_SF.from_data(data)?, + wh_rtg: Self::WH_RTG.from_data(data)?, + wh_rtg_sf: Self::WH_RTG_SF.from_data(data)?, + ahr_rtg: Self::AHR_RTG.from_data(data)?, + ahr_rtg_sf: Self::AHR_RTG_SF.from_data(data)?, + max_cha_rte: Self::MAX_CHA_RTE.from_data(data)?, + max_cha_rte_sf: Self::MAX_CHA_RTE_SF.from_data(data)?, + max_dis_cha_rte: Self::MAX_DIS_CHA_RTE.from_data(data)?, + max_dis_cha_rte_sf: Self::MAX_DIS_CHA_RTE_SF.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m120 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// DERTyp @@ -221,3 +229,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Nameplate { + const ID: u16 = 120; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m120 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model121.rs b/src/models/model121.rs index f3b29d7..7a05eb0 100644 --- a/src/models/model121.rs +++ b/src/models/model121.rs @@ -1,4 +1,5 @@ //! Basic Settings +pub type Model121 = Settings; /// Basic Settings /// /// Inverter Controls Basic Settings @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.4.2.1, Ref 4: 17 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model121 { +pub struct Settings { /// WMax /// /// Setting for maximum power output. Default to WRtg. @@ -137,7 +138,7 @@ pub struct Model121 { pub ecp_nom_hz_sf: Option, } #[allow(missing_docs)] -impl Model121 { +impl Settings { pub const W_MAX: crate::Point = crate::Point::new(0, 1, true); pub const V_REF: crate::Point = crate::Point::new(1, 1, true); pub const V_REF_OFS: crate::Point = crate::Point::new(2, 1, true); @@ -169,44 +170,51 @@ impl Model121 { pub const MAX_RMP_RTE_SF: crate::Point> = crate::Point::new(28, 1, false); pub const ECP_NOM_HZ_SF: crate::Point> = crate::Point::new(29, 1, false); } -impl crate::Model for Model121 { - const ID: u16 = 121; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - w_max: Self::W_MAX.from_data(data)?, - v_ref: Self::V_REF.from_data(data)?, - v_ref_ofs: Self::V_REF_OFS.from_data(data)?, - v_max: Self::V_MAX.from_data(data)?, - v_min: Self::V_MIN.from_data(data)?, - va_max: Self::VA_MAX.from_data(data)?, - v_ar_max_q1: Self::V_AR_MAX_Q1.from_data(data)?, - v_ar_max_q2: Self::V_AR_MAX_Q2.from_data(data)?, - v_ar_max_q3: Self::V_AR_MAX_Q3.from_data(data)?, - v_ar_max_q4: Self::V_AR_MAX_Q4.from_data(data)?, - w_gra: Self::W_GRA.from_data(data)?, - pf_min_q1: Self::PF_MIN_Q1.from_data(data)?, - pf_min_q2: Self::PF_MIN_Q2.from_data(data)?, - pf_min_q3: Self::PF_MIN_Q3.from_data(data)?, - pf_min_q4: Self::PF_MIN_Q4.from_data(data)?, - v_ar_act: Self::V_AR_ACT.from_data(data)?, - clc_tot_va: Self::CLC_TOT_VA.from_data(data)?, - max_rmp_rte: Self::MAX_RMP_RTE.from_data(data)?, - ecp_nom_hz: Self::ECP_NOM_HZ.from_data(data)?, - conn_ph: Self::CONN_PH.from_data(data)?, - w_max_sf: Self::W_MAX_SF.from_data(data)?, - v_ref_sf: Self::V_REF_SF.from_data(data)?, - v_ref_ofs_sf: Self::V_REF_OFS_SF.from_data(data)?, - v_min_max_sf: Self::V_MIN_MAX_SF.from_data(data)?, - va_max_sf: Self::VA_MAX_SF.from_data(data)?, - v_ar_max_sf: Self::V_AR_MAX_SF.from_data(data)?, - w_gra_sf: Self::W_GRA_SF.from_data(data)?, - pf_min_sf: Self::PF_MIN_SF.from_data(data)?, - max_rmp_rte_sf: Self::MAX_RMP_RTE_SF.from_data(data)?, - ecp_nom_hz_sf: Self::ECP_NOM_HZ_SF.from_data(data)?, - }) +impl crate::Group for Settings { + const LEN: u16 = 30; +} +impl Settings { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + w_max: Self::W_MAX.from_data(data)?, + v_ref: Self::V_REF.from_data(data)?, + v_ref_ofs: Self::V_REF_OFS.from_data(data)?, + v_max: Self::V_MAX.from_data(data)?, + v_min: Self::V_MIN.from_data(data)?, + va_max: Self::VA_MAX.from_data(data)?, + v_ar_max_q1: Self::V_AR_MAX_Q1.from_data(data)?, + v_ar_max_q2: Self::V_AR_MAX_Q2.from_data(data)?, + v_ar_max_q3: Self::V_AR_MAX_Q3.from_data(data)?, + v_ar_max_q4: Self::V_AR_MAX_Q4.from_data(data)?, + w_gra: Self::W_GRA.from_data(data)?, + pf_min_q1: Self::PF_MIN_Q1.from_data(data)?, + pf_min_q2: Self::PF_MIN_Q2.from_data(data)?, + pf_min_q3: Self::PF_MIN_Q3.from_data(data)?, + pf_min_q4: Self::PF_MIN_Q4.from_data(data)?, + v_ar_act: Self::V_AR_ACT.from_data(data)?, + clc_tot_va: Self::CLC_TOT_VA.from_data(data)?, + max_rmp_rte: Self::MAX_RMP_RTE.from_data(data)?, + ecp_nom_hz: Self::ECP_NOM_HZ.from_data(data)?, + conn_ph: Self::CONN_PH.from_data(data)?, + w_max_sf: Self::W_MAX_SF.from_data(data)?, + v_ref_sf: Self::V_REF_SF.from_data(data)?, + v_ref_ofs_sf: Self::V_REF_OFS_SF.from_data(data)?, + v_min_max_sf: Self::V_MIN_MAX_SF.from_data(data)?, + va_max_sf: Self::VA_MAX_SF.from_data(data)?, + v_ar_max_sf: Self::V_AR_MAX_SF.from_data(data)?, + w_gra_sf: Self::W_GRA_SF.from_data(data)?, + pf_min_sf: Self::PF_MIN_SF.from_data(data)?, + max_rmp_rte_sf: Self::MAX_RMP_RTE_SF.from_data(data)?, + ecp_nom_hz_sf: Self::ECP_NOM_HZ_SF.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m121 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// VArAct @@ -331,3 +339,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Settings { + const ID: u16 = 121; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m121 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model122.rs b/src/models/model122.rs index 9767218..d863f17 100644 --- a/src/models/model122.rs +++ b/src/models/model122.rs @@ -1,4 +1,5 @@ //! Measurements_Status +pub type Model122 = Status; /// Measurements_Status /// /// Inverter Controls Extended Measurements and Status @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.14.3.2, Ref 4: 17 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model122 { +pub struct Status { /// PVConn /// /// PV inverter present/available status. Enumerated value. @@ -91,7 +92,7 @@ pub struct Model122 { pub ris_sf: Option, } #[allow(missing_docs)] -impl Model122 { +impl Status { pub const PV_CONN: crate::Point = crate::Point::new(0, 1, false); pub const STOR_CONN: crate::Point = crate::Point::new(1, 1, false); pub const ECP_CONN: crate::Point = crate::Point::new(2, 1, false); @@ -114,34 +115,41 @@ impl Model122 { pub const RIS: crate::Point> = crate::Point::new(42, 1, false); pub const RIS_SF: crate::Point> = crate::Point::new(43, 1, false); } -impl crate::Model for Model122 { - const ID: u16 = 122; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - pv_conn: Self::PV_CONN.from_data(data)?, - stor_conn: Self::STOR_CONN.from_data(data)?, - ecp_conn: Self::ECP_CONN.from_data(data)?, - act_wh: Self::ACT_WH.from_data(data)?, - act_v_ah: Self::ACT_V_AH.from_data(data)?, - act_v_arh_q1: Self::ACT_V_ARH_Q1.from_data(data)?, - act_v_arh_q2: Self::ACT_V_ARH_Q2.from_data(data)?, - act_v_arh_q3: Self::ACT_V_ARH_Q3.from_data(data)?, - act_v_arh_q4: Self::ACT_V_ARH_Q4.from_data(data)?, - v_ar_aval: Self::V_AR_AVAL.from_data(data)?, - v_ar_aval_sf: Self::V_AR_AVAL_SF.from_data(data)?, - w_aval: Self::W_AVAL.from_data(data)?, - w_aval_sf: Self::W_AVAL_SF.from_data(data)?, - st_set_lim_msk: Self::ST_SET_LIM_MSK.from_data(data)?, - st_act_ctl: Self::ST_ACT_CTL.from_data(data)?, - tm_src: Self::TM_SRC.from_data(data)?, - tms: Self::TMS.from_data(data)?, - rt_st: Self::RT_ST.from_data(data)?, - ris: Self::RIS.from_data(data)?, - ris_sf: Self::RIS_SF.from_data(data)?, - }) +impl crate::Group for Status { + const LEN: u16 = 44; +} +impl Status { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + pv_conn: Self::PV_CONN.from_data(data)?, + stor_conn: Self::STOR_CONN.from_data(data)?, + ecp_conn: Self::ECP_CONN.from_data(data)?, + act_wh: Self::ACT_WH.from_data(data)?, + act_v_ah: Self::ACT_V_AH.from_data(data)?, + act_v_arh_q1: Self::ACT_V_ARH_Q1.from_data(data)?, + act_v_arh_q2: Self::ACT_V_ARH_Q2.from_data(data)?, + act_v_arh_q3: Self::ACT_V_ARH_Q3.from_data(data)?, + act_v_arh_q4: Self::ACT_V_ARH_Q4.from_data(data)?, + v_ar_aval: Self::V_AR_AVAL.from_data(data)?, + v_ar_aval_sf: Self::V_AR_AVAL_SF.from_data(data)?, + w_aval: Self::W_AVAL.from_data(data)?, + w_aval_sf: Self::W_AVAL_SF.from_data(data)?, + st_set_lim_msk: Self::ST_SET_LIM_MSK.from_data(data)?, + st_act_ctl: Self::ST_ACT_CTL.from_data(data)?, + tm_src: Self::TM_SRC.from_data(data)?, + tms: Self::TMS.from_data(data)?, + rt_st: Self::RT_ST.from_data(data)?, + ris: Self::RIS.from_data(data)?, + ris_sf: Self::RIS_SF.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m122 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -359,3 +367,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Status { + const ID: u16 = 122; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m122 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model123.rs b/src/models/model123.rs index 004d77a..b41df3b 100644 --- a/src/models/model123.rs +++ b/src/models/model123.rs @@ -1,4 +1,5 @@ //! Immediate Controls +pub type Model123 = Controls; /// Immediate Controls /// /// Immediate Inverter Controls @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.7.1.2, 8.7.2.2, 8.7.3.2 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model123 { +pub struct Controls { /// Conn_WinTms /// /// Time window for connect/disconnect. @@ -105,7 +106,7 @@ pub struct Model123 { pub v_ar_pct_sf: Option, } #[allow(missing_docs)] -impl Model123 { +impl Controls { pub const CONN_WIN_TMS: crate::Point> = crate::Point::new(0, 1, true); pub const CONN_RVRT_TMS: crate::Point> = crate::Point::new(1, 1, true); pub const CONN: crate::Point = crate::Point::new(2, 1, true); @@ -134,38 +135,45 @@ impl Model123 { pub const OUT_PF_SET_SF: crate::Point = crate::Point::new(22, 1, false); pub const V_AR_PCT_SF: crate::Point> = crate::Point::new(23, 1, false); } -impl crate::Model for Model123 { - const ID: u16 = 123; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - conn_win_tms: Self::CONN_WIN_TMS.from_data(data)?, - conn_rvrt_tms: Self::CONN_RVRT_TMS.from_data(data)?, - conn: Self::CONN.from_data(data)?, - w_max_lim_pct: Self::W_MAX_LIM_PCT.from_data(data)?, - w_max_lim_pct_win_tms: Self::W_MAX_LIM_PCT_WIN_TMS.from_data(data)?, - w_max_lim_pct_rvrt_tms: Self::W_MAX_LIM_PCT_RVRT_TMS.from_data(data)?, - w_max_lim_pct_rmp_tms: Self::W_MAX_LIM_PCT_RMP_TMS.from_data(data)?, - w_max_lim_ena: Self::W_MAX_LIM_ENA.from_data(data)?, - out_pf_set: Self::OUT_PF_SET.from_data(data)?, - out_pf_set_win_tms: Self::OUT_PF_SET_WIN_TMS.from_data(data)?, - out_pf_set_rvrt_tms: Self::OUT_PF_SET_RVRT_TMS.from_data(data)?, - out_pf_set_rmp_tms: Self::OUT_PF_SET_RMP_TMS.from_data(data)?, - out_pf_set_ena: Self::OUT_PF_SET_ENA.from_data(data)?, - v_ar_w_max_pct: Self::V_AR_W_MAX_PCT.from_data(data)?, - v_ar_max_pct: Self::V_AR_MAX_PCT.from_data(data)?, - v_ar_aval_pct: Self::V_AR_AVAL_PCT.from_data(data)?, - v_ar_pct_win_tms: Self::V_AR_PCT_WIN_TMS.from_data(data)?, - v_ar_pct_rvrt_tms: Self::V_AR_PCT_RVRT_TMS.from_data(data)?, - v_ar_pct_rmp_tms: Self::V_AR_PCT_RMP_TMS.from_data(data)?, - v_ar_pct_mod: Self::V_AR_PCT_MOD.from_data(data)?, - v_ar_pct_ena: Self::V_AR_PCT_ENA.from_data(data)?, - w_max_lim_pct_sf: Self::W_MAX_LIM_PCT_SF.from_data(data)?, - out_pf_set_sf: Self::OUT_PF_SET_SF.from_data(data)?, - v_ar_pct_sf: Self::V_AR_PCT_SF.from_data(data)?, - }) +impl crate::Group for Controls { + const LEN: u16 = 24; +} +impl Controls { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + conn_win_tms: Self::CONN_WIN_TMS.from_data(data)?, + conn_rvrt_tms: Self::CONN_RVRT_TMS.from_data(data)?, + conn: Self::CONN.from_data(data)?, + w_max_lim_pct: Self::W_MAX_LIM_PCT.from_data(data)?, + w_max_lim_pct_win_tms: Self::W_MAX_LIM_PCT_WIN_TMS.from_data(data)?, + w_max_lim_pct_rvrt_tms: Self::W_MAX_LIM_PCT_RVRT_TMS.from_data(data)?, + w_max_lim_pct_rmp_tms: Self::W_MAX_LIM_PCT_RMP_TMS.from_data(data)?, + w_max_lim_ena: Self::W_MAX_LIM_ENA.from_data(data)?, + out_pf_set: Self::OUT_PF_SET.from_data(data)?, + out_pf_set_win_tms: Self::OUT_PF_SET_WIN_TMS.from_data(data)?, + out_pf_set_rvrt_tms: Self::OUT_PF_SET_RVRT_TMS.from_data(data)?, + out_pf_set_rmp_tms: Self::OUT_PF_SET_RMP_TMS.from_data(data)?, + out_pf_set_ena: Self::OUT_PF_SET_ENA.from_data(data)?, + v_ar_w_max_pct: Self::V_AR_W_MAX_PCT.from_data(data)?, + v_ar_max_pct: Self::V_AR_MAX_PCT.from_data(data)?, + v_ar_aval_pct: Self::V_AR_AVAL_PCT.from_data(data)?, + v_ar_pct_win_tms: Self::V_AR_PCT_WIN_TMS.from_data(data)?, + v_ar_pct_rvrt_tms: Self::V_AR_PCT_RVRT_TMS.from_data(data)?, + v_ar_pct_rmp_tms: Self::V_AR_PCT_RMP_TMS.from_data(data)?, + v_ar_pct_mod: Self::V_AR_PCT_MOD.from_data(data)?, + v_ar_pct_ena: Self::V_AR_PCT_ENA.from_data(data)?, + w_max_lim_pct_sf: Self::W_MAX_LIM_PCT_SF.from_data(data)?, + out_pf_set_sf: Self::OUT_PF_SET_SF.from_data(data)?, + v_ar_pct_sf: Self::V_AR_PCT_SF.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m123 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Conn @@ -372,3 +380,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Controls { + const ID: u16 = 123; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m123 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model124.rs b/src/models/model124.rs index 52ca4f4..dda509a 100644 --- a/src/models/model124.rs +++ b/src/models/model124.rs @@ -1,4 +1,5 @@ //! Storage +pub type Model124 = StorageBasic; /// Storage /// /// Basic Storage Controls @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.7.4.2 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model124 { +pub struct StorageBasic { /// WChaMax /// /// Setpoint for maximum charge. @@ -103,7 +104,7 @@ pub struct Model124 { pub in_out_w_rte_sf: Option, } #[allow(missing_docs)] -impl Model124 { +impl StorageBasic { pub const W_CHA_MAX: crate::Point = crate::Point::new(0, 1, true); pub const W_CHA_GRA: crate::Point = crate::Point::new(1, 1, true); pub const W_DIS_CHA_GRA: crate::Point = crate::Point::new(2, 1, true); @@ -132,38 +133,45 @@ impl Model124 { pub const IN_BAT_V_SF: crate::Point> = crate::Point::new(22, 1, false); pub const IN_OUT_W_RTE_SF: crate::Point> = crate::Point::new(23, 1, false); } -impl crate::Model for Model124 { - const ID: u16 = 124; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - w_cha_max: Self::W_CHA_MAX.from_data(data)?, - w_cha_gra: Self::W_CHA_GRA.from_data(data)?, - w_dis_cha_gra: Self::W_DIS_CHA_GRA.from_data(data)?, - stor_ctl_mod: Self::STOR_CTL_MOD.from_data(data)?, - va_cha_max: Self::VA_CHA_MAX.from_data(data)?, - min_rsv_pct: Self::MIN_RSV_PCT.from_data(data)?, - cha_state: Self::CHA_STATE.from_data(data)?, - stor_aval: Self::STOR_AVAL.from_data(data)?, - in_bat_v: Self::IN_BAT_V.from_data(data)?, - cha_st: Self::CHA_ST.from_data(data)?, - out_w_rte: Self::OUT_W_RTE.from_data(data)?, - in_w_rte: Self::IN_W_RTE.from_data(data)?, - in_out_w_rte_win_tms: Self::IN_OUT_W_RTE_WIN_TMS.from_data(data)?, - in_out_w_rte_rvrt_tms: Self::IN_OUT_W_RTE_RVRT_TMS.from_data(data)?, - in_out_w_rte_rmp_tms: Self::IN_OUT_W_RTE_RMP_TMS.from_data(data)?, - cha_gri_set: Self::CHA_GRI_SET.from_data(data)?, - w_cha_max_sf: Self::W_CHA_MAX_SF.from_data(data)?, - w_cha_dis_cha_gra_sf: Self::W_CHA_DIS_CHA_GRA_SF.from_data(data)?, - va_cha_max_sf: Self::VA_CHA_MAX_SF.from_data(data)?, - min_rsv_pct_sf: Self::MIN_RSV_PCT_SF.from_data(data)?, - cha_state_sf: Self::CHA_STATE_SF.from_data(data)?, - stor_aval_sf: Self::STOR_AVAL_SF.from_data(data)?, - in_bat_v_sf: Self::IN_BAT_V_SF.from_data(data)?, - in_out_w_rte_sf: Self::IN_OUT_W_RTE_SF.from_data(data)?, - }) +impl crate::Group for StorageBasic { + const LEN: u16 = 24; +} +impl StorageBasic { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + w_cha_max: Self::W_CHA_MAX.from_data(data)?, + w_cha_gra: Self::W_CHA_GRA.from_data(data)?, + w_dis_cha_gra: Self::W_DIS_CHA_GRA.from_data(data)?, + stor_ctl_mod: Self::STOR_CTL_MOD.from_data(data)?, + va_cha_max: Self::VA_CHA_MAX.from_data(data)?, + min_rsv_pct: Self::MIN_RSV_PCT.from_data(data)?, + cha_state: Self::CHA_STATE.from_data(data)?, + stor_aval: Self::STOR_AVAL.from_data(data)?, + in_bat_v: Self::IN_BAT_V.from_data(data)?, + cha_st: Self::CHA_ST.from_data(data)?, + out_w_rte: Self::OUT_W_RTE.from_data(data)?, + in_w_rte: Self::IN_W_RTE.from_data(data)?, + in_out_w_rte_win_tms: Self::IN_OUT_W_RTE_WIN_TMS.from_data(data)?, + in_out_w_rte_rvrt_tms: Self::IN_OUT_W_RTE_RVRT_TMS.from_data(data)?, + in_out_w_rte_rmp_tms: Self::IN_OUT_W_RTE_RMP_TMS.from_data(data)?, + cha_gri_set: Self::CHA_GRI_SET.from_data(data)?, + w_cha_max_sf: Self::W_CHA_MAX_SF.from_data(data)?, + w_cha_dis_cha_gra_sf: Self::W_CHA_DIS_CHA_GRA_SF.from_data(data)?, + va_cha_max_sf: Self::VA_CHA_MAX_SF.from_data(data)?, + min_rsv_pct_sf: Self::MIN_RSV_PCT_SF.from_data(data)?, + cha_state_sf: Self::CHA_STATE_SF.from_data(data)?, + stor_aval_sf: Self::STOR_AVAL_SF.from_data(data)?, + in_bat_v_sf: Self::IN_BAT_V_SF.from_data(data)?, + in_out_w_rte_sf: Self::IN_OUT_W_RTE_SF.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m124 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -288,3 +296,13 @@ impl crate::Value for Option { } } } +impl crate::Model for StorageBasic { + const ID: u16 = 124; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m124 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model125.rs b/src/models/model125.rs index 9128936..21f9cc6 100644 --- a/src/models/model125.rs +++ b/src/models/model125.rs @@ -1,4 +1,5 @@ //! Pricing +pub type Model125 = Pricing; /// Pricing /// /// Pricing Signal @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.7.5.1; Ref 4: 6 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model125 { +pub struct Pricing { /// ModEna /// /// Is price-based charge/discharge mode active? @@ -37,7 +38,7 @@ pub struct Model125 { pub sig_sf: i16, } #[allow(missing_docs)] -impl Model125 { +impl Pricing { pub const MOD_ENA: crate::Point = crate::Point::new(0, 1, true); pub const SIG_TYPE: crate::Point> = crate::Point::new(1, 1, true); pub const SIG: crate::Point = crate::Point::new(2, 1, true); @@ -46,21 +47,28 @@ impl Model125 { pub const RMP_TMS: crate::Point> = crate::Point::new(5, 1, true); pub const SIG_SF: crate::Point = crate::Point::new(6, 1, false); } -impl crate::Model for Model125 { - const ID: u16 = 125; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - mod_ena: Self::MOD_ENA.from_data(data)?, - sig_type: Self::SIG_TYPE.from_data(data)?, - sig: Self::SIG.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvt_tms: Self::RVT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - sig_sf: Self::SIG_SF.from_data(data)?, - }) +impl crate::Group for Pricing { + const LEN: u16 = 8; +} +impl Pricing { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + mod_ena: Self::MOD_ENA.from_data(data)?, + sig_type: Self::SIG_TYPE.from_data(data)?, + sig: Self::SIG.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvt_tms: Self::RVT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + sig_sf: Self::SIG_SF.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m125 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -142,3 +150,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Pricing { + const ID: u16 = 125; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m125 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model126.rs b/src/models/model126.rs index 6d085ef..f3f86fa 100644 --- a/src/models/model126.rs +++ b/src/models/model126.rs @@ -1,4 +1,5 @@ //! Static Volt-VAR +pub type Model126 = VoltVar; /// Static Volt-VAR /// /// Static Volt-VAR Arrays @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.8.1.2 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model126 { +pub struct VoltVar { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -45,9 +46,11 @@ pub struct Model126 { pub dept_ref_sf: i16, #[allow(missing_docs)] pub rmp_inc_dec_sf: Option, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model126 { +impl VoltVar { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -59,24 +62,33 @@ impl Model126 { pub const DEPT_REF_SF: crate::Point = crate::Point::new(8, 1, false); pub const RMP_INC_DEC_SF: crate::Point> = crate::Point::new(9, 1, false); } -impl crate::Model for Model126 { - const ID: u16 = 126; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, - rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, - }) +impl crate::Group for VoltVar { + const LEN: u16 = 10; +} +impl VoltVar { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, + rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m126 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -111,3 +123,417 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// DeptRef + /// + /// Meaning of dependent variable: 1=%WMax 2=%VArMax 3=%VArAval. + pub dept_ref: CurveDeptRef, + /// V1 + /// + /// Point 1 Volts. + pub v1: u16, + /// VAr1 + /// + /// Point 1 VARs. + pub v_ar1: i16, + /// V2 + /// + /// Point 2 Volts. + pub v2: Option, + /// VAr2 + /// + /// Point 2 VARs. + pub v_ar2: Option, + /// V3 + /// + /// Point 3 Volts. + pub v3: Option, + /// VAr3 + /// + /// Point 3 VARs. + pub v_ar3: Option, + /// V4 + /// + /// Point 4 Volts. + pub v4: Option, + /// VAr4 + /// + /// Point 4 VARs. + pub v_ar4: Option, + /// V5 + /// + /// Point 5 Volts. + pub v5: Option, + /// VAr5 + /// + /// Point 5 VARs. + pub v_ar5: Option, + /// V6 + /// + /// Point 6 Volts. + pub v6: Option, + /// VAr6 + /// + /// Point 6 VARs. + pub v_ar6: Option, + /// V7 + /// + /// Point 7 Volts. + pub v7: Option, + /// VAr7 + /// + /// Point 7 VARs. + pub v_ar7: Option, + /// V8 + /// + /// Point 8 Volts. + pub v8: Option, + /// VAr8 + /// + /// Point 8 VARs. + pub v_ar8: Option, + /// V9 + /// + /// Point 9 Volts. + pub v9: Option, + /// VAr9 + /// + /// Point 9 VARs. + pub v_ar9: Option, + /// V10 + /// + /// Point 10 Volts. + pub v10: Option, + /// VAr10 + /// + /// Point 10 VARs. + pub v_ar10: Option, + /// V11 + /// + /// Point 11 Volts. + pub v11: Option, + /// VAr11 + /// + /// Point 11 VARs. + pub v_ar11: Option, + /// V12 + /// + /// Point 12 Volts. + pub v12: Option, + /// VAr12 + /// + /// Point 12 VARs. + pub v_ar12: Option, + /// V13 + /// + /// Point 13 Volts. + pub v13: Option, + /// VAr13 + /// + /// Point 13 VARs. + pub v_ar13: Option, + /// V14 + /// + /// Point 14 Volts. + pub v14: Option, + /// VAr14 + /// + /// Point 14 VARs. + pub v_ar14: Option, + /// V15 + /// + /// Point 15 Volts. + pub v15: Option, + /// VAr15 + /// + /// Point 15 VARs. + pub v_ar15: Option, + /// V16 + /// + /// Point 16 Volts. + pub v16: Option, + /// VAr16 + /// + /// Point 16 VARs. + pub v_ar16: Option, + /// V17 + /// + /// Point 17 Volts. + pub v17: Option, + /// VAr17 + /// + /// Point 17 VARs. + pub v_ar17: Option, + /// V18 + /// + /// Point 18 Volts. + pub v18: Option, + /// VAr18 + /// + /// Point 18 VARs. + pub v_ar18: Option, + /// V19 + /// + /// Point 19 Volts. + pub v19: Option, + /// VAr19 + /// + /// Point 19 VARs. + pub v_ar19: Option, + /// V20 + /// + /// Point 20 Volts. + pub v20: Option, + /// VAr20 + /// + /// Point 20 VARs. + pub v_ar20: Option, + /// CrvNam + /// + /// Optional description for curve. (Max 16 chars) + pub crv_nam: Option, + /// RmpTms + /// + /// The time of the PT1 in seconds (time to accomplish a change of 95%). + pub rmp_tms: Option, + /// RmpDecTmm + /// + /// The maximum rate at which the VAR value may be reduced in response to changes in the voltage value. %refVal is %WMax %VArMax or %VArAval depending on value of DeptRef. + pub rmp_dec_tmm: Option, + /// RmpIncTmm + /// + /// The maximum rate at which the VAR value may be increased in response to changes in the voltage value. %refVal is %WMax %VArMax or %VArAval depending on value of DeptRef. + pub rmp_inc_tmm: Option, + /// ReadOnly + /// + /// Boolean flag indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const DEPT_REF: crate::Point = crate::Point::new(1, 1, true); + pub const V1: crate::Point = crate::Point::new(2, 1, true); + pub const V_AR1: crate::Point = crate::Point::new(3, 1, true); + pub const V2: crate::Point> = crate::Point::new(4, 1, true); + pub const V_AR2: crate::Point> = crate::Point::new(5, 1, true); + pub const V3: crate::Point> = crate::Point::new(6, 1, true); + pub const V_AR3: crate::Point> = crate::Point::new(7, 1, true); + pub const V4: crate::Point> = crate::Point::new(8, 1, true); + pub const V_AR4: crate::Point> = crate::Point::new(9, 1, true); + pub const V5: crate::Point> = crate::Point::new(10, 1, true); + pub const V_AR5: crate::Point> = crate::Point::new(11, 1, true); + pub const V6: crate::Point> = crate::Point::new(12, 1, true); + pub const V_AR6: crate::Point> = crate::Point::new(13, 1, true); + pub const V7: crate::Point> = crate::Point::new(14, 1, true); + pub const V_AR7: crate::Point> = crate::Point::new(15, 1, true); + pub const V8: crate::Point> = crate::Point::new(16, 1, true); + pub const V_AR8: crate::Point> = crate::Point::new(17, 1, true); + pub const V9: crate::Point> = crate::Point::new(18, 1, true); + pub const V_AR9: crate::Point> = crate::Point::new(19, 1, true); + pub const V10: crate::Point> = crate::Point::new(20, 1, true); + pub const V_AR10: crate::Point> = crate::Point::new(21, 1, true); + pub const V11: crate::Point> = crate::Point::new(22, 1, true); + pub const V_AR11: crate::Point> = crate::Point::new(23, 1, true); + pub const V12: crate::Point> = crate::Point::new(24, 1, true); + pub const V_AR12: crate::Point> = crate::Point::new(25, 1, true); + pub const V13: crate::Point> = crate::Point::new(26, 1, true); + pub const V_AR13: crate::Point> = crate::Point::new(27, 1, true); + pub const V14: crate::Point> = crate::Point::new(28, 1, true); + pub const V_AR14: crate::Point> = crate::Point::new(29, 1, true); + pub const V15: crate::Point> = crate::Point::new(30, 1, true); + pub const V_AR15: crate::Point> = crate::Point::new(31, 1, true); + pub const V16: crate::Point> = crate::Point::new(32, 1, true); + pub const V_AR16: crate::Point> = crate::Point::new(33, 1, true); + pub const V17: crate::Point> = crate::Point::new(34, 1, true); + pub const V_AR17: crate::Point> = crate::Point::new(35, 1, true); + pub const V18: crate::Point> = crate::Point::new(36, 1, true); + pub const V_AR18: crate::Point> = crate::Point::new(37, 1, true); + pub const V19: crate::Point> = crate::Point::new(38, 1, true); + pub const V_AR19: crate::Point> = crate::Point::new(39, 1, true); + pub const V20: crate::Point> = crate::Point::new(40, 1, true); + pub const V_AR20: crate::Point> = crate::Point::new(41, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(42, 8, true); + pub const RMP_TMS: crate::Point> = crate::Point::new(50, 1, true); + pub const RMP_DEC_TMM: crate::Point> = crate::Point::new(51, 1, true); + pub const RMP_INC_TMM: crate::Point> = crate::Point::new(52, 1, true); + pub const READ_ONLY: crate::Point = crate::Point::new(53, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 54; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + dept_ref: Self::DEPT_REF.from_data(data)?, + v1: Self::V1.from_data(data)?, + v_ar1: Self::V_AR1.from_data(data)?, + v2: Self::V2.from_data(data)?, + v_ar2: Self::V_AR2.from_data(data)?, + v3: Self::V3.from_data(data)?, + v_ar3: Self::V_AR3.from_data(data)?, + v4: Self::V4.from_data(data)?, + v_ar4: Self::V_AR4.from_data(data)?, + v5: Self::V5.from_data(data)?, + v_ar5: Self::V_AR5.from_data(data)?, + v6: Self::V6.from_data(data)?, + v_ar6: Self::V_AR6.from_data(data)?, + v7: Self::V7.from_data(data)?, + v_ar7: Self::V_AR7.from_data(data)?, + v8: Self::V8.from_data(data)?, + v_ar8: Self::V_AR8.from_data(data)?, + v9: Self::V9.from_data(data)?, + v_ar9: Self::V_AR9.from_data(data)?, + v10: Self::V10.from_data(data)?, + v_ar10: Self::V_AR10.from_data(data)?, + v11: Self::V11.from_data(data)?, + v_ar11: Self::V_AR11.from_data(data)?, + v12: Self::V12.from_data(data)?, + v_ar12: Self::V_AR12.from_data(data)?, + v13: Self::V13.from_data(data)?, + v_ar13: Self::V_AR13.from_data(data)?, + v14: Self::V14.from_data(data)?, + v_ar14: Self::V_AR14.from_data(data)?, + v15: Self::V15.from_data(data)?, + v_ar15: Self::V_AR15.from_data(data)?, + v16: Self::V16.from_data(data)?, + v_ar16: Self::V_AR16.from_data(data)?, + v17: Self::V17.from_data(data)?, + v_ar17: Self::V_AR17.from_data(data)?, + v18: Self::V18.from_data(data)?, + v_ar18: Self::V_AR18.from_data(data)?, + v19: Self::V19.from_data(data)?, + v_ar19: Self::V_AR19.from_data(data)?, + v20: Self::V20.from_data(data)?, + v_ar20: Self::V_AR20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + rmp_dec_tmm: Self::RMP_DEC_TMM.from_data(data)?, + rmp_inc_tmm: Self::RMP_INC_TMM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &VoltVar, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &VoltVar, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// DeptRef +/// +/// Meaning of dependent variable: 1=%WMax 2=%VArMax 3=%VArAval. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveDeptRef { + #[allow(missing_docs)] + WMax = 1, + #[allow(missing_docs)] + VArMax = 2, + #[allow(missing_docs)] + VArAval = 3, +} +impl crate::Value for CurveDeptRef { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveDeptRef::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// ReadOnly +/// +/// Boolean flag indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for VoltVar { + const ID: u16 = 126; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m126 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model127.rs b/src/models/model127.rs index 12db6f3..9878162 100644 --- a/src/models/model127.rs +++ b/src/models/model127.rs @@ -1,4 +1,5 @@ //! Freq-Watt Param +pub type Model127 = FreqWattParam; /// Freq-Watt Param /// /// Parameterized Frequency-Watt @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.9.1.2, 8.9.4.2 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model127 { +pub struct FreqWattParam { /// WGra /// /// The slope of the reduction in the maximum allowed watts output as a function of frequency. @@ -45,7 +46,7 @@ pub struct Model127 { pub rmp_inc_dec_sf: Option, } #[allow(missing_docs)] -impl Model127 { +impl FreqWattParam { pub const W_GRA: crate::Point = crate::Point::new(0, 1, true); pub const HZ_STR: crate::Point = crate::Point::new(1, 1, true); pub const HZ_STOP: crate::Point = crate::Point::new(2, 1, true); @@ -56,23 +57,30 @@ impl Model127 { pub const HZ_STR_STOP_SF: crate::Point> = crate::Point::new(7, 1, false); pub const RMP_INC_DEC_SF: crate::Point> = crate::Point::new(8, 1, false); } -impl crate::Model for Model127 { - const ID: u16 = 127; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - w_gra: Self::W_GRA.from_data(data)?, - hz_str: Self::HZ_STR.from_data(data)?, - hz_stop: Self::HZ_STOP.from_data(data)?, - hys_ena: Self::HYS_ENA.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - hz_stop_w_gra: Self::HZ_STOP_W_GRA.from_data(data)?, - w_gra_sf: Self::W_GRA_SF.from_data(data)?, - hz_str_stop_sf: Self::HZ_STR_STOP_SF.from_data(data)?, - rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, - }) +impl crate::Group for FreqWattParam { + const LEN: u16 = 10; +} +impl FreqWattParam { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + w_gra: Self::W_GRA.from_data(data)?, + hz_str: Self::HZ_STR.from_data(data)?, + hz_stop: Self::HZ_STOP.from_data(data)?, + hys_ena: Self::HYS_ENA.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + hz_stop_w_gra: Self::HZ_STOP_W_GRA.from_data(data)?, + w_gra_sf: Self::W_GRA_SF.from_data(data)?, + hz_str_stop_sf: Self::HZ_STR_STOP_SF.from_data(data)?, + rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m127 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -140,3 +148,13 @@ impl crate::Value for Option { } } } +impl crate::Model for FreqWattParam { + const ID: u16 = 127; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m127 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model128.rs b/src/models/model128.rs index ad14428..164e686 100644 --- a/src/models/model128.rs +++ b/src/models/model128.rs @@ -1,4 +1,5 @@ //! Dynamic Reactive Current +pub type Model128 = ReactiveCurrent; /// Dynamic Reactive Current /// /// Dynamic Reactive Current @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.10.1.2; Ref 4: 12 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model128 { +pub struct ReactiveCurrent { /// ArGraMod /// /// Indicates if gradients trend toward zero at the edges of the deadband or trend toward zero at the center of the deadband. @@ -61,7 +62,7 @@ pub struct Model128 { pub v_ref_pct_sf: Option, } #[allow(missing_docs)] -impl Model128 { +impl ReactiveCurrent { pub const AR_GRA_MOD: crate::Point = crate::Point::new(0, 1, true); pub const AR_GRA_SAG: crate::Point = crate::Point::new(1, 1, true); pub const AR_GRA_SWELL: crate::Point = crate::Point::new(2, 1, true); @@ -76,27 +77,34 @@ impl Model128 { pub const AR_GRA_SF: crate::Point = crate::Point::new(11, 1, false); pub const V_REF_PCT_SF: crate::Point> = crate::Point::new(12, 1, false); } -impl crate::Model for Model128 { - const ID: u16 = 128; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ar_gra_mod: Self::AR_GRA_MOD.from_data(data)?, - ar_gra_sag: Self::AR_GRA_SAG.from_data(data)?, - ar_gra_swell: Self::AR_GRA_SWELL.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - fil_tms: Self::FIL_TMS.from_data(data)?, - db_v_min: Self::DB_V_MIN.from_data(data)?, - db_v_max: Self::DB_V_MAX.from_data(data)?, - blk_zn_v: Self::BLK_ZN_V.from_data(data)?, - hys_blk_zn_v: Self::HYS_BLK_ZN_V.from_data(data)?, - blk_zn_tmms: Self::BLK_ZN_TMMS.from_data(data)?, - hold_tmms: Self::HOLD_TMMS.from_data(data)?, - ar_gra_sf: Self::AR_GRA_SF.from_data(data)?, - v_ref_pct_sf: Self::V_REF_PCT_SF.from_data(data)?, - }) +impl crate::Group for ReactiveCurrent { + const LEN: u16 = 14; +} +impl ReactiveCurrent { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ar_gra_mod: Self::AR_GRA_MOD.from_data(data)?, + ar_gra_sag: Self::AR_GRA_SAG.from_data(data)?, + ar_gra_swell: Self::AR_GRA_SWELL.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + fil_tms: Self::FIL_TMS.from_data(data)?, + db_v_min: Self::DB_V_MIN.from_data(data)?, + db_v_max: Self::DB_V_MAX.from_data(data)?, + blk_zn_v: Self::BLK_ZN_V.from_data(data)?, + hys_blk_zn_v: Self::HYS_BLK_ZN_V.from_data(data)?, + blk_zn_tmms: Self::BLK_ZN_TMMS.from_data(data)?, + hold_tmms: Self::HOLD_TMMS.from_data(data)?, + ar_gra_sf: Self::AR_GRA_SF.from_data(data)?, + v_ref_pct_sf: Self::V_REF_PCT_SF.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m128 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// ArGraMod @@ -171,3 +179,13 @@ impl crate::Value for Option { } } } +impl crate::Model for ReactiveCurrent { + const ID: u16 = 128; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m128 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model129.rs b/src/models/model129.rs index 104ac62..a57b971 100644 --- a/src/models/model129.rs +++ b/src/models/model129.rs @@ -1,4 +1,5 @@ //! LVRTD +pub type Model129 = Lvrt; /// LVRTD /// /// LVRT Must Disconnect @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model129 { +pub struct Lvrt { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -49,9 +50,11 @@ pub struct Model129 { /// /// Scale factor for percent VRef. pub v_sf: i16, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model129 { +impl Lvrt { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -62,23 +65,32 @@ impl Model129 { pub const TMS_SF: crate::Point = crate::Point::new(7, 1, false); pub const V_SF: crate::Point = crate::Point::new(8, 1, false); } -impl crate::Model for Model129 { - const ID: u16 = 129; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - }) +impl crate::Group for Lvrt { + const LEN: u16 = 10; +} +impl Lvrt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m129 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -114,3 +126,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 must disconnect duration. + pub tms1: u16, + /// V1 + /// + /// Point 1 must disconnect voltage. + pub v1: u16, + /// Tms2 + /// + /// Point 2 must disconnect duration. + pub tms2: Option, + /// V2 + /// + /// Point 2 must disconnect voltage. + pub v2: Option, + /// Tms3 + /// + /// Point 3 must disconnect duration. + pub tms3: Option, + /// V3 + /// + /// Point 3 must disconnect voltage. + pub v3: Option, + /// Tms4 + /// + /// Point 4 must disconnect duration. + pub tms4: Option, + /// V4 + /// + /// Point 4 must disconnect voltage. + pub v4: Option, + /// Tms5 + /// + /// Point 5 must disconnect duration. + pub tms5: Option, + /// V5 + /// + /// Point 5 must disconnect voltage. + pub v5: Option, + /// Tms6 + /// + /// Point 6 must disconnect duration. + pub tms6: Option, + /// V6 + /// + /// Point 6 must disconnect voltage. + pub v6: Option, + /// Tms7 + /// + /// Point 7 must disconnect duration. + pub tms7: Option, + /// V7 + /// + /// Point 7 must disconnect voltage. + pub v7: Option, + /// Tms8 + /// + /// Point 8 must disconnect duration. + pub tms8: Option, + /// V8 + /// + /// Point 8 must disconnect voltage. + pub v8: Option, + /// Tms9 + /// + /// Point 9 must disconnect duration. + pub tms9: Option, + /// V9 + /// + /// Point 9 must disconnect voltage. + pub v9: Option, + /// Tms10 + /// + /// Point 10 must disconnect duration. + pub tms10: Option, + /// V10 + /// + /// Point 10 must disconnect voltage. + pub v10: Option, + /// Tms11 + /// + /// Point 11 must disconnect duration. + pub tms11: Option, + /// V11 + /// + /// Point 11 must disconnect voltage. + pub v11: Option, + /// Tms12 + /// + /// Point 12 must disconnect duration. + pub tms12: Option, + /// V12 + /// + /// Point 12 must disconnect voltage. + pub v12: Option, + /// Tms13 + /// + /// Point 13 must disconnect duration. + pub tms13: Option, + /// V13 + /// + /// Point 13 must disconnect voltage. + pub v13: Option, + /// Tms14 + /// + /// Point 14 must disconnect duration. + pub tms14: Option, + /// V14 + /// + /// Point 14 must disconnect voltage. + pub v14: Option, + /// Tms15 + /// + /// Point 15 must disconnect duration. + pub tms15: Option, + /// V15 + /// + /// Point 15 must disconnect voltage. + pub v15: Option, + /// Tms16 + /// + /// Point 16 must disconnect duration. + pub tms16: Option, + /// V16 + /// + /// Point 16 must disconnect voltage. + pub v16: Option, + /// Tms17 + /// + /// Point 17 must disconnect duration. + pub tms17: Option, + /// V17 + /// + /// Point 17 must disconnect voltage. + pub v17: Option, + /// Tms18 + /// + /// Point 18 must disconnect duration. + pub tms18: Option, + /// V18 + /// + /// Point 18 must disconnect voltage. + pub v18: Option, + /// Tms19 + /// + /// Point 19 must disconnect duration. + pub tms19: Option, + /// V19 + /// + /// Point 19 must disconnect voltage. + pub v19: Option, + /// Tms20 + /// + /// Point 20 must disconnect duration. + pub tms20: Option, + /// V20 + /// + /// Point 20 must disconnect voltage. + pub v20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const V1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const V2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const V3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const V4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const V5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const V6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const V7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const V8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const V9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const V10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const V11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const V12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const V13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const V14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const V15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const V16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const V17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const V18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const V19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const V20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + v1: Self::V1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + v2: Self::V2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + v3: Self::V3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + v4: Self::V4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + v5: Self::V5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + v6: Self::V6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + v7: Self::V7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + v8: Self::V8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + v9: Self::V9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + v10: Self::V10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + v11: Self::V11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + v12: Self::V12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + v13: Self::V13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + v14: Self::V14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + v15: Self::V15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + v16: Self::V16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + v17: Self::V17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + v18: Self::V18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + v19: Self::V19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + v20: Self::V20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Lvrt, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Lvrt, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Lvrt { + const ID: u16 = 129; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m129 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model13.rs b/src/models/model13.rs index 1c8c994..2d4b259 100644 --- a/src/models/model13.rs +++ b/src/models/model13.rs @@ -84,29 +84,36 @@ impl Model13 { pub const DOM_NAM: crate::Point> = crate::Point::new(149, 12, true); pub const HOST_NAM: crate::Point> = crate::Point::new(161, 12, true); } -impl crate::Model for Model13 { - const ID: u16 = 13; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - nam: Self::NAM.from_data(data)?, - cfg_st: Self::CFG_ST.from_data(data)?, - chg_st: Self::CHG_ST.from_data(data)?, - cap: Self::CAP.from_data(data)?, - cfg: Self::CFG.from_data(data)?, - ctl: Self::CTL.from_data(data)?, - addr: Self::ADDR.from_data(data)?, - cidr: Self::CIDR.from_data(data)?, - gw: Self::GW.from_data(data)?, - dns1: Self::DNS1.from_data(data)?, - dns2: Self::DNS2.from_data(data)?, - ntp1: Self::NTP1.from_data(data)?, - ntp2: Self::NTP2.from_data(data)?, - dom_nam: Self::DOM_NAM.from_data(data)?, - host_nam: Self::HOST_NAM.from_data(data)?, - }) +impl crate::Group for Model13 { + const LEN: u16 = 174; +} +impl Model13 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + nam: Self::NAM.from_data(data)?, + cfg_st: Self::CFG_ST.from_data(data)?, + chg_st: Self::CHG_ST.from_data(data)?, + cap: Self::CAP.from_data(data)?, + cfg: Self::CFG.from_data(data)?, + ctl: Self::CTL.from_data(data)?, + addr: Self::ADDR.from_data(data)?, + cidr: Self::CIDR.from_data(data)?, + gw: Self::GW.from_data(data)?, + dns1: Self::DNS1.from_data(data)?, + dns2: Self::DNS2.from_data(data)?, + ntp1: Self::NTP1.from_data(data)?, + ntp2: Self::NTP2.from_data(data)?, + dom_nam: Self::DOM_NAM.from_data(data)?, + host_nam: Self::HOST_NAM.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m13 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Config Status @@ -304,3 +311,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Model13 { + const ID: u16 = 13; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m13 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model130.rs b/src/models/model130.rs index 925f0ab..b448235 100644 --- a/src/models/model130.rs +++ b/src/models/model130.rs @@ -1,4 +1,5 @@ //! HVRTD +pub type Model130 = Hvrt; /// HVRTD /// /// HVRT Must Disconnect @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model130 { +pub struct Hvrt { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -49,9 +50,11 @@ pub struct Model130 { /// /// Scale factor for percent VRef. pub v_sf: i16, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model130 { +impl Hvrt { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -62,23 +65,32 @@ impl Model130 { pub const TMS_SF: crate::Point = crate::Point::new(7, 1, false); pub const V_SF: crate::Point = crate::Point::new(8, 1, false); } -impl crate::Model for Model130 { - const ID: u16 = 130; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - }) +impl crate::Group for Hvrt { + const LEN: u16 = 10; +} +impl Hvrt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m130 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -114,3 +126,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 must disconnect duration. + pub tms1: u16, + /// V1 + /// + /// Point 1 must disconnect voltage. + pub v1: u16, + /// Tms2 + /// + /// Point 2 must disconnect duration. + pub tms2: Option, + /// V2 + /// + /// Point 2 must disconnect voltage. + pub v2: Option, + /// Tms3 + /// + /// Point 3 must disconnect duration. + pub tms3: Option, + /// V3 + /// + /// Point 3 must disconnect voltage. + pub v3: Option, + /// Tms4 + /// + /// Point 4 must disconnect duration. + pub tms4: Option, + /// V4 + /// + /// Point 4 must disconnect voltage. + pub v4: Option, + /// Tms5 + /// + /// Point 5 must disconnect duration. + pub tms5: Option, + /// V5 + /// + /// Point 5 must disconnect voltage. + pub v5: Option, + /// Tms6 + /// + /// Point 6 must disconnect duration. + pub tms6: Option, + /// V6 + /// + /// Point 6 must disconnect voltage. + pub v6: Option, + /// Tms7 + /// + /// Point 7 must disconnect duration. + pub tms7: Option, + /// V7 + /// + /// Point 7 must disconnect voltage. + pub v7: Option, + /// Tms8 + /// + /// Point 8 must disconnect duration. + pub tms8: Option, + /// V8 + /// + /// Point 8 must disconnect voltage. + pub v8: Option, + /// Tms9 + /// + /// Point 9 must disconnect duration. + pub tms9: Option, + /// V9 + /// + /// Point 9 must disconnect voltage. + pub v9: Option, + /// Tms10 + /// + /// Point 10 must disconnect duration. + pub tms10: Option, + /// V10 + /// + /// Point 10 must disconnect voltage. + pub v10: Option, + /// Tms11 + /// + /// Point 11 must disconnect duration. + pub tms11: Option, + /// V11 + /// + /// Point 11 must disconnect voltage. + pub v11: Option, + /// Tms12 + /// + /// Point 12 must disconnect duration. + pub tms12: Option, + /// V12 + /// + /// Point 12 must disconnect voltage. + pub v12: Option, + /// Tms13 + /// + /// Point 13 must disconnect duration. + pub tms13: Option, + /// V13 + /// + /// Point 13 must disconnect voltage. + pub v13: Option, + /// Tms14 + /// + /// Point 14 must disconnect duration. + pub tms14: Option, + /// V14 + /// + /// Point 14 must disconnect voltage. + pub v14: Option, + /// Tms15 + /// + /// Point 15 must disconnect duration. + pub tms15: Option, + /// V15 + /// + /// Point 15 must disconnect voltage. + pub v15: Option, + /// Tms16 + /// + /// Point 16 must disconnect duration. + pub tms16: Option, + /// V16 + /// + /// Point 16 must disconnect voltage. + pub v16: Option, + /// Tms17 + /// + /// Point 17 must disconnect duration. + pub tms17: Option, + /// V17 + /// + /// Point 17 must disconnect voltage. + pub v17: Option, + /// Tms18 + /// + /// Point 18 must disconnect duration. + pub tms18: Option, + /// V18 + /// + /// Point 18 must disconnect voltage. + pub v18: Option, + /// Tms19 + /// + /// Point 19 must disconnect duration. + pub tms19: Option, + /// V19 + /// + /// Point 19 must disconnect voltage. + pub v19: Option, + /// Tms20 + /// + /// Point 20 must disconnect duration. + pub tms20: Option, + /// V20 + /// + /// Point 20 must disconnect voltage. + pub v20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const V1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const V2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const V3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const V4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const V5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const V6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const V7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const V8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const V9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const V10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const V11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const V12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const V13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const V14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const V15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const V16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const V17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const V18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const V19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const V20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + v1: Self::V1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + v2: Self::V2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + v3: Self::V3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + v4: Self::V4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + v5: Self::V5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + v6: Self::V6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + v7: Self::V7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + v8: Self::V8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + v9: Self::V9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + v10: Self::V10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + v11: Self::V11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + v12: Self::V12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + v13: Self::V13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + v14: Self::V14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + v15: Self::V15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + v16: Self::V16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + v17: Self::V17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + v18: Self::V18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + v19: Self::V19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + v20: Self::V20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Hvrt, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Hvrt, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Hvrt { + const ID: u16 = 130; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m130 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model131.rs b/src/models/model131.rs index b239008..ea04564 100644 --- a/src/models/model131.rs +++ b/src/models/model131.rs @@ -1,4 +1,5 @@ //! Watt-PF +pub type Model131 = WattPf; /// Watt-PF /// /// Watt-Power Factor @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.11.1.2 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model131 { +pub struct WattPf { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -47,9 +48,11 @@ pub struct Model131 { /// /// Scale factor for increment and decrement ramps. pub rmp_inc_dec_sf: Option, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model131 { +impl WattPf { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -61,24 +64,33 @@ impl Model131 { pub const PF_SF: crate::Point = crate::Point::new(8, 1, false); pub const RMP_INC_DEC_SF: crate::Point> = crate::Point::new(9, 1, false); } -impl crate::Model for Model131 { - const ID: u16 = 131; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, - }) +impl crate::Group for WattPf { + const LEN: u16 = 10; +} +impl WattPf { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m131 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -113,3 +125,369 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// W1 + /// + /// Point 1 Watts. + pub w1: i16, + /// PF1 + /// + /// Point 1 PF in EEI notation. + pub pf1: i16, + /// W2 + /// + /// Point 2 Watts. + pub w2: Option, + /// PF2 + /// + /// Point 2 PF in EEI notation. + pub pf2: Option, + /// W3 + /// + /// Point 3 Watts. + pub w3: Option, + /// PF3 + /// + /// Point 3 PF in EEI notation. + pub pf3: Option, + /// W4 + /// + /// Point 4 Watts. + pub w4: Option, + /// PF4 + /// + /// Point 4 PF in EEI notation. + pub pf4: Option, + /// W5 + /// + /// Point 5 Watts. + pub w5: Option, + /// PF5 + /// + /// Point 5 PF in EEI notation. + pub pf5: Option, + /// W6 + /// + /// Point 6 Watts. + pub w6: Option, + /// PF6 + /// + /// Point 6 PF in EEI notation. + pub pf6: Option, + /// W7 + /// + /// Point 7 Watts. + pub w7: Option, + /// PF7 + /// + /// Point 7 PF in EEI notation. + pub pf7: Option, + /// W8 + /// + /// Point 8 Watts. + pub w8: Option, + /// PF8 + /// + /// Point 8 PF in EEI notation. + pub pf8: Option, + /// W9 + /// + /// Point 9 Watts. + pub w9: Option, + /// PF9 + /// + /// Point 9 PF in EEI notation. + pub pf9: Option, + /// W10 + /// + /// Point 10 Watts. + pub w10: Option, + /// PF10 + /// + /// Point 10 PF in EEI notation. + pub pf10: Option, + /// W11 + /// + /// Point 11 Watts. + pub w11: Option, + /// PF11 + /// + /// Point 11 PF in EEI notation. + pub pf11: Option, + /// W12 + /// + /// Point 12 Watts. + pub w12: Option, + /// PF12 + /// + /// Point 12 PF in EEI notation. + pub pf12: Option, + /// W13 + /// + /// Point 13 Watts. + pub w13: Option, + /// PF13 + /// + /// Point 13 PF in EEI notation. + pub pf13: Option, + /// W14 + /// + /// Point 14 Watts. + pub w14: Option, + /// PF14 + /// + /// Point 14 PF in EEI notation. + pub pf14: Option, + /// W15 + /// + /// Point 15 Watts. + pub w15: Option, + /// PF15 + /// + /// Point 15 PF in EEI notation. + pub pf15: Option, + /// W16 + /// + /// Point 16 Watts. + pub w16: Option, + /// PF16 + /// + /// Point 16 PF in EEI notation. + pub pf16: Option, + /// W17 + /// + /// Point 17 Watts. + pub w17: Option, + /// PF17 + /// + /// Point 17 PF in EEI notation. + pub pf17: Option, + /// W18 + /// + /// Point 18 Watts. + pub w18: Option, + /// PF18 + /// + /// Point 18 PF in EEI notation. + pub pf18: Option, + /// W19 + /// + /// Point 19 Watts. + pub w19: Option, + /// PF19 + /// + /// Point 19 PF in EEI notation. + pub pf19: Option, + /// W20 + /// + /// Point 20 Watts. + pub w20: Option, + /// PF20 + /// + /// Point 20 PF in EEI notation. + pub pf20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// RmpPT1Tms + /// + /// The time of the PT1 in seconds (time to accomplish a change of 95%). + pub rmp_pt1_tms: Option, + /// RmpDecTmm + /// + /// The maximum rate at which the power factor may be reduced in response to changes in the power value. + pub rmp_dec_tmm: Option, + /// RmpIncTmm + /// + /// The maximum rate at which the power factor may be increased in response to changes in the power value. + pub rmp_inc_tmm: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const W1: crate::Point = crate::Point::new(1, 1, true); + pub const PF1: crate::Point = crate::Point::new(2, 1, true); + pub const W2: crate::Point> = crate::Point::new(3, 1, true); + pub const PF2: crate::Point> = crate::Point::new(4, 1, true); + pub const W3: crate::Point> = crate::Point::new(5, 1, true); + pub const PF3: crate::Point> = crate::Point::new(6, 1, true); + pub const W4: crate::Point> = crate::Point::new(7, 1, true); + pub const PF4: crate::Point> = crate::Point::new(8, 1, true); + pub const W5: crate::Point> = crate::Point::new(9, 1, true); + pub const PF5: crate::Point> = crate::Point::new(10, 1, true); + pub const W6: crate::Point> = crate::Point::new(11, 1, true); + pub const PF6: crate::Point> = crate::Point::new(12, 1, true); + pub const W7: crate::Point> = crate::Point::new(13, 1, true); + pub const PF7: crate::Point> = crate::Point::new(14, 1, true); + pub const W8: crate::Point> = crate::Point::new(15, 1, true); + pub const PF8: crate::Point> = crate::Point::new(16, 1, true); + pub const W9: crate::Point> = crate::Point::new(17, 1, true); + pub const PF9: crate::Point> = crate::Point::new(18, 1, true); + pub const W10: crate::Point> = crate::Point::new(19, 1, true); + pub const PF10: crate::Point> = crate::Point::new(20, 1, true); + pub const W11: crate::Point> = crate::Point::new(21, 1, true); + pub const PF11: crate::Point> = crate::Point::new(22, 1, true); + pub const W12: crate::Point> = crate::Point::new(23, 1, true); + pub const PF12: crate::Point> = crate::Point::new(24, 1, true); + pub const W13: crate::Point> = crate::Point::new(25, 1, true); + pub const PF13: crate::Point> = crate::Point::new(26, 1, true); + pub const W14: crate::Point> = crate::Point::new(27, 1, true); + pub const PF14: crate::Point> = crate::Point::new(28, 1, true); + pub const W15: crate::Point> = crate::Point::new(29, 1, true); + pub const PF15: crate::Point> = crate::Point::new(30, 1, true); + pub const W16: crate::Point> = crate::Point::new(31, 1, true); + pub const PF16: crate::Point> = crate::Point::new(32, 1, true); + pub const W17: crate::Point> = crate::Point::new(33, 1, true); + pub const PF17: crate::Point> = crate::Point::new(34, 1, true); + pub const W18: crate::Point> = crate::Point::new(35, 1, true); + pub const PF18: crate::Point> = crate::Point::new(36, 1, true); + pub const W19: crate::Point> = crate::Point::new(37, 1, true); + pub const PF19: crate::Point> = crate::Point::new(38, 1, true); + pub const W20: crate::Point> = crate::Point::new(39, 1, true); + pub const PF20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const RMP_PT1_TMS: crate::Point> = crate::Point::new(49, 1, true); + pub const RMP_DEC_TMM: crate::Point> = crate::Point::new(50, 1, true); + pub const RMP_INC_TMM: crate::Point> = crate::Point::new(51, 1, true); + pub const READ_ONLY: crate::Point = crate::Point::new(52, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 54; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + w1: Self::W1.from_data(data)?, + pf1: Self::PF1.from_data(data)?, + w2: Self::W2.from_data(data)?, + pf2: Self::PF2.from_data(data)?, + w3: Self::W3.from_data(data)?, + pf3: Self::PF3.from_data(data)?, + w4: Self::W4.from_data(data)?, + pf4: Self::PF4.from_data(data)?, + w5: Self::W5.from_data(data)?, + pf5: Self::PF5.from_data(data)?, + w6: Self::W6.from_data(data)?, + pf6: Self::PF6.from_data(data)?, + w7: Self::W7.from_data(data)?, + pf7: Self::PF7.from_data(data)?, + w8: Self::W8.from_data(data)?, + pf8: Self::PF8.from_data(data)?, + w9: Self::W9.from_data(data)?, + pf9: Self::PF9.from_data(data)?, + w10: Self::W10.from_data(data)?, + pf10: Self::PF10.from_data(data)?, + w11: Self::W11.from_data(data)?, + pf11: Self::PF11.from_data(data)?, + w12: Self::W12.from_data(data)?, + pf12: Self::PF12.from_data(data)?, + w13: Self::W13.from_data(data)?, + pf13: Self::PF13.from_data(data)?, + w14: Self::W14.from_data(data)?, + pf14: Self::PF14.from_data(data)?, + w15: Self::W15.from_data(data)?, + pf15: Self::PF15.from_data(data)?, + w16: Self::W16.from_data(data)?, + pf16: Self::PF16.from_data(data)?, + w17: Self::W17.from_data(data)?, + pf17: Self::PF17.from_data(data)?, + w18: Self::W18.from_data(data)?, + pf18: Self::PF18.from_data(data)?, + w19: Self::W19.from_data(data)?, + pf19: Self::PF19.from_data(data)?, + w20: Self::W20.from_data(data)?, + pf20: Self::PF20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + rmp_pt1_tms: Self::RMP_PT1_TMS.from_data(data)?, + rmp_dec_tmm: Self::RMP_DEC_TMM.from_data(data)?, + rmp_inc_tmm: Self::RMP_INC_TMM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &WattPf, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &WattPf, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for WattPf { + const ID: u16 = 131; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m131 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model132.rs b/src/models/model132.rs index 7484a35..38463bd 100644 --- a/src/models/model132.rs +++ b/src/models/model132.rs @@ -1,4 +1,5 @@ //! Volt-Watt +pub type Model132 = VoltWatt; /// Volt-Watt /// /// Volt-Watt @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.12.1.2 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model132 { +pub struct VoltWatt { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -47,9 +48,11 @@ pub struct Model132 { /// /// Scale factor for increment and decrement ramps. pub rmp_inc_dec_sf: Option, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model132 { +impl VoltWatt { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -61,24 +64,33 @@ impl Model132 { pub const DEPT_REF_SF: crate::Point = crate::Point::new(8, 1, false); pub const RMP_INC_DEC_SF: crate::Point> = crate::Point::new(9, 1, false); } -impl crate::Model for Model132 { - const ID: u16 = 132; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, - rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, - }) +impl crate::Group for VoltWatt { + const LEN: u16 = 10; +} +impl VoltWatt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, + rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m132 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -113,3 +125,415 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// DeptRef + /// + /// Defines the meaning of the Watts DeptRef. 1=% WMax 2=% WAvail + pub dept_ref: CurveDeptRef, + /// V1 + /// + /// Point 1 Volts. + pub v1: u16, + /// W1 + /// + /// Point 1 Watts. + pub w1: i16, + /// V2 + /// + /// Point 2 Volts. + pub v2: Option, + /// W2 + /// + /// Point 2 Watts. + pub w2: Option, + /// V3 + /// + /// Point 3 Volts. + pub v3: Option, + /// W3 + /// + /// Point 3 Watts. + pub w3: Option, + /// V4 + /// + /// Point 4 Volts. + pub v4: Option, + /// W4 + /// + /// Point 4 Watts. + pub w4: Option, + /// V5 + /// + /// Point 5 Volts. + pub v5: Option, + /// W5 + /// + /// Point 5 Watts. + pub w5: Option, + /// V6 + /// + /// Point 6 Volts. + pub v6: Option, + /// W6 + /// + /// Point 6 Watts. + pub w6: Option, + /// V7 + /// + /// Point 7 Volts. + pub v7: Option, + /// W7 + /// + /// Point 7 Watts. + pub w7: Option, + /// V8 + /// + /// Point 8 Volts. + pub v8: Option, + /// W8 + /// + /// Point 8 Watts. + pub w8: Option, + /// V9 + /// + /// Point 9 Volts. + pub v9: Option, + /// W9 + /// + /// Point 9 Watts. + pub w9: Option, + /// V10 + /// + /// Point 10 Volts. + pub v10: Option, + /// W10 + /// + /// Point 10 Watts. + pub w10: Option, + /// V11 + /// + /// Point 11 Volts. + pub v11: Option, + /// W11 + /// + /// Point 11 Watts. + pub w11: Option, + /// V12 + /// + /// Point 12 Volts. + pub v12: Option, + /// W12 + /// + /// Point 12 Watts. + pub w12: Option, + /// V13 + /// + /// Point 13 Volts. + pub v13: Option, + /// W13 + /// + /// Point 13 Watts. + pub w13: Option, + /// V14 + /// + /// Point 14 Volts. + pub v14: Option, + /// W14 + /// + /// Point 14 Watts. + pub w14: Option, + /// V15 + /// + /// Point 15 Volts. + pub v15: Option, + /// W15 + /// + /// Point 15 Watts. + pub w15: Option, + /// V16 + /// + /// Point 16 Volts. + pub v16: Option, + /// W16 + /// + /// Point 16 Watts. + pub w16: Option, + /// V17 + /// + /// Point 17 Volts. + pub v17: Option, + /// W17 + /// + /// Point 17 Watts. + pub w17: Option, + /// V18 + /// + /// Point 18 Volts. + pub v18: Option, + /// W18 + /// + /// Point 18 Watts. + pub w18: Option, + /// V19 + /// + /// Point 19 Volts. + pub v19: Option, + /// W19 + /// + /// Point 19 Watts. + pub w19: Option, + /// V20 + /// + /// Point 20 Volts. + pub v20: Option, + /// W20 + /// + /// Point 20 Watts. + pub w20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// RmpPt1Tms + /// + /// The time of the PT1 in seconds (time to accomplish a change of 95%). + pub rmp_pt1_tms: Option, + /// RmpDecTmm + /// + /// The maximum rate at which the watt value may be reduced in response to changes in the voltage value. + pub rmp_dec_tmm: Option, + /// RmpIncTmm + /// + /// The maximum rate at which the watt value may be increased in response to changes in the voltage value. + pub rmp_inc_tmm: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const DEPT_REF: crate::Point = crate::Point::new(1, 1, true); + pub const V1: crate::Point = crate::Point::new(2, 1, true); + pub const W1: crate::Point = crate::Point::new(3, 1, true); + pub const V2: crate::Point> = crate::Point::new(4, 1, true); + pub const W2: crate::Point> = crate::Point::new(5, 1, true); + pub const V3: crate::Point> = crate::Point::new(6, 1, true); + pub const W3: crate::Point> = crate::Point::new(7, 1, true); + pub const V4: crate::Point> = crate::Point::new(8, 1, true); + pub const W4: crate::Point> = crate::Point::new(9, 1, true); + pub const V5: crate::Point> = crate::Point::new(10, 1, true); + pub const W5: crate::Point> = crate::Point::new(11, 1, true); + pub const V6: crate::Point> = crate::Point::new(12, 1, true); + pub const W6: crate::Point> = crate::Point::new(13, 1, true); + pub const V7: crate::Point> = crate::Point::new(14, 1, true); + pub const W7: crate::Point> = crate::Point::new(15, 1, true); + pub const V8: crate::Point> = crate::Point::new(16, 1, true); + pub const W8: crate::Point> = crate::Point::new(17, 1, true); + pub const V9: crate::Point> = crate::Point::new(18, 1, true); + pub const W9: crate::Point> = crate::Point::new(19, 1, true); + pub const V10: crate::Point> = crate::Point::new(20, 1, true); + pub const W10: crate::Point> = crate::Point::new(21, 1, true); + pub const V11: crate::Point> = crate::Point::new(22, 1, true); + pub const W11: crate::Point> = crate::Point::new(23, 1, true); + pub const V12: crate::Point> = crate::Point::new(24, 1, true); + pub const W12: crate::Point> = crate::Point::new(25, 1, true); + pub const V13: crate::Point> = crate::Point::new(26, 1, true); + pub const W13: crate::Point> = crate::Point::new(27, 1, true); + pub const V14: crate::Point> = crate::Point::new(28, 1, true); + pub const W14: crate::Point> = crate::Point::new(29, 1, true); + pub const V15: crate::Point> = crate::Point::new(30, 1, true); + pub const W15: crate::Point> = crate::Point::new(31, 1, true); + pub const V16: crate::Point> = crate::Point::new(32, 1, true); + pub const W16: crate::Point> = crate::Point::new(33, 1, true); + pub const V17: crate::Point> = crate::Point::new(34, 1, true); + pub const W17: crate::Point> = crate::Point::new(35, 1, true); + pub const V18: crate::Point> = crate::Point::new(36, 1, true); + pub const W18: crate::Point> = crate::Point::new(37, 1, true); + pub const V19: crate::Point> = crate::Point::new(38, 1, true); + pub const W19: crate::Point> = crate::Point::new(39, 1, true); + pub const V20: crate::Point> = crate::Point::new(40, 1, true); + pub const W20: crate::Point> = crate::Point::new(41, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(42, 8, true); + pub const RMP_PT1_TMS: crate::Point> = crate::Point::new(50, 1, true); + pub const RMP_DEC_TMM: crate::Point> = crate::Point::new(51, 1, true); + pub const RMP_INC_TMM: crate::Point> = crate::Point::new(52, 1, true); + pub const READ_ONLY: crate::Point = crate::Point::new(53, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 54; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + dept_ref: Self::DEPT_REF.from_data(data)?, + v1: Self::V1.from_data(data)?, + w1: Self::W1.from_data(data)?, + v2: Self::V2.from_data(data)?, + w2: Self::W2.from_data(data)?, + v3: Self::V3.from_data(data)?, + w3: Self::W3.from_data(data)?, + v4: Self::V4.from_data(data)?, + w4: Self::W4.from_data(data)?, + v5: Self::V5.from_data(data)?, + w5: Self::W5.from_data(data)?, + v6: Self::V6.from_data(data)?, + w6: Self::W6.from_data(data)?, + v7: Self::V7.from_data(data)?, + w7: Self::W7.from_data(data)?, + v8: Self::V8.from_data(data)?, + w8: Self::W8.from_data(data)?, + v9: Self::V9.from_data(data)?, + w9: Self::W9.from_data(data)?, + v10: Self::V10.from_data(data)?, + w10: Self::W10.from_data(data)?, + v11: Self::V11.from_data(data)?, + w11: Self::W11.from_data(data)?, + v12: Self::V12.from_data(data)?, + w12: Self::W12.from_data(data)?, + v13: Self::V13.from_data(data)?, + w13: Self::W13.from_data(data)?, + v14: Self::V14.from_data(data)?, + w14: Self::W14.from_data(data)?, + v15: Self::V15.from_data(data)?, + w15: Self::W15.from_data(data)?, + v16: Self::V16.from_data(data)?, + w16: Self::W16.from_data(data)?, + v17: Self::V17.from_data(data)?, + w17: Self::W17.from_data(data)?, + v18: Self::V18.from_data(data)?, + w18: Self::W18.from_data(data)?, + v19: Self::V19.from_data(data)?, + w19: Self::W19.from_data(data)?, + v20: Self::V20.from_data(data)?, + w20: Self::W20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + rmp_pt1_tms: Self::RMP_PT1_TMS.from_data(data)?, + rmp_dec_tmm: Self::RMP_DEC_TMM.from_data(data)?, + rmp_inc_tmm: Self::RMP_INC_TMM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &VoltWatt, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &VoltWatt, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// DeptRef +/// +/// Defines the meaning of the Watts DeptRef. 1=% WMax 2=% WAvail +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveDeptRef { + #[allow(missing_docs)] + WMax = 1, + #[allow(missing_docs)] + WAval = 2, +} +impl crate::Value for CurveDeptRef { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveDeptRef::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for VoltWatt { + const ID: u16 = 132; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m132 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model133.rs b/src/models/model133.rs index 3628516..4a9647b 100644 --- a/src/models/model133.rs +++ b/src/models/model133.rs @@ -1,4 +1,5 @@ //! Basic Scheduling +pub type Model133 = Schedule; /// Basic Scheduling /// /// Basic Scheduling @@ -6,7 +7,7 @@ /// Detail: Ref 2: 2.2.8 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model133 { +pub struct Schedule { /// ActSchd /// /// Bitfield of active schedules @@ -23,26 +24,37 @@ pub struct Model133 { /// /// Number of schedule entries supported (maximum of 10). pub n_pts: u16, + #[allow(missing_docs)] + pub repeating: Vec, } #[allow(missing_docs)] -impl Model133 { +impl Schedule { pub const ACT_SCHD: crate::Point = crate::Point::new(0, 2, true); pub const MOD_ENA: crate::Point = crate::Point::new(2, 1, true); pub const N_SCHD: crate::Point = crate::Point::new(3, 1, false); pub const N_PTS: crate::Point = crate::Point::new(4, 1, false); } -impl crate::Model for Model133 { - const ID: u16 = 133; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_schd: Self::ACT_SCHD.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - n_schd: Self::N_SCHD.from_data(data)?, - n_pts: Self::N_PTS.from_data(data)?, - }) +impl crate::Group for Schedule { + const LEN: u16 = 6; +} +impl Schedule { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_schd: Self::ACT_SCHD.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + n_schd: Self::N_SCHD.from_data(data)?, + n_pts: Self::N_PTS.from_data(data)?, + repeating: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m133 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -126,3 +138,407 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + /// ActPts + /// + /// Number of active entries in schedule. + pub act_pts: u16, + /// StrTms + /// + /// Schedule start in seconds since 2000 JAN 01 00:00:00 UTC. + pub str_tms: u32, + /// RepPer + /// + /// The repetition count for time-based schedules (0=repeat forever) + pub rep_per: u16, + /// SchdTyp + /// + /// The repetition frequency for time-based schedules: no repeat=0 + pub intv_typ: RepeatingIntvTyp, + /// XTyp + /// + /// The meaning of the X-values in the array. + pub x_typ: RepeatingXTyp, + /// X_SF + /// + /// Scale factor for schedule range values. + pub x_sf: i16, + /// YTyp + /// + /// The meaning of the Y-values in the array. + pub y_typ: RepeatingYTyp, + /// Y_SF + /// + /// Scale factor for schedule target values. + pub y_sf: i16, + /// X1 + /// + /// Entry 1 range. + pub x1: i32, + /// Y1 + /// + /// Entry 1 target. + pub y1: i32, + /// X2 + /// + /// Entry 2 range. + pub x2: Option, + /// Y2 + /// + /// Entry 2 target. + pub y2: Option, + /// X3 + /// + /// Entry 3 range. + pub x3: Option, + /// Y3 + /// + /// Entry 3 target. + pub y3: Option, + /// X4 + /// + /// Entry 4 range. + pub x4: Option, + /// Y4 + /// + /// Entry 4 target. + pub y4: Option, + /// X5 + /// + /// Entry 15range. + pub x5: Option, + /// Y5 + /// + /// Entry 5 target. + pub y5: Option, + /// X6 + /// + /// Entry 6 range. + pub x6: Option, + /// Y6 + /// + /// Entry 6 target. + pub y6: Option, + /// X7 + /// + /// Entry 7 range. + pub x7: Option, + /// Y7 + /// + /// Entry 7 target. + pub y7: Option, + /// X8 + /// + /// Entry 8 range. + pub x8: Option, + /// Y8 + /// + /// Entry 8 target. + pub y8: Option, + /// X9 + /// + /// Entry 9 range. + pub x9: Option, + /// Y9 + /// + /// Entry 9 target. + pub y9: Option, + /// X10 + /// + /// Entry 10 range. + pub x10: Option, + /// Y10 + /// + /// Entry 10 target. + pub y10: Option, + /// Nam + /// + /// Optional description for schedule. + pub nam: Option, + /// WinTms + /// + /// Time window for schedule entry change. + pub win_tms: Option, + /// RmpTms + /// + /// Ramp time for moving from current target to new target. + pub rmp_tms: Option, + /// ActIndx + /// + /// Index of active entry in the active schedule. + pub act_indx: u16, +} +#[allow(missing_docs)] +impl Repeating { + pub const ACT_PTS: crate::Point = crate::Point::new(0, 1, true); + pub const STR_TMS: crate::Point = crate::Point::new(1, 2, true); + pub const REP_PER: crate::Point = crate::Point::new(3, 1, true); + pub const INTV_TYP: crate::Point = crate::Point::new(4, 1, true); + pub const X_TYP: crate::Point = crate::Point::new(5, 1, true); + pub const X_SF: crate::Point = crate::Point::new(6, 1, true); + pub const Y_TYP: crate::Point = crate::Point::new(7, 1, true); + pub const Y_SF: crate::Point = crate::Point::new(8, 1, true); + pub const X1: crate::Point = crate::Point::new(9, 2, true); + pub const Y1: crate::Point = crate::Point::new(11, 2, true); + pub const X2: crate::Point> = crate::Point::new(13, 2, true); + pub const Y2: crate::Point> = crate::Point::new(15, 2, true); + pub const X3: crate::Point> = crate::Point::new(17, 2, true); + pub const Y3: crate::Point> = crate::Point::new(19, 2, true); + pub const X4: crate::Point> = crate::Point::new(21, 2, true); + pub const Y4: crate::Point> = crate::Point::new(23, 2, true); + pub const X5: crate::Point> = crate::Point::new(25, 2, true); + pub const Y5: crate::Point> = crate::Point::new(27, 2, true); + pub const X6: crate::Point> = crate::Point::new(29, 2, true); + pub const Y6: crate::Point> = crate::Point::new(31, 2, true); + pub const X7: crate::Point> = crate::Point::new(33, 2, true); + pub const Y7: crate::Point> = crate::Point::new(35, 2, true); + pub const X8: crate::Point> = crate::Point::new(37, 2, true); + pub const Y8: crate::Point> = crate::Point::new(39, 2, true); + pub const X9: crate::Point> = crate::Point::new(41, 2, true); + pub const Y9: crate::Point> = crate::Point::new(43, 2, true); + pub const X10: crate::Point> = crate::Point::new(45, 2, true); + pub const Y10: crate::Point> = crate::Point::new(47, 2, true); + pub const NAM: crate::Point> = crate::Point::new(49, 8, true); + pub const WIN_TMS: crate::Point> = crate::Point::new(57, 1, true); + pub const RMP_TMS: crate::Point> = crate::Point::new(58, 1, true); + pub const ACT_INDX: crate::Point = crate::Point::new(59, 1, false); +} +impl crate::Group for Repeating { + const LEN: u16 = 60; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pts: Self::ACT_PTS.from_data(data)?, + str_tms: Self::STR_TMS.from_data(data)?, + rep_per: Self::REP_PER.from_data(data)?, + intv_typ: Self::INTV_TYP.from_data(data)?, + x_typ: Self::X_TYP.from_data(data)?, + x_sf: Self::X_SF.from_data(data)?, + y_typ: Self::Y_TYP.from_data(data)?, + y_sf: Self::Y_SF.from_data(data)?, + x1: Self::X1.from_data(data)?, + y1: Self::Y1.from_data(data)?, + x2: Self::X2.from_data(data)?, + y2: Self::Y2.from_data(data)?, + x3: Self::X3.from_data(data)?, + y3: Self::Y3.from_data(data)?, + x4: Self::X4.from_data(data)?, + y4: Self::Y4.from_data(data)?, + x5: Self::X5.from_data(data)?, + y5: Self::Y5.from_data(data)?, + x6: Self::X6.from_data(data)?, + y6: Self::Y6.from_data(data)?, + x7: Self::X7.from_data(data)?, + y7: Self::Y7.from_data(data)?, + x8: Self::X8.from_data(data)?, + y8: Self::Y8.from_data(data)?, + x9: Self::X9.from_data(data)?, + y9: Self::Y9.from_data(data)?, + x10: Self::X10.from_data(data)?, + y10: Self::Y10.from_data(data)?, + nam: Self::NAM.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + act_indx: Self::ACT_INDX.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Schedule, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Schedule, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// SchdTyp +/// +/// The repetition frequency for time-based schedules: no repeat=0 +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum RepeatingIntvTyp { + #[allow(missing_docs)] + Onetime = 0, + #[allow(missing_docs)] + Daily = 1, + #[allow(missing_docs)] + Weekly = 2, + #[allow(missing_docs)] + Monthly = 3, + #[allow(missing_docs)] + Weekday = 4, + #[allow(missing_docs)] + Holiday = 5, + #[allow(missing_docs)] + Weekend = 6, + #[allow(missing_docs)] + Yearly = 7, +} +impl crate::Value for RepeatingIntvTyp { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + RepeatingIntvTyp::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// XTyp +/// +/// The meaning of the X-values in the array. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum RepeatingXTyp { + #[allow(missing_docs)] + Unset = 0, + #[allow(missing_docs)] + Time = 1, + #[allow(missing_docs)] + Temp = 2, + #[allow(missing_docs)] + Price = 3, + #[allow(missing_docs)] + Other = 99, +} +impl crate::Value for RepeatingXTyp { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + RepeatingXTyp::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// YTyp +/// +/// The meaning of the Y-values in the array. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum RepeatingYTyp { + #[allow(missing_docs)] + Unset = 0, + #[allow(missing_docs)] + WMax = 1, + #[allow(missing_docs)] + Rsrvd2 = 2, + #[allow(missing_docs)] + Pf = 3, + #[allow(missing_docs)] + Rsrvd4 = 4, + #[allow(missing_docs)] + WattPrice = 5, + #[allow(missing_docs)] + VarPrice = 6, + #[allow(missing_docs)] + Rsrvd7 = 7, + #[allow(missing_docs)] + VoltVarArray = 8, + #[allow(missing_docs)] + WChaGra = 9, + #[allow(missing_docs)] + WDisChaGra = 10, + #[allow(missing_docs)] + VArAval = 11, + #[allow(missing_docs)] + Schedule = 12, + #[allow(missing_docs)] + Other = 99, +} +impl crate::Value for RepeatingYTyp { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + RepeatingYTyp::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Schedule { + const ID: u16 = 133; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m133 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model134.rs b/src/models/model134.rs index 3eaca82..7791898 100644 --- a/src/models/model134.rs +++ b/src/models/model134.rs @@ -1,4 +1,5 @@ //! Freq-Watt Crv +pub type Model134 = FreqWatt; /// Freq-Watt Crv /// /// Curve-Based Frequency-Watt @@ -6,7 +7,7 @@ /// Detail: Ref 3: 8.9.1.2, 8.9.4.2 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model134 { +pub struct FreqWatt { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -47,9 +48,11 @@ pub struct Model134 { /// /// Scale factor for increment and decrement ramps. pub rmp_inc_dec_sf: Option, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model134 { +impl FreqWatt { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -61,24 +64,33 @@ impl Model134 { pub const W_SF: crate::Point = crate::Point::new(8, 1, false); pub const RMP_INC_DEC_SF: crate::Point> = crate::Point::new(9, 1, false); } -impl crate::Model for Model134 { - const ID: u16 = 134; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, - }) +impl crate::Group for FreqWatt { + const LEN: u16 = 10; +} +impl FreqWatt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m134 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -114,3 +126,430 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Hz1 + /// + /// Point 1 Hertz. + pub hz1: u16, + /// W1 + /// + /// Point 1 Watts. + pub w1: i16, + /// Hz2 + /// + /// Point 2 Hertz. + pub hz2: Option, + /// W2 + /// + /// Point 2 Watts. + pub w2: Option, + /// Hz3 + /// + /// Point 3 Hertz. + pub hz3: Option, + /// W3 + /// + /// Point 3 Watts. + pub w3: Option, + /// Hz4 + /// + /// Point 4 Hertz. + pub hz4: Option, + /// W4 + /// + /// Point 4 Watts. + pub w4: Option, + /// Hz5 + /// + /// Point 5 Hertz. + pub hz5: Option, + /// W5 + /// + /// Point 5 Watts. + pub w5: Option, + /// Hz6 + /// + /// Point 6 Hertz. + pub hz6: Option, + /// W6 + /// + /// Point 6 Watts. + pub w6: Option, + /// Hz7 + /// + /// Point 7 Hertz. + pub hz7: Option, + /// W7 + /// + /// Point 7 Watts. + pub w7: Option, + /// Hz8 + /// + /// Point 8 Hertz. + pub hz8: Option, + /// W8 + /// + /// Point 8 Watts. + pub w8: Option, + /// Hz9 + /// + /// Point 9 Hertz. + pub hz9: Option, + /// W9 + /// + /// Point 9 Watts. + pub w9: Option, + /// Hz10 + /// + /// Point 10 Hertz. + pub hz10: Option, + /// W10 + /// + /// Point 10 Watts. + pub w10: Option, + /// Hz11 + /// + /// Point 11 Hertz. + pub hz11: Option, + /// W11 + /// + /// Point 11 Watts. + pub w11: Option, + /// Hz12 + /// + /// Point 12 Hertz. + pub hz12: Option, + /// W12 + /// + /// Point 12 Watts. + pub w12: Option, + /// Hz13 + /// + /// Point 13 Hertz. + pub hz13: Option, + /// W13 + /// + /// Point 13 Watts. + pub w13: Option, + /// Hz14 + /// + /// Point 14 Hertz. + pub hz14: Option, + /// W14 + /// + /// Point 14 Watts. + pub w14: Option, + /// Hz15 + /// + /// Point 15 Hertz. + pub hz15: Option, + /// W15 + /// + /// Point 15 Watts. + pub w15: Option, + /// Hz16 + /// + /// Point 16 Hertz. + pub hz16: Option, + /// W16 + /// + /// Point 16 Watts. + pub w16: Option, + /// Hz17 + /// + /// Point 17 Hertz. + pub hz17: Option, + /// W17 + /// + /// Point 17 Watts. + pub w17: Option, + /// Hz18 + /// + /// Point 18 Hertz. + pub hz18: Option, + /// W18 + /// + /// Point 18 Watts. + pub w18: Option, + /// Hz19 + /// + /// Point 19 Hertz. + pub hz19: Option, + /// W19 + /// + /// Point 19 Watts. + pub w19: Option, + /// Hz20 + /// + /// Point 20 Hertz. + pub hz20: Option, + /// W20 + /// + /// Point 20 Watts. + pub w20: Option, + /// CrvNam + /// + /// Optional description for curve. (Max 16 chars) + pub crv_nam: Option, + /// RmpPT1Tms + /// + /// The time of the PT1 in seconds (time to accomplish a change of 95%). + pub rmp_pt1_tms: Option, + /// RmpDecTmm + /// + /// The maximum rate at which the power value may be reduced in response to changes in the frequency value. + pub rmp_dec_tmm: Option, + /// RmpIncTmm + /// + /// The maximum rate at which the power value may be increased in response to changes in the frequency value. + pub rmp_inc_tmm: Option, + /// RmpRsUp + /// + /// The maximum rate at which the power may be increased after releasing the frozen value of snap shot function. + pub rmp_rs_up: Option, + /// SnptW + /// + /// 1=enable snapshot/capture mode + pub snpt_w: CurveSnptW, + /// WRef + /// + /// Reference active power (default = WMax). + pub w_ref: Option, + /// WRefStrHz + /// + /// Frequency deviation from nominal frequency at the time of the snapshot to start constraining power output. + pub w_ref_str_hz: Option, + /// WRefStopHz + /// + /// Frequency deviation from nominal frequency at which to release the power output. + pub w_ref_stop_hz: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const HZ1: crate::Point = crate::Point::new(1, 1, true); + pub const W1: crate::Point = crate::Point::new(2, 1, true); + pub const HZ2: crate::Point> = crate::Point::new(3, 1, true); + pub const W2: crate::Point> = crate::Point::new(4, 1, true); + pub const HZ3: crate::Point> = crate::Point::new(5, 1, true); + pub const W3: crate::Point> = crate::Point::new(6, 1, true); + pub const HZ4: crate::Point> = crate::Point::new(7, 1, true); + pub const W4: crate::Point> = crate::Point::new(8, 1, true); + pub const HZ5: crate::Point> = crate::Point::new(9, 1, true); + pub const W5: crate::Point> = crate::Point::new(10, 1, true); + pub const HZ6: crate::Point> = crate::Point::new(11, 1, true); + pub const W6: crate::Point> = crate::Point::new(12, 1, true); + pub const HZ7: crate::Point> = crate::Point::new(13, 1, true); + pub const W7: crate::Point> = crate::Point::new(14, 1, true); + pub const HZ8: crate::Point> = crate::Point::new(15, 1, true); + pub const W8: crate::Point> = crate::Point::new(16, 1, true); + pub const HZ9: crate::Point> = crate::Point::new(17, 1, true); + pub const W9: crate::Point> = crate::Point::new(18, 1, true); + pub const HZ10: crate::Point> = crate::Point::new(19, 1, true); + pub const W10: crate::Point> = crate::Point::new(20, 1, true); + pub const HZ11: crate::Point> = crate::Point::new(21, 1, true); + pub const W11: crate::Point> = crate::Point::new(22, 1, true); + pub const HZ12: crate::Point> = crate::Point::new(23, 1, true); + pub const W12: crate::Point> = crate::Point::new(24, 1, true); + pub const HZ13: crate::Point> = crate::Point::new(25, 1, true); + pub const W13: crate::Point> = crate::Point::new(26, 1, true); + pub const HZ14: crate::Point> = crate::Point::new(27, 1, true); + pub const W14: crate::Point> = crate::Point::new(28, 1, true); + pub const HZ15: crate::Point> = crate::Point::new(29, 1, true); + pub const W15: crate::Point> = crate::Point::new(30, 1, true); + pub const HZ16: crate::Point> = crate::Point::new(31, 1, true); + pub const W16: crate::Point> = crate::Point::new(32, 1, true); + pub const HZ17: crate::Point> = crate::Point::new(33, 1, true); + pub const W17: crate::Point> = crate::Point::new(34, 1, true); + pub const HZ18: crate::Point> = crate::Point::new(35, 1, true); + pub const W18: crate::Point> = crate::Point::new(36, 1, true); + pub const HZ19: crate::Point> = crate::Point::new(37, 1, true); + pub const W19: crate::Point> = crate::Point::new(38, 1, true); + pub const HZ20: crate::Point> = crate::Point::new(39, 1, true); + pub const W20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const RMP_PT1_TMS: crate::Point> = crate::Point::new(49, 1, true); + pub const RMP_DEC_TMM: crate::Point> = crate::Point::new(50, 1, true); + pub const RMP_INC_TMM: crate::Point> = crate::Point::new(51, 1, true); + pub const RMP_RS_UP: crate::Point> = crate::Point::new(52, 1, true); + pub const SNPT_W: crate::Point = crate::Point::new(53, 1, true); + pub const W_REF: crate::Point> = crate::Point::new(54, 1, true); + pub const W_REF_STR_HZ: crate::Point> = crate::Point::new(55, 1, true); + pub const W_REF_STOP_HZ: crate::Point> = crate::Point::new(56, 1, true); + pub const READ_ONLY: crate::Point = crate::Point::new(57, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 58; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + hz1: Self::HZ1.from_data(data)?, + w1: Self::W1.from_data(data)?, + hz2: Self::HZ2.from_data(data)?, + w2: Self::W2.from_data(data)?, + hz3: Self::HZ3.from_data(data)?, + w3: Self::W3.from_data(data)?, + hz4: Self::HZ4.from_data(data)?, + w4: Self::W4.from_data(data)?, + hz5: Self::HZ5.from_data(data)?, + w5: Self::W5.from_data(data)?, + hz6: Self::HZ6.from_data(data)?, + w6: Self::W6.from_data(data)?, + hz7: Self::HZ7.from_data(data)?, + w7: Self::W7.from_data(data)?, + hz8: Self::HZ8.from_data(data)?, + w8: Self::W8.from_data(data)?, + hz9: Self::HZ9.from_data(data)?, + w9: Self::W9.from_data(data)?, + hz10: Self::HZ10.from_data(data)?, + w10: Self::W10.from_data(data)?, + hz11: Self::HZ11.from_data(data)?, + w11: Self::W11.from_data(data)?, + hz12: Self::HZ12.from_data(data)?, + w12: Self::W12.from_data(data)?, + hz13: Self::HZ13.from_data(data)?, + w13: Self::W13.from_data(data)?, + hz14: Self::HZ14.from_data(data)?, + w14: Self::W14.from_data(data)?, + hz15: Self::HZ15.from_data(data)?, + w15: Self::W15.from_data(data)?, + hz16: Self::HZ16.from_data(data)?, + w16: Self::W16.from_data(data)?, + hz17: Self::HZ17.from_data(data)?, + w17: Self::W17.from_data(data)?, + hz18: Self::HZ18.from_data(data)?, + w18: Self::W18.from_data(data)?, + hz19: Self::HZ19.from_data(data)?, + w19: Self::W19.from_data(data)?, + hz20: Self::HZ20.from_data(data)?, + w20: Self::W20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + rmp_pt1_tms: Self::RMP_PT1_TMS.from_data(data)?, + rmp_dec_tmm: Self::RMP_DEC_TMM.from_data(data)?, + rmp_inc_tmm: Self::RMP_INC_TMM.from_data(data)?, + rmp_rs_up: Self::RMP_RS_UP.from_data(data)?, + snpt_w: Self::SNPT_W.from_data(data)?, + w_ref: Self::W_REF.from_data(data)?, + w_ref_str_hz: Self::W_REF_STR_HZ.from_data(data)?, + w_ref_stop_hz: Self::W_REF_STOP_HZ.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &FreqWatt, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &FreqWatt, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +bitflags::bitflags! { + #[doc = " SnptW"] #[doc = " "] #[doc = " 1=enable snapshot/capture mode"] + #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", + derive(::serde::Serialize, ::serde::Deserialize))] pub struct CurveSnptW : u16 {} +} +impl crate::Value for CurveSnptW { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535u16 { + Ok(Some(CurveSnptW::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535u16.encode() + } + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for FreqWatt { + const ID: u16 = 134; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m134 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model135.rs b/src/models/model135.rs index fbc56ce..cc7a70a 100644 --- a/src/models/model135.rs +++ b/src/models/model135.rs @@ -1,4 +1,5 @@ //! LFRT +pub type Model135 = Lfrt; /// LFRT /// /// Low Frequency Ride-through @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model135 { +pub struct Lfrt { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -49,9 +50,11 @@ pub struct Model135 { /// /// Scale factor for frequency. pub hz_sf: i16, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model135 { +impl Lfrt { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -62,23 +65,32 @@ impl Model135 { pub const TMS_SF: crate::Point = crate::Point::new(7, 1, false); pub const HZ_SF: crate::Point = crate::Point::new(8, 1, false); } -impl crate::Model for Model135 { - const ID: u16 = 135; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - }) +impl crate::Group for Lfrt { + const LEN: u16 = 10; +} +impl Lfrt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m135 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -114,3 +126,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 must disconnect duration. + pub tms1: u16, + /// Hz1 + /// + /// Point 1 must disconnect frequency. + pub hz1: u16, + /// Tms2 + /// + /// Point 2 must disconnect duration. + pub tms2: Option, + /// Hz2 + /// + /// Point 2 must disconnect frequency. + pub hz2: Option, + /// Tms3 + /// + /// Point 3 must disconnect duration. + pub tms3: Option, + /// Hz3 + /// + /// Point 3 must disconnect frequency. + pub hz3: Option, + /// Tms4 + /// + /// Point 4 must disconnect duration. + pub tms4: Option, + /// Hz4 + /// + /// Point 4 must disconnect frequency. + pub hz4: Option, + /// Tms5 + /// + /// Point 5 must disconnect duration. + pub tms5: Option, + /// Hz5 + /// + /// Point 5 must disconnect frequency. + pub hz5: Option, + /// Tms6 + /// + /// Point 6 must disconnect duration. + pub tms6: Option, + /// Hz6 + /// + /// Point 6 must disconnect frequency. + pub hz6: Option, + /// Tms7 + /// + /// Point 7 must disconnect duration. + pub tms7: Option, + /// Hz7 + /// + /// Point 7 must disconnect frequency. + pub hz7: Option, + /// Tms8 + /// + /// Point 8 must disconnect duration. + pub tms8: Option, + /// Hz8 + /// + /// Point 8 must disconnect frequency. + pub hz8: Option, + /// Tms9 + /// + /// Point 9 must disconnect duration. + pub tms9: Option, + /// Hz9 + /// + /// Point 9 must disconnect frequency. + pub hz9: Option, + /// Tms10 + /// + /// Point 10 must disconnect duration. + pub tms10: Option, + /// Hz10 + /// + /// Point 10 must disconnect frequency. + pub hz10: Option, + /// Tms11 + /// + /// Point 11 must disconnect duration. + pub tms11: Option, + /// Hz11 + /// + /// Point 11 must disconnect frequency. + pub hz11: Option, + /// Tms12 + /// + /// Point 12 must disconnect duration. + pub tms12: Option, + /// Hz12 + /// + /// Point 12 must disconnect frequency. + pub hz12: Option, + /// Tms13 + /// + /// Point 13 must disconnect duration. + pub tms13: Option, + /// Hz13 + /// + /// Point 13 must disconnect frequency. + pub hz13: Option, + /// Tms14 + /// + /// Point 14 must disconnect duration. + pub tms14: Option, + /// Hz14 + /// + /// Point 14 must disconnect frequency. + pub hz14: Option, + /// Tms15 + /// + /// Point 15 must disconnect duration. + pub tms15: Option, + /// Hz15 + /// + /// Point 15 must disconnect frequency. + pub hz15: Option, + /// Tms16 + /// + /// Point 16 must disconnect duration. + pub tms16: Option, + /// Hz16 + /// + /// Point 16 must disconnect frequency. + pub hz16: Option, + /// Tms17 + /// + /// Point 17 must disconnect duration. + pub tms17: Option, + /// Hz17 + /// + /// Point 17 must disconnect frequency. + pub hz17: Option, + /// Tms18 + /// + /// Point 18 must disconnect duration. + pub tms18: Option, + /// Hz18 + /// + /// Point 18 must disconnect frequency. + pub hz18: Option, + /// Tms19 + /// + /// Point 19 must disconnect duration. + pub tms19: Option, + /// Hz19 + /// + /// Point 19 must disconnect frequency. + pub hz19: Option, + /// Tms20 + /// + /// Point 20 must disconnect duration. + pub tms20: Option, + /// Hz20 + /// + /// Point 20 must disconnect frequency. + pub hz20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const HZ1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const HZ2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const HZ3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const HZ4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const HZ5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const HZ6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const HZ7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const HZ8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const HZ9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const HZ10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const HZ11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const HZ12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const HZ13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const HZ14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const HZ15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const HZ16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const HZ17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const HZ18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const HZ19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const HZ20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + hz1: Self::HZ1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + hz2: Self::HZ2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + hz3: Self::HZ3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + hz4: Self::HZ4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + hz5: Self::HZ5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + hz6: Self::HZ6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + hz7: Self::HZ7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + hz8: Self::HZ8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + hz9: Self::HZ9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + hz10: Self::HZ10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + hz11: Self::HZ11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + hz12: Self::HZ12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + hz13: Self::HZ13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + hz14: Self::HZ14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + hz15: Self::HZ15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + hz16: Self::HZ16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + hz17: Self::HZ17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + hz18: Self::HZ18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + hz19: Self::HZ19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + hz20: Self::HZ20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Lfrt, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Lfrt, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Lfrt { + const ID: u16 = 135; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m135 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model136.rs b/src/models/model136.rs index b030b23..870c0ec 100644 --- a/src/models/model136.rs +++ b/src/models/model136.rs @@ -1,4 +1,5 @@ //! HFRT +pub type Model136 = Hfrt; /// HFRT /// /// High Frequency Ride-through @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model136 { +pub struct Hfrt { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -49,9 +50,11 @@ pub struct Model136 { /// /// Scale factor for frequency. pub hz_sf: i16, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model136 { +impl Hfrt { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -62,23 +65,32 @@ impl Model136 { pub const TMS_SF: crate::Point = crate::Point::new(7, 1, false); pub const HZ_SF: crate::Point = crate::Point::new(8, 1, false); } -impl crate::Model for Model136 { - const ID: u16 = 136; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - }) +impl crate::Group for Hfrt { + const LEN: u16 = 10; +} +impl Hfrt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m136 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -114,3 +126,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 must disconnect duration. + pub tms1: u16, + /// Hz1 + /// + /// Point 1 must disconnect frequency. + pub hz1: u16, + /// Tms2 + /// + /// Point 2 must disconnect duration. + pub tms2: Option, + /// Hz2 + /// + /// Point 2 must disconnect frequency. + pub hz2: Option, + /// Tms3 + /// + /// Point 3 must disconnect duration. + pub tms3: Option, + /// Hz3 + /// + /// Point 3 must disconnect frequency. + pub hz3: Option, + /// Tms4 + /// + /// Point 4 must disconnect duration. + pub tms4: Option, + /// Hz4 + /// + /// Point 4 must disconnect frequency. + pub hz4: Option, + /// Tms5 + /// + /// Point 5 must disconnect duration. + pub tms5: Option, + /// Hz5 + /// + /// Point 5 must disconnect frequency. + pub hz5: Option, + /// Tms6 + /// + /// Point 6 must disconnect duration. + pub tms6: Option, + /// Hz6 + /// + /// Point 6 must disconnect frequency. + pub hz6: Option, + /// Tms7 + /// + /// Point 7 must disconnect duration. + pub tms7: Option, + /// Hz7 + /// + /// Point 7 must disconnect frequency. + pub hz7: Option, + /// Tms8 + /// + /// Point 8 must disconnect duration. + pub tms8: Option, + /// Hz8 + /// + /// Point 8 must disconnect frequency. + pub hz8: Option, + /// Tms9 + /// + /// Point 9 must disconnect duration. + pub tms9: Option, + /// Hz9 + /// + /// Point 9 must disconnect frequency. + pub hz9: Option, + /// Tms10 + /// + /// Point 10 must disconnect duration. + pub tms10: Option, + /// Hz10 + /// + /// Point 10 must disconnect frequency. + pub hz10: Option, + /// Tms11 + /// + /// Point 11 must disconnect duration. + pub tms11: Option, + /// Hz11 + /// + /// Point 11 must disconnect frequency. + pub hz11: Option, + /// Tms12 + /// + /// Point 12 must disconnect duration. + pub tms12: Option, + /// Hz12 + /// + /// Point 12 must disconnect frequency. + pub hz12: Option, + /// Tms13 + /// + /// Point 13 must disconnect duration. + pub tms13: Option, + /// Hz13 + /// + /// Point 13 must disconnect frequency. + pub hz13: Option, + /// Tms14 + /// + /// Point 14 must disconnect duration. + pub tms14: Option, + /// Hz14 + /// + /// Point 14 must disconnect frequency. + pub hz14: Option, + /// Tms15 + /// + /// Point 15 must disconnect duration. + pub tms15: Option, + /// Hz15 + /// + /// Point 15 must disconnect frequency. + pub hz15: Option, + /// Tms16 + /// + /// Point 16 must disconnect duration. + pub tms16: Option, + /// Hz16 + /// + /// Point 16 must disconnect frequency. + pub hz16: Option, + /// Tms17 + /// + /// Point 17 must disconnect duration. + pub tms17: Option, + /// Hz17 + /// + /// Point 17 must disconnect frequency. + pub hz17: Option, + /// Tms18 + /// + /// Point 18 must disconnect duration. + pub tms18: Option, + /// Hz18 + /// + /// Point 18 must disconnect frequency. + pub hz18: Option, + /// Tms19 + /// + /// Point 19 must disconnect duration. + pub tms19: Option, + /// Hz19 + /// + /// Point 19 must disconnect frequency. + pub hz19: Option, + /// Tms20 + /// + /// Point 20 must disconnect duration. + pub tms20: Option, + /// Hz20 + /// + /// Point 20 must disconnect frequency. + pub hz20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const HZ1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const HZ2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const HZ3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const HZ4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const HZ5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const HZ6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const HZ7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const HZ8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const HZ9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const HZ10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const HZ11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const HZ12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const HZ13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const HZ14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const HZ15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const HZ16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const HZ17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const HZ18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const HZ19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const HZ20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + hz1: Self::HZ1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + hz2: Self::HZ2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + hz3: Self::HZ3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + hz4: Self::HZ4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + hz5: Self::HZ5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + hz6: Self::HZ6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + hz7: Self::HZ7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + hz8: Self::HZ8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + hz9: Self::HZ9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + hz10: Self::HZ10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + hz11: Self::HZ11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + hz12: Self::HZ12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + hz13: Self::HZ13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + hz14: Self::HZ14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + hz15: Self::HZ15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + hz16: Self::HZ16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + hz17: Self::HZ17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + hz18: Self::HZ18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + hz19: Self::HZ19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + hz20: Self::HZ20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Hfrt, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Hfrt, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Hfrt { + const ID: u16 = 136; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m136 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model137.rs b/src/models/model137.rs index b4c31a1..cc828bf 100644 --- a/src/models/model137.rs +++ b/src/models/model137.rs @@ -1,4 +1,5 @@ //! LVRTC +pub type Model137 = Lvrtc; /// LVRTC /// /// LVRT must remain connected @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model137 { +pub struct Lvrtc { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -49,9 +50,11 @@ pub struct Model137 { /// /// Scale factor for percent VRef. pub v_sf: i16, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model137 { +impl Lvrtc { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -62,23 +65,32 @@ impl Model137 { pub const TMS_SF: crate::Point = crate::Point::new(7, 1, false); pub const V_SF: crate::Point = crate::Point::new(8, 1, false); } -impl crate::Model for Model137 { - const ID: u16 = 137; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - }) +impl crate::Group for Lvrtc { + const LEN: u16 = 10; +} +impl Lvrtc { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m137 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -114,3 +126,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 must remain connected duration. + pub tms1: u16, + /// V1 + /// + /// Point 1 must remain connected voltage. + pub v1: u16, + /// Tms2 + /// + /// Point 2 must remain connected duration. + pub tms2: Option, + /// V2 + /// + /// Point 2 must remain connected voltage. + pub v2: Option, + /// Tms3 + /// + /// Point 3 must remain connected duration. + pub tms3: Option, + /// V3 + /// + /// Point 3 must remain connected voltage. + pub v3: Option, + /// Tms4 + /// + /// Point 4 must remain connected duration. + pub tms4: Option, + /// V4 + /// + /// Point 4 must remain connected voltage. + pub v4: Option, + /// Tms5 + /// + /// Point 5 must remain connected duration. + pub tms5: Option, + /// V5 + /// + /// Point 5 must remain connected voltage. + pub v5: Option, + /// Tms6 + /// + /// Point 6 must remain connected duration. + pub tms6: Option, + /// V6 + /// + /// Point 6 must remain connected voltage. + pub v6: Option, + /// Tms7 + /// + /// Point 7 must remain connected duration. + pub tms7: Option, + /// V7 + /// + /// Point 7 must remain connected voltage. + pub v7: Option, + /// Tms8 + /// + /// Point 8 must remain connected duration. + pub tms8: Option, + /// V8 + /// + /// Point 8 must remain connected voltage. + pub v8: Option, + /// Tms9 + /// + /// Point 9 must remain connected duration. + pub tms9: Option, + /// V9 + /// + /// Point 9 must remain connected voltage. + pub v9: Option, + /// Tms10 + /// + /// Point 10 must remain connected duration. + pub tms10: Option, + /// V10 + /// + /// Point 10 must remain connected voltage. + pub v10: Option, + /// Tms11 + /// + /// Point 11 must remain connected duration. + pub tms11: Option, + /// V11 + /// + /// Point 11 must remain connected voltage. + pub v11: Option, + /// Tms12 + /// + /// Point 12 must remain connected duration. + pub tms12: Option, + /// V12 + /// + /// Point 12 must remain connected voltage. + pub v12: Option, + /// Tms13 + /// + /// Point 13 must remain connected duration. + pub tms13: Option, + /// V13 + /// + /// Point 13 must remain connected voltage. + pub v13: Option, + /// Tms14 + /// + /// Point 14 must remain connected duration. + pub tms14: Option, + /// V14 + /// + /// Point 14 must remain connected voltage. + pub v14: Option, + /// Tms15 + /// + /// Point 15 must remain connected duration. + pub tms15: Option, + /// V15 + /// + /// Point 15 must remain connected voltage. + pub v15: Option, + /// Tms16 + /// + /// Point 16 must remain connected duration. + pub tms16: Option, + /// V16 + /// + /// Point 16 must remain connected voltage. + pub v16: Option, + /// Tms17 + /// + /// Point 17 must remain connected duration. + pub tms17: Option, + /// V17 + /// + /// Point 17 must remain connected voltage. + pub v17: Option, + /// Tms18 + /// + /// Point 18 must remain connected duration. + pub tms18: Option, + /// V18 + /// + /// Point 18 must remain connected voltage. + pub v18: Option, + /// Tms19 + /// + /// Point 19 must remain connected duration. + pub tms19: Option, + /// V19 + /// + /// Point 19 must remain connected voltage. + pub v19: Option, + /// Tms20 + /// + /// Point 20 must remain connected duration. + pub tms20: Option, + /// V20 + /// + /// Point 20 must remain connected voltage. + pub v20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const V1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const V2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const V3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const V4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const V5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const V6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const V7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const V8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const V9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const V10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const V11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const V12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const V13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const V14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const V15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const V16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const V17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const V18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const V19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const V20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + v1: Self::V1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + v2: Self::V2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + v3: Self::V3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + v4: Self::V4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + v5: Self::V5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + v6: Self::V6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + v7: Self::V7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + v8: Self::V8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + v9: Self::V9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + v10: Self::V10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + v11: Self::V11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + v12: Self::V12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + v13: Self::V13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + v14: Self::V14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + v15: Self::V15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + v16: Self::V16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + v17: Self::V17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + v18: Self::V18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + v19: Self::V19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + v20: Self::V20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Lvrtc, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Lvrtc, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Lvrtc { + const ID: u16 = 137; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m137 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model138.rs b/src/models/model138.rs index f8811a9..f8c6ade 100644 --- a/src/models/model138.rs +++ b/src/models/model138.rs @@ -1,4 +1,5 @@ //! HVRTC +pub type Model138 = Hvrtc; /// HVRTC /// /// HVRT must remain connected @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model138 { +pub struct Hvrtc { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -49,9 +50,11 @@ pub struct Model138 { /// /// Scale factor for percent VRef. pub v_sf: i16, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model138 { +impl Hvrtc { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -62,23 +65,32 @@ impl Model138 { pub const TMS_SF: crate::Point = crate::Point::new(7, 1, false); pub const V_SF: crate::Point = crate::Point::new(8, 1, false); } -impl crate::Model for Model138 { - const ID: u16 = 138; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - }) +impl crate::Group for Hvrtc { + const LEN: u16 = 10; +} +impl Hvrtc { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m138 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -114,3 +126,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 must remain connected duration. + pub tms1: u16, + /// V1 + /// + /// Point 1 must remain connected voltage. + pub v1: u16, + /// Tms2 + /// + /// Point 2 must remain connected duration. + pub tms2: Option, + /// V2 + /// + /// Point 2 must remain connected voltage. + pub v2: Option, + /// Tms3 + /// + /// Point 3 must remain connected duration. + pub tms3: Option, + /// V3 + /// + /// Point 3 must remain connected voltage. + pub v3: Option, + /// Tms4 + /// + /// Point 4 must remain connected duration. + pub tms4: Option, + /// V4 + /// + /// Point 4 must remain connected voltage. + pub v4: Option, + /// Tms5 + /// + /// Point 5 must remain connected duration. + pub tms5: Option, + /// V5 + /// + /// Point 5 must remain connected voltage. + pub v5: Option, + /// Tms6 + /// + /// Point 6 must remain connected duration. + pub tms6: Option, + /// V6 + /// + /// Point 6 must remain connected voltage. + pub v6: Option, + /// Tms7 + /// + /// Point 7 must remain connected duration. + pub tms7: Option, + /// V7 + /// + /// Point 7 must remain connected voltage. + pub v7: Option, + /// Tms8 + /// + /// Point 8 must remain connected duration. + pub tms8: Option, + /// V8 + /// + /// Point 8 must remain connected voltage. + pub v8: Option, + /// Tms9 + /// + /// Point 9 must remain connected duration. + pub tms9: Option, + /// V9 + /// + /// Point 9 must remain connected voltage. + pub v9: Option, + /// Tms10 + /// + /// Point 10 must remain connected duration. + pub tms10: Option, + /// V10 + /// + /// Point 10 must remain connected voltage. + pub v10: Option, + /// Tms11 + /// + /// Point 11 must remain connected duration. + pub tms11: Option, + /// V11 + /// + /// Point 11 must remain connected voltage. + pub v11: Option, + /// Tms12 + /// + /// Point 12 must remain connected duration. + pub tms12: Option, + /// V12 + /// + /// Point 12 must remain connected voltage. + pub v12: Option, + /// Tms13 + /// + /// Point 13 must remain connected duration. + pub tms13: Option, + /// V13 + /// + /// Point 13 must remain connected voltage. + pub v13: Option, + /// Tms14 + /// + /// Point 14 must remain connected duration. + pub tms14: Option, + /// V14 + /// + /// Point 14 must remain connected voltage. + pub v14: Option, + /// Tms15 + /// + /// Point 15 must remain connected duration. + pub tms15: Option, + /// V15 + /// + /// Point 15 must remain connected voltage. + pub v15: Option, + /// Tms16 + /// + /// Point 16 must remain connected duration. + pub tms16: Option, + /// V16 + /// + /// Point 16 must remain connected voltage. + pub v16: Option, + /// Tms17 + /// + /// Point 17 must remain connected duration. + pub tms17: Option, + /// V17 + /// + /// Point 17 must remain connected voltage. + pub v17: Option, + /// Tms18 + /// + /// Point 18 must remain connected duration. + pub tms18: Option, + /// V18 + /// + /// Point 18 must remain connected voltage. + pub v18: Option, + /// Tms19 + /// + /// Point 19 must remain connected duration. + pub tms19: Option, + /// V19 + /// + /// Point 19 must remain connected voltage. + pub v19: Option, + /// Tms20 + /// + /// Point 20 must remain connected duration. + pub tms20: Option, + /// V20 + /// + /// Point 20 must remain connected voltage. + pub v20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const V1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const V2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const V3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const V4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const V5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const V6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const V7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const V8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const V9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const V10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const V11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const V12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const V13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const V14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const V15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const V16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const V17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const V18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const V19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const V20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + v1: Self::V1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + v2: Self::V2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + v3: Self::V3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + v4: Self::V4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + v5: Self::V5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + v6: Self::V6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + v7: Self::V7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + v8: Self::V8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + v9: Self::V9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + v10: Self::V10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + v11: Self::V11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + v12: Self::V12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + v13: Self::V13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + v14: Self::V14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + v15: Self::V15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + v16: Self::V16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + v17: Self::V17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + v18: Self::V18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + v19: Self::V19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + v20: Self::V20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Hvrtc, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Hvrtc, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Hvrtc { + const ID: u16 = 138; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m138 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model139.rs b/src/models/model139.rs index b43e4da..91d5f68 100644 --- a/src/models/model139.rs +++ b/src/models/model139.rs @@ -1,4 +1,5 @@ //! LVRTX +pub type Model139 = Lvrtx; /// LVRTX /// /// LVRT extended curve @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model139 { +pub struct Lvrtx { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -51,9 +52,11 @@ pub struct Model139 { pub v_sf: i16, #[allow(missing_docs)] pub crv_type: CrvType, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model139 { +impl Lvrtx { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -65,24 +68,33 @@ impl Model139 { pub const V_SF: crate::Point = crate::Point::new(8, 1, false); pub const CRV_TYPE: crate::Point = crate::Point::new(9, 1, false); } -impl crate::Model for Model139 { - const ID: u16 = 139; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - crv_type: Self::CRV_TYPE.from_data(data)?, - }) +impl crate::Group for Lvrtx { + const LEN: u16 = 10; +} +impl Lvrtx { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + crv_type: Self::CRV_TYPE.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m139 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -154,3 +166,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 duration. + pub tms1: u16, + /// V1 + /// + /// Point 1 voltage. + pub v1: u16, + /// Tms2 + /// + /// Point 2 duration. + pub tms2: Option, + /// V2 + /// + /// Point 2 voltage. + pub v2: Option, + /// Tms3 + /// + /// Point 3 duration. + pub tms3: Option, + /// V3 + /// + /// Point 3 voltage. + pub v3: Option, + /// Tms4 + /// + /// Point 4 duration. + pub tms4: Option, + /// V4 + /// + /// Point 4 voltage. + pub v4: Option, + /// Tms5 + /// + /// Point 5 duration. + pub tms5: Option, + /// V5 + /// + /// Point 5 voltage. + pub v5: Option, + /// Tms6 + /// + /// Point 6 duration. + pub tms6: Option, + /// V6 + /// + /// Point 6 voltage. + pub v6: Option, + /// Tms7 + /// + /// Point 7 duration. + pub tms7: Option, + /// V7 + /// + /// Point 7 voltage. + pub v7: Option, + /// Tms8 + /// + /// Point 8 duration. + pub tms8: Option, + /// V8 + /// + /// Point 8 voltage. + pub v8: Option, + /// Tms9 + /// + /// Point 9 duration. + pub tms9: Option, + /// V9 + /// + /// Point 9 voltage. + pub v9: Option, + /// Tms10 + /// + /// Point 10 duration. + pub tms10: Option, + /// V10 + /// + /// Point 10 voltage. + pub v10: Option, + /// Tms11 + /// + /// Point 11 duration. + pub tms11: Option, + /// V11 + /// + /// Point 11 voltage. + pub v11: Option, + /// Tms12 + /// + /// Point 12 duration. + pub tms12: Option, + /// V12 + /// + /// Point 12 voltage. + pub v12: Option, + /// Tms13 + /// + /// Point 13 duration. + pub tms13: Option, + /// V13 + /// + /// Point 13 voltage. + pub v13: Option, + /// Tms14 + /// + /// Point 14 duration. + pub tms14: Option, + /// V14 + /// + /// Point 14 voltage. + pub v14: Option, + /// Tms15 + /// + /// Point 15 duration. + pub tms15: Option, + /// V15 + /// + /// Point 15 voltage. + pub v15: Option, + /// Tms16 + /// + /// Point 16 duration. + pub tms16: Option, + /// V16 + /// + /// Point 16 voltage. + pub v16: Option, + /// Tms17 + /// + /// Point 17 duration. + pub tms17: Option, + /// V17 + /// + /// Point 17 voltage. + pub v17: Option, + /// Tms18 + /// + /// Point 18 duration. + pub tms18: Option, + /// V18 + /// + /// Point 18 voltage. + pub v18: Option, + /// Tms19 + /// + /// Point 19 duration. + pub tms19: Option, + /// V19 + /// + /// Point 19 voltage. + pub v19: Option, + /// Tms20 + /// + /// Point 20 duration. + pub tms20: Option, + /// V20 + /// + /// Point 20 voltage. + pub v20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const V1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const V2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const V3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const V4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const V5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const V6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const V7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const V8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const V9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const V10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const V11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const V12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const V13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const V14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const V15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const V16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const V17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const V18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const V19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const V20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + v1: Self::V1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + v2: Self::V2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + v3: Self::V3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + v4: Self::V4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + v5: Self::V5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + v6: Self::V6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + v7: Self::V7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + v8: Self::V8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + v9: Self::V9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + v10: Self::V10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + v11: Self::V11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + v12: Self::V12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + v13: Self::V13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + v14: Self::V14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + v15: Self::V15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + v16: Self::V16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + v17: Self::V17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + v18: Self::V18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + v19: Self::V19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + v20: Self::V20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Lvrtx, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Lvrtx, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Lvrtx { + const ID: u16 = 139; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m139 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model14.rs b/src/models/model14.rs index 1c22055..4dafbe3 100644 --- a/src/models/model14.rs +++ b/src/models/model14.rs @@ -49,22 +49,29 @@ impl Model14 { pub const USER: crate::Point> = crate::Point::new(28, 12, true); pub const PW: crate::Point> = crate::Point::new(40, 12, true); } -impl crate::Model for Model14 { - const ID: u16 = 14; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - nam: Self::NAM.from_data(data)?, - cap: Self::CAP.from_data(data)?, - cfg: Self::CFG.from_data(data)?, - typ: Self::TYP.from_data(data)?, - addr: Self::ADDR.from_data(data)?, - port: Self::PORT.from_data(data)?, - user: Self::USER.from_data(data)?, - pw: Self::PW.from_data(data)?, - }) +impl crate::Group for Model14 { + const LEN: u16 = 52; +} +impl Model14 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + nam: Self::NAM.from_data(data)?, + cap: Self::CAP.from_data(data)?, + cfg: Self::CFG.from_data(data)?, + typ: Self::TYP.from_data(data)?, + addr: Self::ADDR.from_data(data)?, + port: Self::PORT.from_data(data)?, + user: Self::USER.from_data(data)?, + pw: Self::PW.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m14 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -132,3 +139,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Model14 { + const ID: u16 = 14; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m14 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model140.rs b/src/models/model140.rs index bfab851..77118d8 100644 --- a/src/models/model140.rs +++ b/src/models/model140.rs @@ -1,4 +1,5 @@ //! HVRTX +pub type Model140 = Hvrtx; /// HVRTX /// /// HVRT extended curve @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model140 { +pub struct Hvrtx { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -51,9 +52,11 @@ pub struct Model140 { pub v_sf: i16, #[allow(missing_docs)] pub crv_type: CrvType, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model140 { +impl Hvrtx { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -65,24 +68,33 @@ impl Model140 { pub const V_SF: crate::Point = crate::Point::new(8, 1, false); pub const CRV_TYPE: crate::Point = crate::Point::new(9, 1, false); } -impl crate::Model for Model140 { - const ID: u16 = 140; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - crv_type: Self::CRV_TYPE.from_data(data)?, - }) +impl crate::Group for Hvrtx { + const LEN: u16 = 10; +} +impl Hvrtx { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + crv_type: Self::CRV_TYPE.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m140 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -154,3 +166,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 duration. + pub tms1: u16, + /// V1 + /// + /// Point 1 voltage. + pub v1: u16, + /// Tms2 + /// + /// Point 2 duration. + pub tms2: Option, + /// V2 + /// + /// Point 2 voltage. + pub v2: Option, + /// Tms3 + /// + /// Point 3 duration. + pub tms3: Option, + /// V3 + /// + /// Point 3 voltage. + pub v3: Option, + /// Tms4 + /// + /// Point 4 duration. + pub tms4: Option, + /// V4 + /// + /// Point 4 voltage. + pub v4: Option, + /// Tms5 + /// + /// Point 5 duration. + pub tms5: Option, + /// V5 + /// + /// Point 5 voltage. + pub v5: Option, + /// Tms6 + /// + /// Point 6 duration. + pub tms6: Option, + /// V6 + /// + /// Point 6 voltage. + pub v6: Option, + /// Tms7 + /// + /// Point 7 duration. + pub tms7: Option, + /// V7 + /// + /// Point 7 voltage. + pub v7: Option, + /// Tms8 + /// + /// Point 8 duration. + pub tms8: Option, + /// V8 + /// + /// Point 8 voltage. + pub v8: Option, + /// Tms9 + /// + /// Point 9 duration. + pub tms9: Option, + /// V9 + /// + /// Point 9 voltage. + pub v9: Option, + /// Tms10 + /// + /// Point 10 duration. + pub tms10: Option, + /// V10 + /// + /// Point 10 voltage. + pub v10: Option, + /// Tms11 + /// + /// Point 11 duration. + pub tms11: Option, + /// V11 + /// + /// Point 11 voltage. + pub v11: Option, + /// Tms12 + /// + /// Point 12 duration. + pub tms12: Option, + /// V12 + /// + /// Point 12 voltage. + pub v12: Option, + /// Tms13 + /// + /// Point 13 duration. + pub tms13: Option, + /// V13 + /// + /// Point 13 voltage. + pub v13: Option, + /// Tms14 + /// + /// Point 14 duration. + pub tms14: Option, + /// V14 + /// + /// Point 14 voltage. + pub v14: Option, + /// Tms15 + /// + /// Point 15 duration. + pub tms15: Option, + /// V15 + /// + /// Point 15 voltage. + pub v15: Option, + /// Tms16 + /// + /// Point 16 duration. + pub tms16: Option, + /// V16 + /// + /// Point 16 voltage. + pub v16: Option, + /// Tms17 + /// + /// Point 17 duration. + pub tms17: Option, + /// V17 + /// + /// Point 17 voltage. + pub v17: Option, + /// Tms18 + /// + /// Point 18 duration. + pub tms18: Option, + /// V18 + /// + /// Point 18 voltage. + pub v18: Option, + /// Tms19 + /// + /// Point 19 duration. + pub tms19: Option, + /// V19 + /// + /// Point 19 voltage. + pub v19: Option, + /// Tms20 + /// + /// Point 20 duration. + pub tms20: Option, + /// V20 + /// + /// Point 20 voltage. + pub v20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const V1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const V2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const V3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const V4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const V5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const V6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const V7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const V8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const V9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const V10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const V11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const V12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const V13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const V14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const V15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const V16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const V17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const V18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const V19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const V20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + v1: Self::V1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + v2: Self::V2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + v3: Self::V3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + v4: Self::V4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + v5: Self::V5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + v6: Self::V6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + v7: Self::V7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + v8: Self::V8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + v9: Self::V9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + v10: Self::V10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + v11: Self::V11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + v12: Self::V12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + v13: Self::V13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + v14: Self::V14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + v15: Self::V15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + v16: Self::V16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + v17: Self::V17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + v18: Self::V18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + v19: Self::V19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + v20: Self::V20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Hvrtx, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Hvrtx, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Hvrtx { + const ID: u16 = 140; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m140 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model141.rs b/src/models/model141.rs index fd168c3..1373d62 100644 --- a/src/models/model141.rs +++ b/src/models/model141.rs @@ -1,4 +1,5 @@ //! LFRTC +pub type Model141 = Lfrtc; /// LFRTC /// /// LFRT must remain connected @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model141 { +pub struct Lfrtc { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -49,9 +50,11 @@ pub struct Model141 { /// /// Scale factor for frequency. pub hz_sf: i16, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model141 { +impl Lfrtc { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -62,23 +65,32 @@ impl Model141 { pub const TMS_SF: crate::Point = crate::Point::new(7, 1, false); pub const HZ_SF: crate::Point = crate::Point::new(8, 1, false); } -impl crate::Model for Model141 { - const ID: u16 = 141; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - }) +impl crate::Group for Lfrtc { + const LEN: u16 = 10; +} +impl Lfrtc { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m141 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -114,3 +126,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 must remain connected duration. + pub tms1: u16, + /// Hz1 + /// + /// Point 1 must remain connected frequency. + pub hz1: u16, + /// Tms2 + /// + /// Point 2 must remain connected duration. + pub tms2: Option, + /// Hz2 + /// + /// Point 2 must remain connected frequency. + pub hz2: Option, + /// Tms3 + /// + /// Point 3 must remain connected duration. + pub tms3: Option, + /// Hz3 + /// + /// Point 3 must remain connected frequency. + pub hz3: Option, + /// Tms4 + /// + /// Point 4 must remain connected duration. + pub tms4: Option, + /// Hz4 + /// + /// Point 4 must remain connected frequency. + pub hz4: Option, + /// Tms5 + /// + /// Point 5 must remain connected duration. + pub tms5: Option, + /// Hz5 + /// + /// Point 5 must remain connected frequency. + pub hz5: Option, + /// Tms6 + /// + /// Point 6 must remain connected duration. + pub tms6: Option, + /// Hz6 + /// + /// Point 6 must remain connected frequency. + pub hz6: Option, + /// Tms7 + /// + /// Point 7 must remain connected duration. + pub tms7: Option, + /// Hz7 + /// + /// Point 7 must remain connected frequency. + pub hz7: Option, + /// Tms8 + /// + /// Point 8 must remain connected duration. + pub tms8: Option, + /// Hz8 + /// + /// Point 8 must remain connected frequency. + pub hz8: Option, + /// Tms9 + /// + /// Point 9 must remain connected duration. + pub tms9: Option, + /// Hz9 + /// + /// Point 9 must remain connected frequency. + pub hz9: Option, + /// Tms10 + /// + /// Point 10 must remain connected duration. + pub tms10: Option, + /// Hz10 + /// + /// Point 10 must remain connected frequency. + pub hz10: Option, + /// Tms11 + /// + /// Point 11 must remain connected duration. + pub tms11: Option, + /// Hz11 + /// + /// Point 11 must remain connected frequency. + pub hz11: Option, + /// Tms12 + /// + /// Point 12 must remain connected duration. + pub tms12: Option, + /// Hz12 + /// + /// Point 12 must remain connected frequency. + pub hz12: Option, + /// Tms13 + /// + /// Point 13 must remain connected duration. + pub tms13: Option, + /// Hz13 + /// + /// Point 13 must remain connected frequency. + pub hz13: Option, + /// Tms14 + /// + /// Point 14 must remain connected duration. + pub tms14: Option, + /// Hz14 + /// + /// Point 14 must remain connected frequency. + pub hz14: Option, + /// Tms15 + /// + /// Point 15 must remain connected duration. + pub tms15: Option, + /// Hz15 + /// + /// Point 15 must remain connected frequency. + pub hz15: Option, + /// Tms16 + /// + /// Point 16 must remain connected duration. + pub tms16: Option, + /// Hz16 + /// + /// Point 16 must remain connected frequency. + pub hz16: Option, + /// Tms17 + /// + /// Point 17 must remain connected duration. + pub tms17: Option, + /// Hz17 + /// + /// Point 17 must remain connected frequency. + pub hz17: Option, + /// Tms18 + /// + /// Point 18 must remain connected duration. + pub tms18: Option, + /// Hz18 + /// + /// Point 18 must remain connected frequency. + pub hz18: Option, + /// Tms19 + /// + /// Point 19 must remain connected duration. + pub tms19: Option, + /// Hz19 + /// + /// Point 19 must remain connected frequency. + pub hz19: Option, + /// Tms20 + /// + /// Point 20 must remain connected duration. + pub tms20: Option, + /// Hz20 + /// + /// Point 20 must remain connected frequency. + pub hz20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const HZ1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const HZ2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const HZ3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const HZ4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const HZ5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const HZ6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const HZ7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const HZ8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const HZ9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const HZ10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const HZ11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const HZ12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const HZ13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const HZ14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const HZ15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const HZ16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const HZ17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const HZ18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const HZ19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const HZ20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + hz1: Self::HZ1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + hz2: Self::HZ2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + hz3: Self::HZ3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + hz4: Self::HZ4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + hz5: Self::HZ5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + hz6: Self::HZ6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + hz7: Self::HZ7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + hz8: Self::HZ8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + hz9: Self::HZ9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + hz10: Self::HZ10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + hz11: Self::HZ11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + hz12: Self::HZ12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + hz13: Self::HZ13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + hz14: Self::HZ14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + hz15: Self::HZ15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + hz16: Self::HZ16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + hz17: Self::HZ17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + hz18: Self::HZ18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + hz19: Self::HZ19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + hz20: Self::HZ20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Lfrtc, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Lfrtc, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Lfrtc { + const ID: u16 = 141; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m141 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model142.rs b/src/models/model142.rs index 2062c65..9704749 100644 --- a/src/models/model142.rs +++ b/src/models/model142.rs @@ -1,4 +1,5 @@ //! HFRTC +pub type Model142 = Hfrtc; /// HFRTC /// /// HFRT must remain connected @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model142 { +pub struct Hfrtc { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -49,9 +50,11 @@ pub struct Model142 { /// /// Scale factor for frequency. pub hz_sf: i16, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model142 { +impl Hfrtc { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -62,23 +65,32 @@ impl Model142 { pub const TMS_SF: crate::Point = crate::Point::new(7, 1, false); pub const HZ_SF: crate::Point = crate::Point::new(8, 1, false); } -impl crate::Model for Model142 { - const ID: u16 = 142; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - }) +impl crate::Group for Hfrtc { + const LEN: u16 = 10; +} +impl Hfrtc { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m142 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -114,3 +126,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 must remain connected duration. + pub tms1: u16, + /// Hz1 + /// + /// Point 1 must remain connected frequency. + pub hz1: u16, + /// Tms2 + /// + /// Point 2 must remain connected duration. + pub tms2: Option, + /// Hz2 + /// + /// Point 2 must remain connected frequency. + pub hz2: Option, + /// Tms3 + /// + /// Point 3 must remain connected duration. + pub tms3: Option, + /// Hz3 + /// + /// Point 3 must remain connected frequency. + pub hz3: Option, + /// Tms4 + /// + /// Point 4 must remain connected duration. + pub tms4: Option, + /// Hz4 + /// + /// Point 4 must remain connected frequency. + pub hz4: Option, + /// Tms5 + /// + /// Point 5 must remain connected duration. + pub tms5: Option, + /// Hz5 + /// + /// Point 5 must remain connected frequency. + pub hz5: Option, + /// Tms6 + /// + /// Point 6 must remain connected duration. + pub tms6: Option, + /// Hz6 + /// + /// Point 6 must remain connected frequency. + pub hz6: Option, + /// Tms7 + /// + /// Point 7 must remain connected duration. + pub tms7: Option, + /// Hz7 + /// + /// Point 7 must remain connected frequency. + pub hz7: Option, + /// Tms8 + /// + /// Point 8 must remain connected duration. + pub tms8: Option, + /// Hz8 + /// + /// Point 8 must remain connected frequency. + pub hz8: Option, + /// Tms9 + /// + /// Point 9 must remain connected duration. + pub tms9: Option, + /// Hz9 + /// + /// Point 9 must remain connected frequency. + pub hz9: Option, + /// Tms10 + /// + /// Point 10 must remain connected duration. + pub tms10: Option, + /// Hz10 + /// + /// Point 10 must remain connected frequency. + pub hz10: Option, + /// Tms11 + /// + /// Point 11 must remain connected duration. + pub tms11: Option, + /// Hz11 + /// + /// Point 11 must remain connected frequency. + pub hz11: Option, + /// Tms12 + /// + /// Point 12 must remain connected duration. + pub tms12: Option, + /// Hz12 + /// + /// Point 12 must remain connected frequency. + pub hz12: Option, + /// Tms13 + /// + /// Point 13 must remain connected duration. + pub tms13: Option, + /// Hz13 + /// + /// Point 13 must remain connected frequency. + pub hz13: Option, + /// Tms14 + /// + /// Point 14 must remain connected duration. + pub tms14: Option, + /// Hz14 + /// + /// Point 14 must remain connected frequency. + pub hz14: Option, + /// Tms15 + /// + /// Point 15 must remain connected duration. + pub tms15: Option, + /// Hz15 + /// + /// Point 15 must remain connected frequency. + pub hz15: Option, + /// Tms16 + /// + /// Point 16 must remain connected duration. + pub tms16: Option, + /// Hz16 + /// + /// Point 16 must remain connected frequency. + pub hz16: Option, + /// Tms17 + /// + /// Point 17 must remain connected duration. + pub tms17: Option, + /// Hz17 + /// + /// Point 17 must remain connected frequency. + pub hz17: Option, + /// Tms18 + /// + /// Point 18 must remain connected duration. + pub tms18: Option, + /// Hz18 + /// + /// Point 18 must remain connected frequency. + pub hz18: Option, + /// Tms19 + /// + /// Point 19 must remain connected duration. + pub tms19: Option, + /// Hz19 + /// + /// Point 19 must remain connected frequency. + pub hz19: Option, + /// Tms20 + /// + /// Point 20 must remain connected duration. + pub tms20: Option, + /// Hz20 + /// + /// Point 20 must remain connected frequency. + pub hz20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const HZ1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const HZ2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const HZ3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const HZ4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const HZ5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const HZ6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const HZ7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const HZ8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const HZ9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const HZ10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const HZ11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const HZ12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const HZ13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const HZ14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const HZ15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const HZ16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const HZ17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const HZ18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const HZ19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const HZ20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + hz1: Self::HZ1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + hz2: Self::HZ2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + hz3: Self::HZ3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + hz4: Self::HZ4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + hz5: Self::HZ5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + hz6: Self::HZ6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + hz7: Self::HZ7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + hz8: Self::HZ8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + hz9: Self::HZ9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + hz10: Self::HZ10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + hz11: Self::HZ11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + hz12: Self::HZ12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + hz13: Self::HZ13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + hz14: Self::HZ14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + hz15: Self::HZ15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + hz16: Self::HZ16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + hz17: Self::HZ17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + hz18: Self::HZ18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + hz19: Self::HZ19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + hz20: Self::HZ20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Hfrtc, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Hfrtc, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Hfrtc { + const ID: u16 = 142; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m142 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model143.rs b/src/models/model143.rs index 8094efd..2c246dc 100644 --- a/src/models/model143.rs +++ b/src/models/model143.rs @@ -1,4 +1,5 @@ //! LFRTX +pub type Model143 = Lfrtx; /// LFRTX /// /// LFRT extended curve @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model143 { +pub struct Lfrtx { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -51,9 +52,11 @@ pub struct Model143 { pub hz_sf: i16, #[allow(missing_docs)] pub crv_type: CrvType, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model143 { +impl Lfrtx { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -65,24 +68,33 @@ impl Model143 { pub const HZ_SF: crate::Point = crate::Point::new(8, 1, false); pub const CRV_TYPE: crate::Point = crate::Point::new(9, 1, false); } -impl crate::Model for Model143 { - const ID: u16 = 143; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - crv_type: Self::CRV_TYPE.from_data(data)?, - }) +impl crate::Group for Lfrtx { + const LEN: u16 = 10; +} +impl Lfrtx { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + crv_type: Self::CRV_TYPE.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m143 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -154,3 +166,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 duration. + pub tms1: u16, + /// Hz1 + /// + /// Point 1 frequency. + pub hz1: u16, + /// Tms2 + /// + /// Point 2 duration. + pub tms2: Option, + /// Hz2 + /// + /// Point 2 frequency. + pub hz2: Option, + /// Tms3 + /// + /// Point 3 duration. + pub tms3: Option, + /// Hz3 + /// + /// Point 3 frequency. + pub hz3: Option, + /// Tms4 + /// + /// Point 4 duration. + pub tms4: Option, + /// Hz4 + /// + /// Point 4 frequency. + pub hz4: Option, + /// Tms5 + /// + /// Point 5 duration. + pub tms5: Option, + /// Hz5 + /// + /// Point 5 frequency. + pub hz5: Option, + /// Tms6 + /// + /// Point 6 duration. + pub tms6: Option, + /// Hz6 + /// + /// Point 6 frequency. + pub hz6: Option, + /// Tms7 + /// + /// Point 7 duration. + pub tms7: Option, + /// Hz7 + /// + /// Point 7 frequency. + pub hz7: Option, + /// Tms8 + /// + /// Point 8 duration. + pub tms8: Option, + /// Hz8 + /// + /// Point 8 frequency. + pub hz8: Option, + /// Tms9 + /// + /// Point 9 duration. + pub tms9: Option, + /// Hz9 + /// + /// Point 9 frequency. + pub hz9: Option, + /// Tms10 + /// + /// Point 10 duration. + pub tms10: Option, + /// Hz10 + /// + /// Point 10 frequency. + pub hz10: Option, + /// Tms11 + /// + /// Point 11 duration. + pub tms11: Option, + /// Hz11 + /// + /// Point 11 frequency. + pub hz11: Option, + /// Tms12 + /// + /// Point 12 duration. + pub tms12: Option, + /// Hz12 + /// + /// Point 12 frequency. + pub hz12: Option, + /// Tms13 + /// + /// Point 13 duration. + pub tms13: Option, + /// Hz13 + /// + /// Point 13 frequency. + pub hz13: Option, + /// Tms14 + /// + /// Point 14 duration. + pub tms14: Option, + /// Hz14 + /// + /// Point 14 frequency. + pub hz14: Option, + /// Tms15 + /// + /// Point 15 duration. + pub tms15: Option, + /// Hz15 + /// + /// Point 15 frequency. + pub hz15: Option, + /// Tms16 + /// + /// Point 16 duration. + pub tms16: Option, + /// Hz16 + /// + /// Point 16 frequency. + pub hz16: Option, + /// Tms17 + /// + /// Point 17 duration. + pub tms17: Option, + /// Hz17 + /// + /// Point 17 frequency. + pub hz17: Option, + /// Tms18 + /// + /// Point 18 duration. + pub tms18: Option, + /// Hz18 + /// + /// Point 18 frequency. + pub hz18: Option, + /// Tms19 + /// + /// Point 19 duration. + pub tms19: Option, + /// Hz19 + /// + /// Point 19 frequency. + pub hz19: Option, + /// Tms20 + /// + /// Point 20 duration. + pub tms20: Option, + /// Hz20 + /// + /// Point 20 frequency. + pub hz20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const HZ1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const HZ2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const HZ3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const HZ4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const HZ5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const HZ6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const HZ7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const HZ8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const HZ9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const HZ10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const HZ11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const HZ12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const HZ13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const HZ14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const HZ15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const HZ16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const HZ17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const HZ18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const HZ19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const HZ20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + hz1: Self::HZ1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + hz2: Self::HZ2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + hz3: Self::HZ3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + hz4: Self::HZ4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + hz5: Self::HZ5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + hz6: Self::HZ6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + hz7: Self::HZ7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + hz8: Self::HZ8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + hz9: Self::HZ9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + hz10: Self::HZ10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + hz11: Self::HZ11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + hz12: Self::HZ12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + hz13: Self::HZ13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + hz14: Self::HZ14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + hz15: Self::HZ15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + hz16: Self::HZ16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + hz17: Self::HZ17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + hz18: Self::HZ18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + hz19: Self::HZ19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + hz20: Self::HZ20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Lfrtx, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Lfrtx, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Lfrtx { + const ID: u16 = 143; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m143 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model144.rs b/src/models/model144.rs index baa8130..79277d5 100644 --- a/src/models/model144.rs +++ b/src/models/model144.rs @@ -1,4 +1,5 @@ //! HFRTX +pub type Model144 = Hfrtx; /// HFRTX /// /// HFRT extended curve @@ -6,7 +7,7 @@ /// Detail: Ref 4: 11 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model144 { +pub struct Hfrtx { /// ActCrv /// /// Index of active curve. 0=no active curve. @@ -51,9 +52,11 @@ pub struct Model144 { pub hz_sf: i16, #[allow(missing_docs)] pub crv_type: CrvType, + #[allow(missing_docs)] + pub curve: Vec, } #[allow(missing_docs)] -impl Model144 { +impl Hfrtx { pub const ACT_CRV: crate::Point = crate::Point::new(0, 1, true); pub const MOD_ENA: crate::Point = crate::Point::new(1, 1, true); pub const WIN_TMS: crate::Point> = crate::Point::new(2, 1, true); @@ -65,24 +68,33 @@ impl Model144 { pub const HZ_SF: crate::Point = crate::Point::new(8, 1, false); pub const CRV_TYPE: crate::Point = crate::Point::new(9, 1, false); } -impl crate::Model for Model144 { - const ID: u16 = 144; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - act_crv: Self::ACT_CRV.from_data(data)?, - mod_ena: Self::MOD_ENA.from_data(data)?, - win_tms: Self::WIN_TMS.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rmp_tms: Self::RMP_TMS.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - crv_type: Self::CRV_TYPE.from_data(data)?, - }) +impl crate::Group for Hfrtx { + const LEN: u16 = 10; +} +impl Hfrtx { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_crv: Self::ACT_CRV.from_data(data)?, + mod_ena: Self::MOD_ENA.from_data(data)?, + win_tms: Self::WIN_TMS.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rmp_tms: Self::RMP_TMS.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + crv_type: Self::CRV_TYPE.from_data(data)?, + curve: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m144 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.curve) = Curve::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -154,3 +166,351 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Curve { + /// ActPt + /// + /// Number of active points in array. + pub act_pt: u16, + /// Tms1 + /// + /// Point 1 duration. + pub tms1: u16, + /// Hz1 + /// + /// Point 1 frequency. + pub hz1: u16, + /// Tms2 + /// + /// Point 2 duration. + pub tms2: Option, + /// Hz2 + /// + /// Point 2 frequency. + pub hz2: Option, + /// Tms3 + /// + /// Point 3 duration. + pub tms3: Option, + /// Hz3 + /// + /// Point 3 frequency. + pub hz3: Option, + /// Tms4 + /// + /// Point 4 duration. + pub tms4: Option, + /// Hz4 + /// + /// Point 4 frequency. + pub hz4: Option, + /// Tms5 + /// + /// Point 5 duration. + pub tms5: Option, + /// Hz5 + /// + /// Point 5 frequency. + pub hz5: Option, + /// Tms6 + /// + /// Point 6 duration. + pub tms6: Option, + /// Hz6 + /// + /// Point 6 frequency. + pub hz6: Option, + /// Tms7 + /// + /// Point 7 duration. + pub tms7: Option, + /// Hz7 + /// + /// Point 7 frequency. + pub hz7: Option, + /// Tms8 + /// + /// Point 8 duration. + pub tms8: Option, + /// Hz8 + /// + /// Point 8 frequency. + pub hz8: Option, + /// Tms9 + /// + /// Point 9 duration. + pub tms9: Option, + /// Hz9 + /// + /// Point 9 frequency. + pub hz9: Option, + /// Tms10 + /// + /// Point 10 duration. + pub tms10: Option, + /// Hz10 + /// + /// Point 10 frequency. + pub hz10: Option, + /// Tms11 + /// + /// Point 11 duration. + pub tms11: Option, + /// Hz11 + /// + /// Point 11 frequency. + pub hz11: Option, + /// Tms12 + /// + /// Point 12 duration. + pub tms12: Option, + /// Hz12 + /// + /// Point 12 frequency. + pub hz12: Option, + /// Tms13 + /// + /// Point 13 duration. + pub tms13: Option, + /// Hz13 + /// + /// Point 13 frequency. + pub hz13: Option, + /// Tms14 + /// + /// Point 14 duration. + pub tms14: Option, + /// Hz14 + /// + /// Point 14 frequency. + pub hz14: Option, + /// Tms15 + /// + /// Point 15 duration. + pub tms15: Option, + /// Hz15 + /// + /// Point 15 frequency. + pub hz15: Option, + /// Tms16 + /// + /// Point 16 duration. + pub tms16: Option, + /// Hz16 + /// + /// Point 16 frequency. + pub hz16: Option, + /// Tms17 + /// + /// Point 17 duration. + pub tms17: Option, + /// Hz17 + /// + /// Point 17 frequency. + pub hz17: Option, + /// Tms18 + /// + /// Point 18 duration. + pub tms18: Option, + /// Hz18 + /// + /// Point 18 frequency. + pub hz18: Option, + /// Tms19 + /// + /// Point 19 duration. + pub tms19: Option, + /// Hz19 + /// + /// Point 19 frequency. + pub hz19: Option, + /// Tms20 + /// + /// Point 20 duration. + pub tms20: Option, + /// Hz20 + /// + /// Point 20 frequency. + pub hz20: Option, + /// CrvNam + /// + /// Optional description for curve. + pub crv_nam: Option, + /// ReadOnly + /// + /// Enumerated value indicates if curve is read-only or can be modified. + pub read_only: CurveReadOnly, +} +#[allow(missing_docs)] +impl Curve { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const TMS1: crate::Point = crate::Point::new(1, 1, true); + pub const HZ1: crate::Point = crate::Point::new(2, 1, true); + pub const TMS2: crate::Point> = crate::Point::new(3, 1, true); + pub const HZ2: crate::Point> = crate::Point::new(4, 1, true); + pub const TMS3: crate::Point> = crate::Point::new(5, 1, true); + pub const HZ3: crate::Point> = crate::Point::new(6, 1, true); + pub const TMS4: crate::Point> = crate::Point::new(7, 1, true); + pub const HZ4: crate::Point> = crate::Point::new(8, 1, true); + pub const TMS5: crate::Point> = crate::Point::new(9, 1, true); + pub const HZ5: crate::Point> = crate::Point::new(10, 1, true); + pub const TMS6: crate::Point> = crate::Point::new(11, 1, true); + pub const HZ6: crate::Point> = crate::Point::new(12, 1, true); + pub const TMS7: crate::Point> = crate::Point::new(13, 1, true); + pub const HZ7: crate::Point> = crate::Point::new(14, 1, true); + pub const TMS8: crate::Point> = crate::Point::new(15, 1, true); + pub const HZ8: crate::Point> = crate::Point::new(16, 1, true); + pub const TMS9: crate::Point> = crate::Point::new(17, 1, true); + pub const HZ9: crate::Point> = crate::Point::new(18, 1, true); + pub const TMS10: crate::Point> = crate::Point::new(19, 1, true); + pub const HZ10: crate::Point> = crate::Point::new(20, 1, true); + pub const TMS11: crate::Point> = crate::Point::new(21, 1, true); + pub const HZ11: crate::Point> = crate::Point::new(22, 1, true); + pub const TMS12: crate::Point> = crate::Point::new(23, 1, true); + pub const HZ12: crate::Point> = crate::Point::new(24, 1, true); + pub const TMS13: crate::Point> = crate::Point::new(25, 1, true); + pub const HZ13: crate::Point> = crate::Point::new(26, 1, true); + pub const TMS14: crate::Point> = crate::Point::new(27, 1, true); + pub const HZ14: crate::Point> = crate::Point::new(28, 1, true); + pub const TMS15: crate::Point> = crate::Point::new(29, 1, true); + pub const HZ15: crate::Point> = crate::Point::new(30, 1, true); + pub const TMS16: crate::Point> = crate::Point::new(31, 1, true); + pub const HZ16: crate::Point> = crate::Point::new(32, 1, true); + pub const TMS17: crate::Point> = crate::Point::new(33, 1, true); + pub const HZ17: crate::Point> = crate::Point::new(34, 1, true); + pub const TMS18: crate::Point> = crate::Point::new(35, 1, true); + pub const HZ18: crate::Point> = crate::Point::new(36, 1, true); + pub const TMS19: crate::Point> = crate::Point::new(37, 1, true); + pub const HZ19: crate::Point> = crate::Point::new(38, 1, true); + pub const TMS20: crate::Point> = crate::Point::new(39, 1, true); + pub const HZ20: crate::Point> = crate::Point::new(40, 1, true); + pub const CRV_NAM: crate::Point> = crate::Point::new(41, 8, true); + pub const READ_ONLY: crate::Point = crate::Point::new(49, 1, false); +} +impl crate::Group for Curve { + const LEN: u16 = 50; +} +impl Curve { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + tms1: Self::TMS1.from_data(data)?, + hz1: Self::HZ1.from_data(data)?, + tms2: Self::TMS2.from_data(data)?, + hz2: Self::HZ2.from_data(data)?, + tms3: Self::TMS3.from_data(data)?, + hz3: Self::HZ3.from_data(data)?, + tms4: Self::TMS4.from_data(data)?, + hz4: Self::HZ4.from_data(data)?, + tms5: Self::TMS5.from_data(data)?, + hz5: Self::HZ5.from_data(data)?, + tms6: Self::TMS6.from_data(data)?, + hz6: Self::HZ6.from_data(data)?, + tms7: Self::TMS7.from_data(data)?, + hz7: Self::HZ7.from_data(data)?, + tms8: Self::TMS8.from_data(data)?, + hz8: Self::HZ8.from_data(data)?, + tms9: Self::TMS9.from_data(data)?, + hz9: Self::HZ9.from_data(data)?, + tms10: Self::TMS10.from_data(data)?, + hz10: Self::HZ10.from_data(data)?, + tms11: Self::TMS11.from_data(data)?, + hz11: Self::HZ11.from_data(data)?, + tms12: Self::TMS12.from_data(data)?, + hz12: Self::HZ12.from_data(data)?, + tms13: Self::TMS13.from_data(data)?, + hz13: Self::HZ13.from_data(data)?, + tms14: Self::TMS14.from_data(data)?, + hz14: Self::HZ14.from_data(data)?, + tms15: Self::TMS15.from_data(data)?, + hz15: Self::HZ15.from_data(data)?, + tms16: Self::TMS16.from_data(data)?, + hz16: Self::HZ16.from_data(data)?, + tms17: Self::TMS17.from_data(data)?, + hz17: Self::HZ17.from_data(data)?, + tms18: Self::TMS18.from_data(data)?, + hz18: Self::HZ18.from_data(data)?, + tms19: Self::TMS19.from_data(data)?, + hz19: Self::HZ19.from_data(data)?, + tms20: Self::TMS20.from_data(data)?, + hz20: Self::HZ20.from_data(data)?, + crv_nam: Self::CRV_NAM.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Hfrtx, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Hfrtx, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Curve::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// ReadOnly +/// +/// Enumerated value indicates if curve is read-only or can be modified. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CurveReadOnly { + #[allow(missing_docs)] + Readwrite = 0, + #[allow(missing_docs)] + Readonly = 1, +} +impl crate::Value for CurveReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CurveReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for Hfrtx { + const ID: u16 = 144; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m144 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model145.rs b/src/models/model145.rs index 651a947..f397ae0 100644 --- a/src/models/model145.rs +++ b/src/models/model145.rs @@ -1,10 +1,11 @@ //! Extended Settings +pub type Model145 = ExtSettings; /// Extended Settings /// /// Inverter controls extended settings #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model145 { +pub struct ExtSettings { /// Ramp Up Rate /// /// Ramp up rate as a percentage of max current. @@ -39,7 +40,7 @@ pub struct Model145 { pub rmp_sf: Option, } #[allow(missing_docs)] -impl Model145 { +impl ExtSettings { pub const NOM_RMP_UP_RTE: crate::Point> = crate::Point::new(0, 1, true); pub const NOM_RMP_DN_RTE: crate::Point> = crate::Point::new(1, 1, true); pub const EMG_RMP_UP_RTE: crate::Point> = crate::Point::new(2, 1, true); @@ -49,21 +50,38 @@ impl Model145 { pub const A_GRA: crate::Point> = crate::Point::new(6, 1, true); pub const RMP_SF: crate::Point> = crate::Point::new(7, 1, false); } -impl crate::Model for Model145 { - const ID: u16 = 145; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - nom_rmp_up_rte: Self::NOM_RMP_UP_RTE.from_data(data)?, - nom_rmp_dn_rte: Self::NOM_RMP_DN_RTE.from_data(data)?, - emg_rmp_up_rte: Self::EMG_RMP_UP_RTE.from_data(data)?, - emg_rmp_dn_rte: Self::EMG_RMP_DN_RTE.from_data(data)?, - conn_rmp_up_rte: Self::CONN_RMP_UP_RTE.from_data(data)?, - conn_rmp_dn_rte: Self::CONN_RMP_DN_RTE.from_data(data)?, - a_gra: Self::A_GRA.from_data(data)?, - rmp_sf: Self::RMP_SF.from_data(data)?, - }) +impl crate::Group for ExtSettings { + const LEN: u16 = 8; +} +impl ExtSettings { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + nom_rmp_up_rte: Self::NOM_RMP_UP_RTE.from_data(data)?, + nom_rmp_dn_rte: Self::NOM_RMP_DN_RTE.from_data(data)?, + emg_rmp_up_rte: Self::EMG_RMP_UP_RTE.from_data(data)?, + emg_rmp_dn_rte: Self::EMG_RMP_DN_RTE.from_data(data)?, + conn_rmp_up_rte: Self::CONN_RMP_UP_RTE.from_data(data)?, + conn_rmp_dn_rte: Self::CONN_RMP_DN_RTE.from_data(data)?, + a_gra: Self::A_GRA.from_data(data)?, + rmp_sf: Self::RMP_SF.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } +} +impl crate::Model for ExtSettings { + const ID: u16 = 145; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m145 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model15.rs b/src/models/model15.rs index 3204c58..92bde6f 100644 --- a/src/models/model15.rs +++ b/src/models/model15.rs @@ -69,25 +69,42 @@ impl Model15 { pub const OUT_DSC_CNT: crate::Point> = crate::Point::new(19, 2, false); pub const OUT_ERR_CNT: crate::Point> = crate::Point::new(21, 2, false); } +impl crate::Group for Model15 { + const LEN: u16 = 24; +} +impl Model15 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + clr: Self::CLR.from_data(data)?, + in_cnt: Self::IN_CNT.from_data(data)?, + in_uc_cnt: Self::IN_UC_CNT.from_data(data)?, + in_n_uc_cnt: Self::IN_N_UC_CNT.from_data(data)?, + in_dsc_cnt: Self::IN_DSC_CNT.from_data(data)?, + in_err_cnt: Self::IN_ERR_CNT.from_data(data)?, + in_unk_cnt: Self::IN_UNK_CNT.from_data(data)?, + out_cnt: Self::OUT_CNT.from_data(data)?, + out_uc_cnt: Self::OUT_UC_CNT.from_data(data)?, + out_n_uc_cnt: Self::OUT_N_UC_CNT.from_data(data)?, + out_dsc_cnt: Self::OUT_DSC_CNT.from_data(data)?, + out_err_cnt: Self::OUT_ERR_CNT.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } +} impl crate::Model for Model15 { const ID: u16 = 15; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - clr: Self::CLR.from_data(data)?, - in_cnt: Self::IN_CNT.from_data(data)?, - in_uc_cnt: Self::IN_UC_CNT.from_data(data)?, - in_n_uc_cnt: Self::IN_N_UC_CNT.from_data(data)?, - in_dsc_cnt: Self::IN_DSC_CNT.from_data(data)?, - in_err_cnt: Self::IN_ERR_CNT.from_data(data)?, - in_unk_cnt: Self::IN_UNK_CNT.from_data(data)?, - out_cnt: Self::OUT_CNT.from_data(data)?, - out_uc_cnt: Self::OUT_UC_CNT.from_data(data)?, - out_n_uc_cnt: Self::OUT_N_UC_CNT.from_data(data)?, - out_dsc_cnt: Self::OUT_DSC_CNT.from_data(data)?, - out_err_cnt: Self::OUT_ERR_CNT.from_data(data)?, - }) - } fn addr(models: &crate::Models) -> crate::ModelAddr { models.m15 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model16.rs b/src/models/model16.rs index 1afe068..bbee6c9 100644 --- a/src/models/model16.rs +++ b/src/models/model16.rs @@ -59,24 +59,31 @@ impl Model16 { pub const MAC: crate::Point> = crate::Point::new(46, 4, false); pub const LNK_CTL: crate::Point> = crate::Point::new(50, 1, true); } -impl crate::Model for Model16 { - const ID: u16 = 16; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - nam: Self::NAM.from_data(data)?, - cfg: Self::CFG.from_data(data)?, - ctl: Self::CTL.from_data(data)?, - addr: Self::ADDR.from_data(data)?, - msk: Self::MSK.from_data(data)?, - gw: Self::GW.from_data(data)?, - dns1: Self::DNS1.from_data(data)?, - dns2: Self::DNS2.from_data(data)?, - mac: Self::MAC.from_data(data)?, - lnk_ctl: Self::LNK_CTL.from_data(data)?, - }) +impl crate::Group for Model16 { + const LEN: u16 = 52; +} +impl Model16 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + nam: Self::NAM.from_data(data)?, + cfg: Self::CFG.from_data(data)?, + ctl: Self::CTL.from_data(data)?, + addr: Self::ADDR.from_data(data)?, + msk: Self::MSK.from_data(data)?, + gw: Self::GW.from_data(data)?, + dns1: Self::DNS1.from_data(data)?, + dns2: Self::DNS2.from_data(data)?, + mac: Self::MAC.from_data(data)?, + lnk_ctl: Self::LNK_CTL.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m16 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Config @@ -186,3 +193,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Model16 { + const ID: u16 = 16; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m16 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model160.rs b/src/models/model160.rs index 3476790..fa289fa 100644 --- a/src/models/model160.rs +++ b/src/models/model160.rs @@ -1,8 +1,9 @@ //! Multiple MPPT Inverter Extension Model +pub type Model160 = Mppt; /// Multiple MPPT Inverter Extension Model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model160 { +pub struct Mppt { /// Current Scale Factor pub dca_sf: Option, /// Voltage Scale Factor @@ -17,9 +18,11 @@ pub struct Model160 { pub n: Option, /// Timestamp Period pub tms_per: Option, + #[allow(missing_docs)] + pub module: Vec, } #[allow(missing_docs)] -impl Model160 { +impl Mppt { pub const DCA_SF: crate::Point> = crate::Point::new(0, 1, false); pub const DCV_SF: crate::Point> = crate::Point::new(1, 1, false); pub const DCW_SF: crate::Point> = crate::Point::new(2, 1, false); @@ -28,21 +31,30 @@ impl Model160 { pub const N: crate::Point> = crate::Point::new(6, 1, false); pub const TMS_PER: crate::Point> = crate::Point::new(7, 1, false); } -impl crate::Model for Model160 { - const ID: u16 = 160; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - dca_sf: Self::DCA_SF.from_data(data)?, - dcv_sf: Self::DCV_SF.from_data(data)?, - dcw_sf: Self::DCW_SF.from_data(data)?, - dcwh_sf: Self::DCWH_SF.from_data(data)?, - evt: Self::EVT.from_data(data)?, - n: Self::N.from_data(data)?, - tms_per: Self::TMS_PER.from_data(data)?, - }) +impl crate::Group for Mppt { + const LEN: u16 = 8; +} +impl Mppt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + dca_sf: Self::DCA_SF.from_data(data)?, + dcv_sf: Self::DCV_SF.from_data(data)?, + dcw_sf: Self::DCW_SF.from_data(data)?, + dcwh_sf: Self::DCWH_SF.from_data(data)?, + evt: Self::EVT.from_data(data)?, + n: Self::N.from_data(data)?, + tms_per: Self::TMS_PER.from_data(data)?, + module: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m160 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.module) = Module::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -91,3 +103,193 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Module { + /// Input ID + pub id: Option, + /// Input ID String + pub id_str: Option, + /// DC Current + pub dca: Option, + /// DC Voltage + pub dcv: Option, + /// DC Power + pub dcw: Option, + /// Lifetime Energy + pub dcwh: Option, + /// Timestamp + pub tms: Option, + /// Temperature + pub tmp: Option, + /// Operating State + pub dc_st: Option, + /// Module Events + pub dc_evt: Option, +} +#[allow(missing_docs)] +impl Module { + pub const ID: crate::Point> = crate::Point::new(0, 1, false); + pub const ID_STR: crate::Point> = crate::Point::new(1, 8, false); + pub const DCA: crate::Point> = crate::Point::new(9, 1, false); + pub const DCV: crate::Point> = crate::Point::new(10, 1, false); + pub const DCW: crate::Point> = crate::Point::new(11, 1, false); + pub const DCWH: crate::Point> = crate::Point::new(12, 2, false); + pub const TMS: crate::Point> = crate::Point::new(14, 2, false); + pub const TMP: crate::Point> = crate::Point::new(16, 1, false); + pub const DC_ST: crate::Point> = crate::Point::new(17, 1, false); + pub const DC_EVT: crate::Point> = crate::Point::new(18, 2, false); +} +impl crate::Group for Module { + const LEN: u16 = 20; +} +impl Module { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + id: Self::ID.from_data(data)?, + id_str: Self::ID_STR.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + dcw: Self::DCW.from_data(data)?, + dcwh: Self::DCWH.from_data(data)?, + tms: Self::TMS.from_data(data)?, + tmp: Self::TMP.from_data(data)?, + dc_st: Self::DC_ST.from_data(data)?, + dc_evt: Self::DC_EVT.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Mppt, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Mppt, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Module::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Operating State +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum ModuleDcSt { + #[allow(missing_docs)] + Off = 1, + #[allow(missing_docs)] + Sleeping = 2, + #[allow(missing_docs)] + Starting = 3, + #[allow(missing_docs)] + Mppt = 4, + #[allow(missing_docs)] + Throttled = 5, + #[allow(missing_docs)] + ShuttingDown = 6, + #[allow(missing_docs)] + Fault = 7, + #[allow(missing_docs)] + Standby = 8, + #[allow(missing_docs)] + Test = 9, + #[allow(missing_docs)] + Reserved10 = 10, +} +impl crate::Value for ModuleDcSt { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + ModuleDcSt::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Module Events"] #[derive(Copy, Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub + struct ModuleDcEvt : u32 { #[allow(missing_docs)] const GroundFault = 1; + #[allow(missing_docs)] const InputOverVoltage = 2; #[allow(missing_docs)] const + Reserved2 = 4; #[allow(missing_docs)] const DcDisconnect = 8; #[allow(missing_docs)] + const Reserved4 = 16; #[allow(missing_docs)] const CabinetOpen = 32; + #[allow(missing_docs)] const ManualShutdown = 64; #[allow(missing_docs)] const + OverTemp = 128; #[allow(missing_docs)] const Reserved8 = 256; #[allow(missing_docs)] + const Reserved9 = 512; #[allow(missing_docs)] const Reserved10 = 1024; + #[allow(missing_docs)] const Reserved11 = 2048; #[allow(missing_docs)] const + BlownFuse = 4096; #[allow(missing_docs)] const UnderTemp = 8192; + #[allow(missing_docs)] const MemoryLoss = 16384; #[allow(missing_docs)] const + ArcDetection = 32768; #[allow(missing_docs)] const Reserved16 = 65536; + #[allow(missing_docs)] const Reserved17 = 131072; #[allow(missing_docs)] const + Reserved18 = 262144; #[allow(missing_docs)] const Reserved19 = 524288; + #[allow(missing_docs)] const TestFailed = 1048576; #[allow(missing_docs)] const + InputUnderVoltage = 2097152; #[allow(missing_docs)] const InputOverCurrent = 4194304; + } +} +impl crate::Value for ModuleDcEvt { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(ModuleDcEvt::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +impl crate::Model for Mppt { + const ID: u16 = 160; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m160 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model17.rs b/src/models/model17.rs index edac726..a5517af 100644 --- a/src/models/model17.rs +++ b/src/models/model17.rs @@ -49,22 +49,29 @@ impl Model17 { pub const TYP: crate::Point> = crate::Point::new(10, 1, false); pub const PCOL: crate::Point> = crate::Point::new(11, 1, false); } -impl crate::Model for Model17 { - const ID: u16 = 17; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - nam: Self::NAM.from_data(data)?, - rte: Self::RTE.from_data(data)?, - bits: Self::BITS.from_data(data)?, - pty: Self::PTY.from_data(data)?, - dup: Self::DUP.from_data(data)?, - flw: Self::FLW.from_data(data)?, - typ: Self::TYP.from_data(data)?, - pcol: Self::PCOL.from_data(data)?, - }) +impl crate::Group for Model17 { + const LEN: u16 = 12; +} +impl Model17 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + nam: Self::NAM.from_data(data)?, + rte: Self::RTE.from_data(data)?, + bits: Self::BITS.from_data(data)?, + pty: Self::PTY.from_data(data)?, + dup: Self::DUP.from_data(data)?, + flw: Self::FLW.from_data(data)?, + typ: Self::TYP.from_data(data)?, + pcol: Self::PCOL.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m17 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Parity @@ -275,3 +282,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Model17 { + const ID: u16 = 17; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m17 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model18.rs b/src/models/model18.rs index b5f910b..76bc40e 100644 --- a/src/models/model18.rs +++ b/src/models/model18.rs @@ -34,18 +34,35 @@ impl Model18 { pub const NUM: crate::Point> = crate::Point::new(10, 6, true); pub const PIN: crate::Point> = crate::Point::new(16, 6, true); } +impl crate::Group for Model18 { + const LEN: u16 = 22; +} +impl Model18 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + nam: Self::NAM.from_data(data)?, + imei: Self::IMEI.from_data(data)?, + apn: Self::APN.from_data(data)?, + num: Self::NUM.from_data(data)?, + pin: Self::PIN.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } +} impl crate::Model for Model18 { const ID: u16 = 18; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - nam: Self::NAM.from_data(data)?, - imei: Self::IMEI.from_data(data)?, - apn: Self::APN.from_data(data)?, - num: Self::NUM.from_data(data)?, - pin: Self::PIN.from_data(data)?, - }) - } fn addr(models: &crate::Models) -> crate::ModelAddr { models.m18 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model19.rs b/src/models/model19.rs index 9b86bcf..f0e2e2d 100644 --- a/src/models/model19.rs +++ b/src/models/model19.rs @@ -54,23 +54,30 @@ impl Model19 { pub const USR_NAM: crate::Point> = crate::Point::new(11, 12, false); pub const PW: crate::Point> = crate::Point::new(23, 6, false); } -impl crate::Model for Model19 { - const ID: u16 = 19; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - nam: Self::NAM.from_data(data)?, - rte: Self::RTE.from_data(data)?, - bits: Self::BITS.from_data(data)?, - pty: Self::PTY.from_data(data)?, - dup: Self::DUP.from_data(data)?, - flw: Self::FLW.from_data(data)?, - auth: Self::AUTH.from_data(data)?, - usr_nam: Self::USR_NAM.from_data(data)?, - pw: Self::PW.from_data(data)?, - }) +impl crate::Group for Model19 { + const LEN: u16 = 30; +} +impl Model19 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + nam: Self::NAM.from_data(data)?, + rte: Self::RTE.from_data(data)?, + bits: Self::BITS.from_data(data)?, + pty: Self::PTY.from_data(data)?, + dup: Self::DUP.from_data(data)?, + flw: Self::FLW.from_data(data)?, + auth: Self::AUTH.from_data(data)?, + usr_nam: Self::USR_NAM.from_data(data)?, + pw: Self::PW.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m19 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Parity @@ -239,3 +246,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Model19 { + const ID: u16 = 19; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m19 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model2.rs b/src/models/model2.rs index 3106dea..153ce79 100644 --- a/src/models/model2.rs +++ b/src/models/model2.rs @@ -1,10 +1,11 @@ //! Basic Aggregator +pub type Model2 = Aggregator; /// Basic Aggregator /// /// Aggregates a collection of models for a given model id #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model2 { +pub struct Aggregator { /// AID /// /// Aggregated model id @@ -47,7 +48,7 @@ pub struct Model2 { pub ctl_vl: Option, } #[allow(missing_docs)] -impl Model2 { +impl Aggregator { pub const AID: crate::Point = crate::Point::new(0, 1, false); pub const N: crate::Point = crate::Point::new(1, 1, false); pub const UN: crate::Point = crate::Point::new(2, 1, false); @@ -59,24 +60,31 @@ impl Model2 { pub const CTL_VND: crate::Point> = crate::Point::new(10, 2, false); pub const CTL_VL: crate::Point> = crate::Point::new(12, 2, false); } -impl crate::Model for Model2 { - const ID: u16 = 2; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - aid: Self::AID.from_data(data)?, - n: Self::N.from_data(data)?, - un: Self::UN.from_data(data)?, - st: Self::ST.from_data(data)?, - st_vnd: Self::ST_VND.from_data(data)?, - evt: Self::EVT.from_data(data)?, - evt_vnd: Self::EVT_VND.from_data(data)?, - ctl: Self::CTL.from_data(data)?, - ctl_vnd: Self::CTL_VND.from_data(data)?, - ctl_vl: Self::CTL_VL.from_data(data)?, - }) +impl crate::Group for Aggregator { + const LEN: u16 = 14; +} +impl Aggregator { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + aid: Self::AID.from_data(data)?, + n: Self::N.from_data(data)?, + un: Self::UN.from_data(data)?, + st: Self::ST.from_data(data)?, + st_vnd: Self::ST_VND.from_data(data)?, + evt: Self::EVT.from_data(data)?, + evt_vnd: Self::EVT_VND.from_data(data)?, + ctl: Self::CTL.from_data(data)?, + ctl_vnd: Self::CTL_VND.from_data(data)?, + ctl_vl: Self::CTL_VL.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m2 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Status @@ -245,3 +253,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Aggregator { + const ID: u16 = 2; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m2 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model201.rs b/src/models/model201.rs index 7a7f477..cf420de 100644 --- a/src/models/model201.rs +++ b/src/models/model201.rs @@ -1,10 +1,11 @@ //! Meter (Single Phase) single phase (AN or AB) meter +pub type Model201 = AcMeterAnOrAb; /// Meter (Single Phase) single phase (AN or AB) meter /// /// Include this model for single phase (AN or AB) metering #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model201 { +pub struct AcMeterAnOrAb { /// Amps /// /// Total AC Current @@ -209,7 +210,7 @@ pub struct Model201 { pub evt: Evt, } #[allow(missing_docs)] -impl Model201 { +impl AcMeterAnOrAb { pub const A: crate::Point = crate::Point::new(0, 1, false); pub const APH_A: crate::Point = crate::Point::new(1, 1, false); pub const APH_B: crate::Point> = crate::Point::new(2, 1, false); @@ -295,86 +296,93 @@ impl Model201 { pub const TOT_V_ARH_SF: crate::Point> = crate::Point::new(102, 1, false); pub const EVT: crate::Point = crate::Point::new(103, 2, false); } -impl crate::Model for Model201 { - const ID: u16 = 201; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - ph_v: Self::PH_V.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - ppv: Self::PPV.from_data(data)?, - pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, - pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, - pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - hz: Self::HZ.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - w: Self::W.from_data(data)?, - wph_a: Self::WPH_A.from_data(data)?, - wph_b: Self::WPH_B.from_data(data)?, - wph_c: Self::WPH_C.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - va: Self::VA.from_data(data)?, - v_aph_a: Self::V_APH_A.from_data(data)?, - v_aph_b: Self::V_APH_B.from_data(data)?, - v_aph_c: Self::V_APH_C.from_data(data)?, - va_sf: Self::VA_SF.from_data(data)?, - var: Self::VAR.from_data(data)?, - va_rph_a: Self::VA_RPH_A.from_data(data)?, - va_rph_b: Self::VA_RPH_B.from_data(data)?, - va_rph_c: Self::VA_RPH_C.from_data(data)?, - var_sf: Self::VAR_SF.from_data(data)?, - pf: Self::PF.from_data(data)?, - p_fph_a: Self::P_FPH_A.from_data(data)?, - p_fph_b: Self::P_FPH_B.from_data(data)?, - p_fph_c: Self::P_FPH_C.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, - tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, - tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, - tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, - tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, - tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, - tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, - tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, - tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, - tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, - tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, - tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, - tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, - tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, - tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, - tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, - tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, - tot_v_ah_sf: Self::TOT_V_AH_SF.from_data(data)?, - tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, - tot_v_arh_imp_q1_ph_a: Self::TOT_V_ARH_IMP_Q1_PH_A.from_data(data)?, - tot_v_arh_imp_q1_ph_b: Self::TOT_V_ARH_IMP_Q1_PH_B.from_data(data)?, - tot_v_arh_imp_q1_ph_c: Self::TOT_V_ARH_IMP_Q1_PH_C.from_data(data)?, - tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, - tot_v_arh_imp_q2_ph_a: Self::TOT_V_ARH_IMP_Q2_PH_A.from_data(data)?, - tot_v_arh_imp_q2_ph_b: Self::TOT_V_ARH_IMP_Q2_PH_B.from_data(data)?, - tot_v_arh_imp_q2_ph_c: Self::TOT_V_ARH_IMP_Q2_PH_C.from_data(data)?, - tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, - tot_v_arh_exp_q3_ph_a: Self::TOT_V_ARH_EXP_Q3_PH_A.from_data(data)?, - tot_v_arh_exp_q3_ph_b: Self::TOT_V_ARH_EXP_Q3_PH_B.from_data(data)?, - tot_v_arh_exp_q3_ph_c: Self::TOT_V_ARH_EXP_Q3_PH_C.from_data(data)?, - tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, - tot_v_arh_exp_q4_ph_a: Self::TOT_V_ARH_EXP_Q4_PH_A.from_data(data)?, - tot_v_arh_exp_q4_ph_b: Self::TOT_V_ARH_EXP_Q4_PH_B.from_data(data)?, - tot_v_arh_exp_q4_ph_c: Self::TOT_V_ARH_EXP_Q4_PH_C.from_data(data)?, - tot_v_arh_sf: Self::TOT_V_ARH_SF.from_data(data)?, - evt: Self::EVT.from_data(data)?, - }) +impl crate::Group for AcMeterAnOrAb { + const LEN: u16 = 105; +} +impl AcMeterAnOrAb { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + ph_v: Self::PH_V.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + ppv: Self::PPV.from_data(data)?, + pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, + pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, + pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + hz: Self::HZ.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + w: Self::W.from_data(data)?, + wph_a: Self::WPH_A.from_data(data)?, + wph_b: Self::WPH_B.from_data(data)?, + wph_c: Self::WPH_C.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + va: Self::VA.from_data(data)?, + v_aph_a: Self::V_APH_A.from_data(data)?, + v_aph_b: Self::V_APH_B.from_data(data)?, + v_aph_c: Self::V_APH_C.from_data(data)?, + va_sf: Self::VA_SF.from_data(data)?, + var: Self::VAR.from_data(data)?, + va_rph_a: Self::VA_RPH_A.from_data(data)?, + va_rph_b: Self::VA_RPH_B.from_data(data)?, + va_rph_c: Self::VA_RPH_C.from_data(data)?, + var_sf: Self::VAR_SF.from_data(data)?, + pf: Self::PF.from_data(data)?, + p_fph_a: Self::P_FPH_A.from_data(data)?, + p_fph_b: Self::P_FPH_B.from_data(data)?, + p_fph_c: Self::P_FPH_C.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, + tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, + tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, + tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, + tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, + tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, + tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, + tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, + tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, + tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, + tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, + tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, + tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, + tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, + tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, + tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, + tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, + tot_v_ah_sf: Self::TOT_V_AH_SF.from_data(data)?, + tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, + tot_v_arh_imp_q1_ph_a: Self::TOT_V_ARH_IMP_Q1_PH_A.from_data(data)?, + tot_v_arh_imp_q1_ph_b: Self::TOT_V_ARH_IMP_Q1_PH_B.from_data(data)?, + tot_v_arh_imp_q1_ph_c: Self::TOT_V_ARH_IMP_Q1_PH_C.from_data(data)?, + tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, + tot_v_arh_imp_q2_ph_a: Self::TOT_V_ARH_IMP_Q2_PH_A.from_data(data)?, + tot_v_arh_imp_q2_ph_b: Self::TOT_V_ARH_IMP_Q2_PH_B.from_data(data)?, + tot_v_arh_imp_q2_ph_c: Self::TOT_V_ARH_IMP_Q2_PH_C.from_data(data)?, + tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, + tot_v_arh_exp_q3_ph_a: Self::TOT_V_ARH_EXP_Q3_PH_A.from_data(data)?, + tot_v_arh_exp_q3_ph_b: Self::TOT_V_ARH_EXP_Q3_PH_B.from_data(data)?, + tot_v_arh_exp_q3_ph_c: Self::TOT_V_ARH_EXP_Q3_PH_C.from_data(data)?, + tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, + tot_v_arh_exp_q4_ph_a: Self::TOT_V_ARH_EXP_Q4_PH_A.from_data(data)?, + tot_v_arh_exp_q4_ph_b: Self::TOT_V_ARH_EXP_Q4_PH_B.from_data(data)?, + tot_v_arh_exp_q4_ph_c: Self::TOT_V_ARH_EXP_Q4_PH_C.from_data(data)?, + tot_v_arh_sf: Self::TOT_V_ARH_SF.from_data(data)?, + evt: Self::EVT.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m201 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -421,3 +429,13 @@ impl crate::Value for Option { } } } +impl crate::Model for AcMeterAnOrAb { + const ID: u16 = 201; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m201 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model202.rs b/src/models/model202.rs index b43fa83..863c6e6 100644 --- a/src/models/model202.rs +++ b/src/models/model202.rs @@ -1,8 +1,9 @@ //! split single phase (ABN) meter +pub type Model202 = AcMeterAbn; /// split single phase (ABN) meter #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model202 { +pub struct AcMeterAbn { /// Amps /// /// Total AC Current @@ -201,7 +202,7 @@ pub struct Model202 { pub evt: Evt, } #[allow(missing_docs)] -impl Model202 { +impl AcMeterAbn { pub const A: crate::Point = crate::Point::new(0, 1, false); pub const APH_A: crate::Point> = crate::Point::new(1, 1, false); pub const APH_B: crate::Point = crate::Point::new(2, 1, false); @@ -287,86 +288,93 @@ impl Model202 { pub const TOT_V_ARH_SF: crate::Point> = crate::Point::new(102, 1, false); pub const EVT: crate::Point = crate::Point::new(103, 2, false); } -impl crate::Model for Model202 { - const ID: u16 = 202; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - ph_v: Self::PH_V.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - ppv: Self::PPV.from_data(data)?, - ph_vph_ab: Self::PH_VPH_AB.from_data(data)?, - ph_vph_bc: Self::PH_VPH_BC.from_data(data)?, - ph_vph_ca: Self::PH_VPH_CA.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - hz: Self::HZ.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - w: Self::W.from_data(data)?, - wph_a: Self::WPH_A.from_data(data)?, - wph_b: Self::WPH_B.from_data(data)?, - wph_c: Self::WPH_C.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - va: Self::VA.from_data(data)?, - v_aph_a: Self::V_APH_A.from_data(data)?, - v_aph_b: Self::V_APH_B.from_data(data)?, - v_aph_c: Self::V_APH_C.from_data(data)?, - va_sf: Self::VA_SF.from_data(data)?, - var: Self::VAR.from_data(data)?, - va_rph_a: Self::VA_RPH_A.from_data(data)?, - va_rph_b: Self::VA_RPH_B.from_data(data)?, - va_rph_c: Self::VA_RPH_C.from_data(data)?, - var_sf: Self::VAR_SF.from_data(data)?, - pf: Self::PF.from_data(data)?, - p_fph_a: Self::P_FPH_A.from_data(data)?, - p_fph_b: Self::P_FPH_B.from_data(data)?, - p_fph_c: Self::P_FPH_C.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, - tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, - tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, - tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, - tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, - tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, - tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, - tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, - tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, - tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, - tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, - tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, - tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, - tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, - tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, - tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, - tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, - tot_v_ah_sf: Self::TOT_V_AH_SF.from_data(data)?, - tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, - tot_v_arh_imp_q1_ph_a: Self::TOT_V_ARH_IMP_Q1_PH_A.from_data(data)?, - tot_v_arh_imp_q1_ph_b: Self::TOT_V_ARH_IMP_Q1_PH_B.from_data(data)?, - tot_v_arh_imp_q1_ph_c: Self::TOT_V_ARH_IMP_Q1_PH_C.from_data(data)?, - tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, - tot_v_arh_imp_q2_ph_a: Self::TOT_V_ARH_IMP_Q2_PH_A.from_data(data)?, - tot_v_arh_imp_q2_ph_b: Self::TOT_V_ARH_IMP_Q2_PH_B.from_data(data)?, - tot_v_arh_imp_q2_ph_c: Self::TOT_V_ARH_IMP_Q2_PH_C.from_data(data)?, - tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, - tot_v_arh_exp_q3_ph_a: Self::TOT_V_ARH_EXP_Q3_PH_A.from_data(data)?, - tot_v_arh_exp_q3_ph_b: Self::TOT_V_ARH_EXP_Q3_PH_B.from_data(data)?, - tot_v_arh_exp_q3_ph_c: Self::TOT_V_ARH_EXP_Q3_PH_C.from_data(data)?, - tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, - tot_v_arh_exp_q4_ph_a: Self::TOT_V_ARH_EXP_Q4_PH_A.from_data(data)?, - tot_v_arh_exp_q4_ph_b: Self::TOT_V_ARH_EXP_Q4_PH_B.from_data(data)?, - tot_v_arh_exp_q4_ph_c: Self::TOT_V_ARH_EXP_Q4_PH_C.from_data(data)?, - tot_v_arh_sf: Self::TOT_V_ARH_SF.from_data(data)?, - evt: Self::EVT.from_data(data)?, - }) +impl crate::Group for AcMeterAbn { + const LEN: u16 = 105; +} +impl AcMeterAbn { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + ph_v: Self::PH_V.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + ppv: Self::PPV.from_data(data)?, + ph_vph_ab: Self::PH_VPH_AB.from_data(data)?, + ph_vph_bc: Self::PH_VPH_BC.from_data(data)?, + ph_vph_ca: Self::PH_VPH_CA.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + hz: Self::HZ.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + w: Self::W.from_data(data)?, + wph_a: Self::WPH_A.from_data(data)?, + wph_b: Self::WPH_B.from_data(data)?, + wph_c: Self::WPH_C.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + va: Self::VA.from_data(data)?, + v_aph_a: Self::V_APH_A.from_data(data)?, + v_aph_b: Self::V_APH_B.from_data(data)?, + v_aph_c: Self::V_APH_C.from_data(data)?, + va_sf: Self::VA_SF.from_data(data)?, + var: Self::VAR.from_data(data)?, + va_rph_a: Self::VA_RPH_A.from_data(data)?, + va_rph_b: Self::VA_RPH_B.from_data(data)?, + va_rph_c: Self::VA_RPH_C.from_data(data)?, + var_sf: Self::VAR_SF.from_data(data)?, + pf: Self::PF.from_data(data)?, + p_fph_a: Self::P_FPH_A.from_data(data)?, + p_fph_b: Self::P_FPH_B.from_data(data)?, + p_fph_c: Self::P_FPH_C.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, + tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, + tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, + tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, + tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, + tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, + tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, + tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, + tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, + tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, + tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, + tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, + tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, + tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, + tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, + tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, + tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, + tot_v_ah_sf: Self::TOT_V_AH_SF.from_data(data)?, + tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, + tot_v_arh_imp_q1_ph_a: Self::TOT_V_ARH_IMP_Q1_PH_A.from_data(data)?, + tot_v_arh_imp_q1_ph_b: Self::TOT_V_ARH_IMP_Q1_PH_B.from_data(data)?, + tot_v_arh_imp_q1_ph_c: Self::TOT_V_ARH_IMP_Q1_PH_C.from_data(data)?, + tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, + tot_v_arh_imp_q2_ph_a: Self::TOT_V_ARH_IMP_Q2_PH_A.from_data(data)?, + tot_v_arh_imp_q2_ph_b: Self::TOT_V_ARH_IMP_Q2_PH_B.from_data(data)?, + tot_v_arh_imp_q2_ph_c: Self::TOT_V_ARH_IMP_Q2_PH_C.from_data(data)?, + tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, + tot_v_arh_exp_q3_ph_a: Self::TOT_V_ARH_EXP_Q3_PH_A.from_data(data)?, + tot_v_arh_exp_q3_ph_b: Self::TOT_V_ARH_EXP_Q3_PH_B.from_data(data)?, + tot_v_arh_exp_q3_ph_c: Self::TOT_V_ARH_EXP_Q3_PH_C.from_data(data)?, + tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, + tot_v_arh_exp_q4_ph_a: Self::TOT_V_ARH_EXP_Q4_PH_A.from_data(data)?, + tot_v_arh_exp_q4_ph_b: Self::TOT_V_ARH_EXP_Q4_PH_B.from_data(data)?, + tot_v_arh_exp_q4_ph_c: Self::TOT_V_ARH_EXP_Q4_PH_C.from_data(data)?, + tot_v_arh_sf: Self::TOT_V_ARH_SF.from_data(data)?, + evt: Self::EVT.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m202 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -419,3 +427,13 @@ impl crate::Value for Option { } } } +impl crate::Model for AcMeterAbn { + const ID: u16 = 202; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m202 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model203.rs b/src/models/model203.rs index 8b9aa91..2512bbb 100644 --- a/src/models/model203.rs +++ b/src/models/model203.rs @@ -1,8 +1,9 @@ //! wye-connect three phase (abcn) meter +pub type Model203 = AcMeterAbcn; /// wye-connect three phase (abcn) meter #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model203 { +pub struct AcMeterAbcn { /// Amps /// /// Total AC Current @@ -201,7 +202,7 @@ pub struct Model203 { pub evt: Evt, } #[allow(missing_docs)] -impl Model203 { +impl AcMeterAbcn { pub const A: crate::Point = crate::Point::new(0, 1, false); pub const APH_A: crate::Point = crate::Point::new(1, 1, false); pub const APH_B: crate::Point = crate::Point::new(2, 1, false); @@ -287,86 +288,93 @@ impl Model203 { pub const TOT_V_ARH_SF: crate::Point> = crate::Point::new(102, 1, false); pub const EVT: crate::Point = crate::Point::new(103, 2, false); } -impl crate::Model for Model203 { - const ID: u16 = 203; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - ph_v: Self::PH_V.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - ppv: Self::PPV.from_data(data)?, - ph_vph_ab: Self::PH_VPH_AB.from_data(data)?, - ph_vph_bc: Self::PH_VPH_BC.from_data(data)?, - ph_vph_ca: Self::PH_VPH_CA.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - hz: Self::HZ.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - w: Self::W.from_data(data)?, - wph_a: Self::WPH_A.from_data(data)?, - wph_b: Self::WPH_B.from_data(data)?, - wph_c: Self::WPH_C.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - va: Self::VA.from_data(data)?, - v_aph_a: Self::V_APH_A.from_data(data)?, - v_aph_b: Self::V_APH_B.from_data(data)?, - v_aph_c: Self::V_APH_C.from_data(data)?, - va_sf: Self::VA_SF.from_data(data)?, - var: Self::VAR.from_data(data)?, - va_rph_a: Self::VA_RPH_A.from_data(data)?, - va_rph_b: Self::VA_RPH_B.from_data(data)?, - va_rph_c: Self::VA_RPH_C.from_data(data)?, - var_sf: Self::VAR_SF.from_data(data)?, - pf: Self::PF.from_data(data)?, - p_fph_a: Self::P_FPH_A.from_data(data)?, - p_fph_b: Self::P_FPH_B.from_data(data)?, - p_fph_c: Self::P_FPH_C.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, - tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, - tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, - tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, - tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, - tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, - tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, - tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, - tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, - tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, - tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, - tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, - tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, - tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, - tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, - tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, - tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, - tot_v_ah_sf: Self::TOT_V_AH_SF.from_data(data)?, - tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, - tot_v_arh_imp_q1_ph_a: Self::TOT_V_ARH_IMP_Q1_PH_A.from_data(data)?, - tot_v_arh_imp_q1_ph_b: Self::TOT_V_ARH_IMP_Q1_PH_B.from_data(data)?, - tot_v_arh_imp_q1_ph_c: Self::TOT_V_ARH_IMP_Q1_PH_C.from_data(data)?, - tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, - tot_v_arh_imp_q2_ph_a: Self::TOT_V_ARH_IMP_Q2_PH_A.from_data(data)?, - tot_v_arh_imp_q2_ph_b: Self::TOT_V_ARH_IMP_Q2_PH_B.from_data(data)?, - tot_v_arh_imp_q2_ph_c: Self::TOT_V_ARH_IMP_Q2_PH_C.from_data(data)?, - tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, - tot_v_arh_exp_q3_ph_a: Self::TOT_V_ARH_EXP_Q3_PH_A.from_data(data)?, - tot_v_arh_exp_q3_ph_b: Self::TOT_V_ARH_EXP_Q3_PH_B.from_data(data)?, - tot_v_arh_exp_q3_ph_c: Self::TOT_V_ARH_EXP_Q3_PH_C.from_data(data)?, - tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, - tot_v_arh_exp_q4_ph_a: Self::TOT_V_ARH_EXP_Q4_PH_A.from_data(data)?, - tot_v_arh_exp_q4_ph_b: Self::TOT_V_ARH_EXP_Q4_PH_B.from_data(data)?, - tot_v_arh_exp_q4_ph_c: Self::TOT_V_ARH_EXP_Q4_PH_C.from_data(data)?, - tot_v_arh_sf: Self::TOT_V_ARH_SF.from_data(data)?, - evt: Self::EVT.from_data(data)?, - }) +impl crate::Group for AcMeterAbcn { + const LEN: u16 = 105; +} +impl AcMeterAbcn { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + ph_v: Self::PH_V.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + ppv: Self::PPV.from_data(data)?, + ph_vph_ab: Self::PH_VPH_AB.from_data(data)?, + ph_vph_bc: Self::PH_VPH_BC.from_data(data)?, + ph_vph_ca: Self::PH_VPH_CA.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + hz: Self::HZ.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + w: Self::W.from_data(data)?, + wph_a: Self::WPH_A.from_data(data)?, + wph_b: Self::WPH_B.from_data(data)?, + wph_c: Self::WPH_C.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + va: Self::VA.from_data(data)?, + v_aph_a: Self::V_APH_A.from_data(data)?, + v_aph_b: Self::V_APH_B.from_data(data)?, + v_aph_c: Self::V_APH_C.from_data(data)?, + va_sf: Self::VA_SF.from_data(data)?, + var: Self::VAR.from_data(data)?, + va_rph_a: Self::VA_RPH_A.from_data(data)?, + va_rph_b: Self::VA_RPH_B.from_data(data)?, + va_rph_c: Self::VA_RPH_C.from_data(data)?, + var_sf: Self::VAR_SF.from_data(data)?, + pf: Self::PF.from_data(data)?, + p_fph_a: Self::P_FPH_A.from_data(data)?, + p_fph_b: Self::P_FPH_B.from_data(data)?, + p_fph_c: Self::P_FPH_C.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, + tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, + tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, + tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, + tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, + tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, + tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, + tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, + tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, + tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, + tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, + tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, + tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, + tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, + tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, + tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, + tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, + tot_v_ah_sf: Self::TOT_V_AH_SF.from_data(data)?, + tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, + tot_v_arh_imp_q1_ph_a: Self::TOT_V_ARH_IMP_Q1_PH_A.from_data(data)?, + tot_v_arh_imp_q1_ph_b: Self::TOT_V_ARH_IMP_Q1_PH_B.from_data(data)?, + tot_v_arh_imp_q1_ph_c: Self::TOT_V_ARH_IMP_Q1_PH_C.from_data(data)?, + tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, + tot_v_arh_imp_q2_ph_a: Self::TOT_V_ARH_IMP_Q2_PH_A.from_data(data)?, + tot_v_arh_imp_q2_ph_b: Self::TOT_V_ARH_IMP_Q2_PH_B.from_data(data)?, + tot_v_arh_imp_q2_ph_c: Self::TOT_V_ARH_IMP_Q2_PH_C.from_data(data)?, + tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, + tot_v_arh_exp_q3_ph_a: Self::TOT_V_ARH_EXP_Q3_PH_A.from_data(data)?, + tot_v_arh_exp_q3_ph_b: Self::TOT_V_ARH_EXP_Q3_PH_B.from_data(data)?, + tot_v_arh_exp_q3_ph_c: Self::TOT_V_ARH_EXP_Q3_PH_C.from_data(data)?, + tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, + tot_v_arh_exp_q4_ph_a: Self::TOT_V_ARH_EXP_Q4_PH_A.from_data(data)?, + tot_v_arh_exp_q4_ph_b: Self::TOT_V_ARH_EXP_Q4_PH_B.from_data(data)?, + tot_v_arh_exp_q4_ph_c: Self::TOT_V_ARH_EXP_Q4_PH_C.from_data(data)?, + tot_v_arh_sf: Self::TOT_V_ARH_SF.from_data(data)?, + evt: Self::EVT.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m203 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -419,3 +427,13 @@ impl crate::Value for Option { } } } +impl crate::Model for AcMeterAbcn { + const ID: u16 = 203; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m203 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model204.rs b/src/models/model204.rs index acc2724..20b7abb 100644 --- a/src/models/model204.rs +++ b/src/models/model204.rs @@ -1,8 +1,9 @@ //! delta-connect three phase (abc) meter +pub type Model204 = AcMeterAbc; /// delta-connect three phase (abc) meter #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model204 { +pub struct AcMeterAbc { /// Amps /// /// Total AC Current @@ -201,7 +202,7 @@ pub struct Model204 { pub evt: Evt, } #[allow(missing_docs)] -impl Model204 { +impl AcMeterAbc { pub const A: crate::Point = crate::Point::new(0, 1, false); pub const APH_A: crate::Point = crate::Point::new(1, 1, false); pub const APH_B: crate::Point = crate::Point::new(2, 1, false); @@ -287,86 +288,93 @@ impl Model204 { pub const TOT_V_ARH_SF: crate::Point> = crate::Point::new(102, 1, false); pub const EVT: crate::Point = crate::Point::new(103, 2, false); } -impl crate::Model for Model204 { - const ID: u16 = 204; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - ph_v: Self::PH_V.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - ppv: Self::PPV.from_data(data)?, - ph_vph_ab: Self::PH_VPH_AB.from_data(data)?, - ph_vph_bc: Self::PH_VPH_BC.from_data(data)?, - ph_vph_ca: Self::PH_VPH_CA.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - hz: Self::HZ.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - w: Self::W.from_data(data)?, - wph_a: Self::WPH_A.from_data(data)?, - wph_b: Self::WPH_B.from_data(data)?, - wph_c: Self::WPH_C.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - va: Self::VA.from_data(data)?, - v_aph_a: Self::V_APH_A.from_data(data)?, - v_aph_b: Self::V_APH_B.from_data(data)?, - v_aph_c: Self::V_APH_C.from_data(data)?, - va_sf: Self::VA_SF.from_data(data)?, - var: Self::VAR.from_data(data)?, - va_rph_a: Self::VA_RPH_A.from_data(data)?, - va_rph_b: Self::VA_RPH_B.from_data(data)?, - va_rph_c: Self::VA_RPH_C.from_data(data)?, - var_sf: Self::VAR_SF.from_data(data)?, - pf: Self::PF.from_data(data)?, - p_fph_a: Self::P_FPH_A.from_data(data)?, - p_fph_b: Self::P_FPH_B.from_data(data)?, - p_fph_c: Self::P_FPH_C.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, - tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, - tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, - tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, - tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, - tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, - tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, - tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, - tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, - tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, - tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, - tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, - tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, - tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, - tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, - tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, - tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, - tot_v_ah_sf: Self::TOT_V_AH_SF.from_data(data)?, - tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, - tot_v_arh_imp_q1_ph_a: Self::TOT_V_ARH_IMP_Q1_PH_A.from_data(data)?, - tot_v_arh_imp_q1_ph_b: Self::TOT_V_ARH_IMP_Q1_PH_B.from_data(data)?, - tot_v_arh_imp_q1_ph_c: Self::TOT_V_ARH_IMP_Q1_PH_C.from_data(data)?, - tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, - tot_v_arh_imp_q2_ph_a: Self::TOT_V_ARH_IMP_Q2_PH_A.from_data(data)?, - tot_v_arh_imp_q2_ph_b: Self::TOT_V_ARH_IMP_Q2_PH_B.from_data(data)?, - tot_v_arh_imp_q2_ph_c: Self::TOT_V_ARH_IMP_Q2_PH_C.from_data(data)?, - tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, - tot_v_arh_exp_q3_ph_a: Self::TOT_V_ARH_EXP_Q3_PH_A.from_data(data)?, - tot_v_arh_exp_q3_ph_b: Self::TOT_V_ARH_EXP_Q3_PH_B.from_data(data)?, - tot_v_arh_exp_q3_ph_c: Self::TOT_V_ARH_EXP_Q3_PH_C.from_data(data)?, - tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, - tot_v_arh_exp_q4_ph_a: Self::TOT_V_ARH_EXP_Q4_PH_A.from_data(data)?, - tot_v_arh_exp_q4_ph_b: Self::TOT_V_ARH_EXP_Q4_PH_B.from_data(data)?, - tot_v_arh_exp_q4_ph_c: Self::TOT_V_ARH_EXP_Q4_PH_C.from_data(data)?, - tot_v_arh_sf: Self::TOT_V_ARH_SF.from_data(data)?, - evt: Self::EVT.from_data(data)?, - }) +impl crate::Group for AcMeterAbc { + const LEN: u16 = 105; +} +impl AcMeterAbc { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + ph_v: Self::PH_V.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + ppv: Self::PPV.from_data(data)?, + ph_vph_ab: Self::PH_VPH_AB.from_data(data)?, + ph_vph_bc: Self::PH_VPH_BC.from_data(data)?, + ph_vph_ca: Self::PH_VPH_CA.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + hz: Self::HZ.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + w: Self::W.from_data(data)?, + wph_a: Self::WPH_A.from_data(data)?, + wph_b: Self::WPH_B.from_data(data)?, + wph_c: Self::WPH_C.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + va: Self::VA.from_data(data)?, + v_aph_a: Self::V_APH_A.from_data(data)?, + v_aph_b: Self::V_APH_B.from_data(data)?, + v_aph_c: Self::V_APH_C.from_data(data)?, + va_sf: Self::VA_SF.from_data(data)?, + var: Self::VAR.from_data(data)?, + va_rph_a: Self::VA_RPH_A.from_data(data)?, + va_rph_b: Self::VA_RPH_B.from_data(data)?, + va_rph_c: Self::VA_RPH_C.from_data(data)?, + var_sf: Self::VAR_SF.from_data(data)?, + pf: Self::PF.from_data(data)?, + p_fph_a: Self::P_FPH_A.from_data(data)?, + p_fph_b: Self::P_FPH_B.from_data(data)?, + p_fph_c: Self::P_FPH_C.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, + tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, + tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, + tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, + tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, + tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, + tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, + tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, + tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, + tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, + tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, + tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, + tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, + tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, + tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, + tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, + tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, + tot_v_ah_sf: Self::TOT_V_AH_SF.from_data(data)?, + tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, + tot_v_arh_imp_q1_ph_a: Self::TOT_V_ARH_IMP_Q1_PH_A.from_data(data)?, + tot_v_arh_imp_q1_ph_b: Self::TOT_V_ARH_IMP_Q1_PH_B.from_data(data)?, + tot_v_arh_imp_q1_ph_c: Self::TOT_V_ARH_IMP_Q1_PH_C.from_data(data)?, + tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, + tot_v_arh_imp_q2_ph_a: Self::TOT_V_ARH_IMP_Q2_PH_A.from_data(data)?, + tot_v_arh_imp_q2_ph_b: Self::TOT_V_ARH_IMP_Q2_PH_B.from_data(data)?, + tot_v_arh_imp_q2_ph_c: Self::TOT_V_ARH_IMP_Q2_PH_C.from_data(data)?, + tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, + tot_v_arh_exp_q3_ph_a: Self::TOT_V_ARH_EXP_Q3_PH_A.from_data(data)?, + tot_v_arh_exp_q3_ph_b: Self::TOT_V_ARH_EXP_Q3_PH_B.from_data(data)?, + tot_v_arh_exp_q3_ph_c: Self::TOT_V_ARH_EXP_Q3_PH_C.from_data(data)?, + tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, + tot_v_arh_exp_q4_ph_a: Self::TOT_V_ARH_EXP_Q4_PH_A.from_data(data)?, + tot_v_arh_exp_q4_ph_b: Self::TOT_V_ARH_EXP_Q4_PH_B.from_data(data)?, + tot_v_arh_exp_q4_ph_c: Self::TOT_V_ARH_EXP_Q4_PH_C.from_data(data)?, + tot_v_arh_sf: Self::TOT_V_ARH_SF.from_data(data)?, + evt: Self::EVT.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m204 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -419,3 +427,13 @@ impl crate::Value for Option { } } } +impl crate::Model for AcMeterAbc { + const ID: u16 = 204; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m204 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model211.rs b/src/models/model211.rs index 5354ed5..e180e73 100644 --- a/src/models/model211.rs +++ b/src/models/model211.rs @@ -1,10 +1,11 @@ //! single phase (AN or AB) meter +pub type Model211 = AcMeterAnOrAbFloat; /// single phase (AN or AB) meter /// /// Detail: Float #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model211 { +pub struct AcMeterAnOrAbFloat { /// Amps /// /// Total AC Current @@ -183,7 +184,7 @@ pub struct Model211 { pub evt: Evt, } #[allow(missing_docs)] -impl Model211 { +impl AcMeterAnOrAbFloat { pub const A: crate::Point = crate::Point::new(0, 2, false); pub const APH_A: crate::Point = crate::Point::new(2, 2, false); pub const APH_B: crate::Point> = crate::Point::new(4, 2, false); @@ -259,76 +260,83 @@ impl Model211 { crate::Point::new(120, 2, false); pub const EVT: crate::Point = crate::Point::new(122, 2, false); } -impl crate::Model for Model211 { - const ID: u16 = 211; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - ph_v: Self::PH_V.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - ppv: Self::PPV.from_data(data)?, - pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, - pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, - pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, - hz: Self::HZ.from_data(data)?, - w: Self::W.from_data(data)?, - wph_a: Self::WPH_A.from_data(data)?, - wph_b: Self::WPH_B.from_data(data)?, - wph_c: Self::WPH_C.from_data(data)?, - va: Self::VA.from_data(data)?, - v_aph_a: Self::V_APH_A.from_data(data)?, - v_aph_b: Self::V_APH_B.from_data(data)?, - v_aph_c: Self::V_APH_C.from_data(data)?, - var: Self::VAR.from_data(data)?, - va_rph_a: Self::VA_RPH_A.from_data(data)?, - va_rph_b: Self::VA_RPH_B.from_data(data)?, - va_rph_c: Self::VA_RPH_C.from_data(data)?, - pf: Self::PF.from_data(data)?, - p_fph_a: Self::P_FPH_A.from_data(data)?, - p_fph_b: Self::P_FPH_B.from_data(data)?, - p_fph_c: Self::P_FPH_C.from_data(data)?, - tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, - tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, - tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, - tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, - tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, - tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, - tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, - tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, - tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, - tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, - tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, - tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, - tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, - tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, - tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, - tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, - tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, - tot_v_arh_imp_q1ph_a: Self::TOT_V_ARH_IMP_Q1PH_A.from_data(data)?, - tot_v_arh_imp_q1ph_b: Self::TOT_V_ARH_IMP_Q1PH_B.from_data(data)?, - tot_v_arh_imp_q1ph_c: Self::TOT_V_ARH_IMP_Q1PH_C.from_data(data)?, - tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, - tot_v_arh_imp_q2ph_a: Self::TOT_V_ARH_IMP_Q2PH_A.from_data(data)?, - tot_v_arh_imp_q2ph_b: Self::TOT_V_ARH_IMP_Q2PH_B.from_data(data)?, - tot_v_arh_imp_q2ph_c: Self::TOT_V_ARH_IMP_Q2PH_C.from_data(data)?, - tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, - tot_v_arh_exp_q3ph_a: Self::TOT_V_ARH_EXP_Q3PH_A.from_data(data)?, - tot_v_arh_exp_q3ph_b: Self::TOT_V_ARH_EXP_Q3PH_B.from_data(data)?, - tot_v_arh_exp_q3ph_c: Self::TOT_V_ARH_EXP_Q3PH_C.from_data(data)?, - tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, - tot_v_arh_exp_q4ph_a: Self::TOT_V_ARH_EXP_Q4PH_A.from_data(data)?, - tot_v_arh_exp_q4ph_b: Self::TOT_V_ARH_EXP_Q4PH_B.from_data(data)?, - tot_v_arh_exp_q4ph_c: Self::TOT_V_ARH_EXP_Q4PH_C.from_data(data)?, - evt: Self::EVT.from_data(data)?, - }) +impl crate::Group for AcMeterAnOrAbFloat { + const LEN: u16 = 124; +} +impl AcMeterAnOrAbFloat { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + ph_v: Self::PH_V.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + ppv: Self::PPV.from_data(data)?, + pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, + pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, + pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, + hz: Self::HZ.from_data(data)?, + w: Self::W.from_data(data)?, + wph_a: Self::WPH_A.from_data(data)?, + wph_b: Self::WPH_B.from_data(data)?, + wph_c: Self::WPH_C.from_data(data)?, + va: Self::VA.from_data(data)?, + v_aph_a: Self::V_APH_A.from_data(data)?, + v_aph_b: Self::V_APH_B.from_data(data)?, + v_aph_c: Self::V_APH_C.from_data(data)?, + var: Self::VAR.from_data(data)?, + va_rph_a: Self::VA_RPH_A.from_data(data)?, + va_rph_b: Self::VA_RPH_B.from_data(data)?, + va_rph_c: Self::VA_RPH_C.from_data(data)?, + pf: Self::PF.from_data(data)?, + p_fph_a: Self::P_FPH_A.from_data(data)?, + p_fph_b: Self::P_FPH_B.from_data(data)?, + p_fph_c: Self::P_FPH_C.from_data(data)?, + tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, + tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, + tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, + tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, + tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, + tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, + tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, + tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, + tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, + tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, + tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, + tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, + tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, + tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, + tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, + tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, + tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, + tot_v_arh_imp_q1ph_a: Self::TOT_V_ARH_IMP_Q1PH_A.from_data(data)?, + tot_v_arh_imp_q1ph_b: Self::TOT_V_ARH_IMP_Q1PH_B.from_data(data)?, + tot_v_arh_imp_q1ph_c: Self::TOT_V_ARH_IMP_Q1PH_C.from_data(data)?, + tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, + tot_v_arh_imp_q2ph_a: Self::TOT_V_ARH_IMP_Q2PH_A.from_data(data)?, + tot_v_arh_imp_q2ph_b: Self::TOT_V_ARH_IMP_Q2PH_B.from_data(data)?, + tot_v_arh_imp_q2ph_c: Self::TOT_V_ARH_IMP_Q2PH_C.from_data(data)?, + tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, + tot_v_arh_exp_q3ph_a: Self::TOT_V_ARH_EXP_Q3PH_A.from_data(data)?, + tot_v_arh_exp_q3ph_b: Self::TOT_V_ARH_EXP_Q3PH_B.from_data(data)?, + tot_v_arh_exp_q3ph_c: Self::TOT_V_ARH_EXP_Q3PH_C.from_data(data)?, + tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, + tot_v_arh_exp_q4ph_a: Self::TOT_V_ARH_EXP_Q4PH_A.from_data(data)?, + tot_v_arh_exp_q4ph_b: Self::TOT_V_ARH_EXP_Q4PH_B.from_data(data)?, + tot_v_arh_exp_q4ph_c: Self::TOT_V_ARH_EXP_Q4PH_C.from_data(data)?, + evt: Self::EVT.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m211 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -381,3 +389,13 @@ impl crate::Value for Option { } } } +impl crate::Model for AcMeterAnOrAbFloat { + const ID: u16 = 211; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m211 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model212.rs b/src/models/model212.rs index 6b79c63..b6e0074 100644 --- a/src/models/model212.rs +++ b/src/models/model212.rs @@ -1,10 +1,11 @@ //! split single phase (ABN) meter +pub type Model212 = AcMeterAbnFloat; /// split single phase (ABN) meter /// /// Detail: Float #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model212 { +pub struct AcMeterAbnFloat { /// Amps /// /// Total AC Current @@ -183,7 +184,7 @@ pub struct Model212 { pub evt: Evt, } #[allow(missing_docs)] -impl Model212 { +impl AcMeterAbnFloat { pub const A: crate::Point = crate::Point::new(0, 2, false); pub const APH_A: crate::Point = crate::Point::new(2, 2, false); pub const APH_B: crate::Point = crate::Point::new(4, 2, false); @@ -259,76 +260,83 @@ impl Model212 { crate::Point::new(120, 2, false); pub const EVT: crate::Point = crate::Point::new(122, 2, false); } -impl crate::Model for Model212 { - const ID: u16 = 212; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - ph_v: Self::PH_V.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - ppv: Self::PPV.from_data(data)?, - pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, - pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, - pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, - hz: Self::HZ.from_data(data)?, - w: Self::W.from_data(data)?, - wph_a: Self::WPH_A.from_data(data)?, - wph_b: Self::WPH_B.from_data(data)?, - wph_c: Self::WPH_C.from_data(data)?, - va: Self::VA.from_data(data)?, - v_aph_a: Self::V_APH_A.from_data(data)?, - v_aph_b: Self::V_APH_B.from_data(data)?, - v_aph_c: Self::V_APH_C.from_data(data)?, - var: Self::VAR.from_data(data)?, - va_rph_a: Self::VA_RPH_A.from_data(data)?, - va_rph_b: Self::VA_RPH_B.from_data(data)?, - va_rph_c: Self::VA_RPH_C.from_data(data)?, - pf: Self::PF.from_data(data)?, - p_fph_a: Self::P_FPH_A.from_data(data)?, - p_fph_b: Self::P_FPH_B.from_data(data)?, - p_fph_c: Self::P_FPH_C.from_data(data)?, - tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, - tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, - tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, - tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, - tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, - tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, - tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, - tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, - tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, - tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, - tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, - tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, - tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, - tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, - tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, - tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, - tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, - tot_v_arh_imp_q1ph_a: Self::TOT_V_ARH_IMP_Q1PH_A.from_data(data)?, - tot_v_arh_imp_q1ph_b: Self::TOT_V_ARH_IMP_Q1PH_B.from_data(data)?, - tot_v_arh_imp_q1ph_c: Self::TOT_V_ARH_IMP_Q1PH_C.from_data(data)?, - tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, - tot_v_arh_imp_q2ph_a: Self::TOT_V_ARH_IMP_Q2PH_A.from_data(data)?, - tot_v_arh_imp_q2ph_b: Self::TOT_V_ARH_IMP_Q2PH_B.from_data(data)?, - tot_v_arh_imp_q2ph_c: Self::TOT_V_ARH_IMP_Q2PH_C.from_data(data)?, - tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, - tot_v_arh_exp_q3ph_a: Self::TOT_V_ARH_EXP_Q3PH_A.from_data(data)?, - tot_v_arh_exp_q3ph_b: Self::TOT_V_ARH_EXP_Q3PH_B.from_data(data)?, - tot_v_arh_exp_q3ph_c: Self::TOT_V_ARH_EXP_Q3PH_C.from_data(data)?, - tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, - tot_v_arh_exp_q4ph_a: Self::TOT_V_ARH_EXP_Q4PH_A.from_data(data)?, - tot_v_arh_exp_q4ph_b: Self::TOT_V_ARH_EXP_Q4PH_B.from_data(data)?, - tot_v_arh_exp_q4ph_c: Self::TOT_V_ARH_EXP_Q4PH_C.from_data(data)?, - evt: Self::EVT.from_data(data)?, - }) +impl crate::Group for AcMeterAbnFloat { + const LEN: u16 = 124; +} +impl AcMeterAbnFloat { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + ph_v: Self::PH_V.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + ppv: Self::PPV.from_data(data)?, + pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, + pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, + pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, + hz: Self::HZ.from_data(data)?, + w: Self::W.from_data(data)?, + wph_a: Self::WPH_A.from_data(data)?, + wph_b: Self::WPH_B.from_data(data)?, + wph_c: Self::WPH_C.from_data(data)?, + va: Self::VA.from_data(data)?, + v_aph_a: Self::V_APH_A.from_data(data)?, + v_aph_b: Self::V_APH_B.from_data(data)?, + v_aph_c: Self::V_APH_C.from_data(data)?, + var: Self::VAR.from_data(data)?, + va_rph_a: Self::VA_RPH_A.from_data(data)?, + va_rph_b: Self::VA_RPH_B.from_data(data)?, + va_rph_c: Self::VA_RPH_C.from_data(data)?, + pf: Self::PF.from_data(data)?, + p_fph_a: Self::P_FPH_A.from_data(data)?, + p_fph_b: Self::P_FPH_B.from_data(data)?, + p_fph_c: Self::P_FPH_C.from_data(data)?, + tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, + tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, + tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, + tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, + tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, + tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, + tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, + tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, + tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, + tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, + tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, + tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, + tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, + tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, + tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, + tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, + tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, + tot_v_arh_imp_q1ph_a: Self::TOT_V_ARH_IMP_Q1PH_A.from_data(data)?, + tot_v_arh_imp_q1ph_b: Self::TOT_V_ARH_IMP_Q1PH_B.from_data(data)?, + tot_v_arh_imp_q1ph_c: Self::TOT_V_ARH_IMP_Q1PH_C.from_data(data)?, + tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, + tot_v_arh_imp_q2ph_a: Self::TOT_V_ARH_IMP_Q2PH_A.from_data(data)?, + tot_v_arh_imp_q2ph_b: Self::TOT_V_ARH_IMP_Q2PH_B.from_data(data)?, + tot_v_arh_imp_q2ph_c: Self::TOT_V_ARH_IMP_Q2PH_C.from_data(data)?, + tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, + tot_v_arh_exp_q3ph_a: Self::TOT_V_ARH_EXP_Q3PH_A.from_data(data)?, + tot_v_arh_exp_q3ph_b: Self::TOT_V_ARH_EXP_Q3PH_B.from_data(data)?, + tot_v_arh_exp_q3ph_c: Self::TOT_V_ARH_EXP_Q3PH_C.from_data(data)?, + tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, + tot_v_arh_exp_q4ph_a: Self::TOT_V_ARH_EXP_Q4PH_A.from_data(data)?, + tot_v_arh_exp_q4ph_b: Self::TOT_V_ARH_EXP_Q4PH_B.from_data(data)?, + tot_v_arh_exp_q4ph_c: Self::TOT_V_ARH_EXP_Q4PH_C.from_data(data)?, + evt: Self::EVT.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m212 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -381,3 +389,13 @@ impl crate::Value for Option { } } } +impl crate::Model for AcMeterAbnFloat { + const ID: u16 = 212; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m212 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model213.rs b/src/models/model213.rs index f31c3d7..edcc124 100644 --- a/src/models/model213.rs +++ b/src/models/model213.rs @@ -1,10 +1,11 @@ //! wye-connect three phase (abcn) meter +pub type Model213 = AcMeterAbcnFloat; /// wye-connect three phase (abcn) meter /// /// Detail: Float #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model213 { +pub struct AcMeterAbcnFloat { /// Amps /// /// Total AC Current @@ -183,7 +184,7 @@ pub struct Model213 { pub evt: Evt, } #[allow(missing_docs)] -impl Model213 { +impl AcMeterAbcnFloat { pub const A: crate::Point = crate::Point::new(0, 2, false); pub const APH_A: crate::Point = crate::Point::new(2, 2, false); pub const APH_B: crate::Point = crate::Point::new(4, 2, false); @@ -259,76 +260,83 @@ impl Model213 { crate::Point::new(120, 2, false); pub const EVT: crate::Point = crate::Point::new(122, 2, false); } -impl crate::Model for Model213 { - const ID: u16 = 213; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - ph_v: Self::PH_V.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - ppv: Self::PPV.from_data(data)?, - pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, - pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, - pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, - hz: Self::HZ.from_data(data)?, - w: Self::W.from_data(data)?, - wph_a: Self::WPH_A.from_data(data)?, - wph_b: Self::WPH_B.from_data(data)?, - wph_c: Self::WPH_C.from_data(data)?, - va: Self::VA.from_data(data)?, - v_aph_a: Self::V_APH_A.from_data(data)?, - v_aph_b: Self::V_APH_B.from_data(data)?, - v_aph_c: Self::V_APH_C.from_data(data)?, - var: Self::VAR.from_data(data)?, - va_rph_a: Self::VA_RPH_A.from_data(data)?, - va_rph_b: Self::VA_RPH_B.from_data(data)?, - va_rph_c: Self::VA_RPH_C.from_data(data)?, - pf: Self::PF.from_data(data)?, - p_fph_a: Self::P_FPH_A.from_data(data)?, - p_fph_b: Self::P_FPH_B.from_data(data)?, - p_fph_c: Self::P_FPH_C.from_data(data)?, - tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, - tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, - tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, - tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, - tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, - tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, - tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, - tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, - tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, - tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, - tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, - tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, - tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, - tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, - tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, - tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, - tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, - tot_v_arh_imp_q1ph_a: Self::TOT_V_ARH_IMP_Q1PH_A.from_data(data)?, - tot_v_arh_imp_q1ph_b: Self::TOT_V_ARH_IMP_Q1PH_B.from_data(data)?, - tot_v_arh_imp_q1ph_c: Self::TOT_V_ARH_IMP_Q1PH_C.from_data(data)?, - tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, - tot_v_arh_imp_q2ph_a: Self::TOT_V_ARH_IMP_Q2PH_A.from_data(data)?, - tot_v_arh_imp_q2ph_b: Self::TOT_V_ARH_IMP_Q2PH_B.from_data(data)?, - tot_v_arh_imp_q2ph_c: Self::TOT_V_ARH_IMP_Q2PH_C.from_data(data)?, - tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, - tot_v_arh_exp_q3ph_a: Self::TOT_V_ARH_EXP_Q3PH_A.from_data(data)?, - tot_v_arh_exp_q3ph_b: Self::TOT_V_ARH_EXP_Q3PH_B.from_data(data)?, - tot_v_arh_exp_q3ph_c: Self::TOT_V_ARH_EXP_Q3PH_C.from_data(data)?, - tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, - tot_v_arh_exp_q4ph_a: Self::TOT_V_ARH_EXP_Q4PH_A.from_data(data)?, - tot_v_arh_exp_q4ph_b: Self::TOT_V_ARH_EXP_Q4PH_B.from_data(data)?, - tot_v_arh_exp_q4ph_c: Self::TOT_V_ARH_EXP_Q4PH_C.from_data(data)?, - evt: Self::EVT.from_data(data)?, - }) +impl crate::Group for AcMeterAbcnFloat { + const LEN: u16 = 124; +} +impl AcMeterAbcnFloat { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + ph_v: Self::PH_V.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + ppv: Self::PPV.from_data(data)?, + pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, + pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, + pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, + hz: Self::HZ.from_data(data)?, + w: Self::W.from_data(data)?, + wph_a: Self::WPH_A.from_data(data)?, + wph_b: Self::WPH_B.from_data(data)?, + wph_c: Self::WPH_C.from_data(data)?, + va: Self::VA.from_data(data)?, + v_aph_a: Self::V_APH_A.from_data(data)?, + v_aph_b: Self::V_APH_B.from_data(data)?, + v_aph_c: Self::V_APH_C.from_data(data)?, + var: Self::VAR.from_data(data)?, + va_rph_a: Self::VA_RPH_A.from_data(data)?, + va_rph_b: Self::VA_RPH_B.from_data(data)?, + va_rph_c: Self::VA_RPH_C.from_data(data)?, + pf: Self::PF.from_data(data)?, + p_fph_a: Self::P_FPH_A.from_data(data)?, + p_fph_b: Self::P_FPH_B.from_data(data)?, + p_fph_c: Self::P_FPH_C.from_data(data)?, + tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, + tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, + tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, + tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, + tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, + tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, + tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, + tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, + tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, + tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, + tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, + tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, + tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, + tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, + tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, + tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, + tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, + tot_v_arh_imp_q1ph_a: Self::TOT_V_ARH_IMP_Q1PH_A.from_data(data)?, + tot_v_arh_imp_q1ph_b: Self::TOT_V_ARH_IMP_Q1PH_B.from_data(data)?, + tot_v_arh_imp_q1ph_c: Self::TOT_V_ARH_IMP_Q1PH_C.from_data(data)?, + tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, + tot_v_arh_imp_q2ph_a: Self::TOT_V_ARH_IMP_Q2PH_A.from_data(data)?, + tot_v_arh_imp_q2ph_b: Self::TOT_V_ARH_IMP_Q2PH_B.from_data(data)?, + tot_v_arh_imp_q2ph_c: Self::TOT_V_ARH_IMP_Q2PH_C.from_data(data)?, + tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, + tot_v_arh_exp_q3ph_a: Self::TOT_V_ARH_EXP_Q3PH_A.from_data(data)?, + tot_v_arh_exp_q3ph_b: Self::TOT_V_ARH_EXP_Q3PH_B.from_data(data)?, + tot_v_arh_exp_q3ph_c: Self::TOT_V_ARH_EXP_Q3PH_C.from_data(data)?, + tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, + tot_v_arh_exp_q4ph_a: Self::TOT_V_ARH_EXP_Q4PH_A.from_data(data)?, + tot_v_arh_exp_q4ph_b: Self::TOT_V_ARH_EXP_Q4PH_B.from_data(data)?, + tot_v_arh_exp_q4ph_c: Self::TOT_V_ARH_EXP_Q4PH_C.from_data(data)?, + evt: Self::EVT.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m213 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -381,3 +389,13 @@ impl crate::Value for Option { } } } +impl crate::Model for AcMeterAbcnFloat { + const ID: u16 = 213; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m213 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model214.rs b/src/models/model214.rs index 56e5c26..19d001a 100644 --- a/src/models/model214.rs +++ b/src/models/model214.rs @@ -1,10 +1,11 @@ //! delta-connect three phase (abc) meter +pub type Model214 = AcMeterAbcFloat; /// delta-connect three phase (abc) meter /// /// Detail: Float #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model214 { +pub struct AcMeterAbcFloat { /// Amps /// /// Total AC Current @@ -183,7 +184,7 @@ pub struct Model214 { pub evt: Evt, } #[allow(missing_docs)] -impl Model214 { +impl AcMeterAbcFloat { pub const A: crate::Point = crate::Point::new(0, 2, false); pub const APH_A: crate::Point = crate::Point::new(2, 2, false); pub const APH_B: crate::Point = crate::Point::new(4, 2, false); @@ -259,76 +260,83 @@ impl Model214 { crate::Point::new(120, 2, false); pub const EVT: crate::Point = crate::Point::new(122, 2, false); } -impl crate::Model for Model214 { - const ID: u16 = 214; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - aph_a: Self::APH_A.from_data(data)?, - aph_b: Self::APH_B.from_data(data)?, - aph_c: Self::APH_C.from_data(data)?, - ph_v: Self::PH_V.from_data(data)?, - ph_vph_a: Self::PH_VPH_A.from_data(data)?, - ph_vph_b: Self::PH_VPH_B.from_data(data)?, - ph_vph_c: Self::PH_VPH_C.from_data(data)?, - ppv: Self::PPV.from_data(data)?, - pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, - pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, - pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, - hz: Self::HZ.from_data(data)?, - w: Self::W.from_data(data)?, - wph_a: Self::WPH_A.from_data(data)?, - wph_b: Self::WPH_B.from_data(data)?, - wph_c: Self::WPH_C.from_data(data)?, - va: Self::VA.from_data(data)?, - v_aph_a: Self::V_APH_A.from_data(data)?, - v_aph_b: Self::V_APH_B.from_data(data)?, - v_aph_c: Self::V_APH_C.from_data(data)?, - var: Self::VAR.from_data(data)?, - va_rph_a: Self::VA_RPH_A.from_data(data)?, - va_rph_b: Self::VA_RPH_B.from_data(data)?, - va_rph_c: Self::VA_RPH_C.from_data(data)?, - pf: Self::PF.from_data(data)?, - p_fph_a: Self::P_FPH_A.from_data(data)?, - p_fph_b: Self::P_FPH_B.from_data(data)?, - p_fph_c: Self::P_FPH_C.from_data(data)?, - tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, - tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, - tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, - tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, - tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, - tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, - tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, - tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, - tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, - tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, - tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, - tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, - tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, - tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, - tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, - tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, - tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, - tot_v_arh_imp_q1ph_a: Self::TOT_V_ARH_IMP_Q1PH_A.from_data(data)?, - tot_v_arh_imp_q1ph_b: Self::TOT_V_ARH_IMP_Q1PH_B.from_data(data)?, - tot_v_arh_imp_q1ph_c: Self::TOT_V_ARH_IMP_Q1PH_C.from_data(data)?, - tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, - tot_v_arh_imp_q2ph_a: Self::TOT_V_ARH_IMP_Q2PH_A.from_data(data)?, - tot_v_arh_imp_q2ph_b: Self::TOT_V_ARH_IMP_Q2PH_B.from_data(data)?, - tot_v_arh_imp_q2ph_c: Self::TOT_V_ARH_IMP_Q2PH_C.from_data(data)?, - tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, - tot_v_arh_exp_q3ph_a: Self::TOT_V_ARH_EXP_Q3PH_A.from_data(data)?, - tot_v_arh_exp_q3ph_b: Self::TOT_V_ARH_EXP_Q3PH_B.from_data(data)?, - tot_v_arh_exp_q3ph_c: Self::TOT_V_ARH_EXP_Q3PH_C.from_data(data)?, - tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, - tot_v_arh_exp_q4ph_a: Self::TOT_V_ARH_EXP_Q4PH_A.from_data(data)?, - tot_v_arh_exp_q4ph_b: Self::TOT_V_ARH_EXP_Q4PH_B.from_data(data)?, - tot_v_arh_exp_q4ph_c: Self::TOT_V_ARH_EXP_Q4PH_C.from_data(data)?, - evt: Self::EVT.from_data(data)?, - }) +impl crate::Group for AcMeterAbcFloat { + const LEN: u16 = 124; +} +impl AcMeterAbcFloat { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + aph_a: Self::APH_A.from_data(data)?, + aph_b: Self::APH_B.from_data(data)?, + aph_c: Self::APH_C.from_data(data)?, + ph_v: Self::PH_V.from_data(data)?, + ph_vph_a: Self::PH_VPH_A.from_data(data)?, + ph_vph_b: Self::PH_VPH_B.from_data(data)?, + ph_vph_c: Self::PH_VPH_C.from_data(data)?, + ppv: Self::PPV.from_data(data)?, + pp_vph_ab: Self::PP_VPH_AB.from_data(data)?, + pp_vph_bc: Self::PP_VPH_BC.from_data(data)?, + pp_vph_ca: Self::PP_VPH_CA.from_data(data)?, + hz: Self::HZ.from_data(data)?, + w: Self::W.from_data(data)?, + wph_a: Self::WPH_A.from_data(data)?, + wph_b: Self::WPH_B.from_data(data)?, + wph_c: Self::WPH_C.from_data(data)?, + va: Self::VA.from_data(data)?, + v_aph_a: Self::V_APH_A.from_data(data)?, + v_aph_b: Self::V_APH_B.from_data(data)?, + v_aph_c: Self::V_APH_C.from_data(data)?, + var: Self::VAR.from_data(data)?, + va_rph_a: Self::VA_RPH_A.from_data(data)?, + va_rph_b: Self::VA_RPH_B.from_data(data)?, + va_rph_c: Self::VA_RPH_C.from_data(data)?, + pf: Self::PF.from_data(data)?, + p_fph_a: Self::P_FPH_A.from_data(data)?, + p_fph_b: Self::P_FPH_B.from_data(data)?, + p_fph_c: Self::P_FPH_C.from_data(data)?, + tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, + tot_wh_exp_ph_a: Self::TOT_WH_EXP_PH_A.from_data(data)?, + tot_wh_exp_ph_b: Self::TOT_WH_EXP_PH_B.from_data(data)?, + tot_wh_exp_ph_c: Self::TOT_WH_EXP_PH_C.from_data(data)?, + tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, + tot_wh_imp_ph_a: Self::TOT_WH_IMP_PH_A.from_data(data)?, + tot_wh_imp_ph_b: Self::TOT_WH_IMP_PH_B.from_data(data)?, + tot_wh_imp_ph_c: Self::TOT_WH_IMP_PH_C.from_data(data)?, + tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, + tot_v_ah_exp_ph_a: Self::TOT_V_AH_EXP_PH_A.from_data(data)?, + tot_v_ah_exp_ph_b: Self::TOT_V_AH_EXP_PH_B.from_data(data)?, + tot_v_ah_exp_ph_c: Self::TOT_V_AH_EXP_PH_C.from_data(data)?, + tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, + tot_v_ah_imp_ph_a: Self::TOT_V_AH_IMP_PH_A.from_data(data)?, + tot_v_ah_imp_ph_b: Self::TOT_V_AH_IMP_PH_B.from_data(data)?, + tot_v_ah_imp_ph_c: Self::TOT_V_AH_IMP_PH_C.from_data(data)?, + tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, + tot_v_arh_imp_q1ph_a: Self::TOT_V_ARH_IMP_Q1PH_A.from_data(data)?, + tot_v_arh_imp_q1ph_b: Self::TOT_V_ARH_IMP_Q1PH_B.from_data(data)?, + tot_v_arh_imp_q1ph_c: Self::TOT_V_ARH_IMP_Q1PH_C.from_data(data)?, + tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, + tot_v_arh_imp_q2ph_a: Self::TOT_V_ARH_IMP_Q2PH_A.from_data(data)?, + tot_v_arh_imp_q2ph_b: Self::TOT_V_ARH_IMP_Q2PH_B.from_data(data)?, + tot_v_arh_imp_q2ph_c: Self::TOT_V_ARH_IMP_Q2PH_C.from_data(data)?, + tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, + tot_v_arh_exp_q3ph_a: Self::TOT_V_ARH_EXP_Q3PH_A.from_data(data)?, + tot_v_arh_exp_q3ph_b: Self::TOT_V_ARH_EXP_Q3PH_B.from_data(data)?, + tot_v_arh_exp_q3ph_c: Self::TOT_V_ARH_EXP_Q3PH_C.from_data(data)?, + tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, + tot_v_arh_exp_q4ph_a: Self::TOT_V_ARH_EXP_Q4PH_A.from_data(data)?, + tot_v_arh_exp_q4ph_b: Self::TOT_V_ARH_EXP_Q4PH_B.from_data(data)?, + tot_v_arh_exp_q4ph_c: Self::TOT_V_ARH_EXP_Q4PH_C.from_data(data)?, + evt: Self::EVT.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m214 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -381,3 +389,13 @@ impl crate::Value for Option { } } } +impl crate::Model for AcMeterAbcFloat { + const ID: u16 = 214; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m214 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model220.rs b/src/models/model220.rs index 2b0425d..c778b41 100644 --- a/src/models/model220.rs +++ b/src/models/model220.rs @@ -1,10 +1,11 @@ //! Secure AC Meter Selected Readings +pub type Model220 = AcMeterSecure; /// Secure AC Meter Selected Readings /// /// Include this model for secure metering #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model220 { +pub struct AcMeterSecure { /// Amps /// /// Total AC Current @@ -115,9 +116,11 @@ pub struct Model220 { /// /// Detail: The value of N must be at least 4 (64 bits) pub n: u16, + #[allow(missing_docs)] + pub repeating: Vec, } #[allow(missing_docs)] -impl Model220 { +impl AcMeterSecure { pub const A: crate::Point = crate::Point::new(0, 1, false); pub const A_SF: crate::Point = crate::Point::new(1, 1, false); pub const PH_V: crate::Point> = crate::Point::new(2, 1, false); @@ -150,45 +153,54 @@ impl Model220 { pub const ALG: crate::Point = crate::Point::new(40, 1, false); pub const N: crate::Point = crate::Point::new(41, 1, false); } -impl crate::Model for Model220 { - const ID: u16 = 220; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a: Self::A.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - ph_v: Self::PH_V.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - hz: Self::HZ.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - w: Self::W.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - va: Self::VA.from_data(data)?, - va_sf: Self::VA_SF.from_data(data)?, - var: Self::VAR.from_data(data)?, - var_sf: Self::VAR_SF.from_data(data)?, - pf: Self::PF.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, - tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, - tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, - tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, - tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, - tot_v_ah_sf: Self::TOT_V_AH_SF.from_data(data)?, - tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, - tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, - tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, - tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, - tot_v_arh_sf: Self::TOT_V_ARH_SF.from_data(data)?, - evt: Self::EVT.from_data(data)?, - ts: Self::TS.from_data(data)?, - ms: Self::MS.from_data(data)?, - seq: Self::SEQ.from_data(data)?, - alg: Self::ALG.from_data(data)?, - n: Self::N.from_data(data)?, - }) +impl crate::Group for AcMeterSecure { + const LEN: u16 = 42; +} +impl AcMeterSecure { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a: Self::A.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + ph_v: Self::PH_V.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + hz: Self::HZ.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + w: Self::W.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + va: Self::VA.from_data(data)?, + va_sf: Self::VA_SF.from_data(data)?, + var: Self::VAR.from_data(data)?, + var_sf: Self::VAR_SF.from_data(data)?, + pf: Self::PF.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + tot_wh_exp: Self::TOT_WH_EXP.from_data(data)?, + tot_wh_imp: Self::TOT_WH_IMP.from_data(data)?, + tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, + tot_v_ah_exp: Self::TOT_V_AH_EXP.from_data(data)?, + tot_v_ah_imp: Self::TOT_V_AH_IMP.from_data(data)?, + tot_v_ah_sf: Self::TOT_V_AH_SF.from_data(data)?, + tot_v_arh_imp_q1: Self::TOT_V_ARH_IMP_Q1.from_data(data)?, + tot_v_arh_imp_q2: Self::TOT_V_ARH_IMP_Q2.from_data(data)?, + tot_v_arh_exp_q3: Self::TOT_V_ARH_EXP_Q3.from_data(data)?, + tot_v_arh_exp_q4: Self::TOT_V_ARH_EXP_Q4.from_data(data)?, + tot_v_arh_sf: Self::TOT_V_ARH_SF.from_data(data)?, + evt: Self::EVT.from_data(data)?, + ts: Self::TS.from_data(data)?, + ms: Self::MS.from_data(data)?, + seq: Self::SEQ.from_data(data)?, + alg: Self::ALG.from_data(data)?, + n: Self::N.from_data(data)?, + repeating: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m220 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -279,3 +291,57 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + #[allow(missing_docs)] + pub ds: u16, +} +#[allow(missing_docs)] +impl Repeating { + pub const DS: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for Repeating { + const LEN: u16 = 1; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ds: Self::DS.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &AcMeterSecure, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &AcMeterSecure, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for AcMeterSecure { + const ID: u16 = 220; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m220 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model3.rs b/src/models/model3.rs index 49f7774..f0064f6 100644 --- a/src/models/model3.rs +++ b/src/models/model3.rs @@ -147,6 +147,8 @@ pub struct Model3 { /// /// Detail: The value of N must be at least 4 (64 bits) pub n: u16, + #[allow(missing_docs)] + pub repeating: Vec, } #[allow(missing_docs)] impl Model3 { @@ -208,71 +210,80 @@ impl Model3 { pub const ALG: crate::Point = crate::Point::new(56, 1, false); pub const N: crate::Point = crate::Point::new(57, 1, false); } -impl crate::Model for Model3 { - const ID: u16 = 3; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - x: Self::X.from_data(data)?, - off1: Self::OFF1.from_data(data)?, - off2: Self::OFF2.from_data(data)?, - off3: Self::OFF3.from_data(data)?, - off4: Self::OFF4.from_data(data)?, - off5: Self::OFF5.from_data(data)?, - off6: Self::OFF6.from_data(data)?, - off7: Self::OFF7.from_data(data)?, - off8: Self::OFF8.from_data(data)?, - off9: Self::OFF9.from_data(data)?, - off10: Self::OFF10.from_data(data)?, - off11: Self::OFF11.from_data(data)?, - off12: Self::OFF12.from_data(data)?, - off13: Self::OFF13.from_data(data)?, - off14: Self::OFF14.from_data(data)?, - off15: Self::OFF15.from_data(data)?, - off16: Self::OFF16.from_data(data)?, - off17: Self::OFF17.from_data(data)?, - off18: Self::OFF18.from_data(data)?, - off19: Self::OFF19.from_data(data)?, - off20: Self::OFF20.from_data(data)?, - off21: Self::OFF21.from_data(data)?, - off22: Self::OFF22.from_data(data)?, - off23: Self::OFF23.from_data(data)?, - off24: Self::OFF24.from_data(data)?, - off25: Self::OFF25.from_data(data)?, - off26: Self::OFF26.from_data(data)?, - off27: Self::OFF27.from_data(data)?, - off28: Self::OFF28.from_data(data)?, - off29: Self::OFF29.from_data(data)?, - off30: Self::OFF30.from_data(data)?, - off31: Self::OFF31.from_data(data)?, - off32: Self::OFF32.from_data(data)?, - off33: Self::OFF33.from_data(data)?, - off34: Self::OFF34.from_data(data)?, - off35: Self::OFF35.from_data(data)?, - off36: Self::OFF36.from_data(data)?, - off37: Self::OFF37.from_data(data)?, - off38: Self::OFF38.from_data(data)?, - off39: Self::OFF39.from_data(data)?, - off40: Self::OFF40.from_data(data)?, - off41: Self::OFF41.from_data(data)?, - off42: Self::OFF42.from_data(data)?, - off43: Self::OFF43.from_data(data)?, - off44: Self::OFF44.from_data(data)?, - off45: Self::OFF45.from_data(data)?, - off46: Self::OFF46.from_data(data)?, - off47: Self::OFF47.from_data(data)?, - off48: Self::OFF48.from_data(data)?, - off49: Self::OFF49.from_data(data)?, - off50: Self::OFF50.from_data(data)?, - ts: Self::TS.from_data(data)?, - ms: Self::MS.from_data(data)?, - seq: Self::SEQ.from_data(data)?, - role: Self::ROLE.from_data(data)?, - alg: Self::ALG.from_data(data)?, - n: Self::N.from_data(data)?, - }) +impl crate::Group for Model3 { + const LEN: u16 = 58; +} +impl Model3 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + x: Self::X.from_data(data)?, + off1: Self::OFF1.from_data(data)?, + off2: Self::OFF2.from_data(data)?, + off3: Self::OFF3.from_data(data)?, + off4: Self::OFF4.from_data(data)?, + off5: Self::OFF5.from_data(data)?, + off6: Self::OFF6.from_data(data)?, + off7: Self::OFF7.from_data(data)?, + off8: Self::OFF8.from_data(data)?, + off9: Self::OFF9.from_data(data)?, + off10: Self::OFF10.from_data(data)?, + off11: Self::OFF11.from_data(data)?, + off12: Self::OFF12.from_data(data)?, + off13: Self::OFF13.from_data(data)?, + off14: Self::OFF14.from_data(data)?, + off15: Self::OFF15.from_data(data)?, + off16: Self::OFF16.from_data(data)?, + off17: Self::OFF17.from_data(data)?, + off18: Self::OFF18.from_data(data)?, + off19: Self::OFF19.from_data(data)?, + off20: Self::OFF20.from_data(data)?, + off21: Self::OFF21.from_data(data)?, + off22: Self::OFF22.from_data(data)?, + off23: Self::OFF23.from_data(data)?, + off24: Self::OFF24.from_data(data)?, + off25: Self::OFF25.from_data(data)?, + off26: Self::OFF26.from_data(data)?, + off27: Self::OFF27.from_data(data)?, + off28: Self::OFF28.from_data(data)?, + off29: Self::OFF29.from_data(data)?, + off30: Self::OFF30.from_data(data)?, + off31: Self::OFF31.from_data(data)?, + off32: Self::OFF32.from_data(data)?, + off33: Self::OFF33.from_data(data)?, + off34: Self::OFF34.from_data(data)?, + off35: Self::OFF35.from_data(data)?, + off36: Self::OFF36.from_data(data)?, + off37: Self::OFF37.from_data(data)?, + off38: Self::OFF38.from_data(data)?, + off39: Self::OFF39.from_data(data)?, + off40: Self::OFF40.from_data(data)?, + off41: Self::OFF41.from_data(data)?, + off42: Self::OFF42.from_data(data)?, + off43: Self::OFF43.from_data(data)?, + off44: Self::OFF44.from_data(data)?, + off45: Self::OFF45.from_data(data)?, + off46: Self::OFF46.from_data(data)?, + off47: Self::OFF47.from_data(data)?, + off48: Self::OFF48.from_data(data)?, + off49: Self::OFF49.from_data(data)?, + off50: Self::OFF50.from_data(data)?, + ts: Self::TS.from_data(data)?, + ms: Self::MS.from_data(data)?, + seq: Self::SEQ.from_data(data)?, + role: Self::ROLE.from_data(data)?, + alg: Self::ALG.from_data(data)?, + n: Self::N.from_data(data)?, + repeating: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m3 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) } } /// Algorithm @@ -319,3 +330,59 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + /// DS + /// + /// Digital Signature + pub ds: u16, +} +#[allow(missing_docs)] +impl Repeating { + pub const DS: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for Repeating { + const LEN: u16 = 1; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ds: Self::DS.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Model3, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Model3, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for Model3 { + const ID: u16 = 3; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m3 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model302.rs b/src/models/model302.rs index cab8b97..7e34412 100644 --- a/src/models/model302.rs +++ b/src/models/model302.rs @@ -1,18 +1,112 @@ //! Irradiance Model +pub type Model302 = Irradiance; /// Irradiance Model /// /// Include to support various irradiance measurements #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model302 {} +pub struct Irradiance { + #[allow(missing_docs)] + pub repeating: Vec, +} #[allow(missing_docs)] -impl Model302 {} -impl crate::Model for Model302 { - const ID: u16 = 302; - fn from_data(#[allow(unused)] data: &[u16]) -> Result { - Ok(Self {}) +impl Irradiance {} +impl crate::Group for Irradiance { + const LEN: u16 = 0; +} +impl Irradiance { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + repeating: Vec::new(), + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) + } +} +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + /// GHI + /// + /// Global Horizontal Irradiance + pub ghi: Option, + /// POAI + /// + /// Plane-of-Array Irradiance + pub poai: Option, + /// DFI + /// + /// Diffuse Irradiance + pub dfi: Option, + /// DNI + /// + /// Direct Normal Irradiance + pub dni: Option, + /// OTI + /// + /// Other Irradiance + pub oti: Option, +} +#[allow(missing_docs)] +impl Repeating { + pub const GHI: crate::Point> = crate::Point::new(0, 1, false); + pub const POAI: crate::Point> = crate::Point::new(1, 1, false); + pub const DFI: crate::Point> = crate::Point::new(2, 1, false); + pub const DNI: crate::Point> = crate::Point::new(3, 1, false); + pub const OTI: crate::Point> = crate::Point::new(4, 1, false); +} +impl crate::Group for Repeating { + const LEN: u16 = 5; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ghi: Self::GHI.from_data(data)?, + poai: Self::POAI.from_data(data)?, + dfi: Self::DFI.from_data(data)?, + dni: Self::DNI.from_data(data)?, + oti: Self::OTI.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Irradiance, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Irradiance, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for Irradiance { + const ID: u16 = 302; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m302 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model303.rs b/src/models/model303.rs index e939694..c389eb3 100644 --- a/src/models/model303.rs +++ b/src/models/model303.rs @@ -1,18 +1,86 @@ //! Back of Module Temperature Model +pub type Model303 = BomTemp; /// Back of Module Temperature Model /// /// Include to support variable number of back of module temperature measurements #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model303 {} +pub struct BomTemp { + #[allow(missing_docs)] + pub temp: Vec, +} #[allow(missing_docs)] -impl Model303 {} -impl crate::Model for Model303 { - const ID: u16 = 303; - fn from_data(#[allow(unused)] data: &[u16]) -> Result { - Ok(Self {}) +impl BomTemp {} +impl crate::Group for BomTemp { + const LEN: u16 = 0; +} +impl BomTemp { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { temp: Vec::new() }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.temp) = Temp::parse_multiple(data, &group)?; + Ok((data, group)) + } +} +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Temp { + /// Temp + /// + /// Back of module temperature measurement + pub tmp_bom: i16, +} +#[allow(missing_docs)] +impl Temp { + pub const TMP_BOM: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for Temp { + const LEN: u16 = 1; +} +impl Temp { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + tmp_bom: Self::TMP_BOM.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &BomTemp, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &BomTemp, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Temp::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for BomTemp { + const ID: u16 = 303; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m303 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model304.rs b/src/models/model304.rs index 2280b93..87a06bf 100644 --- a/src/models/model304.rs +++ b/src/models/model304.rs @@ -1,18 +1,98 @@ //! Inclinometer Model +pub type Model304 = Inclinometer; /// Inclinometer Model /// /// Include to support orientation measurements #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model304 {} +pub struct Inclinometer { + #[allow(missing_docs)] + pub incl: Vec, +} #[allow(missing_docs)] -impl Model304 {} -impl crate::Model for Model304 { - const ID: u16 = 304; - fn from_data(#[allow(unused)] data: &[u16]) -> Result { - Ok(Self {}) +impl Inclinometer {} +impl crate::Group for Inclinometer { + const LEN: u16 = 0; +} +impl Inclinometer { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { incl: Vec::new() }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.incl) = Incl::parse_multiple(data, &group)?; + Ok((data, group)) + } +} +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Incl { + /// X + /// + /// X-Axis inclination + pub inclx: i32, + /// Y + /// + /// Y-Axis inclination + pub incly: Option, + /// Z + /// + /// Z-Axis inclination + pub inclz: Option, +} +#[allow(missing_docs)] +impl Incl { + pub const INCLX: crate::Point = crate::Point::new(0, 2, false); + pub const INCLY: crate::Point> = crate::Point::new(2, 2, false); + pub const INCLZ: crate::Point> = crate::Point::new(4, 2, false); +} +impl crate::Group for Incl { + const LEN: u16 = 6; +} +impl Incl { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + inclx: Self::INCLX.from_data(data)?, + incly: Self::INCLY.from_data(data)?, + inclz: Self::INCLZ.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Inclinometer, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Inclinometer, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Incl::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for Inclinometer { + const ID: u16 = 304; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m304 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model305.rs b/src/models/model305.rs index 67a9360..a88f27a 100644 --- a/src/models/model305.rs +++ b/src/models/model305.rs @@ -1,10 +1,11 @@ //! GPS +pub type Model305 = Location; /// GPS /// /// Include to support location measurements #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model305 { +pub struct Location { /// Tm /// /// UTC 24 hour time stamp to millisecond hhmmss.sssZ format @@ -31,7 +32,7 @@ pub struct Model305 { pub alt: Option, } #[allow(missing_docs)] -impl Model305 { +impl Location { pub const TM: crate::Point> = crate::Point::new(0, 6, false); pub const DATE: crate::Point> = crate::Point::new(6, 4, false); pub const LOC: crate::Point> = crate::Point::new(10, 20, false); @@ -39,19 +40,36 @@ impl Model305 { pub const LONG: crate::Point> = crate::Point::new(32, 2, false); pub const ALT: crate::Point> = crate::Point::new(34, 2, false); } -impl crate::Model for Model305 { - const ID: u16 = 305; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - tm: Self::TM.from_data(data)?, - date: Self::DATE.from_data(data)?, - loc: Self::LOC.from_data(data)?, - lat: Self::LAT.from_data(data)?, - long: Self::LONG.from_data(data)?, - alt: Self::ALT.from_data(data)?, - }) +impl crate::Group for Location { + const LEN: u16 = 36; +} +impl Location { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + tm: Self::TM.from_data(data)?, + date: Self::DATE.from_data(data)?, + loc: Self::LOC.from_data(data)?, + lat: Self::LAT.from_data(data)?, + long: Self::LONG.from_data(data)?, + alt: Self::ALT.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } +} +impl crate::Model for Location { + const ID: u16 = 305; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m305 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model306.rs b/src/models/model306.rs index 7cca378..1095644 100644 --- a/src/models/model306.rs +++ b/src/models/model306.rs @@ -1,10 +1,11 @@ //! Reference Point Model +pub type Model306 = RefPoint; /// Reference Point Model /// /// Include to support a standard reference point #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model306 { +pub struct RefPoint { /// GHI /// /// Global Horizontal Irradiance @@ -23,23 +24,40 @@ pub struct Model306 { pub tmp: Option, } #[allow(missing_docs)] -impl Model306 { +impl RefPoint { pub const GHI: crate::Point> = crate::Point::new(0, 1, false); pub const A: crate::Point> = crate::Point::new(1, 1, false); pub const V: crate::Point> = crate::Point::new(2, 1, false); pub const TMP: crate::Point> = crate::Point::new(3, 1, false); } -impl crate::Model for Model306 { - const ID: u16 = 306; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ghi: Self::GHI.from_data(data)?, - a: Self::A.from_data(data)?, - v: Self::V.from_data(data)?, - tmp: Self::TMP.from_data(data)?, - }) +impl crate::Group for RefPoint { + const LEN: u16 = 4; +} +impl RefPoint { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ghi: Self::GHI.from_data(data)?, + a: Self::A.from_data(data)?, + v: Self::V.from_data(data)?, + tmp: Self::TMP.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } +} +impl crate::Model for RefPoint { + const ID: u16 = 306; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m306 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model307.rs b/src/models/model307.rs index a9b452a..6bb4d7e 100644 --- a/src/models/model307.rs +++ b/src/models/model307.rs @@ -1,4 +1,5 @@ //! Base Met +pub type Model307 = BaseMet; /// Base Met /// /// Base Meteorological Model @@ -6,7 +7,7 @@ /// Detail: This model supersedes model 301 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model307 { +pub struct BaseMet { /// Ambient Temperature pub tmp_amb: Option, /// Relative Humidity @@ -33,7 +34,7 @@ pub struct Model307 { pub soil_wet: Option, } #[allow(missing_docs)] -impl Model307 { +impl BaseMet { pub const TMP_AMB: crate::Point> = crate::Point::new(0, 1, false); pub const RH: crate::Point> = crate::Point::new(1, 1, false); pub const PRES: crate::Point> = crate::Point::new(2, 1, false); @@ -46,24 +47,41 @@ impl Model307 { pub const SUR_WET: crate::Point> = crate::Point::new(9, 1, false); pub const SOIL_WET: crate::Point> = crate::Point::new(10, 1, false); } -impl crate::Model for Model307 { - const ID: u16 = 307; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - tmp_amb: Self::TMP_AMB.from_data(data)?, - rh: Self::RH.from_data(data)?, - pres: Self::PRES.from_data(data)?, - wnd_spd: Self::WND_SPD.from_data(data)?, - wnd_dir: Self::WND_DIR.from_data(data)?, - rain: Self::RAIN.from_data(data)?, - snw: Self::SNW.from_data(data)?, - ppt: Self::PPT.from_data(data)?, - elec_fld: Self::ELEC_FLD.from_data(data)?, - sur_wet: Self::SUR_WET.from_data(data)?, - soil_wet: Self::SOIL_WET.from_data(data)?, - }) +impl crate::Group for BaseMet { + const LEN: u16 = 11; +} +impl BaseMet { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + tmp_amb: Self::TMP_AMB.from_data(data)?, + rh: Self::RH.from_data(data)?, + pres: Self::PRES.from_data(data)?, + wnd_spd: Self::WND_SPD.from_data(data)?, + wnd_dir: Self::WND_DIR.from_data(data)?, + rain: Self::RAIN.from_data(data)?, + snw: Self::SNW.from_data(data)?, + ppt: Self::PPT.from_data(data)?, + elec_fld: Self::ELEC_FLD.from_data(data)?, + sur_wet: Self::SUR_WET.from_data(data)?, + soil_wet: Self::SOIL_WET.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } +} +impl crate::Model for BaseMet { + const ID: u16 = 307; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m307 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model308.rs b/src/models/model308.rs index d504aa6..903e63d 100644 --- a/src/models/model308.rs +++ b/src/models/model308.rs @@ -1,10 +1,11 @@ //! Mini Met Model +pub type Model308 = MiniMet; /// Mini Met Model /// /// Include to support a few basic measurements #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model308 { +pub struct MiniMet { /// GHI /// /// Global Horizontal Irradiance @@ -19,23 +20,40 @@ pub struct Model308 { pub wnd_spd: Option, } #[allow(missing_docs)] -impl Model308 { +impl MiniMet { pub const GHI: crate::Point> = crate::Point::new(0, 1, false); pub const TMP_BOM: crate::Point> = crate::Point::new(1, 1, false); pub const TMP_AMB: crate::Point> = crate::Point::new(2, 1, false); pub const WND_SPD: crate::Point> = crate::Point::new(3, 1, false); } -impl crate::Model for Model308 { - const ID: u16 = 308; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ghi: Self::GHI.from_data(data)?, - tmp_bom: Self::TMP_BOM.from_data(data)?, - tmp_amb: Self::TMP_AMB.from_data(data)?, - wnd_spd: Self::WND_SPD.from_data(data)?, - }) +impl crate::Group for MiniMet { + const LEN: u16 = 4; +} +impl MiniMet { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ghi: Self::GHI.from_data(data)?, + tmp_bom: Self::TMP_BOM.from_data(data)?, + tmp_amb: Self::TMP_AMB.from_data(data)?, + wnd_spd: Self::WND_SPD.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } +} +impl crate::Model for MiniMet { + const ID: u16 = 308; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m308 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model4.rs b/src/models/model4.rs index 179170e..285387b 100644 --- a/src/models/model4.rs +++ b/src/models/model4.rs @@ -153,6 +153,8 @@ pub struct Model4 { /// /// Detail: The value of N must be at least 4 (64 bits) pub n: u16, + #[allow(missing_docs)] + pub repeating: Vec, } #[allow(missing_docs)] impl Model4 { @@ -216,73 +218,82 @@ impl Model4 { pub const ALG: crate::Point = crate::Point::new(58, 1, false); pub const N: crate::Point = crate::Point::new(59, 1, false); } -impl crate::Model for Model4 { - const ID: u16 = 4; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - rq_seq: Self::RQ_SEQ.from_data(data)?, - sts: Self::STS.from_data(data)?, - x: Self::X.from_data(data)?, - val1: Self::VAL1.from_data(data)?, - val2: Self::VAL2.from_data(data)?, - val3: Self::VAL3.from_data(data)?, - val4: Self::VAL4.from_data(data)?, - val5: Self::VAL5.from_data(data)?, - val6: Self::VAL6.from_data(data)?, - val7: Self::VAL7.from_data(data)?, - val8: Self::VAL8.from_data(data)?, - val9: Self::VAL9.from_data(data)?, - val10: Self::VAL10.from_data(data)?, - val11: Self::VAL11.from_data(data)?, - val12: Self::VAL12.from_data(data)?, - val13: Self::VAL13.from_data(data)?, - val14: Self::VAL14.from_data(data)?, - val15: Self::VAL15.from_data(data)?, - val16: Self::VAL16.from_data(data)?, - val17: Self::VAL17.from_data(data)?, - val18: Self::VAL18.from_data(data)?, - val19: Self::VAL19.from_data(data)?, - val20: Self::VAL20.from_data(data)?, - val21: Self::VAL21.from_data(data)?, - val22: Self::VAL22.from_data(data)?, - val23: Self::VAL23.from_data(data)?, - val24: Self::VAL24.from_data(data)?, - val25: Self::VAL25.from_data(data)?, - val26: Self::VAL26.from_data(data)?, - val27: Self::VAL27.from_data(data)?, - val28: Self::VAL28.from_data(data)?, - val29: Self::VAL29.from_data(data)?, - val30: Self::VAL30.from_data(data)?, - val31: Self::VAL31.from_data(data)?, - val32: Self::VAL32.from_data(data)?, - val33: Self::VAL33.from_data(data)?, - val34: Self::VAL34.from_data(data)?, - val35: Self::VAL35.from_data(data)?, - val36: Self::VAL36.from_data(data)?, - val37: Self::VAL37.from_data(data)?, - val38: Self::VAL38.from_data(data)?, - val39: Self::VAL39.from_data(data)?, - val40: Self::VAL40.from_data(data)?, - val41: Self::VAL41.from_data(data)?, - val42: Self::VAL42.from_data(data)?, - val43: Self::VAL43.from_data(data)?, - val44: Self::VAL44.from_data(data)?, - val45: Self::VAL45.from_data(data)?, - val46: Self::VAL46.from_data(data)?, - val47: Self::VAL47.from_data(data)?, - val48: Self::VAL48.from_data(data)?, - val49: Self::VAL49.from_data(data)?, - val50: Self::VAL50.from_data(data)?, - ts: Self::TS.from_data(data)?, - ms: Self::MS.from_data(data)?, - seq: Self::SEQ.from_data(data)?, - alm: Self::ALM.from_data(data)?, - alg: Self::ALG.from_data(data)?, - n: Self::N.from_data(data)?, - }) +impl crate::Group for Model4 { + const LEN: u16 = 60; +} +impl Model4 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + rq_seq: Self::RQ_SEQ.from_data(data)?, + sts: Self::STS.from_data(data)?, + x: Self::X.from_data(data)?, + val1: Self::VAL1.from_data(data)?, + val2: Self::VAL2.from_data(data)?, + val3: Self::VAL3.from_data(data)?, + val4: Self::VAL4.from_data(data)?, + val5: Self::VAL5.from_data(data)?, + val6: Self::VAL6.from_data(data)?, + val7: Self::VAL7.from_data(data)?, + val8: Self::VAL8.from_data(data)?, + val9: Self::VAL9.from_data(data)?, + val10: Self::VAL10.from_data(data)?, + val11: Self::VAL11.from_data(data)?, + val12: Self::VAL12.from_data(data)?, + val13: Self::VAL13.from_data(data)?, + val14: Self::VAL14.from_data(data)?, + val15: Self::VAL15.from_data(data)?, + val16: Self::VAL16.from_data(data)?, + val17: Self::VAL17.from_data(data)?, + val18: Self::VAL18.from_data(data)?, + val19: Self::VAL19.from_data(data)?, + val20: Self::VAL20.from_data(data)?, + val21: Self::VAL21.from_data(data)?, + val22: Self::VAL22.from_data(data)?, + val23: Self::VAL23.from_data(data)?, + val24: Self::VAL24.from_data(data)?, + val25: Self::VAL25.from_data(data)?, + val26: Self::VAL26.from_data(data)?, + val27: Self::VAL27.from_data(data)?, + val28: Self::VAL28.from_data(data)?, + val29: Self::VAL29.from_data(data)?, + val30: Self::VAL30.from_data(data)?, + val31: Self::VAL31.from_data(data)?, + val32: Self::VAL32.from_data(data)?, + val33: Self::VAL33.from_data(data)?, + val34: Self::VAL34.from_data(data)?, + val35: Self::VAL35.from_data(data)?, + val36: Self::VAL36.from_data(data)?, + val37: Self::VAL37.from_data(data)?, + val38: Self::VAL38.from_data(data)?, + val39: Self::VAL39.from_data(data)?, + val40: Self::VAL40.from_data(data)?, + val41: Self::VAL41.from_data(data)?, + val42: Self::VAL42.from_data(data)?, + val43: Self::VAL43.from_data(data)?, + val44: Self::VAL44.from_data(data)?, + val45: Self::VAL45.from_data(data)?, + val46: Self::VAL46.from_data(data)?, + val47: Self::VAL47.from_data(data)?, + val48: Self::VAL48.from_data(data)?, + val49: Self::VAL49.from_data(data)?, + val50: Self::VAL50.from_data(data)?, + ts: Self::TS.from_data(data)?, + ms: Self::MS.from_data(data)?, + seq: Self::SEQ.from_data(data)?, + alm: Self::ALM.from_data(data)?, + alg: Self::ALG.from_data(data)?, + n: Self::N.from_data(data)?, + repeating: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m4 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) } } /// Status @@ -413,3 +424,59 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + /// DS + /// + /// Digital Signature + pub ds: u16, +} +#[allow(missing_docs)] +impl Repeating { + pub const DS: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for Repeating { + const LEN: u16 = 1; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ds: Self::DS.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Model4, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Model4, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for Model4 { + const ID: u16 = 4; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m4 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model401.rs b/src/models/model401.rs index 9f8ad09..49160a5 100644 --- a/src/models/model401.rs +++ b/src/models/model401.rs @@ -1,4 +1,5 @@ //! String Combiner (Current) +pub type Model401 = StringCombinerCurrent; /// String Combiner (Current) /// /// A basic string combiner @@ -6,7 +7,7 @@ /// Detail: This model is SUPERSEDED by model 403 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model401 { +pub struct StringCombinerCurrent { /// Current scale factor pub dca_sf: i16, /// Amp-hour scale factor @@ -45,9 +46,11 @@ pub struct Model401 { /// /// Internal operating temperature pub tmp: Option, + #[allow(missing_docs)] + pub string: Vec, } #[allow(missing_docs)] -impl Model401 { +impl StringCombinerCurrent { pub const DCA_SF: crate::Point = crate::Point::new(0, 1, false); pub const DC_AHR_SF: crate::Point> = crate::Point::new(1, 1, false); pub const DCV_SF: crate::Point> = crate::Point::new(2, 1, false); @@ -60,25 +63,34 @@ impl Model401 { pub const DCV: crate::Point> = crate::Point::new(12, 1, false); pub const TMP: crate::Point> = crate::Point::new(13, 1, false); } -impl crate::Model for Model401 { - const ID: u16 = 401; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - dca_sf: Self::DCA_SF.from_data(data)?, - dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, - dcv_sf: Self::DCV_SF.from_data(data)?, - dca_max: Self::DCA_MAX.from_data(data)?, - n: Self::N.from_data(data)?, - evt: Self::EVT.from_data(data)?, - evt_vnd: Self::EVT_VND.from_data(data)?, - dca: Self::DCA.from_data(data)?, - dc_ahr: Self::DC_AHR.from_data(data)?, - dcv: Self::DCV.from_data(data)?, - tmp: Self::TMP.from_data(data)?, - }) +impl crate::Group for StringCombinerCurrent { + const LEN: u16 = 14; +} +impl StringCombinerCurrent { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + dca_sf: Self::DCA_SF.from_data(data)?, + dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, + dcv_sf: Self::DCV_SF.from_data(data)?, + dca_max: Self::DCA_MAX.from_data(data)?, + n: Self::N.from_data(data)?, + evt: Self::EVT.from_data(data)?, + evt_vnd: Self::EVT_VND.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dc_ahr: Self::DC_AHR.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + tmp: Self::TMP.from_data(data)?, + string: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m401 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.string) = String::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -156,3 +168,159 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct String { + /// ID + /// + /// Uniquely identifies this input set + pub in_id: u16, + /// Input Event + /// + /// String Input Event Flags + pub in_evt: StringInEvt, + /// Input Event Vendor + /// + /// String Input Vendor Event Flags + pub in_evt_vnd: Option, + /// Amps + /// + /// String Input Current + pub in_dca: i16, + /// Amp-hours + /// + /// String Input Amp-Hours + pub in_dc_ahr: Option, +} +#[allow(missing_docs)] +impl String { + pub const IN_ID: crate::Point = crate::Point::new(0, 1, false); + pub const IN_EVT: crate::Point = crate::Point::new(1, 2, false); + pub const IN_EVT_VND: crate::Point> = + crate::Point::new(3, 2, false); + pub const IN_DCA: crate::Point = crate::Point::new(5, 1, false); + pub const IN_DC_AHR: crate::Point> = crate::Point::new(6, 2, false); +} +impl crate::Group for String { + const LEN: u16 = 8; +} +impl String { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + in_id: Self::IN_ID.from_data(data)?, + in_evt: Self::IN_EVT.from_data(data)?, + in_evt_vnd: Self::IN_EVT_VND.from_data(data)?, + in_dca: Self::IN_DCA.from_data(data)?, + in_dc_ahr: Self::IN_DC_AHR.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &StringCombinerCurrent, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &StringCombinerCurrent, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = String::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +bitflags::bitflags! { + #[doc = " Input Event"] #[doc = " "] #[doc = " String Input Event Flags"] + #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", + derive(::serde::Serialize, ::serde::Deserialize))] pub struct StringInEvt : u32 { + #[allow(missing_docs)] const LowVoltage = 1; #[allow(missing_docs)] const LowPower = + 2; #[allow(missing_docs)] const LowEfficiency = 4; #[allow(missing_docs)] const + Current = 8; #[allow(missing_docs)] const Voltage = 16; #[allow(missing_docs)] const + Power = 32; #[allow(missing_docs)] const Pr = 64; #[allow(missing_docs)] const + Disconnected = 128; #[allow(missing_docs)] const FuseFault = 256; + #[allow(missing_docs)] const CombinerFuseFault = 512; #[allow(missing_docs)] const + CombinerCabinetOpen = 1024; #[allow(missing_docs)] const Temp = 2048; + #[allow(missing_docs)] const Groundfault = 4096; #[allow(missing_docs)] const + ReversedPolarity = 8192; #[allow(missing_docs)] const Incompatible = 16384; + #[allow(missing_docs)] const CommError = 32768; #[allow(missing_docs)] const + InternalError = 65536; #[allow(missing_docs)] const Theft = 131072; + #[allow(missing_docs)] const ArcDetected = 262144; } +} +impl crate::Value for StringInEvt { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringInEvt::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Input Event Vendor"] #[doc = " "] #[doc = + " String Input Vendor Event Flags"] #[derive(Copy, Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub + struct StringInEvtVnd : u32 {} +} +impl crate::Value for StringInEvtVnd { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringInEvtVnd::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +impl crate::Model for StringCombinerCurrent { + const ID: u16 = 401; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m401 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model402.rs b/src/models/model402.rs index 27190c0..397c0dd 100644 --- a/src/models/model402.rs +++ b/src/models/model402.rs @@ -1,4 +1,5 @@ //! String Combiner (Advanced) +pub type Model402 = StringCombinerAdvanced; /// String Combiner (Advanced) /// /// An advanced string combiner @@ -6,7 +7,7 @@ /// Detail: This model is SUPERSEDED by model 404 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model402 { +pub struct StringCombinerAdvanced { /// Current scale factor pub dca_sf: i16, /// Amp-hour scale factor @@ -61,9 +62,11 @@ pub struct Model402 { /// /// Output energy pub dc_wh: u32, + #[allow(missing_docs)] + pub string: Vec, } #[allow(missing_docs)] -impl Model402 { +impl StringCombinerAdvanced { pub const DCA_SF: crate::Point = crate::Point::new(0, 1, false); pub const DC_AHR_SF: crate::Point> = crate::Point::new(1, 1, false); pub const DCV_SF: crate::Point> = crate::Point::new(2, 1, false); @@ -81,30 +84,39 @@ impl Model402 { pub const DCPR: crate::Point> = crate::Point::new(17, 1, false); pub const DC_WH: crate::Point = crate::Point::new(18, 2, false); } -impl crate::Model for Model402 { - const ID: u16 = 402; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - dca_sf: Self::DCA_SF.from_data(data)?, - dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, - dcv_sf: Self::DCV_SF.from_data(data)?, - dcw_sf: Self::DCW_SF.from_data(data)?, - dc_wh_sf: Self::DC_WH_SF.from_data(data)?, - dca_max: Self::DCA_MAX.from_data(data)?, - n: Self::N.from_data(data)?, - evt: Self::EVT.from_data(data)?, - evt_vnd: Self::EVT_VND.from_data(data)?, - dca: Self::DCA.from_data(data)?, - dc_ahr: Self::DC_AHR.from_data(data)?, - dcv: Self::DCV.from_data(data)?, - tmp: Self::TMP.from_data(data)?, - dcw: Self::DCW.from_data(data)?, - dcpr: Self::DCPR.from_data(data)?, - dc_wh: Self::DC_WH.from_data(data)?, - }) +impl crate::Group for StringCombinerAdvanced { + const LEN: u16 = 20; +} +impl StringCombinerAdvanced { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + dca_sf: Self::DCA_SF.from_data(data)?, + dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, + dcv_sf: Self::DCV_SF.from_data(data)?, + dcw_sf: Self::DCW_SF.from_data(data)?, + dc_wh_sf: Self::DC_WH_SF.from_data(data)?, + dca_max: Self::DCA_MAX.from_data(data)?, + n: Self::N.from_data(data)?, + evt: Self::EVT.from_data(data)?, + evt_vnd: Self::EVT_VND.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dc_ahr: Self::DC_AHR.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + tmp: Self::TMP.from_data(data)?, + dcw: Self::DCW.from_data(data)?, + dcpr: Self::DCPR.from_data(data)?, + dc_wh: Self::DC_WH.from_data(data)?, + string: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m402 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.string) = String::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -182,3 +194,188 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct String { + /// ID + /// + /// Uniquely identifies this input set + pub in_id: u16, + /// Input Event + /// + /// String Input Event Flags + pub in_evt: StringInEvt, + /// Vendor Event + /// + /// Bitmask value. Vendor defined events + pub evt_vnd: Option, + /// Amps + /// + /// String Input Current + pub in_dca: i16, + /// Amp-hours + /// + /// String Input Amp-Hours + pub in_dc_ahr: Option, + /// Voltage + /// + /// String Input Voltage + pub in_dcv: Option, + /// Watts + /// + /// String Input Power + pub in_dcw: Option, + /// Watt-hours + /// + /// String Input Energy + pub in_dc_wh: Option, + /// PR + /// + /// String Performance Ratio + pub in_dcpr: Option, + /// N + /// + /// Number of modules in this input string + pub in_n: Option, +} +#[allow(missing_docs)] +impl String { + pub const IN_ID: crate::Point = crate::Point::new(0, 1, false); + pub const IN_EVT: crate::Point = crate::Point::new(1, 2, false); + pub const EVT_VND: crate::Point> = crate::Point::new(3, 2, false); + pub const IN_DCA: crate::Point = crate::Point::new(5, 1, false); + pub const IN_DC_AHR: crate::Point> = crate::Point::new(6, 2, false); + pub const IN_DCV: crate::Point> = crate::Point::new(8, 1, false); + pub const IN_DCW: crate::Point> = crate::Point::new(9, 1, false); + pub const IN_DC_WH: crate::Point> = crate::Point::new(10, 2, false); + pub const IN_DCPR: crate::Point> = crate::Point::new(12, 1, false); + pub const IN_N: crate::Point> = crate::Point::new(13, 1, false); +} +impl crate::Group for String { + const LEN: u16 = 14; +} +impl String { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + in_id: Self::IN_ID.from_data(data)?, + in_evt: Self::IN_EVT.from_data(data)?, + evt_vnd: Self::EVT_VND.from_data(data)?, + in_dca: Self::IN_DCA.from_data(data)?, + in_dc_ahr: Self::IN_DC_AHR.from_data(data)?, + in_dcv: Self::IN_DCV.from_data(data)?, + in_dcw: Self::IN_DCW.from_data(data)?, + in_dc_wh: Self::IN_DC_WH.from_data(data)?, + in_dcpr: Self::IN_DCPR.from_data(data)?, + in_n: Self::IN_N.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &StringCombinerAdvanced, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &StringCombinerAdvanced, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = String::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +bitflags::bitflags! { + #[doc = " Input Event"] #[doc = " "] #[doc = " String Input Event Flags"] + #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", + derive(::serde::Serialize, ::serde::Deserialize))] pub struct StringInEvt : u32 { + #[allow(missing_docs)] const LowVoltage = 1; #[allow(missing_docs)] const LowPower = + 2; #[allow(missing_docs)] const LowEfficiency = 4; #[allow(missing_docs)] const + Current = 8; #[allow(missing_docs)] const Voltage = 16; #[allow(missing_docs)] const + Power = 32; #[allow(missing_docs)] const Pr = 64; #[allow(missing_docs)] const + Disconnected = 128; #[allow(missing_docs)] const FuseFault = 256; + #[allow(missing_docs)] const CombinerFuseFault = 512; #[allow(missing_docs)] const + CombinerCabinetOpen = 1024; #[allow(missing_docs)] const Temp = 2048; + #[allow(missing_docs)] const Groundfault = 4096; #[allow(missing_docs)] const + ReversedPolarity = 8192; #[allow(missing_docs)] const Incompatible = 16384; + #[allow(missing_docs)] const CommError = 32768; #[allow(missing_docs)] const + InternalError = 65536; #[allow(missing_docs)] const Theft = 131072; + #[allow(missing_docs)] const ArcDetected = 262144; } +} +impl crate::Value for StringInEvt { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringInEvt::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Vendor Event"] #[doc = " "] #[doc = + " Bitmask value. Vendor defined events"] #[derive(Copy, Clone, Debug, Eq, + PartialEq)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, + ::serde::Deserialize))] pub struct StringEvtVnd : u32 {} +} +impl crate::Value for StringEvtVnd { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringEvtVnd::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +impl crate::Model for StringCombinerAdvanced { + const ID: u16 = 402; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m402 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model403.rs b/src/models/model403.rs index 5233338..5fe5706 100644 --- a/src/models/model403.rs +++ b/src/models/model403.rs @@ -1,4 +1,5 @@ //! String Combiner (Current) +pub type Model403 = StringCombinerCurrentInput; /// String Combiner (Current) /// /// A basic string combiner model @@ -6,7 +7,7 @@ /// Detail: This model supersedes model 401 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model403 { +pub struct StringCombinerCurrentInput { /// Current scale factor pub dca_sf: i16, /// Amp-hour scale factor @@ -49,9 +50,11 @@ pub struct Model403 { pub in_dca_sf: Option, /// Amp-hour scale factor for inputs pub in_dc_ahr_sf: Option, + #[allow(missing_docs)] + pub string: Vec, } #[allow(missing_docs)] -impl Model403 { +impl StringCombinerCurrentInput { pub const DCA_SF: crate::Point = crate::Point::new(0, 1, false); pub const DC_AHR_SF: crate::Point> = crate::Point::new(1, 1, false); pub const DCV_SF: crate::Point> = crate::Point::new(2, 1, false); @@ -66,27 +69,36 @@ impl Model403 { pub const IN_DCA_SF: crate::Point> = crate::Point::new(14, 1, false); pub const IN_DC_AHR_SF: crate::Point> = crate::Point::new(15, 1, false); } -impl crate::Model for Model403 { - const ID: u16 = 403; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - dca_sf: Self::DCA_SF.from_data(data)?, - dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, - dcv_sf: Self::DCV_SF.from_data(data)?, - dca_max: Self::DCA_MAX.from_data(data)?, - n: Self::N.from_data(data)?, - evt: Self::EVT.from_data(data)?, - evt_vnd: Self::EVT_VND.from_data(data)?, - dca: Self::DCA.from_data(data)?, - dc_ahr: Self::DC_AHR.from_data(data)?, - dcv: Self::DCV.from_data(data)?, - tmp: Self::TMP.from_data(data)?, - in_dca_sf: Self::IN_DCA_SF.from_data(data)?, - in_dc_ahr_sf: Self::IN_DC_AHR_SF.from_data(data)?, - }) +impl crate::Group for StringCombinerCurrentInput { + const LEN: u16 = 16; +} +impl StringCombinerCurrentInput { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + dca_sf: Self::DCA_SF.from_data(data)?, + dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, + dcv_sf: Self::DCV_SF.from_data(data)?, + dca_max: Self::DCA_MAX.from_data(data)?, + n: Self::N.from_data(data)?, + evt: Self::EVT.from_data(data)?, + evt_vnd: Self::EVT_VND.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dc_ahr: Self::DC_AHR.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + tmp: Self::TMP.from_data(data)?, + in_dca_sf: Self::IN_DCA_SF.from_data(data)?, + in_dc_ahr_sf: Self::IN_DC_AHR_SF.from_data(data)?, + string: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m403 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.string) = String::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -164,3 +176,159 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct String { + /// ID + /// + /// Uniquely identifies this input set + pub in_id: u16, + /// Input Event + /// + /// String Input Event Flags + pub in_evt: StringInEvt, + /// Input Event Vendor + /// + /// String Input Vendor Event Flags + pub in_evt_vnd: Option, + /// Amps + /// + /// String Input Current + pub in_dca: i16, + /// Amp-hours + /// + /// String Input Amp-Hours + pub in_dc_ahr: Option, +} +#[allow(missing_docs)] +impl String { + pub const IN_ID: crate::Point = crate::Point::new(0, 1, false); + pub const IN_EVT: crate::Point = crate::Point::new(1, 2, false); + pub const IN_EVT_VND: crate::Point> = + crate::Point::new(3, 2, false); + pub const IN_DCA: crate::Point = crate::Point::new(5, 1, false); + pub const IN_DC_AHR: crate::Point> = crate::Point::new(6, 2, false); +} +impl crate::Group for String { + const LEN: u16 = 8; +} +impl String { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + in_id: Self::IN_ID.from_data(data)?, + in_evt: Self::IN_EVT.from_data(data)?, + in_evt_vnd: Self::IN_EVT_VND.from_data(data)?, + in_dca: Self::IN_DCA.from_data(data)?, + in_dc_ahr: Self::IN_DC_AHR.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &StringCombinerCurrentInput, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &StringCombinerCurrentInput, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = String::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +bitflags::bitflags! { + #[doc = " Input Event"] #[doc = " "] #[doc = " String Input Event Flags"] + #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", + derive(::serde::Serialize, ::serde::Deserialize))] pub struct StringInEvt : u32 { + #[allow(missing_docs)] const LowVoltage = 1; #[allow(missing_docs)] const LowPower = + 2; #[allow(missing_docs)] const LowEfficiency = 4; #[allow(missing_docs)] const + Current = 8; #[allow(missing_docs)] const Voltage = 16; #[allow(missing_docs)] const + Power = 32; #[allow(missing_docs)] const Pr = 64; #[allow(missing_docs)] const + Disconnected = 128; #[allow(missing_docs)] const FuseFault = 256; + #[allow(missing_docs)] const CombinerFuseFault = 512; #[allow(missing_docs)] const + CombinerCabinetOpen = 1024; #[allow(missing_docs)] const Temp = 2048; + #[allow(missing_docs)] const Groundfault = 4096; #[allow(missing_docs)] const + ReversedPolarity = 8192; #[allow(missing_docs)] const Incompatible = 16384; + #[allow(missing_docs)] const CommError = 32768; #[allow(missing_docs)] const + InternalError = 65536; #[allow(missing_docs)] const Theft = 131072; + #[allow(missing_docs)] const ArcDetected = 262144; } +} +impl crate::Value for StringInEvt { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringInEvt::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Input Event Vendor"] #[doc = " "] #[doc = + " String Input Vendor Event Flags"] #[derive(Copy, Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub + struct StringInEvtVnd : u32 {} +} +impl crate::Value for StringInEvtVnd { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringInEvtVnd::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +impl crate::Model for StringCombinerCurrentInput { + const ID: u16 = 403; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m403 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model404.rs b/src/models/model404.rs index 9fe4330..b3280d6 100644 --- a/src/models/model404.rs +++ b/src/models/model404.rs @@ -1,4 +1,5 @@ //! String Combiner (Advanced) +pub type Model404 = StringCombinerAdvancedInputs; /// String Combiner (Advanced) /// /// An advanced string combiner including voltage and energy measurements @@ -6,7 +7,7 @@ /// Detail: This model supersedes model 402 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model404 { +pub struct StringCombinerAdvancedInputs { /// Current scale factor pub dca_sf: i16, /// Amp-hour scale factor @@ -71,9 +72,11 @@ pub struct Model404 { pub in_dcw_sf: Option, /// Energy scale factor for inputs pub in_dc_wh_sf: Option, + #[allow(missing_docs)] + pub string: Vec, } #[allow(missing_docs)] -impl Model404 { +impl StringCombinerAdvancedInputs { pub const DCA_SF: crate::Point = crate::Point::new(0, 1, false); pub const DC_AHR_SF: crate::Point> = crate::Point::new(1, 1, false); pub const DCV_SF: crate::Point> = crate::Point::new(2, 1, false); @@ -96,35 +99,44 @@ impl Model404 { pub const IN_DCW_SF: crate::Point> = crate::Point::new(23, 1, false); pub const IN_DC_WH_SF: crate::Point> = crate::Point::new(24, 1, false); } -impl crate::Model for Model404 { - const ID: u16 = 404; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - dca_sf: Self::DCA_SF.from_data(data)?, - dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, - dcv_sf: Self::DCV_SF.from_data(data)?, - dcw_sf: Self::DCW_SF.from_data(data)?, - dc_wh_sf: Self::DC_WH_SF.from_data(data)?, - dca_max: Self::DCA_MAX.from_data(data)?, - n: Self::N.from_data(data)?, - evt: Self::EVT.from_data(data)?, - evt_vnd: Self::EVT_VND.from_data(data)?, - dca: Self::DCA.from_data(data)?, - dc_ahr: Self::DC_AHR.from_data(data)?, - dcv: Self::DCV.from_data(data)?, - tmp: Self::TMP.from_data(data)?, - dcw: Self::DCW.from_data(data)?, - dcpr: Self::DCPR.from_data(data)?, - dc_wh: Self::DC_WH.from_data(data)?, - in_dca_sf: Self::IN_DCA_SF.from_data(data)?, - in_dc_ahr_sf: Self::IN_DC_AHR_SF.from_data(data)?, - in_dcv_sf: Self::IN_DCV_SF.from_data(data)?, - in_dcw_sf: Self::IN_DCW_SF.from_data(data)?, - in_dc_wh_sf: Self::IN_DC_WH_SF.from_data(data)?, - }) +impl crate::Group for StringCombinerAdvancedInputs { + const LEN: u16 = 25; +} +impl StringCombinerAdvancedInputs { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + dca_sf: Self::DCA_SF.from_data(data)?, + dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, + dcv_sf: Self::DCV_SF.from_data(data)?, + dcw_sf: Self::DCW_SF.from_data(data)?, + dc_wh_sf: Self::DC_WH_SF.from_data(data)?, + dca_max: Self::DCA_MAX.from_data(data)?, + n: Self::N.from_data(data)?, + evt: Self::EVT.from_data(data)?, + evt_vnd: Self::EVT_VND.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dc_ahr: Self::DC_AHR.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + tmp: Self::TMP.from_data(data)?, + dcw: Self::DCW.from_data(data)?, + dcpr: Self::DCPR.from_data(data)?, + dc_wh: Self::DC_WH.from_data(data)?, + in_dca_sf: Self::IN_DCA_SF.from_data(data)?, + in_dc_ahr_sf: Self::IN_DC_AHR_SF.from_data(data)?, + in_dcv_sf: Self::IN_DCV_SF.from_data(data)?, + in_dcw_sf: Self::IN_DCW_SF.from_data(data)?, + in_dc_wh_sf: Self::IN_DC_WH_SF.from_data(data)?, + string: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m404 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.string) = String::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -202,3 +214,189 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct String { + /// ID + /// + /// Uniquely identifies this input set + pub in_id: u16, + /// Input Event + /// + /// String Input Event Flags + pub in_evt: StringInEvt, + /// Input Event Vendor + /// + /// String Input Vendor Event Flags + pub in_evt_vnd: Option, + /// Amps + /// + /// String Input Current + pub in_dca: i16, + /// Amp-hours + /// + /// String Input Amp-Hours + pub in_dc_ahr: Option, + /// Voltage + /// + /// String Input Voltage + pub in_dcv: Option, + /// Watts + /// + /// String Input Power + pub in_dcw: Option, + /// Watt-hours + /// + /// String Input Energy + pub in_dc_wh: Option, + /// PR + /// + /// String Performance Ratio + pub in_dcpr: Option, + /// N + /// + /// Number of modules in this input string + pub in_n: Option, +} +#[allow(missing_docs)] +impl String { + pub const IN_ID: crate::Point = crate::Point::new(0, 1, false); + pub const IN_EVT: crate::Point = crate::Point::new(1, 2, false); + pub const IN_EVT_VND: crate::Point> = + crate::Point::new(3, 2, false); + pub const IN_DCA: crate::Point = crate::Point::new(5, 1, false); + pub const IN_DC_AHR: crate::Point> = crate::Point::new(6, 2, false); + pub const IN_DCV: crate::Point> = crate::Point::new(8, 1, false); + pub const IN_DCW: crate::Point> = crate::Point::new(9, 1, false); + pub const IN_DC_WH: crate::Point> = crate::Point::new(10, 2, false); + pub const IN_DCPR: crate::Point> = crate::Point::new(12, 1, false); + pub const IN_N: crate::Point> = crate::Point::new(13, 1, false); +} +impl crate::Group for String { + const LEN: u16 = 14; +} +impl String { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + in_id: Self::IN_ID.from_data(data)?, + in_evt: Self::IN_EVT.from_data(data)?, + in_evt_vnd: Self::IN_EVT_VND.from_data(data)?, + in_dca: Self::IN_DCA.from_data(data)?, + in_dc_ahr: Self::IN_DC_AHR.from_data(data)?, + in_dcv: Self::IN_DCV.from_data(data)?, + in_dcw: Self::IN_DCW.from_data(data)?, + in_dc_wh: Self::IN_DC_WH.from_data(data)?, + in_dcpr: Self::IN_DCPR.from_data(data)?, + in_n: Self::IN_N.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &StringCombinerAdvancedInputs, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &StringCombinerAdvancedInputs, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = String::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +bitflags::bitflags! { + #[doc = " Input Event"] #[doc = " "] #[doc = " String Input Event Flags"] + #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", + derive(::serde::Serialize, ::serde::Deserialize))] pub struct StringInEvt : u32 { + #[allow(missing_docs)] const LowVoltage = 1; #[allow(missing_docs)] const LowPower = + 2; #[allow(missing_docs)] const LowEfficiency = 4; #[allow(missing_docs)] const + Current = 8; #[allow(missing_docs)] const Voltage = 16; #[allow(missing_docs)] const + Power = 32; #[allow(missing_docs)] const Pr = 64; #[allow(missing_docs)] const + Disconnected = 128; #[allow(missing_docs)] const FuseFault = 256; + #[allow(missing_docs)] const CombinerFuseFault = 512; #[allow(missing_docs)] const + CombinerCabinetOpen = 1024; #[allow(missing_docs)] const Temp = 2048; + #[allow(missing_docs)] const Groundfault = 4096; #[allow(missing_docs)] const + ReversedPolarity = 8192; #[allow(missing_docs)] const Incompatible = 16384; + #[allow(missing_docs)] const CommError = 32768; #[allow(missing_docs)] const + InternalError = 65536; #[allow(missing_docs)] const Theft = 131072; + #[allow(missing_docs)] const ArcDetected = 262144; } +} +impl crate::Value for StringInEvt { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringInEvt::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Input Event Vendor"] #[doc = " "] #[doc = + " String Input Vendor Event Flags"] #[derive(Copy, Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub + struct StringInEvtVnd : u32 {} +} +impl crate::Value for StringInEvtVnd { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringInEvtVnd::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +impl crate::Model for StringCombinerAdvancedInputs { + const ID: u16 = 404; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m404 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model5.rs b/src/models/model5.rs index ae5ea95..4f3062f 100644 --- a/src/models/model5.rs +++ b/src/models/model5.rs @@ -207,6 +207,8 @@ pub struct Model5 { /// /// Detail: The value of N must be at least 4 (64 bits) pub n: u16, + #[allow(missing_docs)] + pub repeating: Vec, } #[allow(missing_docs)] impl Model5 { @@ -298,101 +300,110 @@ impl Model5 { pub const ALG: crate::Point = crate::Point::new(86, 1, true); pub const N: crate::Point = crate::Point::new(87, 1, true); } -impl crate::Model for Model5 { - const ID: u16 = 5; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - x: Self::X.from_data(data)?, - off1: Self::OFF1.from_data(data)?, - val1: Self::VAL1.from_data(data)?, - off2: Self::OFF2.from_data(data)?, - val2: Self::VAL2.from_data(data)?, - off3: Self::OFF3.from_data(data)?, - val3: Self::VAL3.from_data(data)?, - off4: Self::OFF4.from_data(data)?, - val4: Self::VAL4.from_data(data)?, - off5: Self::OFF5.from_data(data)?, - val5: Self::VAL5.from_data(data)?, - off6: Self::OFF6.from_data(data)?, - val6: Self::VAL6.from_data(data)?, - off7: Self::OFF7.from_data(data)?, - val7: Self::VAL7.from_data(data)?, - off8: Self::OFF8.from_data(data)?, - val8: Self::VAL8.from_data(data)?, - off9: Self::OFF9.from_data(data)?, - val9: Self::VAL9.from_data(data)?, - off10: Self::OFF10.from_data(data)?, - val10: Self::VAL10.from_data(data)?, - off11: Self::OFF11.from_data(data)?, - val11: Self::VAL11.from_data(data)?, - off12: Self::OFF12.from_data(data)?, - val12: Self::VAL12.from_data(data)?, - off13: Self::OFF13.from_data(data)?, - val13: Self::VAL13.from_data(data)?, - off14: Self::OFF14.from_data(data)?, - val14: Self::VAL14.from_data(data)?, - off15: Self::OFF15.from_data(data)?, - val15: Self::VAL15.from_data(data)?, - off16: Self::OFF16.from_data(data)?, - val16: Self::VAL16.from_data(data)?, - off17: Self::OFF17.from_data(data)?, - val17: Self::VAL17.from_data(data)?, - off18: Self::OFF18.from_data(data)?, - val18: Self::VAL18.from_data(data)?, - off19: Self::OFF19.from_data(data)?, - val19: Self::VAL19.from_data(data)?, - off20: Self::OFF20.from_data(data)?, - val20: Self::VAL20.from_data(data)?, - off21: Self::OFF21.from_data(data)?, - val21: Self::VAL21.from_data(data)?, - off22: Self::OFF22.from_data(data)?, - val22: Self::VAL22.from_data(data)?, - off23: Self::OFF23.from_data(data)?, - val23: Self::VAL23.from_data(data)?, - off24: Self::OFF24.from_data(data)?, - val24: Self::VAL24.from_data(data)?, - off25: Self::OFF25.from_data(data)?, - val25: Self::VAL25.from_data(data)?, - off26: Self::OFF26.from_data(data)?, - val26: Self::VAL26.from_data(data)?, - off27: Self::OFF27.from_data(data)?, - val27: Self::VAL27.from_data(data)?, - off28: Self::OFF28.from_data(data)?, - val28: Self::VAL28.from_data(data)?, - off29: Self::OFF29.from_data(data)?, - val29: Self::VAL29.from_data(data)?, - off30: Self::OFF30.from_data(data)?, - val30: Self::VAL30.from_data(data)?, - off31: Self::OFF31.from_data(data)?, - val31: Self::VAL31.from_data(data)?, - off32: Self::OFF32.from_data(data)?, - val32: Self::VAL32.from_data(data)?, - off33: Self::OFF33.from_data(data)?, - val33: Self::VAL33.from_data(data)?, - off34: Self::OFF34.from_data(data)?, - val34: Self::VAL34.from_data(data)?, - off35: Self::OFF35.from_data(data)?, - val35: Self::VAL35.from_data(data)?, - off36: Self::OFF36.from_data(data)?, - val36: Self::VAL36.from_data(data)?, - off37: Self::OFF37.from_data(data)?, - val37: Self::VAL37.from_data(data)?, - off38: Self::OFF38.from_data(data)?, - val38: Self::VAL38.from_data(data)?, - off39: Self::OFF39.from_data(data)?, - val39: Self::VAL39.from_data(data)?, - off40: Self::OFF40.from_data(data)?, - val40: Self::VAL40.from_data(data)?, - ts: Self::TS.from_data(data)?, - ms: Self::MS.from_data(data)?, - seq: Self::SEQ.from_data(data)?, - role: Self::ROLE.from_data(data)?, - alg: Self::ALG.from_data(data)?, - n: Self::N.from_data(data)?, - }) +impl crate::Group for Model5 { + const LEN: u16 = 88; +} +impl Model5 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + x: Self::X.from_data(data)?, + off1: Self::OFF1.from_data(data)?, + val1: Self::VAL1.from_data(data)?, + off2: Self::OFF2.from_data(data)?, + val2: Self::VAL2.from_data(data)?, + off3: Self::OFF3.from_data(data)?, + val3: Self::VAL3.from_data(data)?, + off4: Self::OFF4.from_data(data)?, + val4: Self::VAL4.from_data(data)?, + off5: Self::OFF5.from_data(data)?, + val5: Self::VAL5.from_data(data)?, + off6: Self::OFF6.from_data(data)?, + val6: Self::VAL6.from_data(data)?, + off7: Self::OFF7.from_data(data)?, + val7: Self::VAL7.from_data(data)?, + off8: Self::OFF8.from_data(data)?, + val8: Self::VAL8.from_data(data)?, + off9: Self::OFF9.from_data(data)?, + val9: Self::VAL9.from_data(data)?, + off10: Self::OFF10.from_data(data)?, + val10: Self::VAL10.from_data(data)?, + off11: Self::OFF11.from_data(data)?, + val11: Self::VAL11.from_data(data)?, + off12: Self::OFF12.from_data(data)?, + val12: Self::VAL12.from_data(data)?, + off13: Self::OFF13.from_data(data)?, + val13: Self::VAL13.from_data(data)?, + off14: Self::OFF14.from_data(data)?, + val14: Self::VAL14.from_data(data)?, + off15: Self::OFF15.from_data(data)?, + val15: Self::VAL15.from_data(data)?, + off16: Self::OFF16.from_data(data)?, + val16: Self::VAL16.from_data(data)?, + off17: Self::OFF17.from_data(data)?, + val17: Self::VAL17.from_data(data)?, + off18: Self::OFF18.from_data(data)?, + val18: Self::VAL18.from_data(data)?, + off19: Self::OFF19.from_data(data)?, + val19: Self::VAL19.from_data(data)?, + off20: Self::OFF20.from_data(data)?, + val20: Self::VAL20.from_data(data)?, + off21: Self::OFF21.from_data(data)?, + val21: Self::VAL21.from_data(data)?, + off22: Self::OFF22.from_data(data)?, + val22: Self::VAL22.from_data(data)?, + off23: Self::OFF23.from_data(data)?, + val23: Self::VAL23.from_data(data)?, + off24: Self::OFF24.from_data(data)?, + val24: Self::VAL24.from_data(data)?, + off25: Self::OFF25.from_data(data)?, + val25: Self::VAL25.from_data(data)?, + off26: Self::OFF26.from_data(data)?, + val26: Self::VAL26.from_data(data)?, + off27: Self::OFF27.from_data(data)?, + val27: Self::VAL27.from_data(data)?, + off28: Self::OFF28.from_data(data)?, + val28: Self::VAL28.from_data(data)?, + off29: Self::OFF29.from_data(data)?, + val29: Self::VAL29.from_data(data)?, + off30: Self::OFF30.from_data(data)?, + val30: Self::VAL30.from_data(data)?, + off31: Self::OFF31.from_data(data)?, + val31: Self::VAL31.from_data(data)?, + off32: Self::OFF32.from_data(data)?, + val32: Self::VAL32.from_data(data)?, + off33: Self::OFF33.from_data(data)?, + val33: Self::VAL33.from_data(data)?, + off34: Self::OFF34.from_data(data)?, + val34: Self::VAL34.from_data(data)?, + off35: Self::OFF35.from_data(data)?, + val35: Self::VAL35.from_data(data)?, + off36: Self::OFF36.from_data(data)?, + val36: Self::VAL36.from_data(data)?, + off37: Self::OFF37.from_data(data)?, + val37: Self::VAL37.from_data(data)?, + off38: Self::OFF38.from_data(data)?, + val38: Self::VAL38.from_data(data)?, + off39: Self::OFF39.from_data(data)?, + val39: Self::VAL39.from_data(data)?, + off40: Self::OFF40.from_data(data)?, + val40: Self::VAL40.from_data(data)?, + ts: Self::TS.from_data(data)?, + ms: Self::MS.from_data(data)?, + seq: Self::SEQ.from_data(data)?, + role: Self::ROLE.from_data(data)?, + alg: Self::ALG.from_data(data)?, + n: Self::N.from_data(data)?, + repeating: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m5 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) } } /// Algorithm @@ -439,3 +450,59 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + /// DS + /// + /// Digital Signature + pub ds: u16, +} +#[allow(missing_docs)] +impl Repeating { + pub const DS: crate::Point = crate::Point::new(0, 1, true); +} +impl crate::Group for Repeating { + const LEN: u16 = 1; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ds: Self::DS.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Model5, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Model5, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for Model5 { + const ID: u16 = 5; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m5 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model501.rs b/src/models/model501.rs index 10128f0..ca28c73 100644 --- a/src/models/model501.rs +++ b/src/models/model501.rs @@ -1,4 +1,5 @@ //! Solar Module +pub type Model501 = SolarModuleFloat; /// Solar Module /// /// A solar module model supporting DC-DC converter @@ -6,7 +7,7 @@ /// Detail: Float #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model501 { +pub struct SolarModuleFloat { /// Status /// /// Enumerated value. Module Status Code @@ -77,7 +78,7 @@ pub struct Model501 { pub in_w: Option, } #[allow(missing_docs)] -impl Model501 { +impl SolarModuleFloat { pub const STAT: crate::Point = crate::Point::new(0, 1, false); pub const STAT_VEND: crate::Point> = crate::Point::new(1, 1, false); pub const EVT: crate::Point = crate::Point::new(2, 2, false); @@ -96,31 +97,38 @@ impl Model501 { pub const IN_WH: crate::Point> = crate::Point::new(27, 2, false); pub const IN_W: crate::Point> = crate::Point::new(29, 2, false); } -impl crate::Model for Model501 { - const ID: u16 = 501; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - stat: Self::STAT.from_data(data)?, - stat_vend: Self::STAT_VEND.from_data(data)?, - evt: Self::EVT.from_data(data)?, - evt_vend: Self::EVT_VEND.from_data(data)?, - ctl: Self::CTL.from_data(data)?, - ctl_vend: Self::CTL_VEND.from_data(data)?, - ctl_val: Self::CTL_VAL.from_data(data)?, - tms: Self::TMS.from_data(data)?, - out_a: Self::OUT_A.from_data(data)?, - out_v: Self::OUT_V.from_data(data)?, - out_wh: Self::OUT_WH.from_data(data)?, - out_w: Self::OUT_W.from_data(data)?, - tmp: Self::TMP.from_data(data)?, - in_a: Self::IN_A.from_data(data)?, - in_v: Self::IN_V.from_data(data)?, - in_wh: Self::IN_WH.from_data(data)?, - in_w: Self::IN_W.from_data(data)?, - }) +impl crate::Group for SolarModuleFloat { + const LEN: u16 = 31; +} +impl SolarModuleFloat { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + stat: Self::STAT.from_data(data)?, + stat_vend: Self::STAT_VEND.from_data(data)?, + evt: Self::EVT.from_data(data)?, + evt_vend: Self::EVT_VEND.from_data(data)?, + ctl: Self::CTL.from_data(data)?, + ctl_vend: Self::CTL_VEND.from_data(data)?, + ctl_val: Self::CTL_VAL.from_data(data)?, + tms: Self::TMS.from_data(data)?, + out_a: Self::OUT_A.from_data(data)?, + out_v: Self::OUT_V.from_data(data)?, + out_wh: Self::OUT_WH.from_data(data)?, + out_w: Self::OUT_W.from_data(data)?, + tmp: Self::TMP.from_data(data)?, + in_a: Self::IN_A.from_data(data)?, + in_v: Self::IN_V.from_data(data)?, + in_wh: Self::IN_WH.from_data(data)?, + in_w: Self::IN_W.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m501 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Status @@ -255,3 +263,13 @@ impl crate::Value for Option { } } } +impl crate::Model for SolarModuleFloat { + const ID: u16 = 501; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m501 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model502.rs b/src/models/model502.rs index 70cc876..64da9b6 100644 --- a/src/models/model502.rs +++ b/src/models/model502.rs @@ -1,4 +1,5 @@ //! Solar Module +pub type Model502 = SolarModule; /// Solar Module /// /// A solar module model supporting DC-DC converter @@ -6,7 +7,7 @@ /// Detail: Integer #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model502 { +pub struct SolarModule { /// Current scale factor pub a_sf: Option, /// Voltage scale factor @@ -85,7 +86,7 @@ pub struct Model502 { pub in_w: Option, } #[allow(missing_docs)] -impl Model502 { +impl SolarModule { pub const A_SF: crate::Point> = crate::Point::new(0, 1, false); pub const V_SF: crate::Point> = crate::Point::new(1, 1, false); pub const W_SF: crate::Point> = crate::Point::new(2, 1, false); @@ -108,35 +109,42 @@ impl Model502 { pub const IN_WH: crate::Point> = crate::Point::new(25, 2, false); pub const IN_W: crate::Point> = crate::Point::new(27, 1, false); } -impl crate::Model for Model502 { - const ID: u16 = 502; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - a_sf: Self::A_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - wh_sf: Self::WH_SF.from_data(data)?, - stat: Self::STAT.from_data(data)?, - stat_vend: Self::STAT_VEND.from_data(data)?, - evt: Self::EVT.from_data(data)?, - evt_vend: Self::EVT_VEND.from_data(data)?, - ctl: Self::CTL.from_data(data)?, - ctl_vend: Self::CTL_VEND.from_data(data)?, - ctl_val: Self::CTL_VAL.from_data(data)?, - tms: Self::TMS.from_data(data)?, - out_a: Self::OUT_A.from_data(data)?, - out_v: Self::OUT_V.from_data(data)?, - out_wh: Self::OUT_WH.from_data(data)?, - out_pw: Self::OUT_PW.from_data(data)?, - tmp: Self::TMP.from_data(data)?, - in_a: Self::IN_A.from_data(data)?, - in_v: Self::IN_V.from_data(data)?, - in_wh: Self::IN_WH.from_data(data)?, - in_w: Self::IN_W.from_data(data)?, - }) +impl crate::Group for SolarModule { + const LEN: u16 = 28; +} +impl SolarModule { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + a_sf: Self::A_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + wh_sf: Self::WH_SF.from_data(data)?, + stat: Self::STAT.from_data(data)?, + stat_vend: Self::STAT_VEND.from_data(data)?, + evt: Self::EVT.from_data(data)?, + evt_vend: Self::EVT_VEND.from_data(data)?, + ctl: Self::CTL.from_data(data)?, + ctl_vend: Self::CTL_VEND.from_data(data)?, + ctl_val: Self::CTL_VAL.from_data(data)?, + tms: Self::TMS.from_data(data)?, + out_a: Self::OUT_A.from_data(data)?, + out_v: Self::OUT_V.from_data(data)?, + out_wh: Self::OUT_WH.from_data(data)?, + out_pw: Self::OUT_PW.from_data(data)?, + tmp: Self::TMP.from_data(data)?, + in_a: Self::IN_A.from_data(data)?, + in_v: Self::IN_V.from_data(data)?, + in_wh: Self::IN_WH.from_data(data)?, + in_w: Self::IN_W.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m502 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Status @@ -271,3 +279,13 @@ impl crate::Value for Option { } } } +impl crate::Model for SolarModule { + const ID: u16 = 502; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m502 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model6.rs b/src/models/model6.rs index 81282d0..91f5484 100644 --- a/src/models/model6.rs +++ b/src/models/model6.rs @@ -211,6 +211,8 @@ pub struct Model6 { /// /// Detail: The value of N must be at least 4 (64 bits) pub n: u16, + #[allow(missing_docs)] + pub repeating: Vec, } #[allow(missing_docs)] impl Model6 { @@ -303,102 +305,111 @@ impl Model6 { pub const ALG: crate::Point = crate::Point::new(88, 1, true); pub const N: crate::Point = crate::Point::new(89, 1, true); } -impl crate::Model for Model6 { - const ID: u16 = 6; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - x: Self::X.from_data(data)?, - off: Self::OFF.from_data(data)?, - val1: Self::VAL1.from_data(data)?, - val2: Self::VAL2.from_data(data)?, - val3: Self::VAL3.from_data(data)?, - val4: Self::VAL4.from_data(data)?, - val5: Self::VAL5.from_data(data)?, - val6: Self::VAL6.from_data(data)?, - val7: Self::VAL7.from_data(data)?, - val8: Self::VAL8.from_data(data)?, - val9: Self::VAL9.from_data(data)?, - val10: Self::VAL10.from_data(data)?, - val11: Self::VAL11.from_data(data)?, - val12: Self::VAL12.from_data(data)?, - val13: Self::VAL13.from_data(data)?, - val14: Self::VAL14.from_data(data)?, - val15: Self::VAL15.from_data(data)?, - val16: Self::VAL16.from_data(data)?, - val17: Self::VAL17.from_data(data)?, - val18: Self::VAL18.from_data(data)?, - val19: Self::VAL19.from_data(data)?, - val20: Self::VAL20.from_data(data)?, - val21: Self::VAL21.from_data(data)?, - val22: Self::VAL22.from_data(data)?, - val23: Self::VAL23.from_data(data)?, - val24: Self::VAL24.from_data(data)?, - val25: Self::VAL25.from_data(data)?, - val26: Self::VAL26.from_data(data)?, - val27: Self::VAL27.from_data(data)?, - val28: Self::VAL28.from_data(data)?, - val29: Self::VAL29.from_data(data)?, - val30: Self::VAL30.from_data(data)?, - val31: Self::VAL31.from_data(data)?, - val32: Self::VAL32.from_data(data)?, - val33: Self::VAL33.from_data(data)?, - val34: Self::VAL34.from_data(data)?, - val35: Self::VAL35.from_data(data)?, - val36: Self::VAL36.from_data(data)?, - val37: Self::VAL37.from_data(data)?, - val38: Self::VAL38.from_data(data)?, - val39: Self::VAL39.from_data(data)?, - val40: Self::VAL40.from_data(data)?, - val41: Self::VAL41.from_data(data)?, - val42: Self::VAL42.from_data(data)?, - val43: Self::VAL43.from_data(data)?, - val44: Self::VAL44.from_data(data)?, - val45: Self::VAL45.from_data(data)?, - val46: Self::VAL46.from_data(data)?, - val47: Self::VAL47.from_data(data)?, - val48: Self::VAL48.from_data(data)?, - val49: Self::VAL49.from_data(data)?, - val50: Self::VAL50.from_data(data)?, - val51: Self::VAL51.from_data(data)?, - val52: Self::VAL52.from_data(data)?, - val53: Self::VAL53.from_data(data)?, - val54: Self::VAL54.from_data(data)?, - val55: Self::VAL55.from_data(data)?, - val56: Self::VAL56.from_data(data)?, - val57: Self::VAL57.from_data(data)?, - val58: Self::VAL58.from_data(data)?, - val59: Self::VAL59.from_data(data)?, - val60: Self::VAL60.from_data(data)?, - val61: Self::VAL61.from_data(data)?, - val62: Self::VAL62.from_data(data)?, - val63: Self::VAL63.from_data(data)?, - val64: Self::VAL64.from_data(data)?, - val65: Self::VAL65.from_data(data)?, - val66: Self::VAL66.from_data(data)?, - val67: Self::VAL67.from_data(data)?, - val68: Self::VAL68.from_data(data)?, - val69: Self::VAL69.from_data(data)?, - val70: Self::VAL70.from_data(data)?, - val71: Self::VAL71.from_data(data)?, - val72: Self::VAL72.from_data(data)?, - val73: Self::VAL73.from_data(data)?, - val74: Self::VAL74.from_data(data)?, - val75: Self::VAL75.from_data(data)?, - val76: Self::VAL76.from_data(data)?, - val77: Self::VAL77.from_data(data)?, - val78: Self::VAL78.from_data(data)?, - val79: Self::VAL79.from_data(data)?, - val80: Self::VAL80.from_data(data)?, - ts: Self::TS.from_data(data)?, - ms: Self::MS.from_data(data)?, - seq: Self::SEQ.from_data(data)?, - role: Self::ROLE.from_data(data)?, - alg: Self::ALG.from_data(data)?, - n: Self::N.from_data(data)?, - }) +impl crate::Group for Model6 { + const LEN: u16 = 90; +} +impl Model6 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + x: Self::X.from_data(data)?, + off: Self::OFF.from_data(data)?, + val1: Self::VAL1.from_data(data)?, + val2: Self::VAL2.from_data(data)?, + val3: Self::VAL3.from_data(data)?, + val4: Self::VAL4.from_data(data)?, + val5: Self::VAL5.from_data(data)?, + val6: Self::VAL6.from_data(data)?, + val7: Self::VAL7.from_data(data)?, + val8: Self::VAL8.from_data(data)?, + val9: Self::VAL9.from_data(data)?, + val10: Self::VAL10.from_data(data)?, + val11: Self::VAL11.from_data(data)?, + val12: Self::VAL12.from_data(data)?, + val13: Self::VAL13.from_data(data)?, + val14: Self::VAL14.from_data(data)?, + val15: Self::VAL15.from_data(data)?, + val16: Self::VAL16.from_data(data)?, + val17: Self::VAL17.from_data(data)?, + val18: Self::VAL18.from_data(data)?, + val19: Self::VAL19.from_data(data)?, + val20: Self::VAL20.from_data(data)?, + val21: Self::VAL21.from_data(data)?, + val22: Self::VAL22.from_data(data)?, + val23: Self::VAL23.from_data(data)?, + val24: Self::VAL24.from_data(data)?, + val25: Self::VAL25.from_data(data)?, + val26: Self::VAL26.from_data(data)?, + val27: Self::VAL27.from_data(data)?, + val28: Self::VAL28.from_data(data)?, + val29: Self::VAL29.from_data(data)?, + val30: Self::VAL30.from_data(data)?, + val31: Self::VAL31.from_data(data)?, + val32: Self::VAL32.from_data(data)?, + val33: Self::VAL33.from_data(data)?, + val34: Self::VAL34.from_data(data)?, + val35: Self::VAL35.from_data(data)?, + val36: Self::VAL36.from_data(data)?, + val37: Self::VAL37.from_data(data)?, + val38: Self::VAL38.from_data(data)?, + val39: Self::VAL39.from_data(data)?, + val40: Self::VAL40.from_data(data)?, + val41: Self::VAL41.from_data(data)?, + val42: Self::VAL42.from_data(data)?, + val43: Self::VAL43.from_data(data)?, + val44: Self::VAL44.from_data(data)?, + val45: Self::VAL45.from_data(data)?, + val46: Self::VAL46.from_data(data)?, + val47: Self::VAL47.from_data(data)?, + val48: Self::VAL48.from_data(data)?, + val49: Self::VAL49.from_data(data)?, + val50: Self::VAL50.from_data(data)?, + val51: Self::VAL51.from_data(data)?, + val52: Self::VAL52.from_data(data)?, + val53: Self::VAL53.from_data(data)?, + val54: Self::VAL54.from_data(data)?, + val55: Self::VAL55.from_data(data)?, + val56: Self::VAL56.from_data(data)?, + val57: Self::VAL57.from_data(data)?, + val58: Self::VAL58.from_data(data)?, + val59: Self::VAL59.from_data(data)?, + val60: Self::VAL60.from_data(data)?, + val61: Self::VAL61.from_data(data)?, + val62: Self::VAL62.from_data(data)?, + val63: Self::VAL63.from_data(data)?, + val64: Self::VAL64.from_data(data)?, + val65: Self::VAL65.from_data(data)?, + val66: Self::VAL66.from_data(data)?, + val67: Self::VAL67.from_data(data)?, + val68: Self::VAL68.from_data(data)?, + val69: Self::VAL69.from_data(data)?, + val70: Self::VAL70.from_data(data)?, + val71: Self::VAL71.from_data(data)?, + val72: Self::VAL72.from_data(data)?, + val73: Self::VAL73.from_data(data)?, + val74: Self::VAL74.from_data(data)?, + val75: Self::VAL75.from_data(data)?, + val76: Self::VAL76.from_data(data)?, + val77: Self::VAL77.from_data(data)?, + val78: Self::VAL78.from_data(data)?, + val79: Self::VAL79.from_data(data)?, + val80: Self::VAL80.from_data(data)?, + ts: Self::TS.from_data(data)?, + ms: Self::MS.from_data(data)?, + seq: Self::SEQ.from_data(data)?, + role: Self::ROLE.from_data(data)?, + alg: Self::ALG.from_data(data)?, + n: Self::N.from_data(data)?, + repeating: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m6 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) } } /// Algorithm @@ -445,3 +456,59 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + /// DS + /// + /// Digital Signature + pub ds: u16, +} +#[allow(missing_docs)] +impl Repeating { + pub const DS: crate::Point = crate::Point::new(0, 1, true); +} +impl crate::Group for Repeating { + const LEN: u16 = 1; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ds: Self::DS.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Model6, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Model6, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for Model6 { + const ID: u16 = 6; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m6 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model601.rs b/src/models/model601.rs index 8be1b05..1c687a8 100644 --- a/src/models/model601.rs +++ b/src/models/model601.rs @@ -1,4 +1,5 @@ //! Tracker Controller DRAFT 2 +pub type Model601 = TrackerController; /// Tracker Controller DRAFT 2 /// /// Monitors and controls multiple trackers @@ -6,7 +7,7 @@ /// Detail: Trackers may include GPS model 305 for location information #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model601 { +pub struct TrackerController { /// Controller /// /// Descriptive name for this control unit @@ -55,9 +56,11 @@ pub struct Model601 { /// /// Number of trackers being controlled. Size of repeating block. pub n: u16, + #[allow(missing_docs)] + pub tracker: Vec, } #[allow(missing_docs)] -impl Model601 { +impl TrackerController { pub const NAM: crate::Point> = crate::Point::new(0, 8, false); pub const TYP: crate::Point = crate::Point::new(8, 1, false); pub const DT_LOC: crate::Point> = crate::Point::new(9, 5, false); @@ -70,25 +73,34 @@ impl Model601 { pub const DGR_SF: crate::Point = crate::Point::new(24, 1, false); pub const N: crate::Point = crate::Point::new(25, 1, false); } -impl crate::Model for Model601 { - const ID: u16 = 601; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - nam: Self::NAM.from_data(data)?, - typ: Self::TYP.from_data(data)?, - dt_loc: Self::DT_LOC.from_data(data)?, - tm_loc: Self::TM_LOC.from_data(data)?, - day: Self::DAY.from_data(data)?, - glbl_el_ctl: Self::GLBL_EL_CTL.from_data(data)?, - glbl_az_ctl: Self::GLBL_AZ_CTL.from_data(data)?, - glbl_ctl: Self::GLBL_CTL.from_data(data)?, - glbl_alm: Self::GLBL_ALM.from_data(data)?, - dgr_sf: Self::DGR_SF.from_data(data)?, - n: Self::N.from_data(data)?, - }) +impl crate::Group for TrackerController { + const LEN: u16 = 26; +} +impl TrackerController { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + nam: Self::NAM.from_data(data)?, + typ: Self::TYP.from_data(data)?, + dt_loc: Self::DT_LOC.from_data(data)?, + tm_loc: Self::TM_LOC.from_data(data)?, + day: Self::DAY.from_data(data)?, + glbl_el_ctl: Self::GLBL_EL_CTL.from_data(data)?, + glbl_az_ctl: Self::GLBL_AZ_CTL.from_data(data)?, + glbl_ctl: Self::GLBL_CTL.from_data(data)?, + glbl_alm: Self::GLBL_ALM.from_data(data)?, + dgr_sf: Self::DGR_SF.from_data(data)?, + n: Self::N.from_data(data)?, + tracker: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m601 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.tracker) = Tracker::parse_multiple(data, &group)?; + Ok((data, group)) } } /// Type @@ -220,3 +232,182 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Tracker { + /// Tracker + /// + /// Descriptive name for this tracker unit + pub id: Option, + /// Target Elevation + /// + /// Auto target elevation in degrees from horizontal. Unimplemented for single axis azimuth tracker type + pub el_trgt: Option, + /// Target Azimuth + /// + /// Auto target azimuth in degrees from true north towards east. Unimplemented for single axis horizontal tracker type + pub az_trgt: Option, + /// Elevation + /// + /// Actual elevation position in degrees from horizontal. Unimplemented for single axis azimuth tracker type + pub el_pos: Option, + /// Azimuth + /// + /// Actual azimuth position in degrees from true north towards east. Unimplemented for single axis horizontal tracker type + pub az_pos: Option, + /// Manual Elevation + /// + /// Manual override target position of elevation in degrees from horizontal. Unimplemented for single axis azimuth tracker type + pub el_ctl: Option, + /// Manual Azimuth + /// + /// Manual override target position of azimuth in degrees from true north towards east. Unimplemented for single axis azimuth tracker type + pub az_ctl: Option, + /// Mode + /// + /// Control register. Normal operation is automatic. Operator can override the position by setting the ElCtl, AzCtl and enabling Manual operation. Entering calibration mode will revert to automatic operation after calibration is complete. + pub ctl: Option, + /// Alarm + /// + /// Tracker alarm conditions + pub alm: Option, +} +#[allow(missing_docs)] +impl Tracker { + pub const ID: crate::Point> = crate::Point::new(0, 8, false); + pub const EL_TRGT: crate::Point> = crate::Point::new(8, 2, false); + pub const AZ_TRGT: crate::Point> = crate::Point::new(10, 2, false); + pub const EL_POS: crate::Point> = crate::Point::new(12, 2, false); + pub const AZ_POS: crate::Point> = crate::Point::new(14, 2, false); + pub const EL_CTL: crate::Point> = crate::Point::new(16, 2, true); + pub const AZ_CTL: crate::Point> = crate::Point::new(18, 2, true); + pub const CTL: crate::Point> = crate::Point::new(20, 1, true); + pub const ALM: crate::Point> = crate::Point::new(21, 1, false); +} +impl crate::Group for Tracker { + const LEN: u16 = 22; +} +impl Tracker { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + id: Self::ID.from_data(data)?, + el_trgt: Self::EL_TRGT.from_data(data)?, + az_trgt: Self::AZ_TRGT.from_data(data)?, + el_pos: Self::EL_POS.from_data(data)?, + az_pos: Self::AZ_POS.from_data(data)?, + el_ctl: Self::EL_CTL.from_data(data)?, + az_ctl: Self::AZ_CTL.from_data(data)?, + ctl: Self::CTL.from_data(data)?, + alm: Self::ALM.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &TrackerController, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &TrackerController, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Tracker::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Mode +/// +/// Control register. Normal operation is automatic. Operator can override the position by setting the ElCtl, AzCtl and enabling Manual operation. Entering calibration mode will revert to automatic operation after calibration is complete. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum TrackerCtl { + #[allow(missing_docs)] + Automatic = 0, + #[allow(missing_docs)] + Manual = 1, + #[allow(missing_docs)] + Calibrate = 2, +} +impl crate::Value for TrackerCtl { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + TrackerCtl::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Alarm"] #[doc = " "] #[doc = " Tracker alarm conditions"] #[derive(Copy, + Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", + derive(::serde::Serialize, ::serde::Deserialize))] pub struct TrackerAlm : u16 { + #[allow(missing_docs)] const SetPoint = 1; #[allow(missing_docs)] const ObsEl = 2; + #[allow(missing_docs)] const ObsAz = 4; } +} +impl crate::Value for TrackerAlm { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535u16 { + Ok(Some(TrackerAlm::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535u16.encode() + } + } +} +impl crate::Model for TrackerController { + const ID: u16 = 601; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m601 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model63001.rs b/src/models/model63001.rs index 8d72922..71c2998 100644 --- a/src/models/model63001.rs +++ b/src/models/model63001.rs @@ -113,6 +113,8 @@ pub struct Model63001 { pub sunssf_6: Option, #[allow(missing_docs)] pub sunssf_7: Option, + #[allow(missing_docs)] + pub repeating: Vec, } #[allow(missing_docs)] impl Model63001 { @@ -178,69 +180,78 @@ impl Model63001 { pub const SUNSSF_6: crate::Point> = crate::Point::new(131, 1, false); pub const SUNSSF_7: crate::Point> = crate::Point::new(132, 1, false); } -impl crate::Model for Model63001 { - const ID: u16 = 63001; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - sunssf_1: Self::SUNSSF_1.from_data(data)?, - sunssf_2: Self::SUNSSF_2.from_data(data)?, - sunssf_3: Self::SUNSSF_3.from_data(data)?, - sunssf_4: Self::SUNSSF_4.from_data(data)?, - int16_1: Self::INT16_1.from_data(data)?, - int16_2: Self::INT16_2.from_data(data)?, - int16_3: Self::INT16_3.from_data(data)?, - int16_4: Self::INT16_4.from_data(data)?, - int16_5: Self::INT16_5.from_data(data)?, - int16_u: Self::INT16_U.from_data(data)?, - uint16_1: Self::UINT16_1.from_data(data)?, - uint16_2: Self::UINT16_2.from_data(data)?, - uint16_3: Self::UINT16_3.from_data(data)?, - uint16_4: Self::UINT16_4.from_data(data)?, - uint16_5: Self::UINT16_5.from_data(data)?, - uint16_u: Self::UINT16_U.from_data(data)?, - acc16: Self::ACC16.from_data(data)?, - acc16_u: Self::ACC16_U.from_data(data)?, - enum16: Self::ENUM16.from_data(data)?, - enum16_u: Self::ENUM16_U.from_data(data)?, - bitfield16: Self::BITFIELD16.from_data(data)?, - bitfield16_u: Self::BITFIELD16_U.from_data(data)?, - int32_1: Self::INT32_1.from_data(data)?, - int32_2: Self::INT32_2.from_data(data)?, - int32_3: Self::INT32_3.from_data(data)?, - int32_4: Self::INT32_4.from_data(data)?, - int32_5: Self::INT32_5.from_data(data)?, - int32_u: Self::INT32_U.from_data(data)?, - uint32_1: Self::UINT32_1.from_data(data)?, - uint32_2: Self::UINT32_2.from_data(data)?, - uint32_3: Self::UINT32_3.from_data(data)?, - uint32_4: Self::UINT32_4.from_data(data)?, - uint32_5: Self::UINT32_5.from_data(data)?, - uint32_u: Self::UINT32_U.from_data(data)?, - acc32: Self::ACC32.from_data(data)?, - acc32_u: Self::ACC32_U.from_data(data)?, - enum32: Self::ENUM32.from_data(data)?, - enum32_u: Self::ENUM32_U.from_data(data)?, - bitfield32: Self::BITFIELD32.from_data(data)?, - bitfield32_u: Self::BITFIELD32_U.from_data(data)?, - ipaddr: Self::IPADDR.from_data(data)?, - ipaddr_u: Self::IPADDR_U.from_data(data)?, - int64: Self::INT64.from_data(data)?, - int64_u: Self::INT64_U.from_data(data)?, - acc64: Self::ACC64.from_data(data)?, - acc64_u: Self::ACC64_U.from_data(data)?, - ipv6addr: Self::IPV6ADDR.from_data(data)?, - ipv6addr_u: Self::IPV6ADDR_U.from_data(data)?, - float32: Self::FLOAT32.from_data(data)?, - float32_u: Self::FLOAT32_U.from_data(data)?, - string: Self::STRING.from_data(data)?, - string_u: Self::STRING_U.from_data(data)?, - sunssf_5: Self::SUNSSF_5.from_data(data)?, - sunssf_6: Self::SUNSSF_6.from_data(data)?, - sunssf_7: Self::SUNSSF_7.from_data(data)?, - }) +impl crate::Group for Model63001 { + const LEN: u16 = 134; +} +impl Model63001 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + sunssf_1: Self::SUNSSF_1.from_data(data)?, + sunssf_2: Self::SUNSSF_2.from_data(data)?, + sunssf_3: Self::SUNSSF_3.from_data(data)?, + sunssf_4: Self::SUNSSF_4.from_data(data)?, + int16_1: Self::INT16_1.from_data(data)?, + int16_2: Self::INT16_2.from_data(data)?, + int16_3: Self::INT16_3.from_data(data)?, + int16_4: Self::INT16_4.from_data(data)?, + int16_5: Self::INT16_5.from_data(data)?, + int16_u: Self::INT16_U.from_data(data)?, + uint16_1: Self::UINT16_1.from_data(data)?, + uint16_2: Self::UINT16_2.from_data(data)?, + uint16_3: Self::UINT16_3.from_data(data)?, + uint16_4: Self::UINT16_4.from_data(data)?, + uint16_5: Self::UINT16_5.from_data(data)?, + uint16_u: Self::UINT16_U.from_data(data)?, + acc16: Self::ACC16.from_data(data)?, + acc16_u: Self::ACC16_U.from_data(data)?, + enum16: Self::ENUM16.from_data(data)?, + enum16_u: Self::ENUM16_U.from_data(data)?, + bitfield16: Self::BITFIELD16.from_data(data)?, + bitfield16_u: Self::BITFIELD16_U.from_data(data)?, + int32_1: Self::INT32_1.from_data(data)?, + int32_2: Self::INT32_2.from_data(data)?, + int32_3: Self::INT32_3.from_data(data)?, + int32_4: Self::INT32_4.from_data(data)?, + int32_5: Self::INT32_5.from_data(data)?, + int32_u: Self::INT32_U.from_data(data)?, + uint32_1: Self::UINT32_1.from_data(data)?, + uint32_2: Self::UINT32_2.from_data(data)?, + uint32_3: Self::UINT32_3.from_data(data)?, + uint32_4: Self::UINT32_4.from_data(data)?, + uint32_5: Self::UINT32_5.from_data(data)?, + uint32_u: Self::UINT32_U.from_data(data)?, + acc32: Self::ACC32.from_data(data)?, + acc32_u: Self::ACC32_U.from_data(data)?, + enum32: Self::ENUM32.from_data(data)?, + enum32_u: Self::ENUM32_U.from_data(data)?, + bitfield32: Self::BITFIELD32.from_data(data)?, + bitfield32_u: Self::BITFIELD32_U.from_data(data)?, + ipaddr: Self::IPADDR.from_data(data)?, + ipaddr_u: Self::IPADDR_U.from_data(data)?, + int64: Self::INT64.from_data(data)?, + int64_u: Self::INT64_U.from_data(data)?, + acc64: Self::ACC64.from_data(data)?, + acc64_u: Self::ACC64_U.from_data(data)?, + ipv6addr: Self::IPV6ADDR.from_data(data)?, + ipv6addr_u: Self::IPV6ADDR_U.from_data(data)?, + float32: Self::FLOAT32.from_data(data)?, + float32_u: Self::FLOAT32_U.from_data(data)?, + string: Self::STRING.from_data(data)?, + string_u: Self::STRING_U.from_data(data)?, + sunssf_5: Self::SUNSSF_5.from_data(data)?, + sunssf_6: Self::SUNSSF_6.from_data(data)?, + sunssf_7: Self::SUNSSF_7.from_data(data)?, + repeating: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m63001 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -367,3 +378,105 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + #[allow(missing_docs)] + pub sunssf_8: Option, + #[allow(missing_docs)] + pub int16_11: Option, + #[allow(missing_docs)] + pub int16_12: Option, + #[allow(missing_docs)] + pub int16_u: Option, + #[allow(missing_docs)] + pub uint16_11: Option, + #[allow(missing_docs)] + pub uint16_12: Option, + #[allow(missing_docs)] + pub uint16_13: Option, + #[allow(missing_docs)] + pub uint16_u: Option, + #[allow(missing_docs)] + pub int32: Option, + #[allow(missing_docs)] + pub int32_u: Option, + #[allow(missing_docs)] + pub uint32: Option, + #[allow(missing_docs)] + pub uint32_u: Option, + #[allow(missing_docs)] + pub sunssf_9: Option, +} +#[allow(missing_docs)] +impl Repeating { + pub const SUNSSF_8: crate::Point> = crate::Point::new(0, 1, false); + pub const INT16_11: crate::Point> = crate::Point::new(1, 1, true); + pub const INT16_12: crate::Point> = crate::Point::new(2, 1, false); + pub const INT16_U: crate::Point> = crate::Point::new(3, 1, false); + pub const UINT16_11: crate::Point> = crate::Point::new(4, 1, true); + pub const UINT16_12: crate::Point> = crate::Point::new(5, 1, false); + pub const UINT16_13: crate::Point> = crate::Point::new(6, 1, false); + pub const UINT16_U: crate::Point> = crate::Point::new(7, 1, false); + pub const INT32: crate::Point> = crate::Point::new(8, 2, true); + pub const INT32_U: crate::Point> = crate::Point::new(10, 2, false); + pub const UINT32: crate::Point> = crate::Point::new(12, 2, true); + pub const UINT32_U: crate::Point> = crate::Point::new(14, 2, false); + pub const SUNSSF_9: crate::Point> = crate::Point::new(16, 1, false); +} +impl crate::Group for Repeating { + const LEN: u16 = 18; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + sunssf_8: Self::SUNSSF_8.from_data(data)?, + int16_11: Self::INT16_11.from_data(data)?, + int16_12: Self::INT16_12.from_data(data)?, + int16_u: Self::INT16_U.from_data(data)?, + uint16_11: Self::UINT16_11.from_data(data)?, + uint16_12: Self::UINT16_12.from_data(data)?, + uint16_13: Self::UINT16_13.from_data(data)?, + uint16_u: Self::UINT16_U.from_data(data)?, + int32: Self::INT32.from_data(data)?, + int32_u: Self::INT32_U.from_data(data)?, + uint32: Self::UINT32.from_data(data)?, + uint32_u: Self::UINT32_U.from_data(data)?, + sunssf_9: Self::SUNSSF_9.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Model63001, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Model63001, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for Model63001 { + const ID: u16 = 63001; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m63001 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model63002.rs b/src/models/model63002.rs index 3761526..750819e 100644 --- a/src/models/model63002.rs +++ b/src/models/model63002.rs @@ -2,15 +2,94 @@ /// SunSpec Test Model 2 #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model63002 {} +pub struct Model63002 { + #[allow(missing_docs)] + pub repeating: Vec, +} #[allow(missing_docs)] impl Model63002 {} +impl crate::Group for Model63002 { + const LEN: u16 = 0; +} +impl Model63002 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + repeating: Vec::new(), + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) + } +} +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + #[allow(missing_docs)] + pub sunssf_1: Option, + #[allow(missing_docs)] + pub int16_1: Option, + #[allow(missing_docs)] + pub int16_2: Option, + #[allow(missing_docs)] + pub sunssf_2: Option, +} +#[allow(missing_docs)] +impl Repeating { + pub const SUNSSF_1: crate::Point> = crate::Point::new(0, 1, false); + pub const INT16_1: crate::Point> = crate::Point::new(1, 1, true); + pub const INT16_2: crate::Point> = crate::Point::new(2, 1, false); + pub const SUNSSF_2: crate::Point> = crate::Point::new(3, 1, false); +} +impl crate::Group for Repeating { + const LEN: u16 = 4; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + sunssf_1: Self::SUNSSF_1.from_data(data)?, + int16_1: Self::INT16_1.from_data(data)?, + int16_2: Self::INT16_2.from_data(data)?, + sunssf_2: Self::SUNSSF_2.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Model63002, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Model63002, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} impl crate::Model for Model63002 { const ID: u16 = 63002; - fn from_data(#[allow(unused)] data: &[u16]) -> Result { - Ok(Self {}) - } fn addr(models: &crate::Models) -> crate::ModelAddr { models.m63002 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model64001.rs b/src/models/model64001.rs index 4c9284b..9557f47 100644 --- a/src/models/model64001.rs +++ b/src/models/model64001.rs @@ -112,49 +112,56 @@ impl Model64001 { pub const S4_VER: crate::Point> = crate::Point::new(64, 2, false); pub const S4_SERIAL: crate::Point> = crate::Point::new(66, 5, false); } -impl crate::Model for Model64001 { - const ID: u16 = 64001; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - cmd: Self::CMD.from_data(data)?, - hw_rev: Self::HW_REV.from_data(data)?, - rsfw_rev: Self::RSFW_REV.from_data(data)?, - osfw_rev: Self::OSFW_REV.from_data(data)?, - prod_rev: Self::PROD_REV.from_data(data)?, - boots: Self::BOOTS.from_data(data)?, - switch: Self::SWITCH.from_data(data)?, - sensors: Self::SENSORS.from_data(data)?, - talking: Self::TALKING.from_data(data)?, - status: Self::STATUS.from_data(data)?, - config: Self::CONFIG.from_data(data)?, - le_dblink: Self::LE_DBLINK.from_data(data)?, - le_don: Self::LE_DON.from_data(data)?, - reserved: Self::RESERVED.from_data(data)?, - loc: Self::LOC.from_data(data)?, - s1id: Self::S1ID.from_data(data)?, - s1_addr: Self::S1_ADDR.from_data(data)?, - s1os_ver: Self::S1OS_VER.from_data(data)?, - s1_ver: Self::S1_VER.from_data(data)?, - s1_serial: Self::S1_SERIAL.from_data(data)?, - s2id: Self::S2ID.from_data(data)?, - s2_addr: Self::S2_ADDR.from_data(data)?, - s2os_ver: Self::S2OS_VER.from_data(data)?, - s2_ver: Self::S2_VER.from_data(data)?, - s2_serial: Self::S2_SERIAL.from_data(data)?, - s3id: Self::S3ID.from_data(data)?, - s3_addr: Self::S3_ADDR.from_data(data)?, - s3os_ver: Self::S3OS_VER.from_data(data)?, - s3_ver: Self::S3_VER.from_data(data)?, - s3_serial: Self::S3_SERIAL.from_data(data)?, - s4id: Self::S4ID.from_data(data)?, - s4_addr: Self::S4_ADDR.from_data(data)?, - s4os_ver: Self::S4OS_VER.from_data(data)?, - s4_ver: Self::S4_VER.from_data(data)?, - s4_serial: Self::S4_SERIAL.from_data(data)?, - }) +impl crate::Group for Model64001 { + const LEN: u16 = 71; +} +impl Model64001 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + cmd: Self::CMD.from_data(data)?, + hw_rev: Self::HW_REV.from_data(data)?, + rsfw_rev: Self::RSFW_REV.from_data(data)?, + osfw_rev: Self::OSFW_REV.from_data(data)?, + prod_rev: Self::PROD_REV.from_data(data)?, + boots: Self::BOOTS.from_data(data)?, + switch: Self::SWITCH.from_data(data)?, + sensors: Self::SENSORS.from_data(data)?, + talking: Self::TALKING.from_data(data)?, + status: Self::STATUS.from_data(data)?, + config: Self::CONFIG.from_data(data)?, + le_dblink: Self::LE_DBLINK.from_data(data)?, + le_don: Self::LE_DON.from_data(data)?, + reserved: Self::RESERVED.from_data(data)?, + loc: Self::LOC.from_data(data)?, + s1id: Self::S1ID.from_data(data)?, + s1_addr: Self::S1_ADDR.from_data(data)?, + s1os_ver: Self::S1OS_VER.from_data(data)?, + s1_ver: Self::S1_VER.from_data(data)?, + s1_serial: Self::S1_SERIAL.from_data(data)?, + s2id: Self::S2ID.from_data(data)?, + s2_addr: Self::S2_ADDR.from_data(data)?, + s2os_ver: Self::S2OS_VER.from_data(data)?, + s2_ver: Self::S2_VER.from_data(data)?, + s2_serial: Self::S2_SERIAL.from_data(data)?, + s3id: Self::S3ID.from_data(data)?, + s3_addr: Self::S3_ADDR.from_data(data)?, + s3os_ver: Self::S3OS_VER.from_data(data)?, + s3_ver: Self::S3_VER.from_data(data)?, + s3_serial: Self::S3_SERIAL.from_data(data)?, + s4id: Self::S4ID.from_data(data)?, + s4_addr: Self::S4_ADDR.from_data(data)?, + s4os_ver: Self::S4OS_VER.from_data(data)?, + s4_ver: Self::S4_VER.from_data(data)?, + s4_serial: Self::S4_SERIAL.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m64001 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -250,3 +257,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Model64001 { + const ID: u16 = 64001; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m64001 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model64020.rs b/src/models/model64020.rs index f774daf..18d4d69 100644 --- a/src/models/model64020.rs +++ b/src/models/model64020.rs @@ -97,6 +97,8 @@ pub struct Model64020 { /// /// always 0 in reading, used the code 0xC0DA during the writing for resetting the system pub reset: Option, + #[allow(missing_docs)] + pub repeating: Vec, } #[allow(missing_docs)] impl Model64020 { @@ -131,43 +133,118 @@ impl Model64020 { pub const RESET_ACCUMULATORS: crate::Point> = crate::Point::new(28, 1, false); pub const RESET: crate::Point> = crate::Point::new(29, 1, false); } +impl crate::Group for Model64020 { + const LEN: u16 = 30; +} +impl Model64020 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + aux0_tmp: Self::AUX0_TMP.from_data(data)?, + aux1_tmp: Self::AUX1_TMP.from_data(data)?, + aux2_tmp: Self::AUX2_TMP.from_data(data)?, + aux3_tmp: Self::AUX3_TMP.from_data(data)?, + aux4_tmp: Self::AUX4_TMP.from_data(data)?, + probe_tmp: Self::PROBE_TMP.from_data(data)?, + main_tmp: Self::MAIN_TMP.from_data(data)?, + sensor_v_sf: Self::SENSOR_V_SF.from_data(data)?, + sensor_a_sf: Self::SENSOR_A_SF.from_data(data)?, + sensor_hz_sf: Self::SENSOR_HZ_SF.from_data(data)?, + sensor1_voltage: Self::SENSOR1_VOLTAGE.from_data(data)?, + sensor2_voltage: Self::SENSOR2_VOLTAGE.from_data(data)?, + sensor3_voltage: Self::SENSOR3_VOLTAGE.from_data(data)?, + sensor4_voltage: Self::SENSOR4_VOLTAGE.from_data(data)?, + sensor5_voltage: Self::SENSOR5_VOLTAGE.from_data(data)?, + sensor6_voltage: Self::SENSOR6_VOLTAGE.from_data(data)?, + sensor7_voltage: Self::SENSOR7_VOLTAGE.from_data(data)?, + sensor1_current: Self::SENSOR1_CURRENT.from_data(data)?, + sensor2_current: Self::SENSOR2_CURRENT.from_data(data)?, + sensor3_current: Self::SENSOR3_CURRENT.from_data(data)?, + sensor4_current: Self::SENSOR4_CURRENT.from_data(data)?, + sensor5_current: Self::SENSOR5_CURRENT.from_data(data)?, + sensor6_current: Self::SENSOR6_CURRENT.from_data(data)?, + sensor7_current: Self::SENSOR7_CURRENT.from_data(data)?, + sensor8: Self::SENSOR8.from_data(data)?, + relay1: Self::RELAY1.from_data(data)?, + relay2: Self::RELAY2.from_data(data)?, + relay3: Self::RELAY3.from_data(data)?, + reset_accumulators: Self::RESET_ACCUMULATORS.from_data(data)?, + reset: Self::RESET.from_data(data)?, + repeating: Vec::new(), + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) + } +} +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + /// Serial number + /// + /// strings of 16 characters + pub serial_number: String, + /// Firmware version + /// + /// string of 11 characters + pub firmware: String, + /// Hardware version + pub hardware: u16, +} +#[allow(missing_docs)] +impl Repeating { + pub const SERIAL_NUMBER: crate::Point = crate::Point::new(0, 9, false); + pub const FIRMWARE: crate::Point = crate::Point::new(9, 6, false); + pub const HARDWARE: crate::Point = crate::Point::new(15, 1, false); +} +impl crate::Group for Repeating { + const LEN: u16 = 16; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + serial_number: Self::SERIAL_NUMBER.from_data(data)?, + firmware: Self::FIRMWARE.from_data(data)?, + hardware: Self::HARDWARE.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Model64020, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Model64020, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} impl crate::Model for Model64020 { const ID: u16 = 64020; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - aux0_tmp: Self::AUX0_TMP.from_data(data)?, - aux1_tmp: Self::AUX1_TMP.from_data(data)?, - aux2_tmp: Self::AUX2_TMP.from_data(data)?, - aux3_tmp: Self::AUX3_TMP.from_data(data)?, - aux4_tmp: Self::AUX4_TMP.from_data(data)?, - probe_tmp: Self::PROBE_TMP.from_data(data)?, - main_tmp: Self::MAIN_TMP.from_data(data)?, - sensor_v_sf: Self::SENSOR_V_SF.from_data(data)?, - sensor_a_sf: Self::SENSOR_A_SF.from_data(data)?, - sensor_hz_sf: Self::SENSOR_HZ_SF.from_data(data)?, - sensor1_voltage: Self::SENSOR1_VOLTAGE.from_data(data)?, - sensor2_voltage: Self::SENSOR2_VOLTAGE.from_data(data)?, - sensor3_voltage: Self::SENSOR3_VOLTAGE.from_data(data)?, - sensor4_voltage: Self::SENSOR4_VOLTAGE.from_data(data)?, - sensor5_voltage: Self::SENSOR5_VOLTAGE.from_data(data)?, - sensor6_voltage: Self::SENSOR6_VOLTAGE.from_data(data)?, - sensor7_voltage: Self::SENSOR7_VOLTAGE.from_data(data)?, - sensor1_current: Self::SENSOR1_CURRENT.from_data(data)?, - sensor2_current: Self::SENSOR2_CURRENT.from_data(data)?, - sensor3_current: Self::SENSOR3_CURRENT.from_data(data)?, - sensor4_current: Self::SENSOR4_CURRENT.from_data(data)?, - sensor5_current: Self::SENSOR5_CURRENT.from_data(data)?, - sensor6_current: Self::SENSOR6_CURRENT.from_data(data)?, - sensor7_current: Self::SENSOR7_CURRENT.from_data(data)?, - sensor8: Self::SENSOR8.from_data(data)?, - relay1: Self::RELAY1.from_data(data)?, - relay2: Self::RELAY2.from_data(data)?, - relay3: Self::RELAY3.from_data(data)?, - reset_accumulators: Self::RESET_ACCUMULATORS.from_data(data)?, - reset: Self::RESET.from_data(data)?, - }) - } fn addr(models: &crate::Models) -> crate::ModelAddr { models.m64020 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model64101.rs b/src/models/model64101.rs index 034d70a..d6f06d4 100644 --- a/src/models/model64101.rs +++ b/src/models/model64101.rs @@ -29,20 +29,37 @@ impl Model64101 { pub const ELTEK_RPS_COS_PHI_REF: crate::Point> = crate::Point::new(6, 1, false); } +impl crate::Group for Model64101 { + const LEN: u16 = 7; +} +impl Model64101 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + eltek_country_code: Self::ELTEK_COUNTRY_CODE.from_data(data)?, + eltek_feeding_phase: Self::ELTEK_FEEDING_PHASE.from_data(data)?, + eltek_apd_method: Self::ELTEK_APD_METHOD.from_data(data)?, + eltek_apd_power_ref: Self::ELTEK_APD_POWER_REF.from_data(data)?, + eltek_rps_method: Self::ELTEK_RPS_METHOD.from_data(data)?, + eltek_rps_q_ref: Self::ELTEK_RPS_Q_REF.from_data(data)?, + eltek_rps_cos_phi_ref: Self::ELTEK_RPS_COS_PHI_REF.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } +} impl crate::Model for Model64101 { const ID: u16 = 64101; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - eltek_country_code: Self::ELTEK_COUNTRY_CODE.from_data(data)?, - eltek_feeding_phase: Self::ELTEK_FEEDING_PHASE.from_data(data)?, - eltek_apd_method: Self::ELTEK_APD_METHOD.from_data(data)?, - eltek_apd_power_ref: Self::ELTEK_APD_POWER_REF.from_data(data)?, - eltek_rps_method: Self::ELTEK_RPS_METHOD.from_data(data)?, - eltek_rps_q_ref: Self::ELTEK_RPS_Q_REF.from_data(data)?, - eltek_rps_cos_phi_ref: Self::ELTEK_RPS_COS_PHI_REF.from_data(data)?, - }) - } fn addr(models: &crate::Models) -> crate::ModelAddr { models.m64101 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model64111.rs b/src/models/model64111.rs index a9d2e66..945262a 100644 --- a/src/models/model64111.rs +++ b/src/models/model64111.rs @@ -76,37 +76,44 @@ impl Model64111 { pub const LIFE_TIME_MAX_BATT: crate::Point = crate::Point::new(21, 1, false); pub const LIFE_TIME_MAX_VOC: crate::Point = crate::Point::new(22, 1, false); } -impl crate::Model for Model64111 { - const ID: u16 = 64111; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - port: Self::PORT.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - p_sf: Self::P_SF.from_data(data)?, - ah_sf: Self::AH_SF.from_data(data)?, - kwh_sf: Self::KWH_SF.from_data(data)?, - batt_v: Self::BATT_V.from_data(data)?, - array_v: Self::ARRAY_V.from_data(data)?, - output_a: Self::OUTPUT_A.from_data(data)?, - input_a: Self::INPUT_A.from_data(data)?, - charger_st: Self::CHARGER_ST.from_data(data)?, - output_w: Self::OUTPUT_W.from_data(data)?, - today_min_bat_v: Self::TODAY_MIN_BAT_V.from_data(data)?, - today_max_bat_v: Self::TODAY_MAX_BAT_V.from_data(data)?, - vocv: Self::VOCV.from_data(data)?, - today_max_voc: Self::TODAY_MAX_VOC.from_data(data)?, - todayk_wh_output: Self::TODAYK_WH_OUTPUT.from_data(data)?, - today_ah_output: Self::TODAY_AH_OUTPUT.from_data(data)?, - life_time_kwh_out: Self::LIFE_TIME_KWH_OUT.from_data(data)?, - life_time_ah_out: Self::LIFE_TIME_AH_OUT.from_data(data)?, - life_time_max_out: Self::LIFE_TIME_MAX_OUT.from_data(data)?, - life_time_max_batt: Self::LIFE_TIME_MAX_BATT.from_data(data)?, - life_time_max_voc: Self::LIFE_TIME_MAX_VOC.from_data(data)?, - }) +impl crate::Group for Model64111 { + const LEN: u16 = 23; +} +impl Model64111 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + port: Self::PORT.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + p_sf: Self::P_SF.from_data(data)?, + ah_sf: Self::AH_SF.from_data(data)?, + kwh_sf: Self::KWH_SF.from_data(data)?, + batt_v: Self::BATT_V.from_data(data)?, + array_v: Self::ARRAY_V.from_data(data)?, + output_a: Self::OUTPUT_A.from_data(data)?, + input_a: Self::INPUT_A.from_data(data)?, + charger_st: Self::CHARGER_ST.from_data(data)?, + output_w: Self::OUTPUT_W.from_data(data)?, + today_min_bat_v: Self::TODAY_MIN_BAT_V.from_data(data)?, + today_max_bat_v: Self::TODAY_MAX_BAT_V.from_data(data)?, + vocv: Self::VOCV.from_data(data)?, + today_max_voc: Self::TODAY_MAX_VOC.from_data(data)?, + todayk_wh_output: Self::TODAYK_WH_OUTPUT.from_data(data)?, + today_ah_output: Self::TODAY_AH_OUTPUT.from_data(data)?, + life_time_kwh_out: Self::LIFE_TIME_KWH_OUT.from_data(data)?, + life_time_ah_out: Self::LIFE_TIME_AH_OUT.from_data(data)?, + life_time_max_out: Self::LIFE_TIME_MAX_OUT.from_data(data)?, + life_time_max_batt: Self::LIFE_TIME_MAX_BATT.from_data(data)?, + life_time_max_voc: Self::LIFE_TIME_MAX_VOC.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m64111 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Operating State @@ -153,3 +160,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Model64111 { + const ID: u16 = 64111; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m64111 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model64112.rs b/src/models/model64112.rs index fb24c52..e463655 100644 --- a/src/models/model64112.rs +++ b/src/models/model64112.rs @@ -225,78 +225,91 @@ impl Model64112 { pub const CC_CONFIG_DATA_LOG_CLR_COMP: crate::Point = crate::Point::new(63, 1, false); } -impl crate::Model for Model64112 { - const ID: u16 = 64112; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - port: Self::PORT.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - c_sf: Self::C_SF.from_data(data)?, - h_sf: Self::H_SF.from_data(data)?, - p_sf: Self::P_SF.from_data(data)?, - ah_sf: Self::AH_SF.from_data(data)?, - kwh_sf: Self::KWH_SF.from_data(data)?, - cc_config_fault: Self::CC_CONFIG_FAULT.from_data(data)?, - cc_config_absorb_v: Self::CC_CONFIG_ABSORB_V.from_data(data)?, - cc_config_absorb_hr: Self::CC_CONFIG_ABSORB_HR.from_data(data)?, - cc_config_absorb_end_a: Self::CC_CONFIG_ABSORB_END_A.from_data(data)?, - cc_config_rebulk_v: Self::CC_CONFIG_REBULK_V.from_data(data)?, - cc_config_float_v: Self::CC_CONFIG_FLOAT_V.from_data(data)?, - cc_config_max_chg_a: Self::CC_CONFIG_MAX_CHG_A.from_data(data)?, - cc_config_equalize_v: Self::CC_CONFIG_EQUALIZE_V.from_data(data)?, - cc_config_equalize_hr: Self::CC_CONFIG_EQUALIZE_HR.from_data(data)?, - cc_config_auto_equalize: Self::CC_CONFIG_AUTO_EQUALIZE.from_data(data)?, - cc_config_mppt_mode: Self::CC_CONFIG_MPPT_MODE.from_data(data)?, - cc_config_sweep_width: Self::CC_CONFIG_SWEEP_WIDTH.from_data(data)?, - cc_config_sweep_max: Self::CC_CONFIG_SWEEP_MAX.from_data(data)?, - cc_config_u_pick_duty_cyc: Self::CC_CONFIG_U_PICK_DUTY_CYC.from_data(data)?, - cc_config_grid_tie: Self::CC_CONFIG_GRID_TIE.from_data(data)?, - cc_config_temp_comp: Self::CC_CONFIG_TEMP_COMP.from_data(data)?, - cc_config_temp_comp_llimt: Self::CC_CONFIG_TEMP_COMP_LLIMT.from_data(data)?, - cc_config_temp_comp_hlimt: Self::CC_CONFIG_TEMP_COMP_HLIMT.from_data(data)?, - cc_config_auto_restart: Self::CC_CONFIG_AUTO_RESTART.from_data(data)?, - cc_config_wakeup_voc: Self::CC_CONFIG_WAKEUP_VOC.from_data(data)?, - cc_config_snooze_mode_a: Self::CC_CONFIG_SNOOZE_MODE_A.from_data(data)?, - cc_config_wakeup_interval: Self::CC_CONFIG_WAKEUP_INTERVAL.from_data(data)?, - cc_config_aux_mode: Self::CC_CONFIG_AUX_MODE.from_data(data)?, - cc_config_aux_control: Self::CC_CONFIG_AUX_CONTROL.from_data(data)?, - cc_config_aux_state: Self::CC_CONFIG_AUX_STATE.from_data(data)?, - cc_config_aux_polarity: Self::CC_CONFIG_AUX_POLARITY.from_data(data)?, - cc_config_aux_l_batt_disc: Self::CC_CONFIG_AUX_L_BATT_DISC.from_data(data)?, - cc_config_aux_l_batt_rcon: Self::CC_CONFIG_AUX_L_BATT_RCON.from_data(data)?, - cc_config_aux_l_batt_dly: Self::CC_CONFIG_AUX_L_BATT_DLY.from_data(data)?, - cc_config_aux_vent_fan_v: Self::CC_CONFIG_AUX_VENT_FAN_V.from_data(data)?, - cc_config_aux_pv_trigger_v: Self::CC_CONFIG_AUX_PV_TRIGGER_V.from_data(data)?, - cc_config_aux_pv_trg_h_tm: Self::CC_CONFIG_AUX_PV_TRG_H_TM.from_data(data)?, - cc_config_aux_nlite_thrs_v: Self::CC_CONFIG_AUX_NLITE_THRS_V.from_data(data)?, - cc_config_aux_nlite_on_tm: Self::CC_CONFIG_AUX_NLITE_ON_TM.from_data(data)?, - cc_config_aux_nlite_on_hist: Self::CC_CONFIG_AUX_NLITE_ON_HIST.from_data(data)?, - cc_config_aux_nlite_off_hist: Self::CC_CONFIG_AUX_NLITE_OFF_HIST.from_data(data)?, - cc_config_aux_error_batt_v: Self::CC_CONFIG_AUX_ERROR_BATT_V.from_data(data)?, - cc_config_aux_divert_h_time: Self::CC_CONFIG_AUX_DIVERT_H_TIME.from_data(data)?, - cc_config_aux_divert_dly_time: Self::CC_CONFIG_AUX_DIVERT_DLY_TIME.from_data(data)?, - cc_config_aux_divert_rel_v: Self::CC_CONFIG_AUX_DIVERT_REL_V.from_data(data)?, - cc_config_aux_divert_hyst_v: Self::CC_CONFIG_AUX_DIVERT_HYST_V.from_data(data)?, - cc_config_major_fw_rev: Self::CC_CONFIG_MAJOR_FW_REV.from_data(data)?, - cc_config_mid_fw_rev: Self::CC_CONFIG_MID_FW_REV.from_data(data)?, - cc_config_minor_fw_rev: Self::CC_CONFIG_MINOR_FW_REV.from_data(data)?, - cc_config_data_log_day_offset: Self::CC_CONFIG_DATA_LOG_DAY_OFFSET.from_data(data)?, - cc_config_data_log_cur_day_off: Self::CC_CONFIG_DATA_LOG_CUR_DAY_OFF.from_data(data)?, - cc_config_data_log_daily_ah: Self::CC_CONFIG_DATA_LOG_DAILY_AH.from_data(data)?, - cc_config_data_log_daily_kwh: Self::CC_CONFIG_DATA_LOG_DAILY_KWH.from_data(data)?, - cc_config_data_log_max_out_a: Self::CC_CONFIG_DATA_LOG_MAX_OUT_A.from_data(data)?, - cc_config_data_log_max_out_w: Self::CC_CONFIG_DATA_LOG_MAX_OUT_W.from_data(data)?, - cc_config_data_log_absorb_t: Self::CC_CONFIG_DATA_LOG_ABSORB_T.from_data(data)?, - cc_config_data_log_float_t: Self::CC_CONFIG_DATA_LOG_FLOAT_T.from_data(data)?, - cc_config_data_log_min_batt_v: Self::CC_CONFIG_DATA_LOG_MIN_BATT_V.from_data(data)?, - cc_config_data_log_max_batt_v: Self::CC_CONFIG_DATA_LOG_MAX_BATT_V.from_data(data)?, - cc_config_data_log_max_input_v: Self::CC_CONFIG_DATA_LOG_MAX_INPUT_V.from_data(data)?, - cc_config_data_log_clear: Self::CC_CONFIG_DATA_LOG_CLEAR.from_data(data)?, - cc_config_data_log_clr_comp: Self::CC_CONFIG_DATA_LOG_CLR_COMP.from_data(data)?, - }) - } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m64112 +impl crate::Group for Model64112 { + const LEN: u16 = 64; +} +impl Model64112 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + port: Self::PORT.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + c_sf: Self::C_SF.from_data(data)?, + h_sf: Self::H_SF.from_data(data)?, + p_sf: Self::P_SF.from_data(data)?, + ah_sf: Self::AH_SF.from_data(data)?, + kwh_sf: Self::KWH_SF.from_data(data)?, + cc_config_fault: Self::CC_CONFIG_FAULT.from_data(data)?, + cc_config_absorb_v: Self::CC_CONFIG_ABSORB_V.from_data(data)?, + cc_config_absorb_hr: Self::CC_CONFIG_ABSORB_HR.from_data(data)?, + cc_config_absorb_end_a: Self::CC_CONFIG_ABSORB_END_A.from_data(data)?, + cc_config_rebulk_v: Self::CC_CONFIG_REBULK_V.from_data(data)?, + cc_config_float_v: Self::CC_CONFIG_FLOAT_V.from_data(data)?, + cc_config_max_chg_a: Self::CC_CONFIG_MAX_CHG_A.from_data(data)?, + cc_config_equalize_v: Self::CC_CONFIG_EQUALIZE_V.from_data(data)?, + cc_config_equalize_hr: Self::CC_CONFIG_EQUALIZE_HR.from_data(data)?, + cc_config_auto_equalize: Self::CC_CONFIG_AUTO_EQUALIZE.from_data(data)?, + cc_config_mppt_mode: Self::CC_CONFIG_MPPT_MODE.from_data(data)?, + cc_config_sweep_width: Self::CC_CONFIG_SWEEP_WIDTH.from_data(data)?, + cc_config_sweep_max: Self::CC_CONFIG_SWEEP_MAX.from_data(data)?, + cc_config_u_pick_duty_cyc: Self::CC_CONFIG_U_PICK_DUTY_CYC.from_data(data)?, + cc_config_grid_tie: Self::CC_CONFIG_GRID_TIE.from_data(data)?, + cc_config_temp_comp: Self::CC_CONFIG_TEMP_COMP.from_data(data)?, + cc_config_temp_comp_llimt: Self::CC_CONFIG_TEMP_COMP_LLIMT.from_data(data)?, + cc_config_temp_comp_hlimt: Self::CC_CONFIG_TEMP_COMP_HLIMT.from_data(data)?, + cc_config_auto_restart: Self::CC_CONFIG_AUTO_RESTART.from_data(data)?, + cc_config_wakeup_voc: Self::CC_CONFIG_WAKEUP_VOC.from_data(data)?, + cc_config_snooze_mode_a: Self::CC_CONFIG_SNOOZE_MODE_A.from_data(data)?, + cc_config_wakeup_interval: Self::CC_CONFIG_WAKEUP_INTERVAL.from_data(data)?, + cc_config_aux_mode: Self::CC_CONFIG_AUX_MODE.from_data(data)?, + cc_config_aux_control: Self::CC_CONFIG_AUX_CONTROL.from_data(data)?, + cc_config_aux_state: Self::CC_CONFIG_AUX_STATE.from_data(data)?, + cc_config_aux_polarity: Self::CC_CONFIG_AUX_POLARITY.from_data(data)?, + cc_config_aux_l_batt_disc: Self::CC_CONFIG_AUX_L_BATT_DISC.from_data(data)?, + cc_config_aux_l_batt_rcon: Self::CC_CONFIG_AUX_L_BATT_RCON.from_data(data)?, + cc_config_aux_l_batt_dly: Self::CC_CONFIG_AUX_L_BATT_DLY.from_data(data)?, + cc_config_aux_vent_fan_v: Self::CC_CONFIG_AUX_VENT_FAN_V.from_data(data)?, + cc_config_aux_pv_trigger_v: Self::CC_CONFIG_AUX_PV_TRIGGER_V.from_data(data)?, + cc_config_aux_pv_trg_h_tm: Self::CC_CONFIG_AUX_PV_TRG_H_TM.from_data(data)?, + cc_config_aux_nlite_thrs_v: Self::CC_CONFIG_AUX_NLITE_THRS_V.from_data(data)?, + cc_config_aux_nlite_on_tm: Self::CC_CONFIG_AUX_NLITE_ON_TM.from_data(data)?, + cc_config_aux_nlite_on_hist: Self::CC_CONFIG_AUX_NLITE_ON_HIST.from_data(data)?, + cc_config_aux_nlite_off_hist: Self::CC_CONFIG_AUX_NLITE_OFF_HIST.from_data(data)?, + cc_config_aux_error_batt_v: Self::CC_CONFIG_AUX_ERROR_BATT_V.from_data(data)?, + cc_config_aux_divert_h_time: Self::CC_CONFIG_AUX_DIVERT_H_TIME.from_data(data)?, + cc_config_aux_divert_dly_time: Self::CC_CONFIG_AUX_DIVERT_DLY_TIME + .from_data(data)?, + cc_config_aux_divert_rel_v: Self::CC_CONFIG_AUX_DIVERT_REL_V.from_data(data)?, + cc_config_aux_divert_hyst_v: Self::CC_CONFIG_AUX_DIVERT_HYST_V.from_data(data)?, + cc_config_major_fw_rev: Self::CC_CONFIG_MAJOR_FW_REV.from_data(data)?, + cc_config_mid_fw_rev: Self::CC_CONFIG_MID_FW_REV.from_data(data)?, + cc_config_minor_fw_rev: Self::CC_CONFIG_MINOR_FW_REV.from_data(data)?, + cc_config_data_log_day_offset: Self::CC_CONFIG_DATA_LOG_DAY_OFFSET + .from_data(data)?, + cc_config_data_log_cur_day_off: Self::CC_CONFIG_DATA_LOG_CUR_DAY_OFF + .from_data(data)?, + cc_config_data_log_daily_ah: Self::CC_CONFIG_DATA_LOG_DAILY_AH.from_data(data)?, + cc_config_data_log_daily_kwh: Self::CC_CONFIG_DATA_LOG_DAILY_KWH.from_data(data)?, + cc_config_data_log_max_out_a: Self::CC_CONFIG_DATA_LOG_MAX_OUT_A.from_data(data)?, + cc_config_data_log_max_out_w: Self::CC_CONFIG_DATA_LOG_MAX_OUT_W.from_data(data)?, + cc_config_data_log_absorb_t: Self::CC_CONFIG_DATA_LOG_ABSORB_T.from_data(data)?, + cc_config_data_log_float_t: Self::CC_CONFIG_DATA_LOG_FLOAT_T.from_data(data)?, + cc_config_data_log_min_batt_v: Self::CC_CONFIG_DATA_LOG_MIN_BATT_V + .from_data(data)?, + cc_config_data_log_max_batt_v: Self::CC_CONFIG_DATA_LOG_MAX_BATT_V + .from_data(data)?, + cc_config_data_log_max_input_v: Self::CC_CONFIG_DATA_LOG_MAX_INPUT_V + .from_data(data)?, + cc_config_data_log_clear: Self::CC_CONFIG_DATA_LOG_CLEAR.from_data(data)?, + cc_config_data_log_clr_comp: Self::CC_CONFIG_DATA_LOG_CLR_COMP.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -736,3 +749,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Model64112 { + const ID: u16 = 64112; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m64112 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model64410.rs b/src/models/model64410.rs index 9b54266..267e89e 100644 --- a/src/models/model64410.rs +++ b/src/models/model64410.rs @@ -1,10 +1,11 @@ //! DC Simulator Control Interface +pub type Model64410 = DcSimInterface; /// DC Simulator Control Interface /// /// A generic DC simulator/power supply control interface for DER electrical testing. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model64410 { +pub struct DcSimInterface { /// Maximum Voltage /// /// Upper Voltage Protection Limit @@ -141,9 +142,15 @@ pub struct Model64410 { /// /// Scale factor for percentages. pub pct_sf: i16, + /// Stored Profiles + /// + /// Stored profile sets. + /// + /// Comments: Stored Pofile Sets - Number of profile sets = NProf - The first set is read-only and indicates the current settings. + pub prof: Vec, } #[allow(missing_docs)] -impl Model64410 { +impl DcSimInterface { pub const V_MAX_LIM: crate::Point> = crate::Point::new(0, 1, true); pub const P_MAX_LIM: crate::Point> = crate::Point::new(1, 1, true); pub const I_MAX_LIM: crate::Point> = crate::Point::new(2, 1, true); @@ -179,48 +186,57 @@ impl Model64410 { pub const I_SLEW_SF: crate::Point = crate::Point::new(66, 1, true); pub const PCT_SF: crate::Point = crate::Point::new(67, 1, true); } -impl crate::Model for Model64410 { - const ID: u16 = 64410; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - v_max_lim: Self::V_MAX_LIM.from_data(data)?, - p_max_lim: Self::P_MAX_LIM.from_data(data)?, - i_max_lim: Self::I_MAX_LIM.from_data(data)?, - mode: Self::MODE.from_data(data)?, - ena: Self::ENA.from_data(data)?, - reset: Self::RESET.from_data(data)?, - v_set: Self::V_SET.from_data(data)?, - p_set: Self::P_SET.from_data(data)?, - i_set: Self::I_SET.from_data(data)?, - en50530: Self::EN50530.from_data(data)?, - vmpp: Self::VMPP.from_data(data)?, - pmpp: Self::PMPP.from_data(data)?, - g_set: Self::G_SET.from_data(data)?, - v_slew_rate: Self::V_SLEW_RATE.from_data(data)?, - p_slew_rate: Self::P_SLEW_RATE.from_data(data)?, - i_slew_rate: Self::I_SLEW_RATE.from_data(data)?, - ena_prof: Self::ENA_PROF.from_data(data)?, - adpt_prof_req: Self::ADPT_PROF_REQ.from_data(data)?, - adpt_prof_rslt: Self::ADPT_PROF_RSLT.from_data(data)?, - v: Self::V.from_data(data)?, - p: Self::P.from_data(data)?, - i: Self::I.from_data(data)?, - errors: Self::ERRORS.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - n_prof: Self::N_PROF.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - g_sf: Self::G_SF.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - v_slew_sf: Self::V_SLEW_SF.from_data(data)?, - p_slew_sf: Self::P_SLEW_SF.from_data(data)?, - i_slew_sf: Self::I_SLEW_SF.from_data(data)?, - pct_sf: Self::PCT_SF.from_data(data)?, - }) +impl crate::Group for DcSimInterface { + const LEN: u16 = 68; +} +impl DcSimInterface { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + v_max_lim: Self::V_MAX_LIM.from_data(data)?, + p_max_lim: Self::P_MAX_LIM.from_data(data)?, + i_max_lim: Self::I_MAX_LIM.from_data(data)?, + mode: Self::MODE.from_data(data)?, + ena: Self::ENA.from_data(data)?, + reset: Self::RESET.from_data(data)?, + v_set: Self::V_SET.from_data(data)?, + p_set: Self::P_SET.from_data(data)?, + i_set: Self::I_SET.from_data(data)?, + en50530: Self::EN50530.from_data(data)?, + vmpp: Self::VMPP.from_data(data)?, + pmpp: Self::PMPP.from_data(data)?, + g_set: Self::G_SET.from_data(data)?, + v_slew_rate: Self::V_SLEW_RATE.from_data(data)?, + p_slew_rate: Self::P_SLEW_RATE.from_data(data)?, + i_slew_rate: Self::I_SLEW_RATE.from_data(data)?, + ena_prof: Self::ENA_PROF.from_data(data)?, + adpt_prof_req: Self::ADPT_PROF_REQ.from_data(data)?, + adpt_prof_rslt: Self::ADPT_PROF_RSLT.from_data(data)?, + v: Self::V.from_data(data)?, + p: Self::P.from_data(data)?, + i: Self::I.from_data(data)?, + errors: Self::ERRORS.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + n_prof: Self::N_PROF.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + g_sf: Self::G_SF.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + v_slew_sf: Self::V_SLEW_SF.from_data(data)?, + p_slew_sf: Self::P_SLEW_SF.from_data(data)?, + i_slew_sf: Self::I_SLEW_SF.from_data(data)?, + pct_sf: Self::PCT_SF.from_data(data)?, + prof: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m64410 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.prof) = Prof::parse_multiple(data, &group)?; + Ok((data, group)) } } /// CV or CC Mode @@ -491,3 +507,184 @@ impl crate::Value for Option { } } } +/// Stored Profiles +/// +/// Stored profile sets. +/// +/// Comments: Stored Pofile Sets - Number of profile sets = NProf - The first set is read-only and indicates the current settings. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Prof { + /// Active Points + /// + /// Number of active points. + pub act_pt: u16, + /// Dependent References + /// + /// Profile references. + pub dept_ref: ProfDeptRef, + /// Stored Profile Points + /// + /// Stored profile points. + /// + /// Comments: Stored Profile Sets - Profile points for each stored profile - Number of profile points contained in NPt + pub pt: Vec, +} +#[allow(missing_docs)] +impl Prof { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const DEPT_REF: crate::Point = crate::Point::new(1, 1, true); +} +impl crate::Group for Prof { + const LEN: u16 = 2; +} +impl Prof { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + dept_ref: Self::DEPT_REF.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DcSimInterface, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DcSimInterface, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_prof { + let group; + (data, group) = Prof::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +bitflags::bitflags! { + #[doc = " Dependent References"] #[doc = " "] #[doc = " Profile references."] + #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", + derive(::serde::Serialize, ::serde::Deserialize))] pub struct ProfDeptRef : u32 { + #[doc = " Voltage"] const Voltage = 1; #[doc = " Power"] const Power = 2; #[doc = + " Current"] const Current = 4; #[doc = " Irradiance"] const Irradiance = 8; } +} +impl crate::Value for ProfDeptRef { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(ProfDeptRef::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +/// Stored Profile Points +/// +/// Stored profile points. +/// +/// Comments: Stored Profile Sets - Profile points for each stored profile - Number of profile points contained in NPt +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Pt { + /// Profile Time + /// + /// Profile time. + pub tms: Option, + /// Voltage Point + /// + /// Profile voltage point in Volts. + pub v: Option, + /// Power Point + /// + /// Profile power point in Watts. + pub p: Option, + /// Current Point + /// + /// Profile current point in Amps. + pub i: Option, + /// Irradiance Point + /// + /// Profile irradiance point as percentage. + pub g: Option, +} +#[allow(missing_docs)] +impl Pt { + pub const TMS: crate::Point> = crate::Point::new(0, 1, true); + pub const V: crate::Point> = crate::Point::new(1, 1, true); + pub const P: crate::Point> = crate::Point::new(2, 1, true); + pub const I: crate::Point> = crate::Point::new(3, 1, true); + pub const G: crate::Point> = crate::Point::new(4, 1, true); +} +impl crate::Group for Pt { + const LEN: u16 = 5; +} +impl Pt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + tms: Self::TMS.from_data(data)?, + v: Self::V.from_data(data)?, + p: Self::P.from_data(data)?, + i: Self::I.from_data(data)?, + g: Self::G.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DcSimInterface, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DcSimInterface, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_pt { + let group; + (data, group) = Pt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for DcSimInterface { + const ID: u16 = 64410; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m64410 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model64411.rs b/src/models/model64411.rs index 7df541d..6ac1f61 100644 --- a/src/models/model64411.rs +++ b/src/models/model64411.rs @@ -1,10 +1,11 @@ //! AC Simulator Control Interface +pub type Model64411 = AcSimInterface; /// AC Simulator Control Interface /// /// A generic AC simulator/power supply control interface for DER electrical testing. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model64411 { +pub struct AcSimInterface { /// Active Phases /// /// Set the number of active phases for the power supply @@ -197,9 +198,15 @@ pub struct Model64411 { /// /// Scale factor for THD values. pub thd_sf: i16, + /// Stored AC Profiles + /// + /// Stored AC profile sets. + /// + /// Comments: Stored AC Profile Sets - Number of profile sets = NProf + pub prof: Vec, } #[allow(missing_docs)] -impl Model64411 { +impl AcSimInterface { pub const PHASES: crate::Point> = crate::Point::new(0, 1, true); pub const PHASE_ANGLE: crate::Point> = crate::Point::new(1, 1, true); pub const V_NOM: crate::Point> = crate::Point::new(2, 1, true); @@ -249,62 +256,71 @@ impl Model64411 { pub const V_SLEW_SF: crate::Point = crate::Point::new(1394, 1, false); pub const THD_SF: crate::Point = crate::Point::new(1395, 1, false); } -impl crate::Model for Model64411 { - const ID: u16 = 64411; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - phases: Self::PHASES.from_data(data)?, - phase_angle: Self::PHASE_ANGLE.from_data(data)?, - v_nom: Self::V_NOM.from_data(data)?, - v_max: Self::V_MAX.from_data(data)?, - i_max: Self::I_MAX.from_data(data)?, - freq: Self::FREQ.from_data(data)?, - output: Self::OUTPUT.from_data(data)?, - relay: Self::RELAY.from_data(data)?, - regen: Self::REGEN.from_data(data)?, - v_set: Self::V_SET.from_data(data)?, - v_set_a: Self::V_SET_A.from_data(data)?, - v_set_b: Self::V_SET_B.from_data(data)?, - v_set_c: Self::V_SET_C.from_data(data)?, - freq_slew: Self::FREQ_SLEW.from_data(data)?, - v_slew: Self::V_SLEW.from_data(data)?, - va: Self::VA.from_data(data)?, - vb: Self::VB.from_data(data)?, - vc: Self::VC.from_data(data)?, - hz: Self::HZ.from_data(data)?, - ia: Self::IA.from_data(data)?, - ib: Self::IB.from_data(data)?, - ic: Self::IC.from_data(data)?, - v_har_a: Self::V_HAR_A.from_data(data)?, - v_har_b: Self::V_HAR_B.from_data(data)?, - v_har_c: Self::V_HAR_C.from_data(data)?, - i_har_a: Self::I_HAR_A.from_data(data)?, - i_har_b: Self::I_HAR_B.from_data(data)?, - i_har_c: Self::I_HAR_C.from_data(data)?, - i_int_har_a: Self::I_INT_HAR_A.from_data(data)?, - i_int_har_b: Self::I_INT_HAR_B.from_data(data)?, - i_int_har_c: Self::I_INT_HAR_C.from_data(data)?, - v_thd_a: Self::V_THD_A.from_data(data)?, - v_thd_b: Self::V_THD_B.from_data(data)?, - v_thd_c: Self::V_THD_C.from_data(data)?, - i_thd_a: Self::I_THD_A.from_data(data)?, - i_thd_b: Self::I_THD_B.from_data(data)?, - i_thd_c: Self::I_THD_C.from_data(data)?, - ena_prof: Self::ENA_PROF.from_data(data)?, - prof_rslt: Self::PROF_RSLT.from_data(data)?, - n_prof: Self::N_PROF.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - hz_slew_sf: Self::HZ_SLEW_SF.from_data(data)?, - v_slew_sf: Self::V_SLEW_SF.from_data(data)?, - thd_sf: Self::THD_SF.from_data(data)?, - }) +impl crate::Group for AcSimInterface { + const LEN: u16 = 1396; +} +impl AcSimInterface { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + phases: Self::PHASES.from_data(data)?, + phase_angle: Self::PHASE_ANGLE.from_data(data)?, + v_nom: Self::V_NOM.from_data(data)?, + v_max: Self::V_MAX.from_data(data)?, + i_max: Self::I_MAX.from_data(data)?, + freq: Self::FREQ.from_data(data)?, + output: Self::OUTPUT.from_data(data)?, + relay: Self::RELAY.from_data(data)?, + regen: Self::REGEN.from_data(data)?, + v_set: Self::V_SET.from_data(data)?, + v_set_a: Self::V_SET_A.from_data(data)?, + v_set_b: Self::V_SET_B.from_data(data)?, + v_set_c: Self::V_SET_C.from_data(data)?, + freq_slew: Self::FREQ_SLEW.from_data(data)?, + v_slew: Self::V_SLEW.from_data(data)?, + va: Self::VA.from_data(data)?, + vb: Self::VB.from_data(data)?, + vc: Self::VC.from_data(data)?, + hz: Self::HZ.from_data(data)?, + ia: Self::IA.from_data(data)?, + ib: Self::IB.from_data(data)?, + ic: Self::IC.from_data(data)?, + v_har_a: Self::V_HAR_A.from_data(data)?, + v_har_b: Self::V_HAR_B.from_data(data)?, + v_har_c: Self::V_HAR_C.from_data(data)?, + i_har_a: Self::I_HAR_A.from_data(data)?, + i_har_b: Self::I_HAR_B.from_data(data)?, + i_har_c: Self::I_HAR_C.from_data(data)?, + i_int_har_a: Self::I_INT_HAR_A.from_data(data)?, + i_int_har_b: Self::I_INT_HAR_B.from_data(data)?, + i_int_har_c: Self::I_INT_HAR_C.from_data(data)?, + v_thd_a: Self::V_THD_A.from_data(data)?, + v_thd_b: Self::V_THD_B.from_data(data)?, + v_thd_c: Self::V_THD_C.from_data(data)?, + i_thd_a: Self::I_THD_A.from_data(data)?, + i_thd_b: Self::I_THD_B.from_data(data)?, + i_thd_c: Self::I_THD_C.from_data(data)?, + ena_prof: Self::ENA_PROF.from_data(data)?, + prof_rslt: Self::PROF_RSLT.from_data(data)?, + n_prof: Self::N_PROF.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + hz_slew_sf: Self::HZ_SLEW_SF.from_data(data)?, + v_slew_sf: Self::V_SLEW_SF.from_data(data)?, + thd_sf: Self::THD_SF.from_data(data)?, + prof: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m64411 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.prof) = Prof::parse_multiple(data, &group)?; + Ok((data, group)) } } /// Output State @@ -511,3 +527,169 @@ impl crate::Value for Option { } } } +/// Stored AC Profiles +/// +/// Stored AC profile sets. +/// +/// Comments: Stored AC Profile Sets - Number of profile sets = NProf +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Prof { + /// Profile Name + /// + /// Profile name. + pub name: Option, + /// Active Points + /// + /// Number of active points. + pub act_pt: u16, + /// Stored AC Profile Points + /// + /// Stored AC profile points. + /// + /// Comments: Stored AC Profile Sets - Profile points for each stored profile - Number of profile points contained in NPt + pub pt: Vec, +} +#[allow(missing_docs)] +impl Prof { + pub const NAME: crate::Point> = crate::Point::new(0, 32, true); + pub const ACT_PT: crate::Point = crate::Point::new(32, 1, true); +} +impl crate::Group for Prof { + const LEN: u16 = 33; +} +impl Prof { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + name: Self::NAME.from_data(data)?, + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &AcSimInterface, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &AcSimInterface, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_prof { + let group; + (data, group) = Prof::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Stored AC Profile Points +/// +/// Stored AC profile points. +/// +/// Comments: Stored AC Profile Sets - Profile points for each stored profile - Number of profile points contained in NPt +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Pt { + /// Profile Time + /// + /// Profile time. + pub tms: Option, + /// Voltage Point + /// + /// Profile voltage phase A point in Volts. + pub va: Option, + /// Voltage Point Phase B + /// + /// Profile voltage phase B point in Volts. + pub vb: Option, + /// Voltage Point Phase C + /// + /// Profile voltage phase C point in Volts. + pub vc: Option, + /// Frequency Point + /// + /// Profile frequency point in Hz. + pub hz: Option, + /// Phase Angle A + /// + /// Profile phase A angle in degrees. + pub phase_angle_a: Option, + /// Phase Angle B + /// + /// Profile phase B angle in degrees. + pub phase_angle_b: Option, + /// Phase Angle C + /// + /// Profile phase C angle in degrees. + pub phase_angle_c: Option, +} +#[allow(missing_docs)] +impl Pt { + pub const TMS: crate::Point> = crate::Point::new(0, 1, true); + pub const VA: crate::Point> = crate::Point::new(1, 1, true); + pub const VB: crate::Point> = crate::Point::new(2, 1, true); + pub const VC: crate::Point> = crate::Point::new(3, 1, true); + pub const HZ: crate::Point> = crate::Point::new(4, 1, true); + pub const PHASE_ANGLE_A: crate::Point> = crate::Point::new(5, 1, true); + pub const PHASE_ANGLE_B: crate::Point> = crate::Point::new(6, 1, true); + pub const PHASE_ANGLE_C: crate::Point> = crate::Point::new(7, 1, true); +} +impl crate::Group for Pt { + const LEN: u16 = 8; +} +impl Pt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + tms: Self::TMS.from_data(data)?, + va: Self::VA.from_data(data)?, + vb: Self::VB.from_data(data)?, + vc: Self::VC.from_data(data)?, + hz: Self::HZ.from_data(data)?, + phase_angle_a: Self::PHASE_ANGLE_A.from_data(data)?, + phase_angle_b: Self::PHASE_ANGLE_B.from_data(data)?, + phase_angle_c: Self::PHASE_ANGLE_C.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &AcSimInterface, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &AcSimInterface, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_pt { + let group; + (data, group) = Pt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for AcSimInterface { + const ID: u16 = 64411; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m64411 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model64412.rs b/src/models/model64412.rs index 85ac474..d32b2c7 100644 --- a/src/models/model64412.rs +++ b/src/models/model64412.rs @@ -1,10 +1,11 @@ //! DER Cyber Exploitation +pub type Model64412 = DerExploitation; /// DER Cyber Exploitation /// /// Operations that represent a hacked DER device #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model64412 { +pub struct DerExploitation { /// DA Manipulation /// /// Modify the device ID of the DER @@ -179,7 +180,7 @@ pub struct Model64412 { pub change_common_model_length: Option, } #[allow(missing_docs)] -impl Model64412 { +impl DerExploitation { pub const DA_MANIPULATION: crate::Point> = crate::Point::new(0, 1, true); pub const FALSIFY_DEVICE_IDENTITY: crate::Point> = @@ -256,57 +257,64 @@ impl Model64412 { pub const CHANGE_COMMON_MODEL_LENGTH: crate::Point> = crate::Point::new(42, 1, true); } -impl crate::Model for Model64412 { - const ID: u16 = 64412; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - da_manipulation: Self::DA_MANIPULATION.from_data(data)?, - falsify_device_identity: Self::FALSIFY_DEVICE_IDENTITY.from_data(data)?, - meas_p_always_nameplate: Self::MEAS_P_ALWAYS_NAMEPLATE.from_data(data)?, - meas_q_always_minimum: Self::MEAS_Q_ALWAYS_MINIMUM.from_data(data)?, - meas_q_always_maximum: Self::MEAS_Q_ALWAYS_MAXIMUM.from_data(data)?, - meas_q_always_zero: Self::MEAS_Q_ALWAYS_ZERO.from_data(data)?, - meas_zero_p: Self::MEAS_ZERO_P.from_data(data)?, - meas_invert_q: Self::MEAS_INVERT_Q.from_data(data)?, - meas_low_v: Self::MEAS_LOW_V.from_data(data)?, - meas_high_v: Self::MEAS_HIGH_V.from_data(data)?, - meas_low_l1v: Self::MEAS_LOW_L1V.from_data(data)?, - meas_high_l1v: Self::MEAS_HIGH_L1V.from_data(data)?, - meas_low_f: Self::MEAS_LOW_F.from_data(data)?, - meas_high_f: Self::MEAS_HIGH_F.from_data(data)?, - meas_low_amps: Self::MEAS_LOW_AMPS.from_data(data)?, - meas_high_amps: Self::MEAS_HIGH_AMPS.from_data(data)?, - meas_high_s: Self::MEAS_HIGH_S.from_data(data)?, - meas_low_s: Self::MEAS_LOW_S.from_data(data)?, - meas_high_q: Self::MEAS_HIGH_Q.from_data(data)?, - meas_low_q: Self::MEAS_LOW_Q.from_data(data)?, - meas_low_pf: Self::MEAS_LOW_PF.from_data(data)?, - meas_low_reversed_pf: Self::MEAS_LOW_REVERSED_PF.from_data(data)?, - nameplate_high_p: Self::NAMEPLATE_HIGH_P.from_data(data)?, - nameplate_low_p: Self::NAMEPLATE_LOW_P.from_data(data)?, - nameplate_high_s: Self::NAMEPLATE_HIGH_S.from_data(data)?, - nameplate_low_s: Self::NAMEPLATE_LOW_S.from_data(data)?, - nameplate_high_q: Self::NAMEPLATE_HIGH_Q.from_data(data)?, - nameplate_low_q: Self::NAMEPLATE_LOW_Q.from_data(data)?, - nameplate_high_nom_v: Self::NAMEPLATE_HIGH_NOM_V.from_data(data)?, - nameplate_low_nom_v: Self::NAMEPLATE_LOW_NOM_V.from_data(data)?, - nameplate_low_amps: Self::NAMEPLATE_LOW_AMPS.from_data(data)?, - nameplate_low_varmaxinj: Self::NAMEPLATE_LOW_VARMAXINJ.from_data(data)?, - nameplate_low_varmaxabs: Self::NAMEPLATE_LOW_VARMAXABS.from_data(data)?, - nameplate_low_pf: Self::NAMEPLATE_LOW_PF.from_data(data)?, - settings_high_nom_v: Self::SETTINGS_HIGH_NOM_V.from_data(data)?, - settings_low_amps: Self::SETTINGS_LOW_AMPS.from_data(data)?, - settings_high_p: Self::SETTINGS_HIGH_P.from_data(data)?, - settings_low_p: Self::SETTINGS_LOW_P.from_data(data)?, - settings_high_va_max: Self::SETTINGS_HIGH_VA_MAX.from_data(data)?, - settings_high_varmaxinj: Self::SETTINGS_HIGH_VARMAXINJ.from_data(data)?, - settings_high_varmaxabs: Self::SETTINGS_HIGH_VARMAXABS.from_data(data)?, - change_common_model_id: Self::CHANGE_COMMON_MODEL_ID.from_data(data)?, - change_common_model_length: Self::CHANGE_COMMON_MODEL_LENGTH.from_data(data)?, - }) - } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m64412 +impl crate::Group for DerExploitation { + const LEN: u16 = 43; +} +impl DerExploitation { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + da_manipulation: Self::DA_MANIPULATION.from_data(data)?, + falsify_device_identity: Self::FALSIFY_DEVICE_IDENTITY.from_data(data)?, + meas_p_always_nameplate: Self::MEAS_P_ALWAYS_NAMEPLATE.from_data(data)?, + meas_q_always_minimum: Self::MEAS_Q_ALWAYS_MINIMUM.from_data(data)?, + meas_q_always_maximum: Self::MEAS_Q_ALWAYS_MAXIMUM.from_data(data)?, + meas_q_always_zero: Self::MEAS_Q_ALWAYS_ZERO.from_data(data)?, + meas_zero_p: Self::MEAS_ZERO_P.from_data(data)?, + meas_invert_q: Self::MEAS_INVERT_Q.from_data(data)?, + meas_low_v: Self::MEAS_LOW_V.from_data(data)?, + meas_high_v: Self::MEAS_HIGH_V.from_data(data)?, + meas_low_l1v: Self::MEAS_LOW_L1V.from_data(data)?, + meas_high_l1v: Self::MEAS_HIGH_L1V.from_data(data)?, + meas_low_f: Self::MEAS_LOW_F.from_data(data)?, + meas_high_f: Self::MEAS_HIGH_F.from_data(data)?, + meas_low_amps: Self::MEAS_LOW_AMPS.from_data(data)?, + meas_high_amps: Self::MEAS_HIGH_AMPS.from_data(data)?, + meas_high_s: Self::MEAS_HIGH_S.from_data(data)?, + meas_low_s: Self::MEAS_LOW_S.from_data(data)?, + meas_high_q: Self::MEAS_HIGH_Q.from_data(data)?, + meas_low_q: Self::MEAS_LOW_Q.from_data(data)?, + meas_low_pf: Self::MEAS_LOW_PF.from_data(data)?, + meas_low_reversed_pf: Self::MEAS_LOW_REVERSED_PF.from_data(data)?, + nameplate_high_p: Self::NAMEPLATE_HIGH_P.from_data(data)?, + nameplate_low_p: Self::NAMEPLATE_LOW_P.from_data(data)?, + nameplate_high_s: Self::NAMEPLATE_HIGH_S.from_data(data)?, + nameplate_low_s: Self::NAMEPLATE_LOW_S.from_data(data)?, + nameplate_high_q: Self::NAMEPLATE_HIGH_Q.from_data(data)?, + nameplate_low_q: Self::NAMEPLATE_LOW_Q.from_data(data)?, + nameplate_high_nom_v: Self::NAMEPLATE_HIGH_NOM_V.from_data(data)?, + nameplate_low_nom_v: Self::NAMEPLATE_LOW_NOM_V.from_data(data)?, + nameplate_low_amps: Self::NAMEPLATE_LOW_AMPS.from_data(data)?, + nameplate_low_varmaxinj: Self::NAMEPLATE_LOW_VARMAXINJ.from_data(data)?, + nameplate_low_varmaxabs: Self::NAMEPLATE_LOW_VARMAXABS.from_data(data)?, + nameplate_low_pf: Self::NAMEPLATE_LOW_PF.from_data(data)?, + settings_high_nom_v: Self::SETTINGS_HIGH_NOM_V.from_data(data)?, + settings_low_amps: Self::SETTINGS_LOW_AMPS.from_data(data)?, + settings_high_p: Self::SETTINGS_HIGH_P.from_data(data)?, + settings_low_p: Self::SETTINGS_LOW_P.from_data(data)?, + settings_high_va_max: Self::SETTINGS_HIGH_VA_MAX.from_data(data)?, + settings_high_varmaxinj: Self::SETTINGS_HIGH_VARMAXINJ.from_data(data)?, + settings_high_varmaxabs: Self::SETTINGS_HIGH_VARMAXABS.from_data(data)?, + change_common_model_id: Self::CHANGE_COMMON_MODEL_ID.from_data(data)?, + change_common_model_length: Self::CHANGE_COMMON_MODEL_LENGTH.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// DA Manipulation @@ -2209,3 +2217,13 @@ impl crate::Value for Option { } } } +impl crate::Model for DerExploitation { + const ID: u16 = 64412; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m64412 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model64413.rs b/src/models/model64413.rs index e53d993..37249fa 100644 --- a/src/models/model64413.rs +++ b/src/models/model64413.rs @@ -1,10 +1,11 @@ //! PV Curves +pub type Model64413 = PvSimCurves; /// PV Curves /// /// Current-Voltage and Power-Voltage Profiles for PV Simulation. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model64413 { +pub struct PvSimCurves { /// IV length /// /// Number of points in the IV curve. @@ -15,23 +16,102 @@ pub struct Model64413 { pub irr: Option, #[allow(missing_docs)] pub irr_sf: Option, + /// Comments: IV Curve Points + pub iv: Vec, } #[allow(missing_docs)] -impl Model64413 { +impl PvSimCurves { pub const IV_LEN: crate::Point> = crate::Point::new(0, 1, false); pub const IRR: crate::Point> = crate::Point::new(1, 1, false); pub const IRR_SF: crate::Point> = crate::Point::new(2, 1, false); } -impl crate::Model for Model64413 { - const ID: u16 = 64413; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - iv_len: Self::IV_LEN.from_data(data)?, - irr: Self::IRR.from_data(data)?, - irr_sf: Self::IRR_SF.from_data(data)?, - }) +impl crate::Group for PvSimCurves { + const LEN: u16 = 3; +} +impl PvSimCurves { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + iv_len: Self::IV_LEN.from_data(data)?, + irr: Self::IRR.from_data(data)?, + irr_sf: Self::IRR_SF.from_data(data)?, + iv: Vec::new(), + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.iv) = Iv::parse_multiple(data, &group)?; + Ok((data, group)) } +} +/// Comments: IV Curve Points +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Iv { + /// Power + /// + /// Power + pub p: Option, + /// Current + /// + /// Current + pub i: Option, + /// Voltage + /// + /// Voltage + pub v: Option, +} +#[allow(missing_docs)] +impl Iv { + pub const P: crate::Point> = crate::Point::new(0, 2, false); + pub const I: crate::Point> = crate::Point::new(2, 2, false); + pub const V: crate::Point> = crate::Point::new(4, 2, false); +} +impl crate::Group for Iv { + const LEN: u16 = 6; +} +impl Iv { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + p: Self::P.from_data(data)?, + i: Self::I.from_data(data)?, + v: Self::V.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &PvSimCurves, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &PvSimCurves, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.iv_len.unwrap_or_default() { + let group; + (data, group) = Iv::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for PvSimCurves { + const ID: u16 = 64413; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m64413 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model64414.rs b/src/models/model64414.rs index 71c734b..8d98bad 100644 --- a/src/models/model64414.rs +++ b/src/models/model64414.rs @@ -1,10 +1,11 @@ //! DER Simulation Controls +pub type Model64414 = DerSimControls; /// DER Simulation Controls /// /// Configuration parameters for the DER device simulator. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model64414 { +pub struct DerSimControls { /// Time offset /// /// Time offset for simulation formatted 'HH:MM:SS' @@ -27,7 +28,7 @@ pub struct Model64414 { pub grid_frequency: Option, } #[allow(missing_docs)] -impl Model64414 { +impl DerSimControls { pub const TIME: crate::Point> = crate::Point::new(0, 10, false); pub const TEMPERATURE: crate::Point> = crate::Point::new(10, 2, true); pub const GRID_MODEL_SOURCE: crate::Point> = @@ -40,22 +41,39 @@ impl Model64414 { pub const GRID_VOLTAGE_C: crate::Point> = crate::Point::new(82, 2, true); pub const GRID_FREQUENCY: crate::Point> = crate::Point::new(84, 2, true); } -impl crate::Model for Model64414 { - const ID: u16 = 64414; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - time: Self::TIME.from_data(data)?, - temperature: Self::TEMPERATURE.from_data(data)?, - grid_model_source: Self::GRID_MODEL_SOURCE.from_data(data)?, - irradiance_model_source: Self::IRRADIANCE_MODEL_SOURCE.from_data(data)?, - irradiance: Self::IRRADIANCE.from_data(data)?, - grid_voltage_a: Self::GRID_VOLTAGE_A.from_data(data)?, - grid_voltage_b: Self::GRID_VOLTAGE_B.from_data(data)?, - grid_voltage_c: Self::GRID_VOLTAGE_C.from_data(data)?, - grid_frequency: Self::GRID_FREQUENCY.from_data(data)?, - }) +impl crate::Group for DerSimControls { + const LEN: u16 = 86; +} +impl DerSimControls { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + time: Self::TIME.from_data(data)?, + temperature: Self::TEMPERATURE.from_data(data)?, + grid_model_source: Self::GRID_MODEL_SOURCE.from_data(data)?, + irradiance_model_source: Self::IRRADIANCE_MODEL_SOURCE.from_data(data)?, + irradiance: Self::IRRADIANCE.from_data(data)?, + grid_voltage_a: Self::GRID_VOLTAGE_A.from_data(data)?, + grid_voltage_b: Self::GRID_VOLTAGE_B.from_data(data)?, + grid_voltage_c: Self::GRID_VOLTAGE_C.from_data(data)?, + grid_frequency: Self::GRID_FREQUENCY.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } +} +impl crate::Model for DerSimControls { + const ID: u16 = 64414; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m64414 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model64415.rs b/src/models/model64415.rs index 057cc3b..d9ff2da 100644 --- a/src/models/model64415.rs +++ b/src/models/model64415.rs @@ -1,10 +1,11 @@ //! CSIP Client Control +pub type Model64415 = CsipControl; /// CSIP Client Control /// /// CSIP Client Control for Alarms and Error tests #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model64415 { +pub struct CsipControl { /// LogEvent Mode Enable /// /// Enable or disable the LogEvent mode @@ -19,23 +20,30 @@ pub struct Model64415 { pub comm004_cert: Option, } #[allow(missing_docs)] -impl Model64415 { +impl CsipControl { pub const LOG_EVENT_ENA: crate::Point> = crate::Point::new(0, 1, true); pub const HTTP_MSG: crate::Point> = crate::Point::new(1, 1, true); pub const COMM004_CERT: crate::Point> = crate::Point::new(2, 1, true); } -impl crate::Model for Model64415 { - const ID: u16 = 64415; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - log_event_ena: Self::LOG_EVENT_ENA.from_data(data)?, - http_msg: Self::HTTP_MSG.from_data(data)?, - comm004_cert: Self::COMM004_CERT.from_data(data)?, - }) +impl crate::Group for CsipControl { + const LEN: u16 = 3; +} +impl CsipControl { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + log_event_ena: Self::LOG_EVENT_ENA.from_data(data)?, + http_msg: Self::HTTP_MSG.from_data(data)?, + comm004_cert: Self::COMM004_CERT.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m64415 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// LogEvent Mode Enable @@ -194,3 +202,13 @@ impl crate::Value for Option { } } } +impl crate::Model for CsipControl { + const ID: u16 = 64415; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m64415 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model7.rs b/src/models/model7.rs index 6cb41ae..acb7839 100644 --- a/src/models/model7.rs +++ b/src/models/model7.rs @@ -45,6 +45,8 @@ pub struct Model7 { /// /// Detail: The value of N must be at least 4 (64 bits) pub n: u16, + #[allow(missing_docs)] + pub repeating: Vec, } #[allow(missing_docs)] impl Model7 { @@ -57,22 +59,31 @@ impl Model7 { pub const ALG: crate::Point = crate::Point::new(8, 1, false); pub const N: crate::Point = crate::Point::new(9, 1, true); } -impl crate::Model for Model7 { - const ID: u16 = 7; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - rq_seq: Self::RQ_SEQ.from_data(data)?, - sts: Self::STS.from_data(data)?, - ts: Self::TS.from_data(data)?, - ms: Self::MS.from_data(data)?, - seq: Self::SEQ.from_data(data)?, - alm: Self::ALM.from_data(data)?, - alg: Self::ALG.from_data(data)?, - n: Self::N.from_data(data)?, - }) +impl crate::Group for Model7 { + const LEN: u16 = 10; +} +impl Model7 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + rq_seq: Self::RQ_SEQ.from_data(data)?, + sts: Self::STS.from_data(data)?, + ts: Self::TS.from_data(data)?, + ms: Self::MS.from_data(data)?, + seq: Self::SEQ.from_data(data)?, + alm: Self::ALM.from_data(data)?, + alg: Self::ALG.from_data(data)?, + n: Self::N.from_data(data)?, + repeating: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m7 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) } } /// Status @@ -205,3 +216,59 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + /// DS + /// + /// Digital Signature + pub ds: u16, +} +#[allow(missing_docs)] +impl Repeating { + pub const DS: crate::Point = crate::Point::new(0, 1, true); +} +impl crate::Group for Repeating { + const LEN: u16 = 1; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ds: Self::DS.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Model7, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Model7, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for Model7 { + const ID: u16 = 7; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m7 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model701.rs b/src/models/model701.rs index 22d6dac..899b3cc 100644 --- a/src/models/model701.rs +++ b/src/models/model701.rs @@ -1,10 +1,11 @@ //! DER AC Measurement +pub type Model701 = DerMeasureAc; /// DER AC Measurement /// /// DER AC measurement model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model701 { +pub struct DerMeasureAc { /// AC Wiring Type /// /// AC wiring type. @@ -313,7 +314,7 @@ pub struct Model701 { pub mn_alrm_info: Option, } #[allow(missing_docs)] -impl Model701 { +impl DerMeasureAc { pub const AC_TYPE: crate::Point = crate::Point::new(0, 1, false); pub const ST: crate::Point> = crate::Point::new(1, 1, false); pub const INV_ST: crate::Point> = crate::Point::new(2, 1, false); @@ -385,84 +386,91 @@ impl Model701 { pub const TMP_SF: crate::Point> = crate::Point::new(120, 1, false); pub const MN_ALRM_INFO: crate::Point> = crate::Point::new(121, 32, false); } -impl crate::Model for Model701 { - const ID: u16 = 701; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ac_type: Self::AC_TYPE.from_data(data)?, - st: Self::ST.from_data(data)?, - inv_st: Self::INV_ST.from_data(data)?, - conn_st: Self::CONN_ST.from_data(data)?, - alrm: Self::ALRM.from_data(data)?, - der_mode: Self::DER_MODE.from_data(data)?, - w: Self::W.from_data(data)?, - va: Self::VA.from_data(data)?, - var: Self::VAR.from_data(data)?, - pf: Self::PF.from_data(data)?, - a: Self::A.from_data(data)?, - llv: Self::LLV.from_data(data)?, - lnv: Self::LNV.from_data(data)?, - hz: Self::HZ.from_data(data)?, - tot_wh_inj: Self::TOT_WH_INJ.from_data(data)?, - tot_wh_abs: Self::TOT_WH_ABS.from_data(data)?, - tot_varh_inj: Self::TOT_VARH_INJ.from_data(data)?, - tot_varh_abs: Self::TOT_VARH_ABS.from_data(data)?, - tmp_amb: Self::TMP_AMB.from_data(data)?, - tmp_cab: Self::TMP_CAB.from_data(data)?, - tmp_snk: Self::TMP_SNK.from_data(data)?, - tmp_trns: Self::TMP_TRNS.from_data(data)?, - tmp_sw: Self::TMP_SW.from_data(data)?, - tmp_ot: Self::TMP_OT.from_data(data)?, - wl1: Self::WL1.from_data(data)?, - val1: Self::VAL1.from_data(data)?, - var_l1: Self::VAR_L1.from_data(data)?, - pfl1: Self::PFL1.from_data(data)?, - al1: Self::AL1.from_data(data)?, - vl1l2: Self::VL1L2.from_data(data)?, - vl1: Self::VL1.from_data(data)?, - tot_wh_inj_l1: Self::TOT_WH_INJ_L1.from_data(data)?, - tot_wh_abs_l1: Self::TOT_WH_ABS_L1.from_data(data)?, - tot_varh_inj_l1: Self::TOT_VARH_INJ_L1.from_data(data)?, - tot_varh_abs_l1: Self::TOT_VARH_ABS_L1.from_data(data)?, - wl2: Self::WL2.from_data(data)?, - val2: Self::VAL2.from_data(data)?, - var_l2: Self::VAR_L2.from_data(data)?, - pfl2: Self::PFL2.from_data(data)?, - al2: Self::AL2.from_data(data)?, - vl2l3: Self::VL2L3.from_data(data)?, - vl2: Self::VL2.from_data(data)?, - tot_wh_inj_l2: Self::TOT_WH_INJ_L2.from_data(data)?, - tot_wh_abs_l2: Self::TOT_WH_ABS_L2.from_data(data)?, - tot_varh_inj_l2: Self::TOT_VARH_INJ_L2.from_data(data)?, - tot_varh_abs_l2: Self::TOT_VARH_ABS_L2.from_data(data)?, - wl3: Self::WL3.from_data(data)?, - val3: Self::VAL3.from_data(data)?, - var_l3: Self::VAR_L3.from_data(data)?, - pfl3: Self::PFL3.from_data(data)?, - al3: Self::AL3.from_data(data)?, - vl3l1: Self::VL3L1.from_data(data)?, - vl3: Self::VL3.from_data(data)?, - tot_wh_inj_l3: Self::TOT_WH_INJ_L3.from_data(data)?, - tot_wh_abs_l3: Self::TOT_WH_ABS_L3.from_data(data)?, - tot_varh_inj_l3: Self::TOT_VARH_INJ_L3.from_data(data)?, - tot_varh_abs_l3: Self::TOT_VARH_ABS_L3.from_data(data)?, - throt_pct: Self::THROT_PCT.from_data(data)?, - throt_src: Self::THROT_SRC.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - va_sf: Self::VA_SF.from_data(data)?, - var_sf: Self::VAR_SF.from_data(data)?, - tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, - tot_varh_sf: Self::TOT_VARH_SF.from_data(data)?, - tmp_sf: Self::TMP_SF.from_data(data)?, - mn_alrm_info: Self::MN_ALRM_INFO.from_data(data)?, - }) +impl crate::Group for DerMeasureAc { + const LEN: u16 = 153; +} +impl DerMeasureAc { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ac_type: Self::AC_TYPE.from_data(data)?, + st: Self::ST.from_data(data)?, + inv_st: Self::INV_ST.from_data(data)?, + conn_st: Self::CONN_ST.from_data(data)?, + alrm: Self::ALRM.from_data(data)?, + der_mode: Self::DER_MODE.from_data(data)?, + w: Self::W.from_data(data)?, + va: Self::VA.from_data(data)?, + var: Self::VAR.from_data(data)?, + pf: Self::PF.from_data(data)?, + a: Self::A.from_data(data)?, + llv: Self::LLV.from_data(data)?, + lnv: Self::LNV.from_data(data)?, + hz: Self::HZ.from_data(data)?, + tot_wh_inj: Self::TOT_WH_INJ.from_data(data)?, + tot_wh_abs: Self::TOT_WH_ABS.from_data(data)?, + tot_varh_inj: Self::TOT_VARH_INJ.from_data(data)?, + tot_varh_abs: Self::TOT_VARH_ABS.from_data(data)?, + tmp_amb: Self::TMP_AMB.from_data(data)?, + tmp_cab: Self::TMP_CAB.from_data(data)?, + tmp_snk: Self::TMP_SNK.from_data(data)?, + tmp_trns: Self::TMP_TRNS.from_data(data)?, + tmp_sw: Self::TMP_SW.from_data(data)?, + tmp_ot: Self::TMP_OT.from_data(data)?, + wl1: Self::WL1.from_data(data)?, + val1: Self::VAL1.from_data(data)?, + var_l1: Self::VAR_L1.from_data(data)?, + pfl1: Self::PFL1.from_data(data)?, + al1: Self::AL1.from_data(data)?, + vl1l2: Self::VL1L2.from_data(data)?, + vl1: Self::VL1.from_data(data)?, + tot_wh_inj_l1: Self::TOT_WH_INJ_L1.from_data(data)?, + tot_wh_abs_l1: Self::TOT_WH_ABS_L1.from_data(data)?, + tot_varh_inj_l1: Self::TOT_VARH_INJ_L1.from_data(data)?, + tot_varh_abs_l1: Self::TOT_VARH_ABS_L1.from_data(data)?, + wl2: Self::WL2.from_data(data)?, + val2: Self::VAL2.from_data(data)?, + var_l2: Self::VAR_L2.from_data(data)?, + pfl2: Self::PFL2.from_data(data)?, + al2: Self::AL2.from_data(data)?, + vl2l3: Self::VL2L3.from_data(data)?, + vl2: Self::VL2.from_data(data)?, + tot_wh_inj_l2: Self::TOT_WH_INJ_L2.from_data(data)?, + tot_wh_abs_l2: Self::TOT_WH_ABS_L2.from_data(data)?, + tot_varh_inj_l2: Self::TOT_VARH_INJ_L2.from_data(data)?, + tot_varh_abs_l2: Self::TOT_VARH_ABS_L2.from_data(data)?, + wl3: Self::WL3.from_data(data)?, + val3: Self::VAL3.from_data(data)?, + var_l3: Self::VAR_L3.from_data(data)?, + pfl3: Self::PFL3.from_data(data)?, + al3: Self::AL3.from_data(data)?, + vl3l1: Self::VL3L1.from_data(data)?, + vl3: Self::VL3.from_data(data)?, + tot_wh_inj_l3: Self::TOT_WH_INJ_L3.from_data(data)?, + tot_wh_abs_l3: Self::TOT_WH_ABS_L3.from_data(data)?, + tot_varh_inj_l3: Self::TOT_VARH_INJ_L3.from_data(data)?, + tot_varh_abs_l3: Self::TOT_VARH_ABS_L3.from_data(data)?, + throt_pct: Self::THROT_PCT.from_data(data)?, + throt_src: Self::THROT_SRC.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + va_sf: Self::VA_SF.from_data(data)?, + var_sf: Self::VAR_SF.from_data(data)?, + tot_wh_sf: Self::TOT_WH_SF.from_data(data)?, + tot_varh_sf: Self::TOT_VARH_SF.from_data(data)?, + tmp_sf: Self::TMP_SF.from_data(data)?, + mn_alrm_info: Self::MN_ALRM_INFO.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m701 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// AC Wiring Type @@ -774,3 +782,13 @@ impl crate::Value for Option { } } } +impl crate::Model for DerMeasureAc { + const ID: u16 = 701; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m701 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model702.rs b/src/models/model702.rs index f8e72fd..5449bbb 100644 --- a/src/models/model702.rs +++ b/src/models/model702.rs @@ -1,10 +1,11 @@ //! DER Capacity +pub type Model702 = DerCapacity; /// DER Capacity /// /// DER capacity model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model702 { +pub struct DerCapacity { /// Active Power Max Rating /// /// Maximum active power rating at unity power factor in watts. @@ -229,7 +230,7 @@ pub struct Model702 { pub s_sf: Option, } #[allow(missing_docs)] -impl Model702 { +impl DerCapacity { pub const W_MAX_RTG: crate::Point> = crate::Point::new(0, 1, false); pub const W_OVR_EXT_RTG: crate::Point> = crate::Point::new(1, 1, false); pub const W_OVR_EXT_RTG_PF: crate::Point> = crate::Point::new(2, 1, false); @@ -286,63 +287,70 @@ impl Model702 { pub const A_SF: crate::Point> = crate::Point::new(48, 1, false); pub const S_SF: crate::Point> = crate::Point::new(49, 1, false); } -impl crate::Model for Model702 { - const ID: u16 = 702; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - w_max_rtg: Self::W_MAX_RTG.from_data(data)?, - w_ovr_ext_rtg: Self::W_OVR_EXT_RTG.from_data(data)?, - w_ovr_ext_rtg_pf: Self::W_OVR_EXT_RTG_PF.from_data(data)?, - w_und_ext_rtg: Self::W_UND_EXT_RTG.from_data(data)?, - w_und_ext_rtg_pf: Self::W_UND_EXT_RTG_PF.from_data(data)?, - va_max_rtg: Self::VA_MAX_RTG.from_data(data)?, - var_max_inj_rtg: Self::VAR_MAX_INJ_RTG.from_data(data)?, - var_max_abs_rtg: Self::VAR_MAX_ABS_RTG.from_data(data)?, - w_cha_rte_max_rtg: Self::W_CHA_RTE_MAX_RTG.from_data(data)?, - w_dis_cha_rte_max_rtg: Self::W_DIS_CHA_RTE_MAX_RTG.from_data(data)?, - va_cha_rte_max_rtg: Self::VA_CHA_RTE_MAX_RTG.from_data(data)?, - va_dis_cha_rte_max_rtg: Self::VA_DIS_CHA_RTE_MAX_RTG.from_data(data)?, - v_nom_rtg: Self::V_NOM_RTG.from_data(data)?, - v_max_rtg: Self::V_MAX_RTG.from_data(data)?, - v_min_rtg: Self::V_MIN_RTG.from_data(data)?, - a_max_rtg: Self::A_MAX_RTG.from_data(data)?, - pf_ovr_ext_rtg: Self::PF_OVR_EXT_RTG.from_data(data)?, - pf_und_ext_rtg: Self::PF_UND_EXT_RTG.from_data(data)?, - react_suscept_rtg: Self::REACT_SUSCEPT_RTG.from_data(data)?, - nor_op_cat_rtg: Self::NOR_OP_CAT_RTG.from_data(data)?, - abn_op_cat_rtg: Self::ABN_OP_CAT_RTG.from_data(data)?, - ctrl_modes: Self::CTRL_MODES.from_data(data)?, - int_island_cat_rtg: Self::INT_ISLAND_CAT_RTG.from_data(data)?, - w_max: Self::W_MAX.from_data(data)?, - w_max_ovr_ext: Self::W_MAX_OVR_EXT.from_data(data)?, - w_ovr_ext_pf: Self::W_OVR_EXT_PF.from_data(data)?, - w_max_und_ext: Self::W_MAX_UND_EXT.from_data(data)?, - w_und_ext_pf: Self::W_UND_EXT_PF.from_data(data)?, - va_max: Self::VA_MAX.from_data(data)?, - var_max_inj: Self::VAR_MAX_INJ.from_data(data)?, - var_max_abs: Self::VAR_MAX_ABS.from_data(data)?, - w_cha_rte_max: Self::W_CHA_RTE_MAX.from_data(data)?, - w_dis_cha_rte_max: Self::W_DIS_CHA_RTE_MAX.from_data(data)?, - va_cha_rte_max: Self::VA_CHA_RTE_MAX.from_data(data)?, - va_dis_cha_rte_max: Self::VA_DIS_CHA_RTE_MAX.from_data(data)?, - v_nom: Self::V_NOM.from_data(data)?, - v_max: Self::V_MAX.from_data(data)?, - v_min: Self::V_MIN.from_data(data)?, - a_max: Self::A_MAX.from_data(data)?, - pf_ovr_ext: Self::PF_OVR_EXT.from_data(data)?, - pf_und_ext: Self::PF_UND_EXT.from_data(data)?, - int_island_cat: Self::INT_ISLAND_CAT.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - va_sf: Self::VA_SF.from_data(data)?, - var_sf: Self::VAR_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - s_sf: Self::S_SF.from_data(data)?, - }) +impl crate::Group for DerCapacity { + const LEN: u16 = 50; +} +impl DerCapacity { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + w_max_rtg: Self::W_MAX_RTG.from_data(data)?, + w_ovr_ext_rtg: Self::W_OVR_EXT_RTG.from_data(data)?, + w_ovr_ext_rtg_pf: Self::W_OVR_EXT_RTG_PF.from_data(data)?, + w_und_ext_rtg: Self::W_UND_EXT_RTG.from_data(data)?, + w_und_ext_rtg_pf: Self::W_UND_EXT_RTG_PF.from_data(data)?, + va_max_rtg: Self::VA_MAX_RTG.from_data(data)?, + var_max_inj_rtg: Self::VAR_MAX_INJ_RTG.from_data(data)?, + var_max_abs_rtg: Self::VAR_MAX_ABS_RTG.from_data(data)?, + w_cha_rte_max_rtg: Self::W_CHA_RTE_MAX_RTG.from_data(data)?, + w_dis_cha_rte_max_rtg: Self::W_DIS_CHA_RTE_MAX_RTG.from_data(data)?, + va_cha_rte_max_rtg: Self::VA_CHA_RTE_MAX_RTG.from_data(data)?, + va_dis_cha_rte_max_rtg: Self::VA_DIS_CHA_RTE_MAX_RTG.from_data(data)?, + v_nom_rtg: Self::V_NOM_RTG.from_data(data)?, + v_max_rtg: Self::V_MAX_RTG.from_data(data)?, + v_min_rtg: Self::V_MIN_RTG.from_data(data)?, + a_max_rtg: Self::A_MAX_RTG.from_data(data)?, + pf_ovr_ext_rtg: Self::PF_OVR_EXT_RTG.from_data(data)?, + pf_und_ext_rtg: Self::PF_UND_EXT_RTG.from_data(data)?, + react_suscept_rtg: Self::REACT_SUSCEPT_RTG.from_data(data)?, + nor_op_cat_rtg: Self::NOR_OP_CAT_RTG.from_data(data)?, + abn_op_cat_rtg: Self::ABN_OP_CAT_RTG.from_data(data)?, + ctrl_modes: Self::CTRL_MODES.from_data(data)?, + int_island_cat_rtg: Self::INT_ISLAND_CAT_RTG.from_data(data)?, + w_max: Self::W_MAX.from_data(data)?, + w_max_ovr_ext: Self::W_MAX_OVR_EXT.from_data(data)?, + w_ovr_ext_pf: Self::W_OVR_EXT_PF.from_data(data)?, + w_max_und_ext: Self::W_MAX_UND_EXT.from_data(data)?, + w_und_ext_pf: Self::W_UND_EXT_PF.from_data(data)?, + va_max: Self::VA_MAX.from_data(data)?, + var_max_inj: Self::VAR_MAX_INJ.from_data(data)?, + var_max_abs: Self::VAR_MAX_ABS.from_data(data)?, + w_cha_rte_max: Self::W_CHA_RTE_MAX.from_data(data)?, + w_dis_cha_rte_max: Self::W_DIS_CHA_RTE_MAX.from_data(data)?, + va_cha_rte_max: Self::VA_CHA_RTE_MAX.from_data(data)?, + va_dis_cha_rte_max: Self::VA_DIS_CHA_RTE_MAX.from_data(data)?, + v_nom: Self::V_NOM.from_data(data)?, + v_max: Self::V_MAX.from_data(data)?, + v_min: Self::V_MIN.from_data(data)?, + a_max: Self::A_MAX.from_data(data)?, + pf_ovr_ext: Self::PF_OVR_EXT.from_data(data)?, + pf_und_ext: Self::PF_UND_EXT.from_data(data)?, + int_island_cat: Self::INT_ISLAND_CAT.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + va_sf: Self::VA_SF.from_data(data)?, + var_sf: Self::VAR_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + s_sf: Self::S_SF.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m702 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Normal Operating Category @@ -538,3 +546,13 @@ impl crate::Value for Option { } } } +impl crate::Model for DerCapacity { + const ID: u16 = 702; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m702 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model703.rs b/src/models/model703.rs index 8a2ebad..e23e8a9 100644 --- a/src/models/model703.rs +++ b/src/models/model703.rs @@ -1,10 +1,11 @@ //! Enter Service +pub type Model703 = DerEnterService; /// Enter Service /// /// Enter service model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model703 { +pub struct DerEnterService { /// Permit Enter Service /// /// Permit enter service. @@ -51,7 +52,7 @@ pub struct Model703 { pub hz_sf: Option, } #[allow(missing_docs)] -impl Model703 { +impl DerEnterService { pub const ES: crate::Point> = crate::Point::new(0, 1, true); pub const ESV_HI: crate::Point> = crate::Point::new(1, 1, true); pub const ESV_LO: crate::Point> = crate::Point::new(2, 1, true); @@ -64,25 +65,32 @@ impl Model703 { pub const V_SF: crate::Point> = crate::Point::new(15, 1, false); pub const HZ_SF: crate::Point> = crate::Point::new(16, 1, false); } -impl crate::Model for Model703 { - const ID: u16 = 703; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - es: Self::ES.from_data(data)?, - esv_hi: Self::ESV_HI.from_data(data)?, - esv_lo: Self::ESV_LO.from_data(data)?, - es_hz_hi: Self::ES_HZ_HI.from_data(data)?, - es_hz_lo: Self::ES_HZ_LO.from_data(data)?, - es_dly_tms: Self::ES_DLY_TMS.from_data(data)?, - es_rnd_tms: Self::ES_RND_TMS.from_data(data)?, - es_rmp_tms: Self::ES_RMP_TMS.from_data(data)?, - es_dly_rem_tms: Self::ES_DLY_REM_TMS.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - }) +impl crate::Group for DerEnterService { + const LEN: u16 = 17; +} +impl DerEnterService { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + es: Self::ES.from_data(data)?, + esv_hi: Self::ESV_HI.from_data(data)?, + esv_lo: Self::ESV_LO.from_data(data)?, + es_hz_hi: Self::ES_HZ_HI.from_data(data)?, + es_hz_lo: Self::ES_HZ_LO.from_data(data)?, + es_dly_tms: Self::ES_DLY_TMS.from_data(data)?, + es_rnd_tms: Self::ES_RND_TMS.from_data(data)?, + es_rmp_tms: Self::ES_RMP_TMS.from_data(data)?, + es_dly_rem_tms: Self::ES_DLY_REM_TMS.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m703 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Permit Enter Service @@ -125,3 +133,13 @@ impl crate::Value for Option { } } } +impl crate::Model for DerEnterService { + const ID: u16 = 703; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m703 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model704.rs b/src/models/model704.rs index c52ffb0..be44f02 100644 --- a/src/models/model704.rs +++ b/src/models/model704.rs @@ -1,10 +1,11 @@ //! DER AC Controls +pub type Model704 = DerCtlAc; /// DER AC Controls /// /// DER AC controls model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model704 { +pub struct DerCtlAc { /// Power Factor Enable (W Inj) Enable /// /// Power factor enable when injecting active power. @@ -191,9 +192,27 @@ pub struct Model704 { /// /// Reactive power pct scale factor. pub var_set_pct_sf: Option, + /// Power Factor (W Inj) + /// + /// Power factor setpoint when injecting active power. + /// + /// Comments: Power Factor Settings + pub pfw_inj: Vec, + /// Reversion Power Factor (W Inj) + /// + /// Reversion power factor setpoint when injecting active power. + pub pfw_inj_rvrt: Vec, + /// Power Factor (W Abs) + /// + /// Power factor setpoint when absorbing active power. + pub pfw_abs: Vec, + /// Reversion Power Factor (W Abs) + /// + /// Reversion power factor setpoint when absorbing active power. + pub pfw_abs_rvrt: Vec, } #[allow(missing_docs)] -impl Model704 { +impl DerCtlAc { pub const PFW_INJ_ENA: crate::Point> = crate::Point::new(0, 1, true); pub const PFW_INJ_ENA_RVRT: crate::Point> = crate::Point::new(1, 1, true); @@ -246,57 +265,72 @@ impl Model704 { pub const VAR_SET_SF: crate::Point> = crate::Point::new(55, 1, false); pub const VAR_SET_PCT_SF: crate::Point> = crate::Point::new(56, 1, false); } -impl crate::Model for Model704 { - const ID: u16 = 704; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - pfw_inj_ena: Self::PFW_INJ_ENA.from_data(data)?, - pfw_inj_ena_rvrt: Self::PFW_INJ_ENA_RVRT.from_data(data)?, - pfw_inj_rvrt_tms: Self::PFW_INJ_RVRT_TMS.from_data(data)?, - pfw_inj_rvrt_rem: Self::PFW_INJ_RVRT_REM.from_data(data)?, - pfw_abs_ena: Self::PFW_ABS_ENA.from_data(data)?, - pfw_abs_ena_rvrt: Self::PFW_ABS_ENA_RVRT.from_data(data)?, - pfw_abs_rvrt_tms: Self::PFW_ABS_RVRT_TMS.from_data(data)?, - pfw_abs_rvrt_rem: Self::PFW_ABS_RVRT_REM.from_data(data)?, - w_max_lim_pct_ena: Self::W_MAX_LIM_PCT_ENA.from_data(data)?, - w_max_lim_pct: Self::W_MAX_LIM_PCT.from_data(data)?, - w_max_lim_pct_rvrt: Self::W_MAX_LIM_PCT_RVRT.from_data(data)?, - w_max_lim_pct_ena_rvrt: Self::W_MAX_LIM_PCT_ENA_RVRT.from_data(data)?, - w_max_lim_pct_rvrt_tms: Self::W_MAX_LIM_PCT_RVRT_TMS.from_data(data)?, - w_max_lim_pct_rvrt_rem: Self::W_MAX_LIM_PCT_RVRT_REM.from_data(data)?, - w_set_ena: Self::W_SET_ENA.from_data(data)?, - w_set_mod: Self::W_SET_MOD.from_data(data)?, - w_set: Self::W_SET.from_data(data)?, - w_set_rvrt: Self::W_SET_RVRT.from_data(data)?, - w_set_pct: Self::W_SET_PCT.from_data(data)?, - w_set_pct_rvrt: Self::W_SET_PCT_RVRT.from_data(data)?, - w_set_ena_rvrt: Self::W_SET_ENA_RVRT.from_data(data)?, - w_set_rvrt_tms: Self::W_SET_RVRT_TMS.from_data(data)?, - w_set_rvrt_rem: Self::W_SET_RVRT_REM.from_data(data)?, - var_set_ena: Self::VAR_SET_ENA.from_data(data)?, - var_set_mod: Self::VAR_SET_MOD.from_data(data)?, - var_set_pri: Self::VAR_SET_PRI.from_data(data)?, - var_set: Self::VAR_SET.from_data(data)?, - var_set_rvrt: Self::VAR_SET_RVRT.from_data(data)?, - var_set_pct: Self::VAR_SET_PCT.from_data(data)?, - var_set_pct_rvrt: Self::VAR_SET_PCT_RVRT.from_data(data)?, - var_set_ena_rvrt: Self::VAR_SET_ENA_RVRT.from_data(data)?, - var_set_rvrt_tms: Self::VAR_SET_RVRT_TMS.from_data(data)?, - var_set_rvrt_rem: Self::VAR_SET_RVRT_REM.from_data(data)?, - w_rmp: Self::W_RMP.from_data(data)?, - w_rmp_ref: Self::W_RMP_REF.from_data(data)?, - var_rmp: Self::VAR_RMP.from_data(data)?, - anti_isl_ena: Self::ANTI_ISL_ENA.from_data(data)?, - pf_sf: Self::PF_SF.from_data(data)?, - w_max_lim_pct_sf: Self::W_MAX_LIM_PCT_SF.from_data(data)?, - w_set_sf: Self::W_SET_SF.from_data(data)?, - w_set_pct_sf: Self::W_SET_PCT_SF.from_data(data)?, - var_set_sf: Self::VAR_SET_SF.from_data(data)?, - var_set_pct_sf: Self::VAR_SET_PCT_SF.from_data(data)?, - }) +impl crate::Group for DerCtlAc { + const LEN: u16 = 57; +} +impl DerCtlAc { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + pfw_inj_ena: Self::PFW_INJ_ENA.from_data(data)?, + pfw_inj_ena_rvrt: Self::PFW_INJ_ENA_RVRT.from_data(data)?, + pfw_inj_rvrt_tms: Self::PFW_INJ_RVRT_TMS.from_data(data)?, + pfw_inj_rvrt_rem: Self::PFW_INJ_RVRT_REM.from_data(data)?, + pfw_abs_ena: Self::PFW_ABS_ENA.from_data(data)?, + pfw_abs_ena_rvrt: Self::PFW_ABS_ENA_RVRT.from_data(data)?, + pfw_abs_rvrt_tms: Self::PFW_ABS_RVRT_TMS.from_data(data)?, + pfw_abs_rvrt_rem: Self::PFW_ABS_RVRT_REM.from_data(data)?, + w_max_lim_pct_ena: Self::W_MAX_LIM_PCT_ENA.from_data(data)?, + w_max_lim_pct: Self::W_MAX_LIM_PCT.from_data(data)?, + w_max_lim_pct_rvrt: Self::W_MAX_LIM_PCT_RVRT.from_data(data)?, + w_max_lim_pct_ena_rvrt: Self::W_MAX_LIM_PCT_ENA_RVRT.from_data(data)?, + w_max_lim_pct_rvrt_tms: Self::W_MAX_LIM_PCT_RVRT_TMS.from_data(data)?, + w_max_lim_pct_rvrt_rem: Self::W_MAX_LIM_PCT_RVRT_REM.from_data(data)?, + w_set_ena: Self::W_SET_ENA.from_data(data)?, + w_set_mod: Self::W_SET_MOD.from_data(data)?, + w_set: Self::W_SET.from_data(data)?, + w_set_rvrt: Self::W_SET_RVRT.from_data(data)?, + w_set_pct: Self::W_SET_PCT.from_data(data)?, + w_set_pct_rvrt: Self::W_SET_PCT_RVRT.from_data(data)?, + w_set_ena_rvrt: Self::W_SET_ENA_RVRT.from_data(data)?, + w_set_rvrt_tms: Self::W_SET_RVRT_TMS.from_data(data)?, + w_set_rvrt_rem: Self::W_SET_RVRT_REM.from_data(data)?, + var_set_ena: Self::VAR_SET_ENA.from_data(data)?, + var_set_mod: Self::VAR_SET_MOD.from_data(data)?, + var_set_pri: Self::VAR_SET_PRI.from_data(data)?, + var_set: Self::VAR_SET.from_data(data)?, + var_set_rvrt: Self::VAR_SET_RVRT.from_data(data)?, + var_set_pct: Self::VAR_SET_PCT.from_data(data)?, + var_set_pct_rvrt: Self::VAR_SET_PCT_RVRT.from_data(data)?, + var_set_ena_rvrt: Self::VAR_SET_ENA_RVRT.from_data(data)?, + var_set_rvrt_tms: Self::VAR_SET_RVRT_TMS.from_data(data)?, + var_set_rvrt_rem: Self::VAR_SET_RVRT_REM.from_data(data)?, + w_rmp: Self::W_RMP.from_data(data)?, + w_rmp_ref: Self::W_RMP_REF.from_data(data)?, + var_rmp: Self::VAR_RMP.from_data(data)?, + anti_isl_ena: Self::ANTI_ISL_ENA.from_data(data)?, + pf_sf: Self::PF_SF.from_data(data)?, + w_max_lim_pct_sf: Self::W_MAX_LIM_PCT_SF.from_data(data)?, + w_set_sf: Self::W_SET_SF.from_data(data)?, + w_set_pct_sf: Self::W_SET_PCT_SF.from_data(data)?, + var_set_sf: Self::VAR_SET_SF.from_data(data)?, + var_set_pct_sf: Self::VAR_SET_PCT_SF.from_data(data)?, + pfw_inj: Vec::new(), + pfw_inj_rvrt: Vec::new(), + pfw_abs: Vec::new(), + pfw_abs_rvrt: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m704 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pfw_inj) = PfwInj::parse_multiple(data, &group)?; + (data, group.pfw_inj_rvrt) = PfwInjRvrt::parse_multiple(data, &group)?; + (data, group.pfw_abs) = PfwAbs::parse_multiple(data, &group)?; + (data, group.pfw_abs_rvrt) = PfwAbsRvrt::parse_multiple(data, &group)?; + Ok((data, group)) } } /// Power Factor Enable (W Inj) Enable @@ -985,3 +1019,407 @@ impl crate::Value for Option { } } } +/// Power Factor (W Inj) +/// +/// Power factor setpoint when injecting active power. +/// +/// Comments: Power Factor Settings +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct PfwInj { + /// Power Factor (W Inj) + /// + /// Power factor setpoint when injecting active power. + pub pf: Option, + /// Power Factor Excitation (W Inj) + /// + /// Power factor excitation setpoint when injecting active power. + pub ext: Option, +} +#[allow(missing_docs)] +impl PfwInj { + pub const PF: crate::Point> = crate::Point::new(0, 1, true); + pub const EXT: crate::Point> = crate::Point::new(1, 1, true); +} +impl crate::Group for PfwInj { + const LEN: u16 = 2; +} +impl PfwInj { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + pf: Self::PF.from_data(data)?, + ext: Self::EXT.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerCtlAc, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerCtlAc, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = PfwInj::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Power Factor Excitation (W Inj) +/// +/// Power factor excitation setpoint when injecting active power. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum PfwInjExt { + /// Over-Excited + /// + /// Power factor over-excited excitation. + OverExcited = 0, + /// Under-Excited + /// + /// Power factor under-excited excitation. + UnderExcited = 1, +} +impl crate::Value for PfwInjExt { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + PfwInjExt::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Reversion Power Factor (W Inj) +/// +/// Reversion power factor setpoint when injecting active power. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct PfwInjRvrt { + /// Reversion Power Factor (W Inj) + /// + /// Reversion power factor setpoint when injecting active power. + pub pf: Option, + /// Reversion PF Excitation (W Inj) + /// + /// Reversion power factor excitation setpoint when injecting active power. + pub ext: Option, +} +#[allow(missing_docs)] +impl PfwInjRvrt { + pub const PF: crate::Point> = crate::Point::new(0, 1, true); + pub const EXT: crate::Point> = crate::Point::new(1, 1, true); +} +impl crate::Group for PfwInjRvrt { + const LEN: u16 = 2; +} +impl PfwInjRvrt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + pf: Self::PF.from_data(data)?, + ext: Self::EXT.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerCtlAc, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerCtlAc, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = PfwInjRvrt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Reversion PF Excitation (W Inj) +/// +/// Reversion power factor excitation setpoint when injecting active power. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum PfwInjRvrtExt { + /// Over-Excited + /// + /// Power factor over-excited excitation. + OverExcited = 0, + /// Under-Excited + /// + /// Power factor under-excited excitation. + UnderExcited = 1, +} +impl crate::Value for PfwInjRvrtExt { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + PfwInjRvrtExt::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Power Factor (W Abs) +/// +/// Power factor setpoint when absorbing active power. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct PfwAbs { + /// Power Factor (W Abs) + /// + /// Power factor setpoint when absorbing active power. + pub pf: Option, + /// Power Factor Excitation (W Abs) + /// + /// Power factor excitation setpoint when absorbing active power. + pub ext: Option, +} +#[allow(missing_docs)] +impl PfwAbs { + pub const PF: crate::Point> = crate::Point::new(0, 1, true); + pub const EXT: crate::Point> = crate::Point::new(1, 1, true); +} +impl crate::Group for PfwAbs { + const LEN: u16 = 2; +} +impl PfwAbs { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + pf: Self::PF.from_data(data)?, + ext: Self::EXT.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerCtlAc, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerCtlAc, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = PfwAbs::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Power Factor Excitation (W Abs) +/// +/// Power factor excitation setpoint when absorbing active power. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum PfwAbsExt { + /// Over-Excited + /// + /// Power factor over-excited excitation. + OverExcited = 0, + /// Under-Excited + /// + /// Power factor under-excited excitation. + UnderExcited = 1, +} +impl crate::Value for PfwAbsExt { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + PfwAbsExt::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Reversion Power Factor (W Abs) +/// +/// Reversion power factor setpoint when absorbing active power. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct PfwAbsRvrt { + /// Reversion Power Factor (W Abs) + /// + /// Reversion power factor setpoint when absorbing active power. + pub pf: Option, + /// Reversion PF Excitation (W Abs) + /// + /// Reversion power factor excitation setpoint when absorbing active power. + pub ext: Option, +} +#[allow(missing_docs)] +impl PfwAbsRvrt { + pub const PF: crate::Point> = crate::Point::new(0, 1, true); + pub const EXT: crate::Point> = crate::Point::new(1, 1, true); +} +impl crate::Group for PfwAbsRvrt { + const LEN: u16 = 2; +} +impl PfwAbsRvrt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + pf: Self::PF.from_data(data)?, + ext: Self::EXT.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerCtlAc, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerCtlAc, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = PfwAbsRvrt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Reversion PF Excitation (W Abs) +/// +/// Reversion power factor excitation setpoint when absorbing active power. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum PfwAbsRvrtExt { + /// Over-Excited + /// + /// Power factor over-excited excitation. + OverExcited = 0, + /// Under-Excited + /// + /// Power factor under-excited excitation. + UnderExcited = 1, +} +impl crate::Value for PfwAbsRvrtExt { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + PfwAbsRvrtExt::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for DerCtlAc { + const ID: u16 = 704; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m704 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model705.rs b/src/models/model705.rs index 1461c53..15a38f8 100644 --- a/src/models/model705.rs +++ b/src/models/model705.rs @@ -1,10 +1,11 @@ //! DER Volt-Var +pub type Model705 = DerVoltVar; /// DER Volt-Var /// /// DER Volt-Var model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model705 { +pub struct DerVoltVar { /// DER Volt-Var Module Enable /// /// Volt-Var control enable. @@ -49,9 +50,15 @@ pub struct Model705 { /// /// Open loop response time scale factor. pub rsp_tms_sf: i16, + /// Stored Curves + /// + /// Stored curve sets. + /// + /// Comments: Stored Curve Sets - Number of curve sets contained in NCrv - The first set is read-only and indicates the current settings. + pub crv: Vec, } #[allow(missing_docs)] -impl Model705 { +impl DerVoltVar { pub const ENA: crate::Point = crate::Point::new(0, 1, true); pub const ADPT_CRV_REQ: crate::Point = crate::Point::new(1, 1, true); pub const ADPT_CRV_RSLT: crate::Point = crate::Point::new(2, 1, false); @@ -64,25 +71,34 @@ impl Model705 { pub const DEPT_REF_SF: crate::Point = crate::Point::new(11, 1, false); pub const RSP_TMS_SF: crate::Point = crate::Point::new(12, 1, false); } -impl crate::Model for Model705 { - const ID: u16 = 705; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ena: Self::ENA.from_data(data)?, - adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, - adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rvrt_rem: Self::RVRT_REM.from_data(data)?, - rvrt_crv: Self::RVRT_CRV.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, - rsp_tms_sf: Self::RSP_TMS_SF.from_data(data)?, - }) +impl crate::Group for DerVoltVar { + const LEN: u16 = 13; +} +impl DerVoltVar { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ena: Self::ENA.from_data(data)?, + adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, + adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rvrt_rem: Self::RVRT_REM.from_data(data)?, + rvrt_crv: Self::RVRT_CRV.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, + rsp_tms_sf: Self::RSP_TMS_SF.from_data(data)?, + crv: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m705 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.crv) = Crv::parse_multiple(data, &group)?; + Ok((data, group)) } } /// DER Volt-Var Module Enable @@ -177,3 +193,360 @@ impl crate::Value for Option { } } } +/// Stored Curves +/// +/// Stored curve sets. +/// +/// Comments: Stored Curve Sets - Number of curve sets contained in NCrv - The first set is read-only and indicates the current settings. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Crv { + /// Active Points + /// + /// Number of active points. + pub act_pt: u16, + /// Dependent Reference + /// + /// Curve dependent reference. + pub dept_ref: CrvDeptRef, + /// Power Priority + /// + /// Power priority. + pub pri: Option, + /// Vref Adjustment + /// + /// Vref adjustment as percentage of nominal voltage. + pub v_ref: Option, + /// Current Autonomous Vref + /// + /// Autonomous vref value as a percentage of nominal voltage. + pub v_ref_auto: Option, + /// Autonomous Vref Enable + /// + /// Enable autonomous vref. + pub v_ref_auto_ena: Option, + /// Auto Vref Time Constant + /// + /// Autonomous vref time constant. + pub v_ref_auto_tms: Option, + /// Open Loop Response Time + /// + /// Open loop response time. + pub rsp_tms: Option, + /// Curve Access + /// + /// Curve read-write access. + pub read_only: CrvReadOnly, + /// Stored Curve Points + /// + /// Stored curve points. + /// + /// Comments: Stored Curve Sets - Curve points for each stored curve - Number of curve points contained in NPt + pub pt: Vec, +} +#[allow(missing_docs)] +impl Crv { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const DEPT_REF: crate::Point = crate::Point::new(1, 1, true); + pub const PRI: crate::Point> = crate::Point::new(2, 1, true); + pub const V_REF: crate::Point> = crate::Point::new(3, 1, true); + pub const V_REF_AUTO: crate::Point> = crate::Point::new(4, 1, false); + pub const V_REF_AUTO_ENA: crate::Point> = + crate::Point::new(5, 1, true); + pub const V_REF_AUTO_TMS: crate::Point> = crate::Point::new(6, 1, true); + pub const RSP_TMS: crate::Point> = crate::Point::new(7, 2, true); + pub const READ_ONLY: crate::Point = crate::Point::new(9, 1, false); +} +impl crate::Group for Crv { + const LEN: u16 = 10; +} +impl Crv { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + dept_ref: Self::DEPT_REF.from_data(data)?, + pri: Self::PRI.from_data(data)?, + v_ref: Self::V_REF.from_data(data)?, + v_ref_auto: Self::V_REF_AUTO.from_data(data)?, + v_ref_auto_ena: Self::V_REF_AUTO_ENA.from_data(data)?, + v_ref_auto_tms: Self::V_REF_AUTO_TMS.from_data(data)?, + rsp_tms: Self::RSP_TMS.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerVoltVar, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerVoltVar, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_crv { + let group; + (data, group) = Crv::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Dependent Reference +/// +/// Curve dependent reference. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvDeptRef { + /// Percent Max Watts + WMaxPct = 0, + /// Percent Max Vars + VarMaxPct = 1, + /// Percent Available Vars + VarAvalPct = 2, + /// Percent Max Apparent Power + VaMaxPct = 3, +} +impl crate::Value for CrvDeptRef { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvDeptRef::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Power Priority +/// +/// Power priority. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvPri { + /// Active Power Priority + /// + /// Active power priority. + Active = 0, + /// Reactive Power Priority + /// + /// Reactive power priority. + Reactive = 1, + /// Vendor Power Priority + /// + /// Power priority is vendor specific mode. + Vendor = 2, +} +impl crate::Value for CrvPri { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvPri::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Autonomous Vref Enable +/// +/// Enable autonomous vref. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvVRefAutoEna { + /// Disabled Flag + /// + /// Disabled flag (Disabled = 0, Enabled = 1). + Disabled = 0, + /// Enabled Flag + /// + /// Enabled flag (Disabled = 0, Enabled = 1). + Enabled = 1, +} +impl crate::Value for CrvVRefAutoEna { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvVRefAutoEna::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Curve Access +/// +/// Curve read-write access. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvReadOnly { + /// Read-Write Access + /// + /// Curve has read-write access. + Rw = 0, + /// Read-Only Access + /// + /// Curve has read-only access. + R = 1, +} +impl crate::Value for CrvReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Stored Curve Points +/// +/// Stored curve points. +/// +/// Comments: Stored Curve Sets - Curve points for each stored curve - Number of curve points contained in NPt +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Pt { + /// Voltage Point + /// + /// Curve voltage point as percentage. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub v: Option, + /// Reactive Power Point + /// + /// Curve reactive power point as set in DeptRef point. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub var: Option, +} +#[allow(missing_docs)] +impl Pt { + pub const V: crate::Point> = crate::Point::new(0, 1, true); + pub const VAR: crate::Point> = crate::Point::new(1, 1, true); +} +impl crate::Group for Pt { + const LEN: u16 = 2; +} +impl Pt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + v: Self::V.from_data(data)?, + var: Self::VAR.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerVoltVar, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerVoltVar, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_pt { + let group; + (data, group) = Pt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for DerVoltVar { + const ID: u16 = 705; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m705 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model706.rs b/src/models/model706.rs index a4ff899..b62fbf1 100644 --- a/src/models/model706.rs +++ b/src/models/model706.rs @@ -1,10 +1,11 @@ //! DER Volt-Watt +pub type Model706 = DerVoltWatt; /// DER Volt-Watt /// /// DER Volt-Watt model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model706 { +pub struct DerVoltWatt { /// DER Volt-Watt Module Enable /// /// Volt-Watt control enable. @@ -49,9 +50,15 @@ pub struct Model706 { /// /// Open loop response time scale factor. pub rsp_tms_sf: i16, + /// Stored Curves + /// + /// Stored curve sets. + /// + /// Comments: Stored curve sets - Number of curve sets contained in NCrv - The first set is read-only and indicates the current settings. + pub crv: Vec, } #[allow(missing_docs)] -impl Model706 { +impl DerVoltWatt { pub const ENA: crate::Point = crate::Point::new(0, 1, true); pub const ADPT_CRV_REQ: crate::Point = crate::Point::new(1, 1, true); pub const ADPT_CRV_RSLT: crate::Point = crate::Point::new(2, 1, false); @@ -64,25 +71,34 @@ impl Model706 { pub const DEPT_REF_SF: crate::Point = crate::Point::new(11, 1, false); pub const RSP_TMS_SF: crate::Point = crate::Point::new(12, 1, false); } -impl crate::Model for Model706 { - const ID: u16 = 706; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ena: Self::ENA.from_data(data)?, - adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, - adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rvrt_rem: Self::RVRT_REM.from_data(data)?, - rvrt_crv: Self::RVRT_CRV.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, - rsp_tms_sf: Self::RSP_TMS_SF.from_data(data)?, - }) +impl crate::Group for DerVoltWatt { + const LEN: u16 = 13; +} +impl DerVoltWatt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ena: Self::ENA.from_data(data)?, + adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, + adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rvrt_rem: Self::RVRT_REM.from_data(data)?, + rvrt_crv: Self::RVRT_CRV.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, + rsp_tms_sf: Self::RSP_TMS_SF.from_data(data)?, + crv: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m706 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.crv) = Crv::parse_multiple(data, &group)?; + Ok((data, group)) } } /// DER Volt-Watt Module Enable @@ -177,3 +193,233 @@ impl crate::Value for Option { } } } +/// Stored Curves +/// +/// Stored curve sets. +/// +/// Comments: Stored curve sets - Number of curve sets contained in NCrv - The first set is read-only and indicates the current settings. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Crv { + /// Active Points + /// + /// Number of active points. + pub act_pt: u16, + /// Dependent Reference + /// + /// Curve dependent reference. + pub dept_ref: CrvDeptRef, + /// Open Loop Response Time + /// + /// Open loop response time. + pub rsp_tms: Option, + /// Curve Access + /// + /// Curve read-write access. + pub read_only: CrvReadOnly, + /// Stored Curve Points + /// + /// Stored curve points. + /// + /// Comments: Stored curve sets - curve points for each stored curve - Number of curve points contained in NPt + pub pt: Vec, +} +#[allow(missing_docs)] +impl Crv { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const DEPT_REF: crate::Point = crate::Point::new(1, 1, true); + pub const RSP_TMS: crate::Point> = crate::Point::new(2, 2, true); + pub const READ_ONLY: crate::Point = crate::Point::new(4, 1, false); +} +impl crate::Group for Crv { + const LEN: u16 = 5; +} +impl Crv { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + dept_ref: Self::DEPT_REF.from_data(data)?, + rsp_tms: Self::RSP_TMS.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerVoltWatt, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerVoltWatt, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_crv { + let group; + (data, group) = Crv::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Dependent Reference +/// +/// Curve dependent reference. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvDeptRef { + #[allow(missing_docs)] + WMaxPct = 0, + #[allow(missing_docs)] + WAvalPct = 1, +} +impl crate::Value for CrvDeptRef { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvDeptRef::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Curve Access +/// +/// Curve read-write access. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvReadOnly { + /// Read-Write Access + /// + /// Curve has read-write access. + Rw = 0, + /// Read-Only Access + /// + /// Curve has read-only access. + R = 1, +} +impl crate::Value for CrvReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Stored Curve Points +/// +/// Stored curve points. +/// +/// Comments: Stored curve sets - curve points for each stored curve - Number of curve points contained in NPt +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Pt { + /// Voltage Point + /// + /// Curve voltage point as percentage. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub v: Option, + /// Dependent Reference + /// + /// Active power in percent of rated active power. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub w: Option, +} +#[allow(missing_docs)] +impl Pt { + pub const V: crate::Point> = crate::Point::new(0, 1, true); + pub const W: crate::Point> = crate::Point::new(1, 1, true); +} +impl crate::Group for Pt { + const LEN: u16 = 2; +} +impl Pt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + v: Self::V.from_data(data)?, + w: Self::W.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerVoltWatt, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerVoltWatt, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_pt { + let group; + (data, group) = Pt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for DerVoltWatt { + const ID: u16 = 706; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m706 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model707.rs b/src/models/model707.rs index 1be9cd6..91e1c86 100644 --- a/src/models/model707.rs +++ b/src/models/model707.rs @@ -1,10 +1,11 @@ //! DER Trip LV +pub type Model707 = DerTripLv; /// DER Trip LV /// /// DER low voltage trip model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model707 { +pub struct DerTripLv { /// DER Trip LV Module Enable /// /// DER low voltage trip control enable. @@ -33,9 +34,15 @@ pub struct Model707 { /// /// Scale factor for curve time points. pub tms_sf: i16, + /// Stored Curves + /// + /// Stored curve sets. + /// + /// Comments: Stored curve sets - Number of curve sets contained in NCrvSet - The first set is read-only and indicates the current settings. + pub crv: Vec, } #[allow(missing_docs)] -impl Model707 { +impl DerTripLv { pub const ENA: crate::Point = crate::Point::new(0, 1, true); pub const ADPT_CRV_REQ: crate::Point = crate::Point::new(1, 1, true); pub const ADPT_CRV_RSLT: crate::Point = crate::Point::new(2, 1, false); @@ -44,21 +51,30 @@ impl Model707 { pub const V_SF: crate::Point = crate::Point::new(5, 1, false); pub const TMS_SF: crate::Point = crate::Point::new(6, 1, false); } -impl crate::Model for Model707 { - const ID: u16 = 707; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ena: Self::ENA.from_data(data)?, - adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, - adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - n_crv_set: Self::N_CRV_SET.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - }) +impl crate::Group for DerTripLv { + const LEN: u16 = 7; +} +impl DerTripLv { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ena: Self::ENA.from_data(data)?, + adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, + adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + n_crv_set: Self::N_CRV_SET.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + crv: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m707 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.crv) = Crv::parse_multiple(data, &group)?; + Ok((data, group)) } } /// DER Trip LV Module Enable @@ -153,3 +169,349 @@ impl crate::Value for Option { } } } +/// Stored Curves +/// +/// Stored curve sets. +/// +/// Comments: Stored curve sets - Number of curve sets contained in NCrvSet - The first set is read-only and indicates the current settings. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Crv { + /// Curve Access + /// + /// Curve read-write access. + pub read_only: CrvReadOnly, + /// Must Trip Curve + /// + /// Stored must trip curve. + /// + /// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt + pub must_trip: Vec, + /// May Trip Curve + /// + /// Stored may trip curve. + pub may_trip: Vec, + /// Momentary Cessation Curve + /// + /// Stored momentary cessation curve. + pub mom_cess: Vec, +} +#[allow(missing_docs)] +impl Crv { + pub const READ_ONLY: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for Crv { + const LEN: u16 = 1; +} +impl Crv { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + read_only: Self::READ_ONLY.from_data(data)?, + must_trip: Vec::new(), + may_trip: Vec::new(), + mom_cess: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripLv, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.must_trip) = MustTrip::parse_multiple(data, model)?; + (data, group.may_trip) = MayTrip::parse_multiple(data, model)?; + (data, group.mom_cess) = MomCess::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripLv, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_crv_set { + let group; + (data, group) = Crv::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Curve Access +/// +/// Curve read-write access. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvReadOnly { + /// Read-Write Access + /// + /// Curve has read-write access. + Rw = 0, + /// Read-Only Access + /// + /// Curve has read-only access. + R = 1, +} +impl crate::Value for CrvReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Must Trip Curve +/// +/// Stored must trip curve. +/// +/// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MustTrip { + /// Number Of Active Points + /// + /// Number of active points in must trip curve. + pub act_pt: Option, + /// Must Trip Curve Points + /// + /// Must trip curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MustTrip { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MustTrip { + const LEN: u16 = 1; +} +impl MustTrip { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripLv, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripLv, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MustTrip::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Must Trip Curve Points +/// +/// Must trip curve points. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Pt { + /// Voltage Point + /// + /// Curve voltage point as percentage. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub v: Option, + /// Time Point + /// + /// Curve time point in seconds. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub tms: Option, +} +#[allow(missing_docs)] +impl Pt { + pub const V: crate::Point> = crate::Point::new(0, 1, true); + pub const TMS: crate::Point> = crate::Point::new(1, 2, true); +} +impl crate::Group for Pt { + const LEN: u16 = 3; +} +impl Pt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + v: Self::V.from_data(data)?, + tms: Self::TMS.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripLv, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripLv, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_pt { + let group; + (data, group) = Pt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// May Trip Curve +/// +/// Stored may trip curve. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MayTrip { + /// Number Of Active Points + /// + /// Number of active points in may trip curve. + pub act_pt: Option, + /// May Trip Curve Points + /// + /// May trip curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MayTrip { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MayTrip { + const LEN: u16 = 1; +} +impl MayTrip { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripLv, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripLv, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MayTrip::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Momentary Cessation Curve +/// +/// Stored momentary cessation curve. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MomCess { + /// Number Of Active Points + /// + /// Number of active points in the momentary cessation curve. + pub act_pt: Option, + /// Mom Cessation Curve Points + /// + /// Momentary cessation curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MomCess { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MomCess { + const LEN: u16 = 1; +} +impl MomCess { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripLv, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripLv, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MomCess::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for DerTripLv { + const ID: u16 = 707; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m707 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model708.rs b/src/models/model708.rs index 8178f78..d65e6f1 100644 --- a/src/models/model708.rs +++ b/src/models/model708.rs @@ -1,10 +1,11 @@ //! DER Trip HV +pub type Model708 = DerTripHv; /// DER Trip HV /// /// DER high voltage trip model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model708 { +pub struct DerTripHv { /// DER Trip HV Module Enable /// /// DER high voltage trip control enable. @@ -33,9 +34,15 @@ pub struct Model708 { /// /// Scale factor for curve time points. pub tms_sf: i16, + /// Stored Curves + /// + /// Stored curve sets. + /// + /// Comments: Stored curve sets - Number of curve sets contained in NCrvSet - The first set is read-only and indicates the current settings. + pub crv: Vec, } #[allow(missing_docs)] -impl Model708 { +impl DerTripHv { pub const ENA: crate::Point = crate::Point::new(0, 1, true); pub const ADPT_CRV_REQ: crate::Point = crate::Point::new(1, 1, true); pub const ADPT_CRV_RSLT: crate::Point = crate::Point::new(2, 1, false); @@ -44,21 +51,30 @@ impl Model708 { pub const V_SF: crate::Point = crate::Point::new(5, 1, false); pub const TMS_SF: crate::Point = crate::Point::new(6, 1, false); } -impl crate::Model for Model708 { - const ID: u16 = 708; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ena: Self::ENA.from_data(data)?, - adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, - adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - n_crv_set: Self::N_CRV_SET.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - }) +impl crate::Group for DerTripHv { + const LEN: u16 = 7; +} +impl DerTripHv { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ena: Self::ENA.from_data(data)?, + adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, + adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + n_crv_set: Self::N_CRV_SET.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + crv: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m708 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.crv) = Crv::parse_multiple(data, &group)?; + Ok((data, group)) } } /// DER Trip HV Module Enable @@ -153,3 +169,349 @@ impl crate::Value for Option { } } } +/// Stored Curves +/// +/// Stored curve sets. +/// +/// Comments: Stored curve sets - Number of curve sets contained in NCrvSet - The first set is read-only and indicates the current settings. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Crv { + /// Curve Access + /// + /// Curve read-write access. + pub read_only: CrvReadOnly, + /// Must Trip Curve + /// + /// Stored must trip curve. + /// + /// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt + pub must_trip: Vec, + /// May Trip Curve + /// + /// Stored may trip curve. + pub may_trip: Vec, + /// Momentary Cessation Curve + /// + /// Stored momentary cessation curve. + pub mom_cess: Vec, +} +#[allow(missing_docs)] +impl Crv { + pub const READ_ONLY: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for Crv { + const LEN: u16 = 1; +} +impl Crv { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + read_only: Self::READ_ONLY.from_data(data)?, + must_trip: Vec::new(), + may_trip: Vec::new(), + mom_cess: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripHv, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.must_trip) = MustTrip::parse_multiple(data, model)?; + (data, group.may_trip) = MayTrip::parse_multiple(data, model)?; + (data, group.mom_cess) = MomCess::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripHv, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_crv_set { + let group; + (data, group) = Crv::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Curve Access +/// +/// Curve read-write access. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvReadOnly { + /// Read-Write Access + /// + /// Curve has read-write access. + Rw = 0, + /// Read-Only Access + /// + /// Curve has read-only access. + R = 1, +} +impl crate::Value for CrvReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Must Trip Curve +/// +/// Stored must trip curve. +/// +/// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MustTrip { + /// Number Of Active Points + /// + /// Number of active points in must trip curve. + pub act_pt: Option, + /// Must Trip Curve Points + /// + /// Must trip curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MustTrip { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MustTrip { + const LEN: u16 = 1; +} +impl MustTrip { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripHv, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripHv, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MustTrip::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Must Trip Curve Points +/// +/// Must trip curve points. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Pt { + /// Voltage Point + /// + /// Curve voltage point as percentage. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub v: Option, + /// Time Point + /// + /// Curve time point in seconds. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub tms: Option, +} +#[allow(missing_docs)] +impl Pt { + pub const V: crate::Point> = crate::Point::new(0, 1, true); + pub const TMS: crate::Point> = crate::Point::new(1, 2, true); +} +impl crate::Group for Pt { + const LEN: u16 = 3; +} +impl Pt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + v: Self::V.from_data(data)?, + tms: Self::TMS.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripHv, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripHv, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_pt { + let group; + (data, group) = Pt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// May Trip Curve +/// +/// Stored may trip curve. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MayTrip { + /// Number Of Active Points + /// + /// Number of active points in may trip curve. + pub act_pt: Option, + /// May Trip Curve Points + /// + /// May trip curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MayTrip { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MayTrip { + const LEN: u16 = 1; +} +impl MayTrip { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripHv, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripHv, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MayTrip::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Momentary Cessation Curve +/// +/// Stored momentary cessation curve. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MomCess { + /// Number Of Active Points + /// + /// Number of active points in the momentary cessation curve. + pub act_pt: Option, + /// Mom Cessation Curve Points + /// + /// Momentary cessation curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MomCess { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MomCess { + const LEN: u16 = 1; +} +impl MomCess { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripHv, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripHv, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MomCess::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for DerTripHv { + const ID: u16 = 708; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m708 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model709.rs b/src/models/model709.rs index 7d959ff..72ac57c 100644 --- a/src/models/model709.rs +++ b/src/models/model709.rs @@ -1,10 +1,11 @@ //! DER Trip LF +pub type Model709 = DerTripLf; /// DER Trip LF /// /// DER low frequency trip model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model709 { +pub struct DerTripLf { /// DER Trip LF Module Enable /// /// DER low frequency trip control enable. @@ -33,9 +34,15 @@ pub struct Model709 { /// /// Scale factor for curve time points. pub tms_sf: i16, + /// Stored Curves + /// + /// Stored curve sets. + /// + /// Comments: Stored curve sets - Number of curve sets contained in NCrvSet - The first set is read-only and indicates the current settings. + pub crv: Vec, } #[allow(missing_docs)] -impl Model709 { +impl DerTripLf { pub const ENA: crate::Point = crate::Point::new(0, 1, true); pub const ADPT_CRV_REQ: crate::Point = crate::Point::new(1, 1, true); pub const ADPT_CRV_RSLT: crate::Point = crate::Point::new(2, 1, false); @@ -44,21 +51,30 @@ impl Model709 { pub const HZ_SF: crate::Point = crate::Point::new(5, 1, false); pub const TMS_SF: crate::Point = crate::Point::new(6, 1, false); } -impl crate::Model for Model709 { - const ID: u16 = 709; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ena: Self::ENA.from_data(data)?, - adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, - adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - n_crv_set: Self::N_CRV_SET.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - }) +impl crate::Group for DerTripLf { + const LEN: u16 = 7; +} +impl DerTripLf { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ena: Self::ENA.from_data(data)?, + adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, + adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + n_crv_set: Self::N_CRV_SET.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + crv: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m709 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.crv) = Crv::parse_multiple(data, &group)?; + Ok((data, group)) } } /// DER Trip LF Module Enable @@ -153,3 +169,349 @@ impl crate::Value for Option { } } } +/// Stored Curves +/// +/// Stored curve sets. +/// +/// Comments: Stored curve sets - Number of curve sets contained in NCrvSet - The first set is read-only and indicates the current settings. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Crv { + /// Curve Access + /// + /// Curve read-write access. + pub read_only: CrvReadOnly, + /// Must Trip Curve + /// + /// Stored must trip curve. + /// + /// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt + pub must_trip: Vec, + /// May Trip Curve + /// + /// Stored may trip curve. + pub may_trip: Vec, + /// Momentary Cessation Curve + /// + /// Stored momentary cessation curve. + pub mom_cess: Vec, +} +#[allow(missing_docs)] +impl Crv { + pub const READ_ONLY: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for Crv { + const LEN: u16 = 1; +} +impl Crv { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + read_only: Self::READ_ONLY.from_data(data)?, + must_trip: Vec::new(), + may_trip: Vec::new(), + mom_cess: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripLf, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.must_trip) = MustTrip::parse_multiple(data, model)?; + (data, group.may_trip) = MayTrip::parse_multiple(data, model)?; + (data, group.mom_cess) = MomCess::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripLf, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_crv_set { + let group; + (data, group) = Crv::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Curve Access +/// +/// Curve read-write access. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvReadOnly { + /// Read-Write Access + /// + /// Curve has read-write access. + Rw = 0, + /// Read-Only Access + /// + /// Curve has read-only access. + R = 1, +} +impl crate::Value for CrvReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Must Trip Curve +/// +/// Stored must trip curve. +/// +/// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MustTrip { + /// Number Of Active Points + /// + /// Number of active points in must trip curve. + pub act_pt: Option, + /// Must Trip Curve Points + /// + /// Must trip curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MustTrip { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MustTrip { + const LEN: u16 = 1; +} +impl MustTrip { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripLf, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripLf, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MustTrip::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Must Trip Curve Points +/// +/// Must trip curve points. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Pt { + /// Frequency Point + /// + /// Curve frequency point. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub hz: Option, + /// Time Point + /// + /// Curve time point in seconds. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub tms: Option, +} +#[allow(missing_docs)] +impl Pt { + pub const HZ: crate::Point> = crate::Point::new(0, 2, true); + pub const TMS: crate::Point> = crate::Point::new(2, 2, true); +} +impl crate::Group for Pt { + const LEN: u16 = 4; +} +impl Pt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + hz: Self::HZ.from_data(data)?, + tms: Self::TMS.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripLf, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripLf, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_pt { + let group; + (data, group) = Pt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// May Trip Curve +/// +/// Stored may trip curve. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MayTrip { + /// Number Of Active Points + /// + /// Number of active points in may trip curve. + pub act_pt: Option, + /// May Trip Curve Points + /// + /// May trip curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MayTrip { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MayTrip { + const LEN: u16 = 1; +} +impl MayTrip { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripLf, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripLf, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MayTrip::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Momentary Cessation Curve +/// +/// Stored momentary cessation curve. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MomCess { + /// Number Of Active Points + /// + /// Number of active points in the momentary cessation curve. + pub act_pt: Option, + /// Mom Cessation Curve Points + /// + /// Momentary cessation curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MomCess { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MomCess { + const LEN: u16 = 1; +} +impl MomCess { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripLf, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripLf, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MomCess::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for DerTripLf { + const ID: u16 = 709; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m709 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model710.rs b/src/models/model710.rs index dbe3d31..cc45c8e 100644 --- a/src/models/model710.rs +++ b/src/models/model710.rs @@ -1,10 +1,11 @@ //! DER Trip HF +pub type Model710 = DerTripHf; /// DER Trip HF /// /// DER high frequency trip model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model710 { +pub struct DerTripHf { /// DER Trip HF Module Enable /// /// DER high frequency trip control enable. @@ -33,9 +34,15 @@ pub struct Model710 { /// /// Scale factor for curve time points. pub tms_sf: i16, + /// Stored Curves + /// + /// Stored curve sets. + /// + /// Comments: Stored curve sets - Number of curve sets contained in NCrvSet - The first set is read-only and indicates the current settings. + pub crv: Vec, } #[allow(missing_docs)] -impl Model710 { +impl DerTripHf { pub const ENA: crate::Point = crate::Point::new(0, 1, true); pub const ADPT_CRV_REQ: crate::Point = crate::Point::new(1, 1, true); pub const ADPT_CRV_RSLT: crate::Point = crate::Point::new(2, 1, false); @@ -44,21 +51,30 @@ impl Model710 { pub const HZ_SF: crate::Point = crate::Point::new(5, 1, false); pub const TMS_SF: crate::Point = crate::Point::new(6, 1, false); } -impl crate::Model for Model710 { - const ID: u16 = 710; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ena: Self::ENA.from_data(data)?, - adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, - adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - n_crv_set: Self::N_CRV_SET.from_data(data)?, - hz_sf: Self::HZ_SF.from_data(data)?, - tms_sf: Self::TMS_SF.from_data(data)?, - }) +impl crate::Group for DerTripHf { + const LEN: u16 = 7; +} +impl DerTripHf { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ena: Self::ENA.from_data(data)?, + adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, + adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + n_crv_set: Self::N_CRV_SET.from_data(data)?, + hz_sf: Self::HZ_SF.from_data(data)?, + tms_sf: Self::TMS_SF.from_data(data)?, + crv: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m710 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.crv) = Crv::parse_multiple(data, &group)?; + Ok((data, group)) } } /// DER Trip HF Module Enable @@ -153,3 +169,349 @@ impl crate::Value for Option { } } } +/// Stored Curves +/// +/// Stored curve sets. +/// +/// Comments: Stored curve sets - Number of curve sets contained in NCrvSet - The first set is read-only and indicates the current settings. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Crv { + /// Curve Access + /// + /// Curve read-write access. + pub read_only: CrvReadOnly, + /// Must Trip Curve + /// + /// Stored must trip curve. + /// + /// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt + pub must_trip: Vec, + /// May Trip Curve + /// + /// Stored may trip curve. + pub may_trip: Vec, + /// Momentary Cessation Curve + /// + /// Stored momentary cessation curve. + pub mom_cess: Vec, +} +#[allow(missing_docs)] +impl Crv { + pub const READ_ONLY: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for Crv { + const LEN: u16 = 1; +} +impl Crv { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + read_only: Self::READ_ONLY.from_data(data)?, + must_trip: Vec::new(), + may_trip: Vec::new(), + mom_cess: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripHf, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.must_trip) = MustTrip::parse_multiple(data, model)?; + (data, group.may_trip) = MayTrip::parse_multiple(data, model)?; + (data, group.mom_cess) = MomCess::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripHf, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_crv_set { + let group; + (data, group) = Crv::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Curve Access +/// +/// Curve read-write access. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvReadOnly { + /// Read-Write Access + /// + /// Curve has read-write access. + Rw = 0, + /// Read-Only Access + /// + /// Curve has read-only access. + R = 1, +} +impl crate::Value for CrvReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Must Trip Curve +/// +/// Stored must trip curve. +/// +/// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MustTrip { + /// Number Of Active Points + /// + /// Number of active points in must trip curve. + pub act_pt: Option, + /// Must Trip Curve Points + /// + /// Must trip curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MustTrip { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MustTrip { + const LEN: u16 = 1; +} +impl MustTrip { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripHf, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripHf, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MustTrip::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Must Trip Curve Points +/// +/// Must trip curve points. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Pt { + /// Frequency Point + /// + /// Curve frequency point. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub hz: Option, + /// Time Point + /// + /// Curve time point in seconds. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. + pub tms: Option, +} +#[allow(missing_docs)] +impl Pt { + pub const HZ: crate::Point> = crate::Point::new(0, 2, true); + pub const TMS: crate::Point> = crate::Point::new(2, 2, true); +} +impl crate::Group for Pt { + const LEN: u16 = 4; +} +impl Pt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + hz: Self::HZ.from_data(data)?, + tms: Self::TMS.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripHf, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripHf, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_pt { + let group; + (data, group) = Pt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// May Trip Curve +/// +/// Stored may trip curve. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MayTrip { + /// Number Of Active Points + /// + /// Number of active points in may trip curve. + pub act_pt: Option, + /// May Trip Curve Points + /// + /// May trip curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MayTrip { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MayTrip { + const LEN: u16 = 1; +} +impl MayTrip { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripHf, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripHf, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MayTrip::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Momentary Cessation Curve +/// +/// Stored momentary cessation curve. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct MomCess { + /// Number Of Active Points + /// + /// Number of active points in the momentary cessation curve. + pub act_pt: Option, + /// Mom Cessation Curve Points + /// + /// Momentary cessation curve points. + pub pt: Vec, +} +#[allow(missing_docs)] +impl MomCess { + pub const ACT_PT: crate::Point> = crate::Point::new(0, 1, true); +} +impl crate::Group for MomCess { + const LEN: u16 = 1; +} +impl MomCess { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerTripHf, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerTripHf, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..1 { + let group; + (data, group) = MomCess::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for DerTripHf { + const ID: u16 = 710; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m710 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model711.rs b/src/models/model711.rs index 265e141..966f9b3 100644 --- a/src/models/model711.rs +++ b/src/models/model711.rs @@ -1,10 +1,11 @@ //! DER Frequency Droop +pub type Model711 = DerFreqDroop; /// DER Frequency Droop /// /// DER Frequency Droop model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model711 { +pub struct DerFreqDroop { /// DER Frequency Droop Module Enable /// /// DER Frequency-Watt (Frequency-Droop) control enable. @@ -45,9 +46,15 @@ pub struct Model711 { /// /// Open loop response time scale factor. pub rsp_tms_sf: i16, + /// Stored Controls + /// + /// Stored control sets. + /// + /// Comments: Stored control sets - Number of control sets contained in NCtl - The first set is read-only and indicates the current settings. + pub ctl: Vec, } #[allow(missing_docs)] -impl Model711 { +impl DerFreqDroop { pub const ENA: crate::Point = crate::Point::new(0, 1, true); pub const ADPT_CTL_REQ: crate::Point = crate::Point::new(1, 1, true); pub const ADPT_CTL_RSLT: crate::Point = crate::Point::new(2, 1, false); @@ -59,24 +66,33 @@ impl Model711 { pub const K_SF: crate::Point = crate::Point::new(10, 1, false); pub const RSP_TMS_SF: crate::Point = crate::Point::new(11, 1, false); } -impl crate::Model for Model711 { - const ID: u16 = 711; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ena: Self::ENA.from_data(data)?, - adpt_ctl_req: Self::ADPT_CTL_REQ.from_data(data)?, - adpt_ctl_rslt: Self::ADPT_CTL_RSLT.from_data(data)?, - n_ctl: Self::N_CTL.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rvrt_rem: Self::RVRT_REM.from_data(data)?, - rvrt_ctl: Self::RVRT_CTL.from_data(data)?, - db_sf: Self::DB_SF.from_data(data)?, - k_sf: Self::K_SF.from_data(data)?, - rsp_tms_sf: Self::RSP_TMS_SF.from_data(data)?, - }) +impl crate::Group for DerFreqDroop { + const LEN: u16 = 12; +} +impl DerFreqDroop { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ena: Self::ENA.from_data(data)?, + adpt_ctl_req: Self::ADPT_CTL_REQ.from_data(data)?, + adpt_ctl_rslt: Self::ADPT_CTL_RSLT.from_data(data)?, + n_ctl: Self::N_CTL.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rvrt_rem: Self::RVRT_REM.from_data(data)?, + rvrt_ctl: Self::RVRT_CTL.from_data(data)?, + db_sf: Self::DB_SF.from_data(data)?, + k_sf: Self::K_SF.from_data(data)?, + rsp_tms_sf: Self::RSP_TMS_SF.from_data(data)?, + ctl: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m711 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.ctl) = Ctl::parse_multiple(data, &group)?; + Ok((data, group)) } } /// DER Frequency Droop Module Enable @@ -171,3 +187,143 @@ impl crate::Value for Option { } } } +/// Stored Controls +/// +/// Stored control sets. +/// +/// Comments: Stored control sets - Number of control sets contained in NCtl - The first set is read-only and indicates the current settings. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Ctl { + /// Over-Frequency Deadband + /// + /// The deadband value for over-frequency conditions in Hz. + pub db_of: u32, + /// Under-Frequency Deadband + /// + /// The deadband value for under-frequency conditions in Hz. + pub db_uf: u32, + /// Over-Frequency Change Ratio + /// + /// Frequency droop per-unit frequency change for over-frequency conditions corresponding to 1 per-unit power output change. + pub k_of: u16, + /// Under-Frequency Change Ratio + /// + /// Frequency droop per-unit frequency change for under-frequency conditions corresponding to 1 per-unit power output change. + pub k_uf: u16, + /// Open-Loop Response Time + /// + /// The open-loop response time in seconds. + pub rsp_tms: u32, + /// Minimum Active Power + /// + /// The minimum active power output due to DER prime mover constraints, in percent of the DER active power rating. The valid range is -100 to 100. This setting applies only to the frequency droop control. + pub p_min: Option, + /// Control Access + /// + /// Control read-write access. + pub read_only: CtlReadOnly, +} +#[allow(missing_docs)] +impl Ctl { + pub const DB_OF: crate::Point = crate::Point::new(0, 2, true); + pub const DB_UF: crate::Point = crate::Point::new(2, 2, true); + pub const K_OF: crate::Point = crate::Point::new(4, 1, true); + pub const K_UF: crate::Point = crate::Point::new(5, 1, true); + pub const RSP_TMS: crate::Point = crate::Point::new(6, 2, true); + pub const P_MIN: crate::Point> = crate::Point::new(8, 1, true); + pub const READ_ONLY: crate::Point = crate::Point::new(9, 1, false); +} +impl crate::Group for Ctl { + const LEN: u16 = 10; +} +impl Ctl { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + db_of: Self::DB_OF.from_data(data)?, + db_uf: Self::DB_UF.from_data(data)?, + k_of: Self::K_OF.from_data(data)?, + k_uf: Self::K_UF.from_data(data)?, + rsp_tms: Self::RSP_TMS.from_data(data)?, + p_min: Self::P_MIN.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerFreqDroop, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerFreqDroop, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_ctl { + let group; + (data, group) = Ctl::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Control Access +/// +/// Control read-write access. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CtlReadOnly { + /// Read-Write Access + /// + /// Control has read-write access. + Rw = 0, + /// Read-Only Access + /// + /// Control has read-only access. + R = 1, +} +impl crate::Value for CtlReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CtlReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for DerFreqDroop { + const ID: u16 = 711; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m711 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model712.rs b/src/models/model712.rs index a5e6f12..d62e0d0 100644 --- a/src/models/model712.rs +++ b/src/models/model712.rs @@ -1,10 +1,11 @@ //! DER Watt-Var +pub type Model712 = DerWattVar; /// DER Watt-Var /// /// DER Watt-Var model. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model712 { +pub struct DerWattVar { /// DER Watt-Var Module Enable /// /// DER Watt-Var control enable. @@ -45,9 +46,15 @@ pub struct Model712 { /// /// Scale factor for curve var points. pub dept_ref_sf: i16, + /// Stored Curves + /// + /// Stored curve sets. + /// + /// Comments: Stored curve sets - Number of curve sets contained in NCrv - The first set is read-only and indicates the current settings. + pub crv: Vec, } #[allow(missing_docs)] -impl Model712 { +impl DerWattVar { pub const ENA: crate::Point = crate::Point::new(0, 1, true); pub const ADPT_CRV_REQ: crate::Point = crate::Point::new(1, 1, true); pub const ADPT_CRV_RSLT: crate::Point = crate::Point::new(2, 1, false); @@ -59,24 +66,33 @@ impl Model712 { pub const W_SF: crate::Point = crate::Point::new(10, 1, false); pub const DEPT_REF_SF: crate::Point = crate::Point::new(11, 1, false); } -impl crate::Model for Model712 { - const ID: u16 = 712; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ena: Self::ENA.from_data(data)?, - adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, - adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, - n_pt: Self::N_PT.from_data(data)?, - n_crv: Self::N_CRV.from_data(data)?, - rvrt_tms: Self::RVRT_TMS.from_data(data)?, - rvrt_rem: Self::RVRT_REM.from_data(data)?, - rvrt_crv: Self::RVRT_CRV.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, - }) +impl crate::Group for DerWattVar { + const LEN: u16 = 12; +} +impl DerWattVar { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ena: Self::ENA.from_data(data)?, + adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, + adpt_crv_rslt: Self::ADPT_CRV_RSLT.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + rvrt_tms: Self::RVRT_TMS.from_data(data)?, + rvrt_rem: Self::RVRT_REM.from_data(data)?, + rvrt_crv: Self::RVRT_CRV.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, + crv: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m712 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.crv) = Crv::parse_multiple(data, &group)?; + Ok((data, group)) } } /// DER Watt-Var Module Enable @@ -171,3 +187,281 @@ impl crate::Value for Option { } } } +/// Stored Curves +/// +/// Stored curve sets. +/// +/// Comments: Stored curve sets - Number of curve sets contained in NCrv - The first set is read-only and indicates the current settings. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Crv { + /// Active Points + /// + /// Number of active points. + pub act_pt: u16, + /// Dependent Reference + /// + /// Curve dependent reference. + pub dept_ref: CrvDeptRef, + /// Power Priority + /// + /// Power priority. + pub pri: Option, + /// Curve Access + /// + /// Curve read-write access. + pub read_only: CrvReadOnly, + /// Stored Curve Points + /// + /// Stored curve points. + /// + /// Comments: Stored curve sets - curve points for each stored curve - Number of curve points contained in NPt + pub pt: Vec, +} +#[allow(missing_docs)] +impl Crv { + pub const ACT_PT: crate::Point = crate::Point::new(0, 1, true); + pub const DEPT_REF: crate::Point = crate::Point::new(1, 1, true); + pub const PRI: crate::Point> = crate::Point::new(2, 1, true); + pub const READ_ONLY: crate::Point = crate::Point::new(3, 1, false); +} +impl crate::Group for Crv { + const LEN: u16 = 4; +} +impl Crv { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + act_pt: Self::ACT_PT.from_data(data)?, + dept_ref: Self::DEPT_REF.from_data(data)?, + pri: Self::PRI.from_data(data)?, + read_only: Self::READ_ONLY.from_data(data)?, + pt: Vec::new(), + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerWattVar, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.pt) = Pt::parse_multiple(data, model)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerWattVar, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_crv { + let group; + (data, group) = Crv::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Dependent Reference +/// +/// Curve dependent reference. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvDeptRef { + /// Percent Max Watts + WMaxPct = 0, + /// Percent Max Vars + VarMaxPct = 1, + /// Percent Available Vars + VarAvalPct = 2, + /// Percent Max Apparent Power + VaMaxPct = 3, +} +impl crate::Value for CrvDeptRef { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvDeptRef::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Power Priority +/// +/// Power priority. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvPri { + /// Active Power Priority + /// + /// Active power priority. + Active = 0, + /// Reactive Power Priority + /// + /// Reactive power priority. + Reactive = 1, +} +impl crate::Value for CrvPri { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvPri::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Curve Access +/// +/// Curve read-write access. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum CrvReadOnly { + /// Read-Write Access + /// + /// Curve has read-write access. + Rw = 0, + /// Read-Only Access + /// + /// Curve has read-only access. + R = 1, +} +impl crate::Value for CrvReadOnly { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + CrvReadOnly::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Stored Curve Points +/// +/// Stored curve points. +/// +/// Comments: Stored curve sets - curve points for each stored curve - Number of curve points contained in NPt +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Pt { + /// Active Power Point + /// + /// Curve active power point as percentage. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. IEEE 1547 implementations must allow 0 values for all three load points. + pub w: Option, + /// Reactive Power Point + /// + /// Curve reactive power point as set in DeptRef point. + /// + /// Detail: Internal curve conformance checks should be conducted when AdptCrvReq is set to 1, not on point writes. IEEE 1547 implementations must allow 0 values for all three load points + pub var: Option, +} +#[allow(missing_docs)] +impl Pt { + pub const W: crate::Point> = crate::Point::new(0, 1, true); + pub const VAR: crate::Point> = crate::Point::new(1, 1, true); +} +impl crate::Group for Pt { + const LEN: u16 = 2; +} +impl Pt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + w: Self::W.from_data(data)?, + var: Self::VAR.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerWattVar, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerWattVar, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_pt { + let group; + (data, group) = Pt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for DerWattVar { + const ID: u16 = 712; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m712 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model713.rs b/src/models/model713.rs index 94a57d1..0ae5a2f 100644 --- a/src/models/model713.rs +++ b/src/models/model713.rs @@ -1,10 +1,11 @@ //! DER Storage Capacity +pub type Model713 = DerStorageCapacity; /// DER Storage Capacity /// /// DER storage capacity. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model713 { +pub struct DerStorageCapacity { /// Energy Rating /// /// Energy rating of the DER storage. @@ -37,7 +38,7 @@ pub struct Model713 { pub pct_sf: Option, } #[allow(missing_docs)] -impl Model713 { +impl DerStorageCapacity { pub const WH_RTG: crate::Point> = crate::Point::new(0, 1, false); pub const WH_AVAIL: crate::Point> = crate::Point::new(1, 1, false); pub const SOC: crate::Point> = crate::Point::new(2, 1, false); @@ -46,21 +47,28 @@ impl Model713 { pub const WH_SF: crate::Point> = crate::Point::new(5, 1, false); pub const PCT_SF: crate::Point> = crate::Point::new(6, 1, false); } -impl crate::Model for Model713 { - const ID: u16 = 713; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - wh_rtg: Self::WH_RTG.from_data(data)?, - wh_avail: Self::WH_AVAIL.from_data(data)?, - soc: Self::SOC.from_data(data)?, - soh: Self::SOH.from_data(data)?, - sta: Self::STA.from_data(data)?, - wh_sf: Self::WH_SF.from_data(data)?, - pct_sf: Self::PCT_SF.from_data(data)?, - }) +impl crate::Group for DerStorageCapacity { + const LEN: u16 = 7; +} +impl DerStorageCapacity { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + wh_rtg: Self::WH_RTG.from_data(data)?, + wh_avail: Self::WH_AVAIL.from_data(data)?, + soc: Self::SOC.from_data(data)?, + soh: Self::SOH.from_data(data)?, + sta: Self::STA.from_data(data)?, + wh_sf: Self::WH_SF.from_data(data)?, + pct_sf: Self::PCT_SF.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m713 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Status @@ -111,3 +119,13 @@ impl crate::Value for Option { } } } +impl crate::Model for DerStorageCapacity { + const ID: u16 = 713; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m713 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model714.rs b/src/models/model714.rs index 01138cf..2ac5912 100644 --- a/src/models/model714.rs +++ b/src/models/model714.rs @@ -1,10 +1,11 @@ //! DER DC Measurement +pub type Model714 = DerMeasureDc; /// DER DC Measurement /// /// DER DC measurement. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model714 { +pub struct DerMeasureDc { /// Port Alarms /// /// Bitfield of ports with active alarms. Bit is 1 if port has an active alarm. Bit 0 is first port. @@ -51,9 +52,11 @@ pub struct Model714 { /// /// Temperature Scale Factor. pub tmp_sf: Option, + /// Comments: DC Port + pub prt: Vec, } #[allow(missing_docs)] -impl Model714 { +impl DerMeasureDc { pub const PRT_ALRMS: crate::Point> = crate::Point::new(0, 2, false); pub const N_PRT: crate::Point> = crate::Point::new(2, 1, false); pub const DCA: crate::Point> = crate::Point::new(3, 1, false); @@ -66,25 +69,34 @@ impl Model714 { pub const DCWH_SF: crate::Point> = crate::Point::new(16, 1, false); pub const TMP_SF: crate::Point> = crate::Point::new(17, 1, false); } -impl crate::Model for Model714 { - const ID: u16 = 714; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - prt_alrms: Self::PRT_ALRMS.from_data(data)?, - n_prt: Self::N_PRT.from_data(data)?, - dca: Self::DCA.from_data(data)?, - dcw: Self::DCW.from_data(data)?, - dc_wh_inj: Self::DC_WH_INJ.from_data(data)?, - dc_wh_abs: Self::DC_WH_ABS.from_data(data)?, - dca_sf: Self::DCA_SF.from_data(data)?, - dcv_sf: Self::DCV_SF.from_data(data)?, - dcw_sf: Self::DCW_SF.from_data(data)?, - dcwh_sf: Self::DCWH_SF.from_data(data)?, - tmp_sf: Self::TMP_SF.from_data(data)?, - }) +impl crate::Group for DerMeasureDc { + const LEN: u16 = 18; +} +impl DerMeasureDc { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + prt_alrms: Self::PRT_ALRMS.from_data(data)?, + n_prt: Self::N_PRT.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dcw: Self::DCW.from_data(data)?, + dc_wh_inj: Self::DC_WH_INJ.from_data(data)?, + dc_wh_abs: Self::DC_WH_ABS.from_data(data)?, + dca_sf: Self::DCA_SF.from_data(data)?, + dcv_sf: Self::DCV_SF.from_data(data)?, + dcw_sf: Self::DCW_SF.from_data(data)?, + dcwh_sf: Self::DCWH_SF.from_data(data)?, + tmp_sf: Self::TMP_SF.from_data(data)?, + prt: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m714 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.prt) = Prt::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -120,3 +132,254 @@ impl crate::Value for Option { } } } +/// Comments: DC Port +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Prt { + /// Port Type + /// + /// Port type. + pub prt_typ: Option, + /// Port ID + /// + /// Port ID. + pub id: Option, + /// Port ID String + /// + /// Port ID string. + pub id_str: Option, + /// DC Current + /// + /// DC current for the port. + pub dca: Option, + /// DC Voltage + /// + /// DC voltage for the port. + pub dcv: Option, + /// DC Power + /// + /// DC power for the port. + pub dcw: Option, + /// DC Energy Injected + /// + /// Total cumulative DC energy injected for the port. + pub dc_wh_inj: Option, + /// DC Energy Absorbed + /// + /// Total cumulative DC energy absorbed for the port. + pub dc_wh_abs: Option, + /// DC Port Temperature + /// + /// DC port temperature. + pub tmp: Option, + /// DC Port Status + /// + /// DC port status. + pub dc_sta: Option, + /// DC Port Alarm + /// + /// DC port alarm. + pub dc_alrm: Option, +} +#[allow(missing_docs)] +impl Prt { + pub const PRT_TYP: crate::Point> = crate::Point::new(0, 1, false); + pub const ID: crate::Point> = crate::Point::new(1, 1, false); + pub const ID_STR: crate::Point> = crate::Point::new(2, 8, false); + pub const DCA: crate::Point> = crate::Point::new(10, 1, false); + pub const DCV: crate::Point> = crate::Point::new(11, 1, false); + pub const DCW: crate::Point> = crate::Point::new(12, 1, false); + pub const DC_WH_INJ: crate::Point> = crate::Point::new(13, 4, false); + pub const DC_WH_ABS: crate::Point> = crate::Point::new(17, 4, false); + pub const TMP: crate::Point> = crate::Point::new(21, 1, false); + pub const DC_STA: crate::Point> = crate::Point::new(22, 1, false); + pub const DC_ALRM: crate::Point> = crate::Point::new(23, 2, false); +} +impl crate::Group for Prt { + const LEN: u16 = 25; +} +impl Prt { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + prt_typ: Self::PRT_TYP.from_data(data)?, + id: Self::ID.from_data(data)?, + id_str: Self::ID_STR.from_data(data)?, + dca: Self::DCA.from_data(data)?, + dcv: Self::DCV.from_data(data)?, + dcw: Self::DCW.from_data(data)?, + dc_wh_inj: Self::DC_WH_INJ.from_data(data)?, + dc_wh_abs: Self::DC_WH_ABS.from_data(data)?, + tmp: Self::TMP.from_data(data)?, + dc_sta: Self::DC_STA.from_data(data)?, + dc_alrm: Self::DC_ALRM.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &DerMeasureDc, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &DerMeasureDc, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_prt.unwrap_or_default() { + let group; + (data, group) = Prt::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +/// Port Type +/// +/// Port type. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum PrtPrtTyp { + /// Photovoltaic + Pv = 0, + /// Energy Storage System + Ess = 1, + /// Electric Vehicle + Ev = 2, + /// Generic Injecting + Inj = 3, + /// Generic Absorbing + Abs = 4, + /// Generic Bidirectional + Bidir = 5, + /// DC to DC + DcDc = 6, +} +impl crate::Value for PrtPrtTyp { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + PrtPrtTyp::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// DC Port Status +/// +/// DC port status. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum PrtDcSta { + /// Off + Off = 0, + /// On + On = 1, + /// Warning + Warning = 2, + /// Error + Error = 3, +} +impl crate::Value for PrtDcSta { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + PrtDcSta::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +bitflags::bitflags! { + #[doc = " DC Port Alarm"] #[doc = " "] #[doc = " DC port alarm."] #[derive(Copy, + Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", + derive(::serde::Serialize, ::serde::Deserialize))] pub struct PrtDcAlrm : u32 { #[doc + = " Ground Fault"] const GroundFault = 1; #[doc = " Input Over Voltage"] const + InputOverVoltage = 2; #[doc = " DC Disconnect"] const DcDisconnect = 8; #[doc = + " Cabinet Open"] const CabinetOpen = 32; #[doc = " Manual Shutdown"] const + ManualShutdown = 64; #[doc = " Over Temperature"] const OverTemp = 128; #[doc = + " Blown Fuse"] const BlownFuse = 4096; #[doc = " Under Temperature"] const UnderTemp + = 8192; #[doc = " Memory Loss"] const MemoryLoss = 16384; #[doc = " Arc Detection"] + const ArcDetection = 32768; #[doc = " Reserved"] const Reserved = 524288; #[doc = + " Test Failed"] const TestFailed = 1048576; #[doc = " Under Voltage"] const + InputUnderVoltage = 2097152; #[doc = " Over Current"] const InputOverCurrent = + 4194304; } +} +impl crate::Value for PrtDcAlrm { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(PrtDcAlrm::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +impl crate::Model for DerMeasureDc { + const ID: u16 = 714; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m714 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model715.rs b/src/models/model715.rs index 284afd3..1c9bce2 100644 --- a/src/models/model715.rs +++ b/src/models/model715.rs @@ -1,10 +1,11 @@ //! DERCtl +pub type Model715 = DerCtl; /// DERCtl /// /// DER Control #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model715 { +pub struct DerCtl { /// Control Mode /// /// DER control mode. Enumeration. @@ -29,26 +30,33 @@ pub struct Model715 { pub op_ctl: Option, } #[allow(missing_docs)] -impl Model715 { +impl DerCtl { pub const LOC_REM_CTL: crate::Point> = crate::Point::new(0, 1, false); pub const DER_HB: crate::Point> = crate::Point::new(1, 2, false); pub const CONTROLLER_HB: crate::Point> = crate::Point::new(3, 2, true); pub const ALARM_RESET: crate::Point> = crate::Point::new(5, 1, true); pub const OP_CTL: crate::Point> = crate::Point::new(6, 1, true); } -impl crate::Model for Model715 { - const ID: u16 = 715; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - loc_rem_ctl: Self::LOC_REM_CTL.from_data(data)?, - der_hb: Self::DER_HB.from_data(data)?, - controller_hb: Self::CONTROLLER_HB.from_data(data)?, - alarm_reset: Self::ALARM_RESET.from_data(data)?, - op_ctl: Self::OP_CTL.from_data(data)?, - }) +impl crate::Group for DerCtl { + const LEN: u16 = 7; +} +impl DerCtl { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + loc_rem_ctl: Self::LOC_REM_CTL.from_data(data)?, + der_hb: Self::DER_HB.from_data(data)?, + controller_hb: Self::CONTROLLER_HB.from_data(data)?, + alarm_reset: Self::ALARM_RESET.from_data(data)?, + op_ctl: Self::OP_CTL.from_data(data)?, + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m715 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Control Mode @@ -139,3 +147,13 @@ impl crate::Value for Option { } } } +impl crate::Model for DerCtl { + const ID: u16 = 715; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m715 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model8.rs b/src/models/model8.rs index d6e2b3e..3aa1643 100644 --- a/src/models/model8.rs +++ b/src/models/model8.rs @@ -13,22 +13,33 @@ pub struct Model8 { /// /// Number of registers to follow for the certificate pub n: u16, + #[allow(missing_docs)] + pub repeating: Vec, } #[allow(missing_docs)] impl Model8 { pub const FMT: crate::Point = crate::Point::new(0, 1, false); pub const N: crate::Point = crate::Point::new(1, 1, false); } -impl crate::Model for Model8 { - const ID: u16 = 8; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - fmt: Self::FMT.from_data(data)?, - n: Self::N.from_data(data)?, - }) +impl crate::Group for Model8 { + const LEN: u16 = 2; +} +impl Model8 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + fmt: Self::FMT.from_data(data)?, + n: Self::N.from_data(data)?, + repeating: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m8 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) } } /// Format @@ -73,3 +84,59 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + /// Cert + /// + /// X.509 Certificate of the device + pub cert: u16, +} +#[allow(missing_docs)] +impl Repeating { + pub const CERT: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for Repeating { + const LEN: u16 = 1; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + cert: Self::CERT.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Model8, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Model8, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for Model8 { + const ID: u16 = 8; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m8 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model801.rs b/src/models/model801.rs index 47e0a76..38ebb5b 100644 --- a/src/models/model801.rs +++ b/src/models/model801.rs @@ -1,27 +1,45 @@ //! Energy Storage Base Model (DEPRECATED) +pub type Model801 = Storage; /// Energy Storage Base Model (DEPRECATED) /// /// This model has been deprecated. #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model801 { +pub struct Storage { /// Deprecated Model /// /// This model has been deprecated. pub deprecated: u16, } #[allow(missing_docs)] -impl Model801 { +impl Storage { pub const DEPRECATED: crate::Point = crate::Point::new(0, 1, false); } -impl crate::Model for Model801 { - const ID: u16 = 801; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - deprecated: Self::DEPRECATED.from_data(data)?, - }) +impl crate::Group for Storage { + const LEN: u16 = 1; +} +impl Storage { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + deprecated: Self::DEPRECATED.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } +} +impl crate::Model for Storage { + const ID: u16 = 801; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m801 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model802.rs b/src/models/model802.rs index 46a2285..9493a36 100644 --- a/src/models/model802.rs +++ b/src/models/model802.rs @@ -1,8 +1,9 @@ //! Battery Base Model +pub type Model802 = Battery; /// Battery Base Model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model802 { +pub struct Battery { /// Nameplate Charge Capacity /// /// Nameplate charge capacity in amp-hours. @@ -247,7 +248,7 @@ pub struct Model802 { pub w_sf: Option, } #[allow(missing_docs)] -impl Model802 { +impl Battery { pub const AH_RTG: crate::Point = crate::Point::new(0, 1, false); pub const WH_RTG: crate::Point = crate::Point::new(1, 1, false); pub const W_CHA_RTE_MAX: crate::Point = crate::Point::new(2, 1, false); @@ -306,70 +307,77 @@ impl Model802 { pub const A_MAX_SF: crate::Point = crate::Point::new(60, 1, false); pub const W_SF: crate::Point> = crate::Point::new(61, 1, false); } -impl crate::Model for Model802 { - const ID: u16 = 802; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - ah_rtg: Self::AH_RTG.from_data(data)?, - wh_rtg: Self::WH_RTG.from_data(data)?, - w_cha_rte_max: Self::W_CHA_RTE_MAX.from_data(data)?, - w_dis_cha_rte_max: Self::W_DIS_CHA_RTE_MAX.from_data(data)?, - dis_cha_rte: Self::DIS_CHA_RTE.from_data(data)?, - soc_max: Self::SOC_MAX.from_data(data)?, - soc_min: Self::SOC_MIN.from_data(data)?, - soc_rsv_max: Self::SOC_RSV_MAX.from_data(data)?, - soc_rsv_min: Self::SOC_RSV_MIN.from_data(data)?, - soc: Self::SOC.from_data(data)?, - do_d: Self::DO_D.from_data(data)?, - soh: Self::SOH.from_data(data)?, - n_cyc: Self::N_CYC.from_data(data)?, - cha_st: Self::CHA_ST.from_data(data)?, - loc_rem_ctl: Self::LOC_REM_CTL.from_data(data)?, - hb: Self::HB.from_data(data)?, - ctrl_hb: Self::CTRL_HB.from_data(data)?, - alm_rst: Self::ALM_RST.from_data(data)?, - typ: Self::TYP.from_data(data)?, - state: Self::STATE.from_data(data)?, - state_vnd: Self::STATE_VND.from_data(data)?, - warr_dt: Self::WARR_DT.from_data(data)?, - evt1: Self::EVT1.from_data(data)?, - evt2: Self::EVT2.from_data(data)?, - evt_vnd1: Self::EVT_VND1.from_data(data)?, - evt_vnd2: Self::EVT_VND2.from_data(data)?, - v: Self::V.from_data(data)?, - v_max: Self::V_MAX.from_data(data)?, - v_min: Self::V_MIN.from_data(data)?, - cell_v_max: Self::CELL_V_MAX.from_data(data)?, - cell_v_max_str: Self::CELL_V_MAX_STR.from_data(data)?, - cell_v_max_mod: Self::CELL_V_MAX_MOD.from_data(data)?, - cell_v_min: Self::CELL_V_MIN.from_data(data)?, - cell_v_min_str: Self::CELL_V_MIN_STR.from_data(data)?, - cell_v_min_mod: Self::CELL_V_MIN_MOD.from_data(data)?, - cell_v_avg: Self::CELL_V_AVG.from_data(data)?, - a: Self::A.from_data(data)?, - a_cha_max: Self::A_CHA_MAX.from_data(data)?, - a_dis_cha_max: Self::A_DIS_CHA_MAX.from_data(data)?, - w: Self::W.from_data(data)?, - req_inv_state: Self::REQ_INV_STATE.from_data(data)?, - req_w: Self::REQ_W.from_data(data)?, - set_op: Self::SET_OP.from_data(data)?, - set_inv_state: Self::SET_INV_STATE.from_data(data)?, - ah_rtg_sf: Self::AH_RTG_SF.from_data(data)?, - wh_rtg_sf: Self::WH_RTG_SF.from_data(data)?, - w_cha_dis_cha_max_sf: Self::W_CHA_DIS_CHA_MAX_SF.from_data(data)?, - dis_cha_rte_sf: Self::DIS_CHA_RTE_SF.from_data(data)?, - soc_sf: Self::SOC_SF.from_data(data)?, - do_d_sf: Self::DO_D_SF.from_data(data)?, - soh_sf: Self::SOH_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - cell_v_sf: Self::CELL_V_SF.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - a_max_sf: Self::A_MAX_SF.from_data(data)?, - w_sf: Self::W_SF.from_data(data)?, - }) - } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m802 +impl crate::Group for Battery { + const LEN: u16 = 62; +} +impl Battery { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + ah_rtg: Self::AH_RTG.from_data(data)?, + wh_rtg: Self::WH_RTG.from_data(data)?, + w_cha_rte_max: Self::W_CHA_RTE_MAX.from_data(data)?, + w_dis_cha_rte_max: Self::W_DIS_CHA_RTE_MAX.from_data(data)?, + dis_cha_rte: Self::DIS_CHA_RTE.from_data(data)?, + soc_max: Self::SOC_MAX.from_data(data)?, + soc_min: Self::SOC_MIN.from_data(data)?, + soc_rsv_max: Self::SOC_RSV_MAX.from_data(data)?, + soc_rsv_min: Self::SOC_RSV_MIN.from_data(data)?, + soc: Self::SOC.from_data(data)?, + do_d: Self::DO_D.from_data(data)?, + soh: Self::SOH.from_data(data)?, + n_cyc: Self::N_CYC.from_data(data)?, + cha_st: Self::CHA_ST.from_data(data)?, + loc_rem_ctl: Self::LOC_REM_CTL.from_data(data)?, + hb: Self::HB.from_data(data)?, + ctrl_hb: Self::CTRL_HB.from_data(data)?, + alm_rst: Self::ALM_RST.from_data(data)?, + typ: Self::TYP.from_data(data)?, + state: Self::STATE.from_data(data)?, + state_vnd: Self::STATE_VND.from_data(data)?, + warr_dt: Self::WARR_DT.from_data(data)?, + evt1: Self::EVT1.from_data(data)?, + evt2: Self::EVT2.from_data(data)?, + evt_vnd1: Self::EVT_VND1.from_data(data)?, + evt_vnd2: Self::EVT_VND2.from_data(data)?, + v: Self::V.from_data(data)?, + v_max: Self::V_MAX.from_data(data)?, + v_min: Self::V_MIN.from_data(data)?, + cell_v_max: Self::CELL_V_MAX.from_data(data)?, + cell_v_max_str: Self::CELL_V_MAX_STR.from_data(data)?, + cell_v_max_mod: Self::CELL_V_MAX_MOD.from_data(data)?, + cell_v_min: Self::CELL_V_MIN.from_data(data)?, + cell_v_min_str: Self::CELL_V_MIN_STR.from_data(data)?, + cell_v_min_mod: Self::CELL_V_MIN_MOD.from_data(data)?, + cell_v_avg: Self::CELL_V_AVG.from_data(data)?, + a: Self::A.from_data(data)?, + a_cha_max: Self::A_CHA_MAX.from_data(data)?, + a_dis_cha_max: Self::A_DIS_CHA_MAX.from_data(data)?, + w: Self::W.from_data(data)?, + req_inv_state: Self::REQ_INV_STATE.from_data(data)?, + req_w: Self::REQ_W.from_data(data)?, + set_op: Self::SET_OP.from_data(data)?, + set_inv_state: Self::SET_INV_STATE.from_data(data)?, + ah_rtg_sf: Self::AH_RTG_SF.from_data(data)?, + wh_rtg_sf: Self::WH_RTG_SF.from_data(data)?, + w_cha_dis_cha_max_sf: Self::W_CHA_DIS_CHA_MAX_SF.from_data(data)?, + dis_cha_rte_sf: Self::DIS_CHA_RTE_SF.from_data(data)?, + soc_sf: Self::SOC_SF.from_data(data)?, + do_d_sf: Self::DO_D_SF.from_data(data)?, + soh_sf: Self::SOH_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + cell_v_sf: Self::CELL_V_SF.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + a_max_sf: Self::A_MAX_SF.from_data(data)?, + w_sf: Self::W_SF.from_data(data)?, + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) } } /// Charge Status @@ -856,3 +864,13 @@ impl crate::Value for Option { } } } +impl crate::Model for Battery { + const ID: u16 = 802; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m802 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model803.rs b/src/models/model803.rs index d83f7a7..399fef4 100644 --- a/src/models/model803.rs +++ b/src/models/model803.rs @@ -1,8 +1,9 @@ //! Lithium-Ion Battery Bank Model +pub type Model803 = LithiumIonBank; /// Lithium-Ion Battery Bank Model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model803 { +pub struct LithiumIonBank { /// String Count /// /// Number of strings in the bank. @@ -113,9 +114,11 @@ pub struct Model803 { pub soc_sf: i16, /// Scale factor for string voltage. pub v_sf: Option, + #[allow(missing_docs)] + pub string: Vec, } #[allow(missing_docs)] -impl Model803 { +impl LithiumIonBank { pub const N_STR: crate::Point = crate::Point::new(0, 1, false); pub const N_STR_CON: crate::Point = crate::Point::new(1, 1, false); pub const MOD_TMP_MAX: crate::Point = crate::Point::new(2, 1, false); @@ -143,39 +146,662 @@ impl Model803 { pub const SOC_SF: crate::Point = crate::Point::new(24, 1, false); pub const V_SF: crate::Point> = crate::Point::new(25, 1, false); } -impl crate::Model for Model803 { - const ID: u16 = 803; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - n_str: Self::N_STR.from_data(data)?, - n_str_con: Self::N_STR_CON.from_data(data)?, - mod_tmp_max: Self::MOD_TMP_MAX.from_data(data)?, - mod_tmp_max_str: Self::MOD_TMP_MAX_STR.from_data(data)?, - mod_tmp_max_mod: Self::MOD_TMP_MAX_MOD.from_data(data)?, - mod_tmp_min: Self::MOD_TMP_MIN.from_data(data)?, - mod_tmp_min_str: Self::MOD_TMP_MIN_STR.from_data(data)?, - mod_tmp_min_mod: Self::MOD_TMP_MIN_MOD.from_data(data)?, - mod_tmp_avg: Self::MOD_TMP_AVG.from_data(data)?, - str_v_max: Self::STR_V_MAX.from_data(data)?, - str_v_max_str: Self::STR_V_MAX_STR.from_data(data)?, - str_v_min: Self::STR_V_MIN.from_data(data)?, - str_v_min_str: Self::STR_V_MIN_STR.from_data(data)?, - str_v_avg: Self::STR_V_AVG.from_data(data)?, - str_a_max: Self::STR_A_MAX.from_data(data)?, - str_a_max_str: Self::STR_A_MAX_STR.from_data(data)?, - str_a_min: Self::STR_A_MIN.from_data(data)?, - str_a_min_str: Self::STR_A_MIN_STR.from_data(data)?, - str_a_avg: Self::STR_A_AVG.from_data(data)?, - n_cell_bal: Self::N_CELL_BAL.from_data(data)?, - cell_v_sf: Self::CELL_V_SF.from_data(data)?, - mod_tmp_sf: Self::MOD_TMP_SF.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - soh_sf: Self::SOH_SF.from_data(data)?, - soc_sf: Self::SOC_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - }) +impl crate::Group for LithiumIonBank { + const LEN: u16 = 26; +} +impl LithiumIonBank { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + n_str: Self::N_STR.from_data(data)?, + n_str_con: Self::N_STR_CON.from_data(data)?, + mod_tmp_max: Self::MOD_TMP_MAX.from_data(data)?, + mod_tmp_max_str: Self::MOD_TMP_MAX_STR.from_data(data)?, + mod_tmp_max_mod: Self::MOD_TMP_MAX_MOD.from_data(data)?, + mod_tmp_min: Self::MOD_TMP_MIN.from_data(data)?, + mod_tmp_min_str: Self::MOD_TMP_MIN_STR.from_data(data)?, + mod_tmp_min_mod: Self::MOD_TMP_MIN_MOD.from_data(data)?, + mod_tmp_avg: Self::MOD_TMP_AVG.from_data(data)?, + str_v_max: Self::STR_V_MAX.from_data(data)?, + str_v_max_str: Self::STR_V_MAX_STR.from_data(data)?, + str_v_min: Self::STR_V_MIN.from_data(data)?, + str_v_min_str: Self::STR_V_MIN_STR.from_data(data)?, + str_v_avg: Self::STR_V_AVG.from_data(data)?, + str_a_max: Self::STR_A_MAX.from_data(data)?, + str_a_max_str: Self::STR_A_MAX_STR.from_data(data)?, + str_a_min: Self::STR_A_MIN.from_data(data)?, + str_a_min_str: Self::STR_A_MIN_STR.from_data(data)?, + str_a_avg: Self::STR_A_AVG.from_data(data)?, + n_cell_bal: Self::N_CELL_BAL.from_data(data)?, + cell_v_sf: Self::CELL_V_SF.from_data(data)?, + mod_tmp_sf: Self::MOD_TMP_SF.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + soh_sf: Self::SOH_SF.from_data(data)?, + soc_sf: Self::SOC_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + string: Vec::new(), + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.string) = String::parse_multiple(data, &group)?; + Ok((data, group)) + } +} +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct String { + /// Module Count + /// + /// Count of modules in the string. + pub str_n_mod: u16, + /// String Status + /// + /// Current status of the string. + pub str_st: StringStrSt, + /// Connection Failure Reason + pub str_con_fail: Option, + /// String State of Charge + /// + /// Battery string state of charge, expressed as a percentage. + pub str_soc: u16, + /// String State of Health + /// + /// Battery string state of health, expressed as a percentage. + pub str_soh: Option, + /// String Current + /// + /// String current measurement. + pub str_a: i16, + /// Max Cell Voltage + /// + /// Maximum voltage for all cells in the string. + pub str_cell_v_max: u16, + /// Max Cell Voltage Module + /// + /// Module containing the maximum cell voltage. + pub str_cell_v_max_mod: Option, + /// Min Cell Voltage + /// + /// Minimum voltage for all cells in the string. + pub str_cell_v_min: u16, + /// Min Cell Voltage Module + /// + /// Module containing the minimum cell voltage. + pub str_cell_v_min_mod: Option, + /// Average Cell Voltage + /// + /// Average voltage for all cells in the string. + pub str_cell_v_avg: u16, + /// Max Module Temperature + /// + /// Maximum temperature for all modules in the bank. + pub str_mod_tmp_max: i16, + /// Max Module Temperature Module + /// + /// Module with the maximum temperature. + pub str_mod_tmp_max_mod: Option, + /// Min Module Temperature + /// + /// Minimum temperature for all modules in the bank. + pub str_mod_tmp_min: i16, + /// Min Module Temperature Module + /// + /// Module with the minimum temperature. + pub str_mod_tmp_min_mod: Option, + /// Average Module Temperature + /// + /// Average temperature for all modules in the bank. + pub str_mod_tmp_avg: i16, + /// Disabled Reason + /// + /// Reason why the string is currently disabled. + pub str_dis_rsn: Option, + /// Contactor Status + /// + /// Status of the contactor(s) for the string. + pub str_con_st: Option, + /// String Event 1 + /// + /// Alarms, warnings and status values. Bit flags. + pub str_evt1: StringStrEvt1, + /// String Event 2 + /// + /// Alarms, warnings and status values. Bit flags. + pub str_evt2: Option, + /// Vendor String Event Bitfield 1 + /// + /// Vendor defined events. + pub str_evt_vnd1: Option, + /// Vendor String Event Bitfield 2 + /// + /// Vendor defined events. + pub str_evt_vnd2: Option, + /// Enable/Disable String + /// + /// Enables and disables the string. + pub str_set_ena: Option, + /// Connect/Disconnect String + /// + /// Connects and disconnects the string. + pub str_set_con: Option, +} +#[allow(missing_docs)] +impl String { + pub const STR_N_MOD: crate::Point = crate::Point::new(0, 1, false); + pub const STR_ST: crate::Point = crate::Point::new(1, 2, false); + pub const STR_CON_FAIL: crate::Point> = + crate::Point::new(3, 1, false); + pub const STR_SOC: crate::Point = crate::Point::new(4, 1, false); + pub const STR_SOH: crate::Point> = crate::Point::new(5, 1, false); + pub const STR_A: crate::Point = crate::Point::new(6, 1, false); + pub const STR_CELL_V_MAX: crate::Point = crate::Point::new(7, 1, false); + pub const STR_CELL_V_MAX_MOD: crate::Point> = crate::Point::new(8, 1, false); + pub const STR_CELL_V_MIN: crate::Point = crate::Point::new(9, 1, false); + pub const STR_CELL_V_MIN_MOD: crate::Point> = crate::Point::new(10, 1, false); + pub const STR_CELL_V_AVG: crate::Point = crate::Point::new(11, 1, false); + pub const STR_MOD_TMP_MAX: crate::Point = crate::Point::new(12, 1, false); + pub const STR_MOD_TMP_MAX_MOD: crate::Point> = + crate::Point::new(13, 1, false); + pub const STR_MOD_TMP_MIN: crate::Point = crate::Point::new(14, 1, false); + pub const STR_MOD_TMP_MIN_MOD: crate::Point> = + crate::Point::new(15, 1, false); + pub const STR_MOD_TMP_AVG: crate::Point = crate::Point::new(16, 1, false); + pub const STR_DIS_RSN: crate::Point> = + crate::Point::new(17, 1, false); + pub const STR_CON_ST: crate::Point> = + crate::Point::new(18, 2, false); + pub const STR_EVT1: crate::Point = crate::Point::new(20, 2, false); + pub const STR_EVT2: crate::Point> = crate::Point::new(22, 2, false); + pub const STR_EVT_VND1: crate::Point> = + crate::Point::new(24, 2, false); + pub const STR_EVT_VND2: crate::Point> = + crate::Point::new(26, 2, false); + pub const STR_SET_ENA: crate::Point> = + crate::Point::new(28, 1, true); + pub const STR_SET_CON: crate::Point> = + crate::Point::new(29, 1, true); +} +impl crate::Group for String { + const LEN: u16 = 32; +} +impl String { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + str_n_mod: Self::STR_N_MOD.from_data(data)?, + str_st: Self::STR_ST.from_data(data)?, + str_con_fail: Self::STR_CON_FAIL.from_data(data)?, + str_soc: Self::STR_SOC.from_data(data)?, + str_soh: Self::STR_SOH.from_data(data)?, + str_a: Self::STR_A.from_data(data)?, + str_cell_v_max: Self::STR_CELL_V_MAX.from_data(data)?, + str_cell_v_max_mod: Self::STR_CELL_V_MAX_MOD.from_data(data)?, + str_cell_v_min: Self::STR_CELL_V_MIN.from_data(data)?, + str_cell_v_min_mod: Self::STR_CELL_V_MIN_MOD.from_data(data)?, + str_cell_v_avg: Self::STR_CELL_V_AVG.from_data(data)?, + str_mod_tmp_max: Self::STR_MOD_TMP_MAX.from_data(data)?, + str_mod_tmp_max_mod: Self::STR_MOD_TMP_MAX_MOD.from_data(data)?, + str_mod_tmp_min: Self::STR_MOD_TMP_MIN.from_data(data)?, + str_mod_tmp_min_mod: Self::STR_MOD_TMP_MIN_MOD.from_data(data)?, + str_mod_tmp_avg: Self::STR_MOD_TMP_AVG.from_data(data)?, + str_dis_rsn: Self::STR_DIS_RSN.from_data(data)?, + str_con_st: Self::STR_CON_ST.from_data(data)?, + str_evt1: Self::STR_EVT1.from_data(data)?, + str_evt2: Self::STR_EVT2.from_data(data)?, + str_evt_vnd1: Self::STR_EVT_VND1.from_data(data)?, + str_evt_vnd2: Self::STR_EVT_VND2.from_data(data)?, + str_set_ena: Self::STR_SET_ENA.from_data(data)?, + str_set_con: Self::STR_SET_CON.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &LithiumIonBank, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &LithiumIonBank, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_str { + let group; + (data, group) = String::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +bitflags::bitflags! { + #[doc = " String Status"] #[doc = " "] #[doc = " Current status of the string."] + #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", + derive(::serde::Serialize, ::serde::Deserialize))] pub struct StringStrSt : u32 { + #[allow(missing_docs)] const StringEnabled = 1; #[allow(missing_docs)] const + ContactorStatus = 2; } +} +impl crate::Value for StringStrSt { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringStrSt::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +/// Connection Failure Reason +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum StringStrConFail { + #[allow(missing_docs)] + NoFailure = 0, + #[allow(missing_docs)] + ButtonPushed = 1, + #[allow(missing_docs)] + StrGroundFault = 2, + #[allow(missing_docs)] + OutsideVoltageRange = 3, + #[allow(missing_docs)] + StringNotEnabled = 4, + #[allow(missing_docs)] + FuseOpen = 5, + #[allow(missing_docs)] + ContactorFailure = 6, + #[allow(missing_docs)] + PrechargeFailure = 7, + #[allow(missing_docs)] + StringFault = 8, +} +impl crate::Value for StringStrConFail { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + StringStrConFail::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Disabled Reason +/// +/// Reason why the string is currently disabled. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum StringStrDisRsn { + #[allow(missing_docs)] + None = 0, + #[allow(missing_docs)] + Fault = 1, + #[allow(missing_docs)] + Maintenance = 2, + #[allow(missing_docs)] + External = 3, + #[allow(missing_docs)] + Other = 4, +} +impl crate::Value for StringStrDisRsn { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + StringStrDisRsn::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Contactor Status"] #[doc = " "] #[doc = + " Status of the contactor(s) for the string."] #[derive(Copy, Clone, Debug, Eq, + PartialEq)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, + ::serde::Deserialize))] pub struct StringStrConSt : u32 { #[allow(missing_docs)] + const Contactor0 = 1; #[allow(missing_docs)] const Contactor1 = 2; + #[allow(missing_docs)] const Contactor2 = 4; #[allow(missing_docs)] const Contactor3 + = 8; #[allow(missing_docs)] const Contactor4 = 16; #[allow(missing_docs)] const + Contactor5 = 32; #[allow(missing_docs)] const Contactor6 = 64; #[allow(missing_docs)] + const Contactor7 = 128; #[allow(missing_docs)] const Contactor8 = 256; + #[allow(missing_docs)] const Contactor9 = 512; #[allow(missing_docs)] const + Contactor10 = 1024; #[allow(missing_docs)] const Contactor11 = 2048; + #[allow(missing_docs)] const Contactor12 = 4096; #[allow(missing_docs)] const + Contactor13 = 8192; #[allow(missing_docs)] const Contactor14 = 16384; + #[allow(missing_docs)] const Contactor15 = 32768; #[allow(missing_docs)] const + Contactor16 = 65536; #[allow(missing_docs)] const Contactor17 = 131072; + #[allow(missing_docs)] const Contactor18 = 262144; #[allow(missing_docs)] const + Contactor19 = 524288; #[allow(missing_docs)] const Contactor20 = 1048576; + #[allow(missing_docs)] const Contactor21 = 2097152; #[allow(missing_docs)] const + Contactor22 = 4194304; #[allow(missing_docs)] const Contactor23 = 8388608; + #[allow(missing_docs)] const Contactor24 = 16777216; #[allow(missing_docs)] const + Contactor25 = 33554432; #[allow(missing_docs)] const Contactor26 = 67108864; + #[allow(missing_docs)] const Contactor27 = 134217728; #[allow(missing_docs)] const + Contactor28 = 268435456; #[allow(missing_docs)] const Contactor29 = 536870912; + #[allow(missing_docs)] const Contactor30 = 1073741824; } +} +impl crate::Value for StringStrConSt { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringStrConSt::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +bitflags::bitflags! { + #[doc = " String Event 1"] #[doc = " "] #[doc = + " Alarms, warnings and status values. Bit flags."] #[derive(Copy, Clone, Debug, Eq, + PartialEq)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, + ::serde::Deserialize))] pub struct StringStrEvt1 : u32 { #[allow(missing_docs)] const + CommunicationError = 1; #[allow(missing_docs)] const OverTempAlarm = 2; + #[allow(missing_docs)] const OverTempWarning = 4; #[allow(missing_docs)] const + UnderTempAlarm = 8; #[allow(missing_docs)] const UnderTempWarning = 16; + #[allow(missing_docs)] const OverChargeCurrentAlarm = 32; #[allow(missing_docs)] + const OverChargeCurrentWarning = 64; #[allow(missing_docs)] const + OverDischargeCurrentAlarm = 128; #[allow(missing_docs)] const + OverDischargeCurrentWarning = 256; #[allow(missing_docs)] const OverVoltAlarm = 512; + #[allow(missing_docs)] const OverVoltWarning = 1024; #[allow(missing_docs)] const + UnderVoltAlarm = 2048; #[allow(missing_docs)] const UnderVoltWarning = 4096; + #[allow(missing_docs)] const UnderSocMinAlarm = 8192; #[allow(missing_docs)] const + UnderSocMinWarning = 16384; #[allow(missing_docs)] const OverSocMaxAlarm = 32768; + #[allow(missing_docs)] const OverSocMaxWarning = 65536; #[allow(missing_docs)] const + VoltageImbalanceWarning = 131072; #[allow(missing_docs)] const + TemperatureImbalanceAlarm = 262144; #[allow(missing_docs)] const + TemperatureImbalanceWarning = 524288; #[allow(missing_docs)] const ContactorError = + 1048576; #[allow(missing_docs)] const FanError = 2097152; #[allow(missing_docs)] + const GroundFault = 4194304; #[allow(missing_docs)] const OpenDoorError = 8388608; + #[allow(missing_docs)] const Reserved1 = 16777216; #[allow(missing_docs)] const + OtherAlarm = 33554432; #[allow(missing_docs)] const OtherWarning = 67108864; + #[allow(missing_docs)] const Reserved2 = 134217728; #[allow(missing_docs)] const + ConfigurationAlarm = 268435456; #[allow(missing_docs)] const ConfigurationWarning = + 536870912; } +} +impl crate::Value for StringStrEvt1 { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringStrEvt1::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +bitflags::bitflags! { + #[doc = " String Event 2"] #[doc = " "] #[doc = + " Alarms, warnings and status values. Bit flags."] #[derive(Copy, Clone, Debug, Eq, + PartialEq)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, + ::serde::Deserialize))] pub struct StringStrEvt2 : u32 {} +} +impl crate::Value for StringStrEvt2 { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringStrEvt2::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Vendor String Event Bitfield 1"] #[doc = " "] #[doc = + " Vendor defined events."] #[derive(Copy, Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub + struct StringStrEvtVnd1 : u32 {} +} +impl crate::Value for StringStrEvtVnd1 { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringStrEvtVnd1::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Vendor String Event Bitfield 2"] #[doc = " "] #[doc = + " Vendor defined events."] #[derive(Copy, Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub + struct StringStrEvtVnd2 : u32 {} +} +impl crate::Value for StringStrEvtVnd2 { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(StringStrEvtVnd2::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +/// Enable/Disable String +/// +/// Enables and disables the string. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum StringStrSetEna { + #[allow(missing_docs)] + EnableString = 1, + #[allow(missing_docs)] + DisableString = 2, +} +impl crate::Value for StringStrSetEna { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + StringStrSetEna::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Connect/Disconnect String +/// +/// Connects and disconnects the string. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum StringStrSetCon { + #[allow(missing_docs)] + ConnectString = 1, + #[allow(missing_docs)] + DisconnectString = 2, +} +impl crate::Value for StringStrSetCon { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + StringStrSetCon::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for LithiumIonBank { + const ID: u16 = 803; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m803 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model804.rs b/src/models/model804.rs index 3278aef..5ac5dd3 100644 --- a/src/models/model804.rs +++ b/src/models/model804.rs @@ -1,8 +1,9 @@ //! Lithium-Ion String Model +pub type Model804 = LithiumIonString; /// Lithium-Ion String Model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model804 { +pub struct LithiumIonString { /// String Index /// /// Index of the string within the bank. @@ -155,9 +156,11 @@ pub struct Model804 { pub cell_v_sf: i16, /// Scale factor for module temperature. pub mod_tmp_sf: i16, + #[allow(missing_docs)] + pub lithium_ion_string_module: Vec, } #[allow(missing_docs)] -impl Model804 { +impl LithiumIonString { pub const IDX: crate::Point = crate::Point::new(0, 1, false); pub const N_MOD: crate::Point = crate::Point::new(1, 1, false); pub const ST: crate::Point = crate::Point::new(2, 2, false); @@ -194,49 +197,59 @@ impl Model804 { pub const CELL_V_SF: crate::Point = crate::Point::new(41, 1, false); pub const MOD_TMP_SF: crate::Point = crate::Point::new(42, 1, false); } -impl crate::Model for Model804 { - const ID: u16 = 804; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - idx: Self::IDX.from_data(data)?, - n_mod: Self::N_MOD.from_data(data)?, - st: Self::ST.from_data(data)?, - con_fail: Self::CON_FAIL.from_data(data)?, - n_cell_bal: Self::N_CELL_BAL.from_data(data)?, - soc: Self::SOC.from_data(data)?, - do_d: Self::DO_D.from_data(data)?, - n_cyc: Self::N_CYC.from_data(data)?, - soh: Self::SOH.from_data(data)?, - a: Self::A.from_data(data)?, - v: Self::V.from_data(data)?, - cell_v_max: Self::CELL_V_MAX.from_data(data)?, - cell_v_max_mod: Self::CELL_V_MAX_MOD.from_data(data)?, - cell_v_min: Self::CELL_V_MIN.from_data(data)?, - cell_v_min_mod: Self::CELL_V_MIN_MOD.from_data(data)?, - cell_v_avg: Self::CELL_V_AVG.from_data(data)?, - mod_tmp_max: Self::MOD_TMP_MAX.from_data(data)?, - mod_tmp_max_mod: Self::MOD_TMP_MAX_MOD.from_data(data)?, - mod_tmp_min: Self::MOD_TMP_MIN.from_data(data)?, - mod_tmp_min_mod: Self::MOD_TMP_MIN_MOD.from_data(data)?, - mod_tmp_avg: Self::MOD_TMP_AVG.from_data(data)?, - con_st: Self::CON_ST.from_data(data)?, - evt1: Self::EVT1.from_data(data)?, - evt2: Self::EVT2.from_data(data)?, - evt_vnd1: Self::EVT_VND1.from_data(data)?, - evt_vnd2: Self::EVT_VND2.from_data(data)?, - set_ena: Self::SET_ENA.from_data(data)?, - set_con: Self::SET_CON.from_data(data)?, - soc_sf: Self::SOC_SF.from_data(data)?, - soh_sf: Self::SOH_SF.from_data(data)?, - do_d_sf: Self::DO_D_SF.from_data(data)?, - a_sf: Self::A_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - cell_v_sf: Self::CELL_V_SF.from_data(data)?, - mod_tmp_sf: Self::MOD_TMP_SF.from_data(data)?, - }) - } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m804 +impl crate::Group for LithiumIonString { + const LEN: u16 = 46; +} +impl LithiumIonString { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + idx: Self::IDX.from_data(data)?, + n_mod: Self::N_MOD.from_data(data)?, + st: Self::ST.from_data(data)?, + con_fail: Self::CON_FAIL.from_data(data)?, + n_cell_bal: Self::N_CELL_BAL.from_data(data)?, + soc: Self::SOC.from_data(data)?, + do_d: Self::DO_D.from_data(data)?, + n_cyc: Self::N_CYC.from_data(data)?, + soh: Self::SOH.from_data(data)?, + a: Self::A.from_data(data)?, + v: Self::V.from_data(data)?, + cell_v_max: Self::CELL_V_MAX.from_data(data)?, + cell_v_max_mod: Self::CELL_V_MAX_MOD.from_data(data)?, + cell_v_min: Self::CELL_V_MIN.from_data(data)?, + cell_v_min_mod: Self::CELL_V_MIN_MOD.from_data(data)?, + cell_v_avg: Self::CELL_V_AVG.from_data(data)?, + mod_tmp_max: Self::MOD_TMP_MAX.from_data(data)?, + mod_tmp_max_mod: Self::MOD_TMP_MAX_MOD.from_data(data)?, + mod_tmp_min: Self::MOD_TMP_MIN.from_data(data)?, + mod_tmp_min_mod: Self::MOD_TMP_MIN_MOD.from_data(data)?, + mod_tmp_avg: Self::MOD_TMP_AVG.from_data(data)?, + con_st: Self::CON_ST.from_data(data)?, + evt1: Self::EVT1.from_data(data)?, + evt2: Self::EVT2.from_data(data)?, + evt_vnd1: Self::EVT_VND1.from_data(data)?, + evt_vnd2: Self::EVT_VND2.from_data(data)?, + set_ena: Self::SET_ENA.from_data(data)?, + set_con: Self::SET_CON.from_data(data)?, + soc_sf: Self::SOC_SF.from_data(data)?, + soh_sf: Self::SOH_SF.from_data(data)?, + do_d_sf: Self::DO_D_SF.from_data(data)?, + a_sf: Self::A_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + cell_v_sf: Self::CELL_V_SF.from_data(data)?, + mod_tmp_sf: Self::MOD_TMP_SF.from_data(data)?, + lithium_ion_string_module: Vec::new(), + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.lithium_ion_string_module) = + LithiumIonStringModule::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -570,3 +583,133 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct LithiumIonStringModule { + /// Module Cell Count + /// + /// Count of all cells in the module. + pub mod_n_cell: u16, + /// Module SoC + /// + /// Module state of charge, expressed as a percentage. + pub mod_soc: Option, + /// Module SoH + /// + /// Module state of health, expressed as a percentage. + pub mod_soh: Option, + /// Max Cell Voltage + /// + /// Maximum voltage for all cells in the module. + pub mod_cell_v_max: u16, + /// Max Cell Voltage Cell + /// + /// Cell with maximum voltage. + pub mod_cell_v_max_cell: Option, + /// Min Cell Voltage + /// + /// Minimum voltage for all cells in the module. + pub mod_cell_v_min: u16, + /// Min Cell Voltage Cell + /// + /// Cell with minimum voltage. + pub mod_cell_v_min_cell: Option, + /// Average Cell Voltage + /// + /// Average voltage for all cells in the module. + pub mod_cell_v_avg: u16, + /// Max Cell Temperature + /// + /// Maximum temperature for all cells in the module. + pub mod_cell_tmp_max: i16, + /// Max Cell Temperature Cell + /// + /// Cell with maximum temperature. + pub mod_cell_tmp_max_cell: Option, + /// Min Cell Temperature + /// + /// Minimum temperature for all cells in the module. + pub mod_cell_tmp_min: i16, + /// Min Cell Temperature Cell + /// + /// Cell with minimum temperature. + pub mod_cell_tmp_min_cell: Option, + /// Average Cell Temperature + /// + /// Average temperature for all cells in the module. + pub mod_cell_tmp_avg: i16, +} +#[allow(missing_docs)] +impl LithiumIonStringModule { + pub const MOD_N_CELL: crate::Point = crate::Point::new(0, 1, false); + pub const MOD_SOC: crate::Point> = crate::Point::new(1, 1, false); + pub const MOD_SOH: crate::Point> = crate::Point::new(2, 1, false); + pub const MOD_CELL_V_MAX: crate::Point = crate::Point::new(3, 1, false); + pub const MOD_CELL_V_MAX_CELL: crate::Point> = crate::Point::new(4, 1, false); + pub const MOD_CELL_V_MIN: crate::Point = crate::Point::new(5, 1, false); + pub const MOD_CELL_V_MIN_CELL: crate::Point> = crate::Point::new(6, 1, false); + pub const MOD_CELL_V_AVG: crate::Point = crate::Point::new(7, 1, false); + pub const MOD_CELL_TMP_MAX: crate::Point = crate::Point::new(8, 1, false); + pub const MOD_CELL_TMP_MAX_CELL: crate::Point> = + crate::Point::new(9, 1, false); + pub const MOD_CELL_TMP_MIN: crate::Point = crate::Point::new(10, 1, false); + pub const MOD_CELL_TMP_MIN_CELL: crate::Point> = + crate::Point::new(11, 1, false); + pub const MOD_CELL_TMP_AVG: crate::Point = crate::Point::new(12, 1, false); +} +impl crate::Group for LithiumIonStringModule { + const LEN: u16 = 16; +} +impl LithiumIonStringModule { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + mod_n_cell: Self::MOD_N_CELL.from_data(data)?, + mod_soc: Self::MOD_SOC.from_data(data)?, + mod_soh: Self::MOD_SOH.from_data(data)?, + mod_cell_v_max: Self::MOD_CELL_V_MAX.from_data(data)?, + mod_cell_v_max_cell: Self::MOD_CELL_V_MAX_CELL.from_data(data)?, + mod_cell_v_min: Self::MOD_CELL_V_MIN.from_data(data)?, + mod_cell_v_min_cell: Self::MOD_CELL_V_MIN_CELL.from_data(data)?, + mod_cell_v_avg: Self::MOD_CELL_V_AVG.from_data(data)?, + mod_cell_tmp_max: Self::MOD_CELL_TMP_MAX.from_data(data)?, + mod_cell_tmp_max_cell: Self::MOD_CELL_TMP_MAX_CELL.from_data(data)?, + mod_cell_tmp_min: Self::MOD_CELL_TMP_MIN.from_data(data)?, + mod_cell_tmp_min_cell: Self::MOD_CELL_TMP_MIN_CELL.from_data(data)?, + mod_cell_tmp_avg: Self::MOD_CELL_TMP_AVG.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &LithiumIonString, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &LithiumIonString, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..model.n_mod { + let group; + (data, group) = LithiumIonStringModule::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for LithiumIonString { + const ID: u16 = 804; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m804 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model805.rs b/src/models/model805.rs index e262fa6..84b074c 100644 --- a/src/models/model805.rs +++ b/src/models/model805.rs @@ -1,8 +1,9 @@ //! Lithium-Ion Module Model +pub type Model805 = LithiumIonModule; /// Lithium-Ion Module Model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model805 { +pub struct LithiumIonModule { /// String Index /// /// Index of the string containing the module. @@ -115,9 +116,11 @@ pub struct Model805 { pub cell_v_sf: i16, /// Scale factor for module temperature. pub tmp_sf: i16, + #[allow(missing_docs)] + pub lithium_ion_module_cell: Vec, } #[allow(missing_docs)] -impl Model805 { +impl LithiumIonModule { pub const STR_IDX: crate::Point = crate::Point::new(0, 1, false); pub const MOD_IDX: crate::Point = crate::Point::new(1, 1, false); pub const N_CELL: crate::Point = crate::Point::new(2, 1, false); @@ -145,39 +148,150 @@ impl Model805 { pub const CELL_V_SF: crate::Point = crate::Point::new(40, 1, false); pub const TMP_SF: crate::Point = crate::Point::new(41, 1, false); } -impl crate::Model for Model805 { - const ID: u16 = 805; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - str_idx: Self::STR_IDX.from_data(data)?, - mod_idx: Self::MOD_IDX.from_data(data)?, - n_cell: Self::N_CELL.from_data(data)?, - soc: Self::SOC.from_data(data)?, - do_d: Self::DO_D.from_data(data)?, - soh: Self::SOH.from_data(data)?, - n_cyc: Self::N_CYC.from_data(data)?, - v: Self::V.from_data(data)?, - cell_v_max: Self::CELL_V_MAX.from_data(data)?, - cell_v_max_cell: Self::CELL_V_MAX_CELL.from_data(data)?, - cell_v_min: Self::CELL_V_MIN.from_data(data)?, - cell_v_min_cell: Self::CELL_V_MIN_CELL.from_data(data)?, - cell_v_avg: Self::CELL_V_AVG.from_data(data)?, - cell_tmp_max: Self::CELL_TMP_MAX.from_data(data)?, - cell_tmp_max_cell: Self::CELL_TMP_MAX_CELL.from_data(data)?, - cell_tmp_min: Self::CELL_TMP_MIN.from_data(data)?, - cell_tmp_min_cell: Self::CELL_TMP_MIN_CELL.from_data(data)?, - cell_tmp_avg: Self::CELL_TMP_AVG.from_data(data)?, - n_cell_bal: Self::N_CELL_BAL.from_data(data)?, - sn: Self::SN.from_data(data)?, - soc_sf: Self::SOC_SF.from_data(data)?, - soh_sf: Self::SOH_SF.from_data(data)?, - do_d_sf: Self::DO_D_SF.from_data(data)?, - v_sf: Self::V_SF.from_data(data)?, - cell_v_sf: Self::CELL_V_SF.from_data(data)?, - tmp_sf: Self::TMP_SF.from_data(data)?, - }) +impl crate::Group for LithiumIonModule { + const LEN: u16 = 42; +} +impl LithiumIonModule { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + str_idx: Self::STR_IDX.from_data(data)?, + mod_idx: Self::MOD_IDX.from_data(data)?, + n_cell: Self::N_CELL.from_data(data)?, + soc: Self::SOC.from_data(data)?, + do_d: Self::DO_D.from_data(data)?, + soh: Self::SOH.from_data(data)?, + n_cyc: Self::N_CYC.from_data(data)?, + v: Self::V.from_data(data)?, + cell_v_max: Self::CELL_V_MAX.from_data(data)?, + cell_v_max_cell: Self::CELL_V_MAX_CELL.from_data(data)?, + cell_v_min: Self::CELL_V_MIN.from_data(data)?, + cell_v_min_cell: Self::CELL_V_MIN_CELL.from_data(data)?, + cell_v_avg: Self::CELL_V_AVG.from_data(data)?, + cell_tmp_max: Self::CELL_TMP_MAX.from_data(data)?, + cell_tmp_max_cell: Self::CELL_TMP_MAX_CELL.from_data(data)?, + cell_tmp_min: Self::CELL_TMP_MIN.from_data(data)?, + cell_tmp_min_cell: Self::CELL_TMP_MIN_CELL.from_data(data)?, + cell_tmp_avg: Self::CELL_TMP_AVG.from_data(data)?, + n_cell_bal: Self::N_CELL_BAL.from_data(data)?, + sn: Self::SN.from_data(data)?, + soc_sf: Self::SOC_SF.from_data(data)?, + soh_sf: Self::SOH_SF.from_data(data)?, + do_d_sf: Self::DO_D_SF.from_data(data)?, + v_sf: Self::V_SF.from_data(data)?, + cell_v_sf: Self::CELL_V_SF.from_data(data)?, + tmp_sf: Self::TMP_SF.from_data(data)?, + lithium_ion_module_cell: Vec::new(), + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.lithium_ion_module_cell) = LithiumIonModuleCell::parse_multiple(data, &group)?; + Ok((data, group)) + } +} +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct LithiumIonModuleCell { + /// Cell Voltage + /// + /// Cell terminal voltage. + pub cell_v: u16, + /// Cell Temperature + /// + /// Cell temperature. + pub cell_tmp: i16, + /// Cell Status + /// + /// Status of the cell. + pub cell_st: Option, +} +#[allow(missing_docs)] +impl LithiumIonModuleCell { + pub const CELL_V: crate::Point = crate::Point::new(0, 1, false); + pub const CELL_TMP: crate::Point = crate::Point::new(1, 1, false); + pub const CELL_ST: crate::Point> = + crate::Point::new(2, 2, false); +} +impl crate::Group for LithiumIonModuleCell { + const LEN: u16 = 4; +} +impl LithiumIonModuleCell { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + cell_v: Self::CELL_V.from_data(data)?, + cell_tmp: Self::CELL_TMP.from_data(data)?, + cell_st: Self::CELL_ST.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &LithiumIonModule, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &LithiumIonModule, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = LithiumIonModuleCell::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +bitflags::bitflags! { + #[doc = " Cell Status"] #[doc = " "] #[doc = " Status of the cell."] #[derive(Copy, + Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", + derive(::serde::Serialize, ::serde::Deserialize))] pub struct + LithiumIonModuleCellCellSt : u32 { #[allow(missing_docs)] const CellIsBalancing = 1; + } +} +impl crate::Value for LithiumIonModuleCellCellSt { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(LithiumIonModuleCellCellSt::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +impl crate::Model for LithiumIonModule { + const ID: u16 = 805; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m805 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model806.rs b/src/models/model806.rs index 126174f..5543777 100644 --- a/src/models/model806.rs +++ b/src/models/model806.rs @@ -1,23 +1,89 @@ //! Flow Battery Model +pub type Model806 = FlowBattery; /// Flow Battery Model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model806 { +pub struct FlowBattery { /// Battery Points To Be Determined pub bat_tbd: u16, + #[allow(missing_docs)] + pub battery_string: Vec, } #[allow(missing_docs)] -impl Model806 { +impl FlowBattery { pub const BAT_TBD: crate::Point = crate::Point::new(0, 1, false); } -impl crate::Model for Model806 { - const ID: u16 = 806; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - bat_tbd: Self::BAT_TBD.from_data(data)?, - }) +impl crate::Group for FlowBattery { + const LEN: u16 = 1; +} +impl FlowBattery { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + bat_tbd: Self::BAT_TBD.from_data(data)?, + battery_string: Vec::new(), + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.battery_string) = BatteryString::parse_multiple(data, &group)?; + Ok((data, group)) } +} +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct BatteryString { + /// Battery String Points To Be Determined + pub bat_st_tbd: u16, +} +#[allow(missing_docs)] +impl BatteryString { + pub const BAT_ST_TBD: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for BatteryString { + const LEN: u16 = 1; +} +impl BatteryString { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + bat_st_tbd: Self::BAT_ST_TBD.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &FlowBattery, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &FlowBattery, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = BatteryString::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for FlowBattery { + const ID: u16 = 806; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m806 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model807.rs b/src/models/model807.rs index b67354c..406a726 100644 --- a/src/models/model807.rs +++ b/src/models/model807.rs @@ -1,8 +1,9 @@ //! Flow Battery String Model +pub type Model807 = FlowBatteryString; /// Flow Battery String Model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model807 { +pub struct FlowBatteryString { /// String Index /// /// Index of the string within the bank. @@ -129,9 +130,11 @@ pub struct Model807 { pub soc_sf: i16, /// Scale factor for open circuit voltage. pub ocv_sf: i16, + #[allow(missing_docs)] + pub module: Vec, } #[allow(missing_docs)] -impl Model807 { +impl FlowBatteryString { pub const IDX: crate::Point = crate::Point::new(0, 1, false); pub const N_MOD: crate::Point = crate::Point::new(1, 1, false); pub const N_MOD_CON: crate::Point = crate::Point::new(2, 1, false); @@ -162,43 +165,52 @@ impl Model807 { pub const SOC_SF: crate::Point = crate::Point::new(31, 1, false); pub const OCV_SF: crate::Point = crate::Point::new(32, 1, false); } -impl crate::Model for Model807 { - const ID: u16 = 807; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - idx: Self::IDX.from_data(data)?, - n_mod: Self::N_MOD.from_data(data)?, - n_mod_con: Self::N_MOD_CON.from_data(data)?, - mod_v_max: Self::MOD_V_MAX.from_data(data)?, - mod_v_max_mod: Self::MOD_V_MAX_MOD.from_data(data)?, - mod_v_min: Self::MOD_V_MIN.from_data(data)?, - mod_v_min_mod: Self::MOD_V_MIN_MOD.from_data(data)?, - mod_v_avg: Self::MOD_V_AVG.from_data(data)?, - cell_v_max: Self::CELL_V_MAX.from_data(data)?, - cell_v_max_mod: Self::CELL_V_MAX_MOD.from_data(data)?, - cell_v_max_stk: Self::CELL_V_MAX_STK.from_data(data)?, - cell_v_min: Self::CELL_V_MIN.from_data(data)?, - cell_v_min_mod: Self::CELL_V_MIN_MOD.from_data(data)?, - cell_v_min_stk: Self::CELL_V_MIN_STK.from_data(data)?, - cell_v_avg: Self::CELL_V_AVG.from_data(data)?, - tmp_max: Self::TMP_MAX.from_data(data)?, - tmp_max_mod: Self::TMP_MAX_MOD.from_data(data)?, - tmp_min: Self::TMP_MIN.from_data(data)?, - tmp_min_mod: Self::TMP_MIN_MOD.from_data(data)?, - tmp_avg: Self::TMP_AVG.from_data(data)?, - evt1: Self::EVT1.from_data(data)?, - evt2: Self::EVT2.from_data(data)?, - evt_vnd1: Self::EVT_VND1.from_data(data)?, - evt_vnd2: Self::EVT_VND2.from_data(data)?, - mod_v_sf: Self::MOD_V_SF.from_data(data)?, - cell_v_sf: Self::CELL_V_SF.from_data(data)?, - tmp_sf: Self::TMP_SF.from_data(data)?, - soc_sf: Self::SOC_SF.from_data(data)?, - ocv_sf: Self::OCV_SF.from_data(data)?, - }) +impl crate::Group for FlowBatteryString { + const LEN: u16 = 34; +} +impl FlowBatteryString { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + idx: Self::IDX.from_data(data)?, + n_mod: Self::N_MOD.from_data(data)?, + n_mod_con: Self::N_MOD_CON.from_data(data)?, + mod_v_max: Self::MOD_V_MAX.from_data(data)?, + mod_v_max_mod: Self::MOD_V_MAX_MOD.from_data(data)?, + mod_v_min: Self::MOD_V_MIN.from_data(data)?, + mod_v_min_mod: Self::MOD_V_MIN_MOD.from_data(data)?, + mod_v_avg: Self::MOD_V_AVG.from_data(data)?, + cell_v_max: Self::CELL_V_MAX.from_data(data)?, + cell_v_max_mod: Self::CELL_V_MAX_MOD.from_data(data)?, + cell_v_max_stk: Self::CELL_V_MAX_STK.from_data(data)?, + cell_v_min: Self::CELL_V_MIN.from_data(data)?, + cell_v_min_mod: Self::CELL_V_MIN_MOD.from_data(data)?, + cell_v_min_stk: Self::CELL_V_MIN_STK.from_data(data)?, + cell_v_avg: Self::CELL_V_AVG.from_data(data)?, + tmp_max: Self::TMP_MAX.from_data(data)?, + tmp_max_mod: Self::TMP_MAX_MOD.from_data(data)?, + tmp_min: Self::TMP_MIN.from_data(data)?, + tmp_min_mod: Self::TMP_MIN_MOD.from_data(data)?, + tmp_avg: Self::TMP_AVG.from_data(data)?, + evt1: Self::EVT1.from_data(data)?, + evt2: Self::EVT2.from_data(data)?, + evt_vnd1: Self::EVT_VND1.from_data(data)?, + evt_vnd2: Self::EVT_VND2.from_data(data)?, + mod_v_sf: Self::MOD_V_SF.from_data(data)?, + cell_v_sf: Self::CELL_V_SF.from_data(data)?, + tmp_sf: Self::TMP_SF.from_data(data)?, + soc_sf: Self::SOC_SF.from_data(data)?, + ocv_sf: Self::OCV_SF.from_data(data)?, + module: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m807 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.module) = Module::parse_multiple(data, &group)?; + Ok((data, group)) } } bitflags::bitflags! { @@ -355,3 +367,522 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Module { + /// Module Index + /// + /// Index of the module within the string. + pub mod_idx: u16, + /// Stack Count + /// + /// Number of stacks in this module. + pub mod_n_stk: u16, + /// Module Status + /// + /// Current status of the module. + pub mod_st: ModuleModSt, + /// Module State of Charge + /// + /// State of charge for this module. + pub mod_soc: u16, + /// Open Circuit Voltage + /// + /// Open circuit voltage for this module. + pub mod_ocv: u16, + /// External Voltage + /// + /// External voltage fo this module. + pub mod_v: u16, + /// Maximum Cell Voltage + /// + /// Maximum voltage for all cells in this module. + pub mod_cell_v_max: Option, + /// Max Cell Voltage Cell + /// + /// Cell with the maximum cell voltage. + pub mod_cell_v_max_cell: Option, + /// Minimum Cell Voltage + /// + /// Minimum voltage for all cells in this module. + pub mod_cell_v_min: Option, + /// Min Cell Voltage Cell + /// + /// Cell with the minimum cell voltage. + pub mod_cell_v_min_cell: Option, + /// Average Cell Voltage + /// + /// Average voltage for all cells in this module. + pub mod_cell_v_avg: Option, + /// Anolyte Temperature + pub mod_ano_tmp: Option, + /// Catholyte Temperature + pub mod_cat_tmp: Option, + /// Contactor Status + pub mod_con_st: Option, + /// Module Event 1 + /// + /// Alarms, warnings and status values. Bit flags. + pub mod_evt1: ModuleModEvt1, + /// Module Event 2 + /// + /// Alarms, warnings and status values. Bit flags. + pub mod_evt2: ModuleModEvt2, + /// Connection Failure Reason + pub mod_con_fail: Option, + /// Enable/Disable Module + /// + /// Enables and disables the module. + pub mod_set_ena: Option, + /// Connect/Disconnect Module + /// + /// Connects and disconnects the module. + pub mod_set_con: Option, + /// Disabled Reason + /// + /// Reason why the module is currently disabled. + pub mod_dis_rsn: Option, +} +#[allow(missing_docs)] +impl Module { + pub const MOD_IDX: crate::Point = crate::Point::new(0, 1, false); + pub const MOD_N_STK: crate::Point = crate::Point::new(1, 1, false); + pub const MOD_ST: crate::Point = crate::Point::new(2, 2, false); + pub const MOD_SOC: crate::Point = crate::Point::new(4, 1, false); + pub const MOD_OCV: crate::Point = crate::Point::new(5, 1, false); + pub const MOD_V: crate::Point = crate::Point::new(6, 1, false); + pub const MOD_CELL_V_MAX: crate::Point> = crate::Point::new(7, 1, false); + pub const MOD_CELL_V_MAX_CELL: crate::Point> = crate::Point::new(8, 1, false); + pub const MOD_CELL_V_MIN: crate::Point> = crate::Point::new(9, 1, false); + pub const MOD_CELL_V_MIN_CELL: crate::Point> = + crate::Point::new(10, 1, false); + pub const MOD_CELL_V_AVG: crate::Point> = crate::Point::new(11, 1, false); + pub const MOD_ANO_TMP: crate::Point> = crate::Point::new(12, 1, false); + pub const MOD_CAT_TMP: crate::Point> = crate::Point::new(13, 1, false); + pub const MOD_CON_ST: crate::Point> = + crate::Point::new(14, 2, false); + pub const MOD_EVT1: crate::Point = crate::Point::new(16, 2, false); + pub const MOD_EVT2: crate::Point = crate::Point::new(18, 2, false); + pub const MOD_CON_FAIL: crate::Point> = + crate::Point::new(20, 1, false); + pub const MOD_SET_ENA: crate::Point> = + crate::Point::new(21, 1, true); + pub const MOD_SET_CON: crate::Point> = + crate::Point::new(22, 1, true); + pub const MOD_DIS_RSN: crate::Point> = + crate::Point::new(23, 1, false); +} +impl crate::Group for Module { + const LEN: u16 = 24; +} +impl Module { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + mod_idx: Self::MOD_IDX.from_data(data)?, + mod_n_stk: Self::MOD_N_STK.from_data(data)?, + mod_st: Self::MOD_ST.from_data(data)?, + mod_soc: Self::MOD_SOC.from_data(data)?, + mod_ocv: Self::MOD_OCV.from_data(data)?, + mod_v: Self::MOD_V.from_data(data)?, + mod_cell_v_max: Self::MOD_CELL_V_MAX.from_data(data)?, + mod_cell_v_max_cell: Self::MOD_CELL_V_MAX_CELL.from_data(data)?, + mod_cell_v_min: Self::MOD_CELL_V_MIN.from_data(data)?, + mod_cell_v_min_cell: Self::MOD_CELL_V_MIN_CELL.from_data(data)?, + mod_cell_v_avg: Self::MOD_CELL_V_AVG.from_data(data)?, + mod_ano_tmp: Self::MOD_ANO_TMP.from_data(data)?, + mod_cat_tmp: Self::MOD_CAT_TMP.from_data(data)?, + mod_con_st: Self::MOD_CON_ST.from_data(data)?, + mod_evt1: Self::MOD_EVT1.from_data(data)?, + mod_evt2: Self::MOD_EVT2.from_data(data)?, + mod_con_fail: Self::MOD_CON_FAIL.from_data(data)?, + mod_set_ena: Self::MOD_SET_ENA.from_data(data)?, + mod_set_con: Self::MOD_SET_CON.from_data(data)?, + mod_dis_rsn: Self::MOD_DIS_RSN.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &FlowBatteryString, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &FlowBatteryString, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Module::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +bitflags::bitflags! { + #[doc = " Module Status"] #[doc = " "] #[doc = " Current status of the module."] + #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", + derive(::serde::Serialize, ::serde::Deserialize))] pub struct ModuleModSt : u32 { + #[allow(missing_docs)] const ModuleEnabled = 1; #[allow(missing_docs)] const + ContactorStatus = 2; } +} +impl crate::Value for ModuleModSt { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(ModuleModSt::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Contactor Status"] #[derive(Copy, Clone, Debug, Eq, PartialEq)] + #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub + struct ModuleModConSt : u32 { #[allow(missing_docs)] const Contactor0 = 1; + #[allow(missing_docs)] const Contactor1 = 2; #[allow(missing_docs)] const Contactor2 + = 4; #[allow(missing_docs)] const Contactor3 = 8; #[allow(missing_docs)] const + Contactor4 = 16; #[allow(missing_docs)] const Contactor5 = 32; #[allow(missing_docs)] + const Contactor6 = 64; #[allow(missing_docs)] const Contactor7 = 128; + #[allow(missing_docs)] const Contactor8 = 256; #[allow(missing_docs)] const + Contactor9 = 512; #[allow(missing_docs)] const Contactor10 = 1024; + #[allow(missing_docs)] const Contactor11 = 2048; #[allow(missing_docs)] const + Contactor12 = 4096; #[allow(missing_docs)] const Contactor13 = 8192; + #[allow(missing_docs)] const Contactor14 = 16384; #[allow(missing_docs)] const + Contactor15 = 32768; #[allow(missing_docs)] const Contactor16 = 65536; + #[allow(missing_docs)] const Contactor17 = 131072; #[allow(missing_docs)] const + Contactor18 = 262144; #[allow(missing_docs)] const Contactor19 = 524288; + #[allow(missing_docs)] const Contactor20 = 1048576; #[allow(missing_docs)] const + Contactor21 = 2097152; #[allow(missing_docs)] const Contactor22 = 4194304; + #[allow(missing_docs)] const Contactor23 = 8388608; #[allow(missing_docs)] const + Contactor24 = 16777216; #[allow(missing_docs)] const Contactor25 = 33554432; + #[allow(missing_docs)] const Contactor26 = 67108864; #[allow(missing_docs)] const + Contactor27 = 134217728; #[allow(missing_docs)] const Contactor28 = 268435456; + #[allow(missing_docs)] const Contactor29 = 536870912; #[allow(missing_docs)] const + Contactor30 = 1073741824; } +} +impl crate::Value for ModuleModConSt { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(ModuleModConSt::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Module Event 1"] #[doc = " "] #[doc = + " Alarms, warnings and status values. Bit flags."] #[derive(Copy, Clone, Debug, Eq, + PartialEq)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, + ::serde::Deserialize))] pub struct ModuleModEvt1 : u32 { #[allow(missing_docs)] const + CommunicationError = 1; #[allow(missing_docs)] const OverTempAlarm = 2; + #[allow(missing_docs)] const OverTempWarning = 4; #[allow(missing_docs)] const + UnderTempAlarm = 8; #[allow(missing_docs)] const UnderTempWarning = 16; + #[allow(missing_docs)] const OverChargeCurrentAlarm = 32; #[allow(missing_docs)] + const OverChargeCurrentWarning = 64; #[allow(missing_docs)] const + OverDischargeCurrentAlarm = 128; #[allow(missing_docs)] const + OverDischargeCurrentWarning = 256; #[allow(missing_docs)] const OverVoltAlarm = 512; + #[allow(missing_docs)] const OverVoltWarning = 1024; #[allow(missing_docs)] const + UnderVoltAlarm = 2048; #[allow(missing_docs)] const UnderVoltWarning = 4096; + #[allow(missing_docs)] const UnderSocMinAlarm = 8192; #[allow(missing_docs)] const + UnderSocMinWarning = 16384; #[allow(missing_docs)] const OverSocMaxAlarm = 32768; + #[allow(missing_docs)] const OverSocMaxWarning = 65536; #[allow(missing_docs)] const + VoltageImbalanceWarning = 131072; #[allow(missing_docs)] const Reserved1 = 262144; + #[allow(missing_docs)] const Reserved2 = 524288; #[allow(missing_docs)] const + ContactorError = 1048576; #[allow(missing_docs)] const FanError = 2097152; + #[allow(missing_docs)] const GroundFault = 4194304; #[allow(missing_docs)] const + OpenDoorError = 8388608; #[allow(missing_docs)] const Reserved3 = 16777216; + #[allow(missing_docs)] const Reserved4 = 33554432; #[allow(missing_docs)] const + Reserved5 = 67108864; #[allow(missing_docs)] const FireAlarm = 134217728; + #[allow(missing_docs)] const ModuleConfigurationAlarm = 268435456; + #[allow(missing_docs)] const ModuleConfigurationWarning = 536870912; } +} +impl crate::Value for ModuleModEvt1 { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(ModuleModEvt1::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +bitflags::bitflags! { + #[doc = " Module Event 2"] #[doc = " "] #[doc = + " Alarms, warnings and status values. Bit flags."] #[derive(Copy, Clone, Debug, Eq, + PartialEq)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, + ::serde::Deserialize))] pub struct ModuleModEvt2 : u32 { #[allow(missing_docs)] const + LeakAlarm = 1; #[allow(missing_docs)] const PumpAlarm = 2; #[allow(missing_docs)] + const HighPressureAlarm = 4; #[allow(missing_docs)] const HighPressureWarning = 8; + #[allow(missing_docs)] const LowFlowAlarm = 16; #[allow(missing_docs)] const + LowFlowWarning = 32; } +} +impl crate::Value for ModuleModEvt2 { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + Ok(Self::from_bits_retain(value)) + } + fn encode(self) -> Box<[u16]> { + self.bits().encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u32::decode(data)?; + if value != 4294967295u32 { + Ok(Some(ModuleModEvt2::from_bits_retain(value))) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 4294967295u32.encode() + } + } +} +/// Connection Failure Reason +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum ModuleModConFail { + #[allow(missing_docs)] + NoFailure = 0, + #[allow(missing_docs)] + ButtonPushed = 1, + #[allow(missing_docs)] + ModuleGroundFault = 2, + #[allow(missing_docs)] + OutsideVoltageRange = 3, + #[allow(missing_docs)] + ModuleNotEnabled = 4, + #[allow(missing_docs)] + FuseOpen = 5, + #[allow(missing_docs)] + ContactorFailure = 6, + #[allow(missing_docs)] + PrechargeFailure = 7, + #[allow(missing_docs)] + ModuleFault = 8, +} +impl crate::Value for ModuleModConFail { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + ModuleModConFail::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Enable/Disable Module +/// +/// Enables and disables the module. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum ModuleModSetEna { + #[allow(missing_docs)] + EnableModule = 1, + #[allow(missing_docs)] + DisableModule = 2, +} +impl crate::Value for ModuleModSetEna { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + ModuleModSetEna::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Connect/Disconnect Module +/// +/// Connects and disconnects the module. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum ModuleModSetCon { + #[allow(missing_docs)] + ConnectModule = 1, + #[allow(missing_docs)] + DisconnectModule = 2, +} +impl crate::Value for ModuleModSetCon { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + ModuleModSetCon::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +/// Disabled Reason +/// +/// Reason why the module is currently disabled. +#[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[repr(u16)] +pub enum ModuleModDisRsn { + #[allow(missing_docs)] + None = 0, + #[allow(missing_docs)] + Fault = 1, + #[allow(missing_docs)] + Maintenance = 2, + #[allow(missing_docs)] + External = 3, + #[allow(missing_docs)] + Other = 4, +} +impl crate::Value for ModuleModDisRsn { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + Self::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue) + } + fn encode(self) -> Box<[u16]> { + (self as u16).encode() + } +} +impl crate::Value for Option { + fn decode(data: &[u16]) -> Result { + let value = u16::decode(data)?; + if value != 65535 { + Ok(Some( + ModuleModDisRsn::from_repr(value).ok_or(crate::DecodeError::InvalidEnumValue)?, + )) + } else { + Ok(None) + } + } + fn encode(self) -> Box<[u16]> { + if let Some(value) = self { + value.encode() + } else { + 65535.encode() + } + } +} +impl crate::Model for FlowBatteryString { + const ID: u16 = 807; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m807 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/models/model808.rs b/src/models/model808.rs index 81f6d76..7611810 100644 --- a/src/models/model808.rs +++ b/src/models/model808.rs @@ -1,23 +1,89 @@ //! Flow Battery Module Model +pub type Model808 = FlowBatteryModule; /// Flow Battery Module Model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model808 { +pub struct FlowBatteryModule { /// Module Points To Be Determined pub module_tbd: u16, + #[allow(missing_docs)] + pub stack: Vec, } #[allow(missing_docs)] -impl Model808 { +impl FlowBatteryModule { pub const MODULE_TBD: crate::Point = crate::Point::new(0, 1, false); } -impl crate::Model for Model808 { - const ID: u16 = 808; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - module_tbd: Self::MODULE_TBD.from_data(data)?, - }) +impl crate::Group for FlowBatteryModule { + const LEN: u16 = 1; +} +impl FlowBatteryModule { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + module_tbd: Self::MODULE_TBD.from_data(data)?, + stack: Vec::new(), + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.stack) = Stack::parse_multiple(data, &group)?; + Ok((data, group)) } +} +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Stack { + /// Stack Points To Be Determined + pub stack_tbd: u16, +} +#[allow(missing_docs)] +impl Stack { + pub const STACK_TBD: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for Stack { + const LEN: u16 = 1; +} +impl Stack { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + stack_tbd: Self::STACK_TBD.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &FlowBatteryModule, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &FlowBatteryModule, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Stack::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for FlowBatteryModule { + const ID: u16 = 808; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m808 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model809.rs b/src/models/model809.rs index aaffb63..8a8fb23 100644 --- a/src/models/model809.rs +++ b/src/models/model809.rs @@ -1,23 +1,89 @@ //! Flow Battery Stack Model +pub type Model809 = FlowBatteryStack; /// Flow Battery Stack Model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct Model809 { +pub struct FlowBatteryStack { /// Stack Points To Be Determined pub stack_tbd: u16, + #[allow(missing_docs)] + pub cell: Vec, } #[allow(missing_docs)] -impl Model809 { +impl FlowBatteryStack { pub const STACK_TBD: crate::Point = crate::Point::new(0, 1, false); } -impl crate::Model for Model809 { - const ID: u16 = 809; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - stack_tbd: Self::STACK_TBD.from_data(data)?, - }) +impl crate::Group for FlowBatteryStack { + const LEN: u16 = 1; +} +impl FlowBatteryStack { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + stack_tbd: Self::STACK_TBD.from_data(data)?, + cell: Vec::new(), + }, + )) + } + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.cell) = Cell::parse_multiple(data, &group)?; + Ok((data, group)) } +} +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Cell { + /// Cell Points To Be Determined + pub cell_tbd: u16, +} +#[allow(missing_docs)] +impl Cell { + pub const CELL_TBD: crate::Point = crate::Point::new(0, 1, false); +} +impl crate::Group for Cell { + const LEN: u16 = 1; +} +impl Cell { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + cell_tbd: Self::CELL_TBD.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &FlowBatteryStack, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &FlowBatteryStack, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Cell::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for FlowBatteryStack { + const ID: u16 = 809; fn addr(models: &crate::Models) -> crate::ModelAddr { models.m809 } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } diff --git a/src/models/model9.rs b/src/models/model9.rs index 88ac047..fe37068 100644 --- a/src/models/model9.rs +++ b/src/models/model9.rs @@ -227,6 +227,8 @@ pub struct Model9 { /// /// Number of registers to follow for the certificate pub n: u16, + #[allow(missing_docs)] + pub repeating: Vec, } #[allow(missing_docs)] impl Model9 { @@ -322,105 +324,114 @@ impl Model9 { pub const ALG: crate::Point = crate::Point::new(90, 1, true); pub const N: crate::Point = crate::Point::new(91, 1, true); } -impl crate::Model for Model9 { - const ID: u16 = 9; - fn from_data(data: &[u16]) -> Result { - Ok(Self { - cert_uid: Self::CERT_UID.from_data(data)?, - cert_role: Self::CERT_ROLE.from_data(data)?, - fmt: Self::FMT.from_data(data)?, - typ: Self::TYP.from_data(data)?, - tot_ln: Self::TOT_LN.from_data(data)?, - frg_ln: Self::FRG_LN.from_data(data)?, - frg1: Self::FRG1.from_data(data)?, - frg2: Self::FRG2.from_data(data)?, - frg3: Self::FRG3.from_data(data)?, - frg4: Self::FRG4.from_data(data)?, - frg5: Self::FRG5.from_data(data)?, - frg6: Self::FRG6.from_data(data)?, - frg7: Self::FRG7.from_data(data)?, - frg8: Self::FRG8.from_data(data)?, - frg9: Self::FRG9.from_data(data)?, - frg10: Self::FRG10.from_data(data)?, - frg11: Self::FRG11.from_data(data)?, - frg12: Self::FRG12.from_data(data)?, - frg13: Self::FRG13.from_data(data)?, - frg14: Self::FRG14.from_data(data)?, - frg15: Self::FRG15.from_data(data)?, - frg16: Self::FRG16.from_data(data)?, - frg17: Self::FRG17.from_data(data)?, - frg18: Self::FRG18.from_data(data)?, - frg19: Self::FRG19.from_data(data)?, - frg20: Self::FRG20.from_data(data)?, - frg21: Self::FRG21.from_data(data)?, - frg22: Self::FRG22.from_data(data)?, - frg23: Self::FRG23.from_data(data)?, - frg24: Self::FRG24.from_data(data)?, - frg25: Self::FRG25.from_data(data)?, - frg26: Self::FRG26.from_data(data)?, - frg27: Self::FRG27.from_data(data)?, - frg28: Self::FRG28.from_data(data)?, - frg29: Self::FRG29.from_data(data)?, - frg30: Self::FRG30.from_data(data)?, - frg31: Self::FRG31.from_data(data)?, - frg32: Self::FRG32.from_data(data)?, - frg33: Self::FRG33.from_data(data)?, - frg34: Self::FRG34.from_data(data)?, - frg35: Self::FRG35.from_data(data)?, - frg36: Self::FRG36.from_data(data)?, - frg37: Self::FRG37.from_data(data)?, - frg38: Self::FRG38.from_data(data)?, - frg39: Self::FRG39.from_data(data)?, - frg40: Self::FRG40.from_data(data)?, - frg41: Self::FRG41.from_data(data)?, - frg42: Self::FRG42.from_data(data)?, - frg43: Self::FRG43.from_data(data)?, - frg44: Self::FRG44.from_data(data)?, - frg45: Self::FRG45.from_data(data)?, - frg46: Self::FRG46.from_data(data)?, - frg47: Self::FRG47.from_data(data)?, - frg48: Self::FRG48.from_data(data)?, - frg49: Self::FRG49.from_data(data)?, - frg50: Self::FRG50.from_data(data)?, - frg51: Self::FRG51.from_data(data)?, - frg52: Self::FRG52.from_data(data)?, - frg53: Self::FRG53.from_data(data)?, - frg54: Self::FRG54.from_data(data)?, - frg55: Self::FRG55.from_data(data)?, - frg56: Self::FRG56.from_data(data)?, - frg57: Self::FRG57.from_data(data)?, - frg58: Self::FRG58.from_data(data)?, - frg59: Self::FRG59.from_data(data)?, - frg60: Self::FRG60.from_data(data)?, - frg61: Self::FRG61.from_data(data)?, - frg62: Self::FRG62.from_data(data)?, - frg63: Self::FRG63.from_data(data)?, - frg64: Self::FRG64.from_data(data)?, - frg65: Self::FRG65.from_data(data)?, - frg66: Self::FRG66.from_data(data)?, - frg67: Self::FRG67.from_data(data)?, - frg68: Self::FRG68.from_data(data)?, - frg69: Self::FRG69.from_data(data)?, - frg70: Self::FRG70.from_data(data)?, - frg71: Self::FRG71.from_data(data)?, - frg72: Self::FRG72.from_data(data)?, - frg73: Self::FRG73.from_data(data)?, - frg74: Self::FRG74.from_data(data)?, - frg75: Self::FRG75.from_data(data)?, - frg78: Self::FRG78.from_data(data)?, - frg79: Self::FRG79.from_data(data)?, - frg80: Self::FRG80.from_data(data)?, - ts: Self::TS.from_data(data)?, - ms: Self::MS.from_data(data)?, - seq: Self::SEQ.from_data(data)?, - uid: Self::UID.from_data(data)?, - role: Self::ROLE.from_data(data)?, - alg: Self::ALG.from_data(data)?, - n: Self::N.from_data(data)?, - }) +impl crate::Group for Model9 { + const LEN: u16 = 92; +} +impl Model9 { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + cert_uid: Self::CERT_UID.from_data(data)?, + cert_role: Self::CERT_ROLE.from_data(data)?, + fmt: Self::FMT.from_data(data)?, + typ: Self::TYP.from_data(data)?, + tot_ln: Self::TOT_LN.from_data(data)?, + frg_ln: Self::FRG_LN.from_data(data)?, + frg1: Self::FRG1.from_data(data)?, + frg2: Self::FRG2.from_data(data)?, + frg3: Self::FRG3.from_data(data)?, + frg4: Self::FRG4.from_data(data)?, + frg5: Self::FRG5.from_data(data)?, + frg6: Self::FRG6.from_data(data)?, + frg7: Self::FRG7.from_data(data)?, + frg8: Self::FRG8.from_data(data)?, + frg9: Self::FRG9.from_data(data)?, + frg10: Self::FRG10.from_data(data)?, + frg11: Self::FRG11.from_data(data)?, + frg12: Self::FRG12.from_data(data)?, + frg13: Self::FRG13.from_data(data)?, + frg14: Self::FRG14.from_data(data)?, + frg15: Self::FRG15.from_data(data)?, + frg16: Self::FRG16.from_data(data)?, + frg17: Self::FRG17.from_data(data)?, + frg18: Self::FRG18.from_data(data)?, + frg19: Self::FRG19.from_data(data)?, + frg20: Self::FRG20.from_data(data)?, + frg21: Self::FRG21.from_data(data)?, + frg22: Self::FRG22.from_data(data)?, + frg23: Self::FRG23.from_data(data)?, + frg24: Self::FRG24.from_data(data)?, + frg25: Self::FRG25.from_data(data)?, + frg26: Self::FRG26.from_data(data)?, + frg27: Self::FRG27.from_data(data)?, + frg28: Self::FRG28.from_data(data)?, + frg29: Self::FRG29.from_data(data)?, + frg30: Self::FRG30.from_data(data)?, + frg31: Self::FRG31.from_data(data)?, + frg32: Self::FRG32.from_data(data)?, + frg33: Self::FRG33.from_data(data)?, + frg34: Self::FRG34.from_data(data)?, + frg35: Self::FRG35.from_data(data)?, + frg36: Self::FRG36.from_data(data)?, + frg37: Self::FRG37.from_data(data)?, + frg38: Self::FRG38.from_data(data)?, + frg39: Self::FRG39.from_data(data)?, + frg40: Self::FRG40.from_data(data)?, + frg41: Self::FRG41.from_data(data)?, + frg42: Self::FRG42.from_data(data)?, + frg43: Self::FRG43.from_data(data)?, + frg44: Self::FRG44.from_data(data)?, + frg45: Self::FRG45.from_data(data)?, + frg46: Self::FRG46.from_data(data)?, + frg47: Self::FRG47.from_data(data)?, + frg48: Self::FRG48.from_data(data)?, + frg49: Self::FRG49.from_data(data)?, + frg50: Self::FRG50.from_data(data)?, + frg51: Self::FRG51.from_data(data)?, + frg52: Self::FRG52.from_data(data)?, + frg53: Self::FRG53.from_data(data)?, + frg54: Self::FRG54.from_data(data)?, + frg55: Self::FRG55.from_data(data)?, + frg56: Self::FRG56.from_data(data)?, + frg57: Self::FRG57.from_data(data)?, + frg58: Self::FRG58.from_data(data)?, + frg59: Self::FRG59.from_data(data)?, + frg60: Self::FRG60.from_data(data)?, + frg61: Self::FRG61.from_data(data)?, + frg62: Self::FRG62.from_data(data)?, + frg63: Self::FRG63.from_data(data)?, + frg64: Self::FRG64.from_data(data)?, + frg65: Self::FRG65.from_data(data)?, + frg66: Self::FRG66.from_data(data)?, + frg67: Self::FRG67.from_data(data)?, + frg68: Self::FRG68.from_data(data)?, + frg69: Self::FRG69.from_data(data)?, + frg70: Self::FRG70.from_data(data)?, + frg71: Self::FRG71.from_data(data)?, + frg72: Self::FRG72.from_data(data)?, + frg73: Self::FRG73.from_data(data)?, + frg74: Self::FRG74.from_data(data)?, + frg75: Self::FRG75.from_data(data)?, + frg78: Self::FRG78.from_data(data)?, + frg79: Self::FRG79.from_data(data)?, + frg80: Self::FRG80.from_data(data)?, + ts: Self::TS.from_data(data)?, + ms: Self::MS.from_data(data)?, + seq: Self::SEQ.from_data(data)?, + uid: Self::UID.from_data(data)?, + role: Self::ROLE.from_data(data)?, + alg: Self::ALG.from_data(data)?, + n: Self::N.from_data(data)?, + repeating: Vec::new(), + }, + )) } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.m9 + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + (data, group.repeating) = Repeating::parse_multiple(data, &group)?; + Ok((data, group)) } } /// Format @@ -555,3 +566,57 @@ impl crate::Value for Option { } } } +#[allow(missing_docs)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct Repeating { + #[allow(missing_docs)] + pub cert: u16, +} +#[allow(missing_docs)] +impl Repeating { + pub const CERT: crate::Point = crate::Point::new(0, 1, true); +} +impl crate::Group for Repeating { + const LEN: u16 = 1; +} +impl Repeating { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + cert: Self::CERT.from_data(data)?, + }, + )) + } + fn parse_group<'a>( + mut data: &'a [u16], + model: &Model9, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + Ok((data, group)) + } + fn parse_multiple<'a>( + mut data: &'a [u16], + model: &Model9, + ) -> Result<(&'a [u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..0 { + let group; + (data, group) = Repeating::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } +} +impl crate::Model for Model9 { + const ID: u16 = 9; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.m9 + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } +} diff --git a/src/point.rs b/src/point.rs index 3b192d9..8df04ad 100644 --- a/src/point.rs +++ b/src/point.rs @@ -1,24 +1,24 @@ use std::marker::PhantomData; use crate::{ - model::Model, value::{DecodeError, Value}, + Group, }; /// Definition of a point #[derive(Debug)] -pub struct Point { +pub struct Point { /// Offset within the model pub offset: u16, /// Length of the data pub length: u16, /// Is this point writable? pub writable: bool, - model: PhantomData, + model: PhantomData, point_type: PhantomData, } -impl Point { +impl Point { /// Create new point definition pub const fn new(offset: u16, length: u16, writable: bool) -> Self { Self { @@ -38,11 +38,3 @@ impl Point { Ok(value) } } - -impl Copy for Point {} - -impl Clone for Point { - fn clone(&self) -> Self { - *self - } -} diff --git a/sunspec-gen/src/gen.rs b/sunspec-gen/src/gen.rs index cbffe98..f51dc3a 100644 --- a/sunspec-gen/src/gen.rs +++ b/sunspec-gen/src/gen.rs @@ -1,8 +1,10 @@ +use std::{collections::HashMap, ptr}; + use proc_macro2::{Literal, TokenStream}; use quote::{format_ident, quote, ToTokens}; use thiserror::Error; -use crate::json::{Model, Point, PointAccess, PointMandatory, PointType}; +use crate::json::{Group, GroupCount, Model, Point, PointAccess, PointMandatory, PointType}; /// This fixes sunspec identifiers which contains things like /// `SoC` and `SoH` which causes heck to transform them to `so_c` @@ -38,6 +40,13 @@ pub enum GenModelError { MissingOffset { model: String, point: String }, #[error("Missing length")] MissingLength { model: String, point: String }, + #[error("Conflicting group definitions for {group} in {model}")] + ConflictingGroupDefinition { model: String, group: String }, +} + +#[derive(Default)] +struct GenState { + groups: HashMap, } pub fn gen_models_struct(models: &[Model]) -> Result { @@ -109,34 +118,96 @@ pub fn gen_models_struct(models: &[Model]) -> Result }) } -pub fn gen_model_struct(model: &Model) -> Result { +pub fn gen_model(model: &Model) -> Result { let module_doc = format!(" {}", model.group.doc.label.as_ref().unwrap()); let model_name = format_ident!("Model{}", model.id); - let model_doc = doc_to_ts(&model.group.doc.to_doc_string()); - let mut points = model.group.points.iter(); - if let Some(Point { name, .. }) = points.next() { - if name != "ID" { - return Err(GenModelError::MissingIdPoint { - model: format!("Model{}", model.id), - point: name.clone(), - }); + let m_name = format_ident!("m{}", model.id); + let model_id = Literal::u16_unsuffixed(model.id); + let group_name = group_ident(&model.group); + let type_alias = if model_name != group_name { + quote! { pub type #model_name = #group_name; } + } else { + quote! {} + }; + let mut state = GenState::default(); + let group = gen_group(&model, &model.group, &mut state)?; + let trait_impl = quote! { + impl crate::Model for #group_name { + const ID: u16 = #model_id; + fn addr(models: &crate::Models) -> crate::ModelAddr { + models.#m_name + } + fn parse(data: &[u16]) -> Result { + let (_, model) = Self::parse_group(data)?; + Ok(model) + } } - } - if let Some(Point { name, .. }) = points.next() { - if name != "L" { - return Err(GenModelError::MissingLPoint { - model: format!("Model{}", model.id), - point: name.clone(), + }; + Ok(quote! { + #![doc = #module_doc] + #type_alias + #group + #trait_impl + }) +} + +fn gen_group( + xmodel: &Model, + group: &Group, + state: &mut GenState, +) -> Result { + let is_root = ptr::eq(&xmodel.group, group); + let group_name_string = upper_camel_case(&group.name); + let group_signature = group_signature(group); + if let Some(previous_signature) = state.groups.get(&group_name_string) { + if previous_signature != &group_signature { + return Err(GenModelError::ConflictingGroupDefinition { + model: format!("Model{}", xmodel.id), + group: group.name.clone(), }); } + return Ok(TokenStream::new()); } - let points = points.as_slice(); - let model_fields = points + state + .groups + .insert(group_name_string.clone(), group_signature); + let group_doc = doc_to_ts(&group.doc.to_doc_string()); + let group_name = format_ident!("{}", group_name_string); + let point_type_prefix = if is_root { + String::new() + } else { + group_name_string.clone() + }; + let mut points = group.points.iter(); + let points = if is_root { + // Skip `ID` and `L` points when generating the root group of a model + if let Some(Point { name, .. }) = points.next() { + if name != "ID" { + return Err(GenModelError::MissingIdPoint { + model: format!("Model{}", xmodel.id), + point: name.clone(), + }); + } + } + if let Some(Point { name, .. }) = points.next() { + if name != "L" { + return Err(GenModelError::MissingLPoint { + model: format!("Model{}", xmodel.id), + point: name.clone(), + }); + } + } + &group.points[2..] + } else { + &group.points[..] + }; + + let point_fields = points .iter() .filter(|point| !point.is_padding()) .map(|point| { let point_name = format_ident!("{}", snake_case(&point.name)); - let point_type = rust_type(point, ""); + let point_type = rust_type(point, &point_type_prefix); let point_doc = doc_to_ts(&point.doc.to_doc_string()); // FIXME add #[allow[missing_docs)] if the doc is empty quote! { @@ -145,13 +216,33 @@ pub fn gen_model_struct(model: &Model) -> Result { } }); - // FIXME do not add empty model docs + let groups = group + .groups + .iter() + // XXX It's quite unfortunate but groups with a count of 0 + // aren't defined properly in the sunspec JSON files. + // XXX + //.filter(|group| group.count != GroupCount::Integer(0)) + .collect::>(); + + let group_fields = groups.iter().map(|group| { + let field_name = format_ident!("{}", snake_case(&group.name)); + let group_type = group_ident(group); + let group_doc = doc_to_ts(&group.doc.to_doc_string()); + quote! { + #group_doc + pub #field_name: Vec<#group_type>, + } + }); + + // FIXME do not add empty group docs let model_struct = quote! { - #model_doc + #group_doc #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] - pub struct #model_name { - #(#model_fields)* + pub struct #group_name { + #(#point_fields)* + #(#group_fields)* } }; @@ -164,7 +255,7 @@ pub fn gen_model_struct(model: &Model) -> Result { .filter(|(_, point)| !point.is_padding()) .map(|(offset, point)| { let point_name = format_ident!("{}", shouty_snake_case(&point.name)); - let point_type = rust_type(point, ""); + let point_type = rust_type(point, &point_type_prefix); let len = Literal::u16_unsuffixed(point.size); let offset = Literal::u16_unsuffixed(offset); let writable = point.access == PointAccess::RW; @@ -176,7 +267,7 @@ pub fn gen_model_struct(model: &Model) -> Result { let model_impl = quote! { #[allow(missing_docs)] - impl #model_name { + impl #group_name { #(#model_impl_consts)* } }; @@ -192,39 +283,90 @@ pub fn gen_model_struct(model: &Model) -> Result { } }); - let model_id = Literal::u16_unsuffixed(model.id); - let allow_unused = points.is_empty().then(|| quote! { #[allow(unused)] }); - let m_name = format_ident!("m{}", model.id); - let trait_impl = quote! { - impl crate::Model for #model_name { - const ID: u16 = #model_id; - fn from_data(#allow_unused data: &[u16]) -> Result { - Ok(Self { - #(#from_data_fields)* - }) + let from_data_groups_default = groups.iter().map(|group| { + let field_name = format_ident!("{}", snake_case(&group.name)); + quote! { + #field_name: Vec::new(), + } + }); + let root_group_name = group_ident(&xmodel.group); + let parse_groups = groups.iter().map(|sub_group| { + let field_name = format_ident!("{}", snake_case(&sub_group.name)); + let group_type = group_ident(sub_group); + if is_root { + quote! { + (data, group.#field_name) = #group_type::parse_multiple(data, &group)?; } - fn addr(models: &crate::Models) -> crate::ModelAddr { - models.#m_name + } else { + quote! { + (data, group.#field_name) = #group_type::parse_multiple(data, model)?; } } - }; + }); + let group_len = Literal::u16_unsuffixed(points.iter().map(|point| point.size).sum()); + let fn_parse_multiple = if !is_root { + gen_group_fn_parse_multiple(group, xmodel) + } else { + quote! {} + }; + let parse_group = if is_root { + quote! { + fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + #(#parse_groups)* + Ok((data, group)) + } + } + } else { + quote! { + fn parse_group<'a>(mut data: &'a [u16], model: &#root_group_name) -> Result<(&'a [u16], Self), crate::DecodeError> { + let mut group; + (data, group) = Self::parse_points(data)?; + #(#parse_groups)* + Ok((data, group)) + } + } + }; + let trait_impl = quote! { + impl crate::Group for #group_name { + const LEN: u16 = #group_len; + } + impl #group_name { + fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + Ok(( + &data[usize::from(::LEN)..], + Self { + #(#from_data_fields)* + #(#from_data_groups_default)* + } + )) + } + #parse_group + #fn_parse_multiple + } + }; let mut extra = TokenStream::new(); for point in points { match point.r#type { PointType::Enum16 | PointType::Enum32 if !point.symbols.is_empty() => { - extra.extend(gen_enum(point, "")); + extra.extend(gen_enum(point, &point_type_prefix)); } PointType::Bitfield16 | PointType::Bitfield32 | PointType::Bitfield64 => { - extra.extend(gen_bitfield(point, "")); + extra.extend(gen_bitfield(point, &point_type_prefix)); } _ => {} } } + for sub_group in groups { + extra.extend(gen_group(xmodel, sub_group, state)?); + } + Ok(quote! { - #![doc = #module_doc] + #model_struct #model_impl #trait_impl @@ -232,6 +374,73 @@ pub fn gen_model_struct(model: &Model) -> Result { }) } +fn gen_group_fn_parse_multiple(group: &Group, model: &Model) -> TokenStream { + let model_name = group_ident(&model.group); + let group_name = group_ident(group); + let group_count = match &group.count { + GroupCount::String(count_field_name) => { + let count_field = format_ident!("{}", snake_case(&count_field_name)); + if let Some(point) = find_point(&model.group, count_field_name) { + if point.mandatory == PointMandatory::M { + quote! { model.#count_field } + } else { + quote! { model.#count_field.unwrap_or_default() } + } + } else { + quote! { model.#count_field.unwrap_or_default() } + } + } + GroupCount::Integer(count_value) => { + let count_value = Literal::u32_unsuffixed(*count_value); + quote! { #count_value } + } + }; + quote! { + fn parse_multiple<'a>(mut data: &'a[u16], model: &#model_name) -> Result<(&'a[u16], Vec), crate::DecodeError> { + let mut groups = Vec::new(); + for _ in 0..#group_count { + let group; + (data, group) = #group_name::parse_group(data, model)?; + groups.push(group); + } + Ok((data, groups)) + } + } +} + +fn group_ident(group: &Group) -> proc_macro2::Ident { + format_ident!("{}", upper_camel_case(&group.name)) +} + +fn find_point<'a>(group: &'a Group, name: &str) -> Option<&'a Point> { + group.points.iter().find(|point| point.name == name) +} + +fn group_signature(group: &Group) -> String { + let mut value = serde_json::to_value(group).expect("serialize group signature"); + strip_doc_fields(&mut value); + serde_json::to_string(&value).expect("serialize group signature") +} + +fn strip_doc_fields(value: &mut serde_json::Value) { + match value { + serde_json::Value::Array(values) => { + for value in values { + strip_doc_fields(value); + } + } + serde_json::Value::Object(values) => { + for field in ["label", "desc", "notes", "detail", "comments"] { + values.remove(field); + } + for value in values.values_mut() { + strip_doc_fields(value); + } + } + _ => {} + } +} + fn gen_enum(point: &Point, prefix: &str) -> TokenStream { let size = point.r#type.size().unwrap(); let repr = format_ident!("u{}", size * 16); diff --git a/sunspec-gen/src/json.rs b/sunspec-gen/src/json.rs index 2a06d75..a09bb29 100644 --- a/sunspec-gen/src/json.rs +++ b/sunspec-gen/src/json.rs @@ -64,7 +64,7 @@ pub enum GroupType { Sync, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)] #[serde(untagged)] pub enum GroupCount { Integer(u32), diff --git a/sunspec-gen/src/main.rs b/sunspec-gen/src/main.rs index 167dbfe..0d91a66 100644 --- a/sunspec-gen/src/main.rs +++ b/sunspec-gen/src/main.rs @@ -2,7 +2,7 @@ use std::{fs, path::PathBuf}; use clap::Parser; use proc_macro2::TokenStream; -use sunspec_gen::gen::{gen_model_struct, gen_models_struct}; +use sunspec_gen::gen::{gen_model, gen_models_struct}; #[derive(Parser)] struct Args { @@ -23,7 +23,7 @@ fn main() -> Result<(), Box> { let filename = format!("model{}.rs", model.id); fs::write( args.target_dir.join(filename), - ts_to_str(gen_model_struct(&model)?).as_bytes(), + ts_to_str(gen_model(&model)?).as_bytes(), )?; } Ok(()) diff --git a/tests/test_model712.rs b/tests/test_model712.rs new file mode 100644 index 0000000..19dddd3 --- /dev/null +++ b/tests/test_model712.rs @@ -0,0 +1,73 @@ +use sunspec::{ + models::model712::{self, Model712}, + Model, +}; + +#[test] +fn test_model712() { + #[rustfmt::skip] + let data = &[ + 0, // Ena + 0, // adpt_crv_req + 1, // adpt_crv_rslt + 6, // n_pt + 2, // n_crv + 65535, 65535, // rvrt_tms + 65535, 65535, // rvrt_rem + 65535, // rvrt_crv + 65534, // w_sf + 65534, // dept_ref_sf + 6, 0, 65535, 1, // crv[0] + 0, 0, // crv[0].pt[0] + 5000, 0, // crv[0].pt[1] + 6000, 0, // crv[0].pt[2] + 8000, 0, // crv[0].pt[3] + 9000, 0, // crv[0].pt[4] + 10000, 0, // crv[0].pt[5] + 0, 0, 65535, 0, // crv[1] + 0, 0, // crv[1].pt[0] + 0, 0, // crv[1].pt[1] + 0, 0, // crv[1].pt[2] + 0, 0, // crv[1].pt[3] + 0, 0, // crv[1].pt[4] + 0, 0, // crv[1].pt[5] + ]; + let m = Model712::parse(data).unwrap(); + assert_eq!(m.ena, model712::Ena::Disabled); + assert_eq!(m.adpt_crv_req, 0); + assert_eq!(m.adpt_crv_rslt, model712::AdptCrvRslt::Completed); + assert_eq!(m.n_pt, 6); + assert_eq!(m.n_crv, 2); + assert_eq!(m.rvrt_tms, None); + assert_eq!(m.rvrt_rem, None); + assert_eq!(m.rvrt_crv, None); + assert_eq!(m.w_sf, -2); + assert_eq!(m.dept_ref_sf, -2); + assert_eq!(m.crv.len(), 2); + assert_eq!(m.crv[0].act_pt, 6); + assert_eq!(m.crv[0].dept_ref, model712::CrvDeptRef::WMaxPct); + assert_eq!(m.crv[0].pri, None); + assert_eq!(m.crv[0].read_only, model712::CrvReadOnly::R); + assert_eq!(m.crv[0].pt.len(), 6); + assert_eq!(m.crv[0].pt[0].w, Some(0)); + assert_eq!(m.crv[0].pt[0].var, Some(0)); + assert_eq!(m.crv[0].pt[1].w, Some(5000)); + assert_eq!(m.crv[0].pt[1].var, Some(0)); + assert_eq!(m.crv[0].pt[2].w, Some(6000)); + assert_eq!(m.crv[0].pt[2].var, Some(0)); + assert_eq!(m.crv[0].pt[3].w, Some(8000)); + assert_eq!(m.crv[0].pt[3].var, Some(0)); + assert_eq!(m.crv[0].pt[4].w, Some(9000)); + assert_eq!(m.crv[0].pt[4].var, Some(0)); + assert_eq!(m.crv[0].pt[5].w, Some(10000)); + assert_eq!(m.crv[0].pt[5].var, Some(0)); + assert_eq!(m.crv[1].act_pt, 0); + assert_eq!(m.crv[1].dept_ref, model712::CrvDeptRef::WMaxPct); + assert_eq!(m.crv[1].pri, None); + assert_eq!(m.crv[1].read_only, model712::CrvReadOnly::Rw); + assert_eq!(m.crv[1].pt.len(), 6); + for pt in &m.crv[1].pt { + assert_eq!(pt.w, Some(0)); + assert_eq!(pt.var, Some(0)); + } +} From 49bc71562493fb255f7710a53fc545f2ba5c42a6 Mon Sep 17 00:00:00 2001 From: "Michael P. Jung" Date: Tue, 31 Mar 2026 00:27:05 +0200 Subject: [PATCH 2/3] Improve code generation for nested and repeating groups This gets rid of all warnings --- src/group.rs | 1 + src/model.rs | 2 +- src/models/model1.rs | 11 +- src/models/model10.rs | 10 +- src/models/model101.rs | 11 +- src/models/model102.rs | 11 +- src/models/model103.rs | 11 +- src/models/model11.rs | 10 +- src/models/model111.rs | 11 +- src/models/model112.rs | 11 +- src/models/model113.rs | 11 +- src/models/model12.rs | 10 +- src/models/model120.rs | 11 +- src/models/model121.rs | 11 +- src/models/model122.rs | 11 +- src/models/model123.rs | 11 +- src/models/model124.rs | 11 +- src/models/model125.rs | 11 +- src/models/model126.rs | 51 +++---- src/models/model127.rs | 11 +- src/models/model128.rs | 11 +- src/models/model129.rs | 51 +++---- src/models/model13.rs | 10 +- src/models/model130.rs | 51 +++---- src/models/model131.rs | 51 +++---- src/models/model132.rs | 51 +++---- src/models/model133.rs | 51 +++---- src/models/model134.rs | 51 +++---- src/models/model135.rs | 51 +++---- src/models/model136.rs | 51 +++---- src/models/model137.rs | 51 +++---- src/models/model138.rs | 51 +++---- src/models/model139.rs | 51 +++---- src/models/model14.rs | 10 +- src/models/model140.rs | 51 +++---- src/models/model141.rs | 51 +++---- src/models/model142.rs | 51 +++---- src/models/model143.rs | 51 +++---- src/models/model144.rs | 51 +++---- src/models/model145.rs | 11 +- src/models/model15.rs | 10 +- src/models/model16.rs | 10 +- src/models/model160.rs | 51 +++---- src/models/model17.rs | 10 +- src/models/model18.rs | 10 +- src/models/model19.rs | 10 +- src/models/model2.rs | 11 +- src/models/model201.rs | 11 +- src/models/model202.rs | 11 +- src/models/model203.rs | 11 +- src/models/model204.rs | 11 +- src/models/model211.rs | 11 +- src/models/model212.rs | 11 +- src/models/model213.rs | 11 +- src/models/model214.rs | 11 +- src/models/model220.rs | 51 +++---- src/models/model3.rs | 50 +++---- src/models/model302.rs | 54 +++----- src/models/model303.rs | 52 +++---- src/models/model304.rs | 52 +++---- src/models/model305.rs | 11 +- src/models/model306.rs | 11 +- src/models/model307.rs | 11 +- src/models/model308.rs | 11 +- src/models/model4.rs | 50 +++---- src/models/model401.rs | 51 +++---- src/models/model402.rs | 51 +++---- src/models/model403.rs | 51 +++---- src/models/model404.rs | 51 +++---- src/models/model5.rs | 50 +++---- src/models/model501.rs | 11 +- src/models/model502.rs | 11 +- src/models/model6.rs | 50 +++---- src/models/model601.rs | 51 +++---- src/models/model63001.rs | 50 +++---- src/models/model63002.rs | 53 +++---- src/models/model64001.rs | 10 +- src/models/model64020.rs | 50 +++---- src/models/model64101.rs | 10 +- src/models/model64111.rs | 10 +- src/models/model64112.rs | 10 +- src/models/model64410.rs | 88 ++++++------ src/models/model64411.rs | 88 ++++++------ src/models/model64412.rs | 11 +- src/models/model64413.rs | 52 ++++--- src/models/model64414.rs | 11 +- src/models/model64415.rs | 11 +- src/models/model7.rs | 50 +++---- src/models/model701.rs | 11 +- src/models/model702.rs | 11 +- src/models/model703.rs | 11 +- src/models/model704.rs | 135 ++++-------------- src/models/model705.rs | 88 ++++++------ src/models/model706.rs | 88 ++++++------ src/models/model707.rs | 198 ++++++++++---------------- src/models/model708.rs | 198 ++++++++++---------------- src/models/model709.rs | 198 ++++++++++---------------- src/models/model710.rs | 198 ++++++++++---------------- src/models/model711.rs | 50 +++---- src/models/model712.rs | 88 ++++++------ src/models/model713.rs | 11 +- src/models/model714.rs | 52 ++++--- src/models/model715.rs | 11 +- src/models/model8.rs | 50 +++---- src/models/model801.rs | 11 +- src/models/model802.rs | 11 +- src/models/model803.rs | 50 +++---- src/models/model804.rs | 52 ++++--- src/models/model805.rs | 52 ++++--- src/models/model806.rs | 51 +++---- src/models/model807.rs | 51 +++---- src/models/model808.rs | 51 +++---- src/models/model809.rs | 51 +++---- src/models/model9.rs | 50 +++---- sunspec-gen/src/gen.rs | 293 +++++++++++++++++++++++++++++++-------- sunspec-gen/src/json.rs | 14 ++ 116 files changed, 2052 insertions(+), 2613 deletions(-) diff --git a/src/group.rs b/src/group.rs index 96fe8e4..660bc81 100644 --- a/src/group.rs +++ b/src/group.rs @@ -1,3 +1,4 @@ +/// Every group and model implements this trait. pub trait Group: Sized { /// Group length (without nested and repeating groups) const LEN: u16; diff --git a/src/model.rs b/src/model.rs index 5d65451..77b752d 100644 --- a/src/model.rs +++ b/src/model.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::{DecodeError, Group, Models}; /// Every model implements this trait which contains methods -/// for accessing +/// for accessing the address and parsing the model. pub trait Model: Sized + Group { /// Model ID const ID: u16; diff --git a/src/models/model1.rs b/src/models/model1.rs index 04003f0..b28efc0 100644 --- a/src/models/model1.rs +++ b/src/models/model1.rs @@ -1,4 +1,5 @@ //! Common +/// Type alias for [`Common`]. pub type Model1 = Common; /// Common /// @@ -46,9 +47,10 @@ impl crate::Group for Common { const LEN: u16 = 66; } impl Common { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { mn: Self::MN.from_data(data)?, md: Self::MD.from_data(data)?, @@ -59,11 +61,6 @@ impl Common { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } impl crate::Model for Common { const ID: u16 = 1; diff --git a/src/models/model10.rs b/src/models/model10.rs index d803a4b..4f7e5e2 100644 --- a/src/models/model10.rs +++ b/src/models/model10.rs @@ -28,9 +28,10 @@ impl crate::Group for Model10 { const LEN: u16 = 4; } impl Model10 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { st: Self::ST.from_data(data)?, ctl: Self::CTL.from_data(data)?, @@ -38,11 +39,6 @@ impl Model10 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Interface Status /// diff --git a/src/models/model101.rs b/src/models/model101.rs index 84f541d..527cdc2 100644 --- a/src/models/model101.rs +++ b/src/models/model101.rs @@ -1,4 +1,5 @@ //! Inverter (Single Phase) +/// Type alias for [`InverterSinglePhase`]. pub type Model101 = InverterSinglePhase; /// Inverter (Single Phase) /// @@ -207,9 +208,10 @@ impl crate::Group for InverterSinglePhase { const LEN: u16 = 50; } impl InverterSinglePhase { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -257,11 +259,6 @@ impl InverterSinglePhase { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Operating State /// diff --git a/src/models/model102.rs b/src/models/model102.rs index 47bbaec..be8260c 100644 --- a/src/models/model102.rs +++ b/src/models/model102.rs @@ -1,4 +1,5 @@ //! Inverter (Split-Phase) +/// Type alias for [`InverterSplitPhase`]. pub type Model102 = InverterSplitPhase; /// Inverter (Split-Phase) /// @@ -211,9 +212,10 @@ impl crate::Group for InverterSplitPhase { const LEN: u16 = 50; } impl InverterSplitPhase { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -261,11 +263,6 @@ impl InverterSplitPhase { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Operating State /// diff --git a/src/models/model103.rs b/src/models/model103.rs index 2dc99ab..a484aaf 100644 --- a/src/models/model103.rs +++ b/src/models/model103.rs @@ -1,4 +1,5 @@ //! Inverter (Three Phase) +/// Type alias for [`InverterThreePhase`]. pub type Model103 = InverterThreePhase; /// Inverter (Three Phase) /// @@ -213,9 +214,10 @@ impl crate::Group for InverterThreePhase { const LEN: u16 = 50; } impl InverterThreePhase { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -263,11 +265,6 @@ impl InverterThreePhase { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Operating State /// diff --git a/src/models/model11.rs b/src/models/model11.rs index ccd7607..581906f 100644 --- a/src/models/model11.rs +++ b/src/models/model11.rs @@ -48,9 +48,10 @@ impl crate::Group for Model11 { const LEN: u16 = 13; } impl Model11 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { spd: Self::SPD.from_data(data)?, cfg_st: Self::CFG_ST.from_data(data)?, @@ -62,11 +63,6 @@ impl Model11 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Interface Status Flags"] #[doc = " "] #[doc = diff --git a/src/models/model111.rs b/src/models/model111.rs index 5e00200..ea16877 100644 --- a/src/models/model111.rs +++ b/src/models/model111.rs @@ -1,4 +1,5 @@ //! Inverter (Single Phase) FLOAT +/// Type alias for [`InverterSinglePhaseFloat`]. pub type Model111 = InverterSinglePhaseFloat; /// Inverter (Single Phase) FLOAT /// @@ -171,9 +172,10 @@ impl crate::Group for InverterSinglePhaseFloat { const LEN: u16 = 60; } impl InverterSinglePhaseFloat { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -209,11 +211,6 @@ impl InverterSinglePhaseFloat { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Operating State /// diff --git a/src/models/model112.rs b/src/models/model112.rs index dbfb297..a10af3e 100644 --- a/src/models/model112.rs +++ b/src/models/model112.rs @@ -1,4 +1,5 @@ //! Inverter (Split Phase) FLOAT +/// Type alias for [`InverterSplitPhaseFloat`]. pub type Model112 = InverterSplitPhaseFloat; /// Inverter (Split Phase) FLOAT /// @@ -173,9 +174,10 @@ impl crate::Group for InverterSplitPhaseFloat { const LEN: u16 = 60; } impl InverterSplitPhaseFloat { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -211,11 +213,6 @@ impl InverterSplitPhaseFloat { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Operating State /// diff --git a/src/models/model113.rs b/src/models/model113.rs index 073dd73..63ef19e 100644 --- a/src/models/model113.rs +++ b/src/models/model113.rs @@ -1,4 +1,5 @@ //! Inverter (Three Phase) FLOAT +/// Type alias for [`InverterThreePhaseFloat`]. pub type Model113 = InverterThreePhaseFloat; /// Inverter (Three Phase) FLOAT /// @@ -177,9 +178,10 @@ impl crate::Group for InverterThreePhaseFloat { const LEN: u16 = 60; } impl InverterThreePhaseFloat { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -215,11 +217,6 @@ impl InverterThreePhaseFloat { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Operating State /// diff --git a/src/models/model12.rs b/src/models/model12.rs index 141d8bf..bca5f28 100644 --- a/src/models/model12.rs +++ b/src/models/model12.rs @@ -88,9 +88,10 @@ impl crate::Group for Model12 { const LEN: u16 = 98; } impl Model12 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { nam: Self::NAM.from_data(data)?, cfg_st: Self::CFG_ST.from_data(data)?, @@ -110,11 +111,6 @@ impl Model12 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Config Status /// diff --git a/src/models/model120.rs b/src/models/model120.rs index f71e1e6..ecefab7 100644 --- a/src/models/model120.rs +++ b/src/models/model120.rs @@ -1,4 +1,5 @@ //! Nameplate +/// Type alias for [`Nameplate`]. pub type Model120 = Nameplate; /// Nameplate /// @@ -151,9 +152,10 @@ impl crate::Group for Nameplate { const LEN: u16 = 26; } impl Nameplate { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { der_typ: Self::DER_TYP.from_data(data)?, w_rtg: Self::W_RTG.from_data(data)?, @@ -183,11 +185,6 @@ impl Nameplate { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// DERTyp /// diff --git a/src/models/model121.rs b/src/models/model121.rs index 7a05eb0..e2bd2c0 100644 --- a/src/models/model121.rs +++ b/src/models/model121.rs @@ -1,4 +1,5 @@ //! Basic Settings +/// Type alias for [`Settings`]. pub type Model121 = Settings; /// Basic Settings /// @@ -174,9 +175,10 @@ impl crate::Group for Settings { const LEN: u16 = 30; } impl Settings { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { w_max: Self::W_MAX.from_data(data)?, v_ref: Self::V_REF.from_data(data)?, @@ -211,11 +213,6 @@ impl Settings { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// VArAct /// diff --git a/src/models/model122.rs b/src/models/model122.rs index d863f17..a05495f 100644 --- a/src/models/model122.rs +++ b/src/models/model122.rs @@ -1,4 +1,5 @@ //! Measurements_Status +/// Type alias for [`Status`]. pub type Model122 = Status; /// Measurements_Status /// @@ -119,9 +120,10 @@ impl crate::Group for Status { const LEN: u16 = 44; } impl Status { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { pv_conn: Self::PV_CONN.from_data(data)?, stor_conn: Self::STOR_CONN.from_data(data)?, @@ -146,11 +148,6 @@ impl Status { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " PVConn"] #[doc = " "] #[doc = diff --git a/src/models/model123.rs b/src/models/model123.rs index b41df3b..35e7cfa 100644 --- a/src/models/model123.rs +++ b/src/models/model123.rs @@ -1,4 +1,5 @@ //! Immediate Controls +/// Type alias for [`Controls`]. pub type Model123 = Controls; /// Immediate Controls /// @@ -139,9 +140,10 @@ impl crate::Group for Controls { const LEN: u16 = 24; } impl Controls { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { conn_win_tms: Self::CONN_WIN_TMS.from_data(data)?, conn_rvrt_tms: Self::CONN_RVRT_TMS.from_data(data)?, @@ -170,11 +172,6 @@ impl Controls { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Conn /// diff --git a/src/models/model124.rs b/src/models/model124.rs index dda509a..4baff23 100644 --- a/src/models/model124.rs +++ b/src/models/model124.rs @@ -1,4 +1,5 @@ //! Storage +/// Type alias for [`StorageBasic`]. pub type Model124 = StorageBasic; /// Storage /// @@ -137,9 +138,10 @@ impl crate::Group for StorageBasic { const LEN: u16 = 24; } impl StorageBasic { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { w_cha_max: Self::W_CHA_MAX.from_data(data)?, w_cha_gra: Self::W_CHA_GRA.from_data(data)?, @@ -168,11 +170,6 @@ impl StorageBasic { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " StorCtl_Mod"] #[doc = " "] #[doc = diff --git a/src/models/model125.rs b/src/models/model125.rs index 21f9cc6..ec02030 100644 --- a/src/models/model125.rs +++ b/src/models/model125.rs @@ -1,4 +1,5 @@ //! Pricing +/// Type alias for [`Pricing`]. pub type Model125 = Pricing; /// Pricing /// @@ -51,9 +52,10 @@ impl crate::Group for Pricing { const LEN: u16 = 8; } impl Pricing { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { mod_ena: Self::MOD_ENA.from_data(data)?, sig_type: Self::SIG_TYPE.from_data(data)?, @@ -65,11 +67,6 @@ impl Pricing { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = diff --git a/src/models/model126.rs b/src/models/model126.rs index f3f86fa..9b11e0d 100644 --- a/src/models/model126.rs +++ b/src/models/model126.rs @@ -1,4 +1,5 @@ //! Static Volt-VAR +/// Type alias for [`VoltVar`]. pub type Model126 = VoltVar; /// Static Volt-VAR /// @@ -66,9 +67,11 @@ impl crate::Group for VoltVar { const LEN: u16 = 10; } impl VoltVar { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -80,16 +83,10 @@ impl VoltVar { v_sf: Self::V_SF.from_data(data)?, dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = " Is Volt-VAR control active."] @@ -370,9 +367,10 @@ impl crate::Group for Curve { const LEN: u16 = 54; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, dept_ref: Self::DEPT_REF.from_data(data)?, @@ -424,24 +422,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &VoltVar, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &VoltVar, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model127.rs b/src/models/model127.rs index 9878162..176614f 100644 --- a/src/models/model127.rs +++ b/src/models/model127.rs @@ -1,4 +1,5 @@ //! Freq-Watt Param +/// Type alias for [`FreqWattParam`]. pub type Model127 = FreqWattParam; /// Freq-Watt Param /// @@ -61,9 +62,10 @@ impl crate::Group for FreqWattParam { const LEN: u16 = 10; } impl FreqWattParam { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { w_gra: Self::W_GRA.from_data(data)?, hz_str: Self::HZ_STR.from_data(data)?, @@ -77,11 +79,6 @@ impl FreqWattParam { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " HysEna"] #[doc = " "] #[doc = " Enable hysteresis"] #[derive(Copy, Clone, diff --git a/src/models/model128.rs b/src/models/model128.rs index 164e686..b6de54f 100644 --- a/src/models/model128.rs +++ b/src/models/model128.rs @@ -1,4 +1,5 @@ //! Dynamic Reactive Current +/// Type alias for [`ReactiveCurrent`]. pub type Model128 = ReactiveCurrent; /// Dynamic Reactive Current /// @@ -81,9 +82,10 @@ impl crate::Group for ReactiveCurrent { const LEN: u16 = 14; } impl ReactiveCurrent { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ar_gra_mod: Self::AR_GRA_MOD.from_data(data)?, ar_gra_sag: Self::AR_GRA_SAG.from_data(data)?, @@ -101,11 +103,6 @@ impl ReactiveCurrent { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// ArGraMod /// diff --git a/src/models/model129.rs b/src/models/model129.rs index a57b971..cf8883b 100644 --- a/src/models/model129.rs +++ b/src/models/model129.rs @@ -1,4 +1,5 @@ //! LVRTD +/// Type alias for [`Lvrt`]. pub type Model129 = Lvrt; /// LVRTD /// @@ -69,9 +70,11 @@ impl crate::Group for Lvrt { const LEN: u16 = 10; } impl Lvrt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -82,16 +85,10 @@ impl Lvrt { n_pt: Self::N_PT.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -353,9 +350,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -403,24 +401,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Lvrt, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Lvrt, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model13.rs b/src/models/model13.rs index 2d4b259..dcdcf86 100644 --- a/src/models/model13.rs +++ b/src/models/model13.rs @@ -88,9 +88,10 @@ impl crate::Group for Model13 { const LEN: u16 = 174; } impl Model13 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { nam: Self::NAM.from_data(data)?, cfg_st: Self::CFG_ST.from_data(data)?, @@ -110,11 +111,6 @@ impl Model13 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Config Status /// diff --git a/src/models/model130.rs b/src/models/model130.rs index b448235..b950a18 100644 --- a/src/models/model130.rs +++ b/src/models/model130.rs @@ -1,4 +1,5 @@ //! HVRTD +/// Type alias for [`Hvrt`]. pub type Model130 = Hvrt; /// HVRTD /// @@ -69,9 +70,11 @@ impl crate::Group for Hvrt { const LEN: u16 = 10; } impl Hvrt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -82,16 +85,10 @@ impl Hvrt { n_pt: Self::N_PT.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -353,9 +350,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -403,24 +401,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Hvrt, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Hvrt, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model131.rs b/src/models/model131.rs index ea04564..eea7c14 100644 --- a/src/models/model131.rs +++ b/src/models/model131.rs @@ -1,4 +1,5 @@ //! Watt-PF +/// Type alias for [`WattPf`]. pub type Model131 = WattPf; /// Watt-PF /// @@ -68,9 +69,11 @@ impl crate::Group for WattPf { const LEN: u16 = 10; } impl WattPf { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -82,16 +85,10 @@ impl WattPf { w_sf: Self::W_SF.from_data(data)?, pf_sf: Self::PF_SF.from_data(data)?, rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = " Is watt-PF mode active."] #[derive(Copy, @@ -367,9 +364,10 @@ impl crate::Group for Curve { const LEN: u16 = 54; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, w1: Self::W1.from_data(data)?, @@ -420,24 +418,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &WattPf, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &WattPf, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model132.rs b/src/models/model132.rs index 38463bd..bab5393 100644 --- a/src/models/model132.rs +++ b/src/models/model132.rs @@ -1,4 +1,5 @@ //! Volt-Watt +/// Type alias for [`VoltWatt`]. pub type Model132 = VoltWatt; /// Volt-Watt /// @@ -68,9 +69,11 @@ impl crate::Group for VoltWatt { const LEN: u16 = 10; } impl VoltWatt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -82,16 +85,10 @@ impl VoltWatt { v_sf: Self::V_SF.from_data(data)?, dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = " Is Volt-Watt control active."] @@ -372,9 +369,10 @@ impl crate::Group for Curve { const LEN: u16 = 54; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, dept_ref: Self::DEPT_REF.from_data(data)?, @@ -426,24 +424,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &VoltWatt, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &VoltWatt, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model133.rs b/src/models/model133.rs index 4a9647b..af53406 100644 --- a/src/models/model133.rs +++ b/src/models/model133.rs @@ -1,4 +1,5 @@ //! Basic Scheduling +/// Type alias for [`Schedule`]. pub type Model133 = Schedule; /// Basic Scheduling /// @@ -38,24 +39,20 @@ impl crate::Group for Schedule { const LEN: u16 = 6; } impl Schedule { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_schd: Self::ACT_SCHD.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, n_schd: Self::N_SCHD.from_data(data)?, n_pts: Self::N_PTS.from_data(data)?, - repeating: Vec::new(), + repeating, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ActSchd"] #[doc = " "] #[doc = " Bitfield of active schedules"] @@ -310,9 +307,10 @@ impl crate::Group for Repeating { const LEN: u16 = 60; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pts: Self::ACT_PTS.from_data(data)?, str_tms: Self::STR_TMS.from_data(data)?, @@ -349,24 +347,21 @@ impl Repeating { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Schedule, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Schedule, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model134.rs b/src/models/model134.rs index 7791898..c130a24 100644 --- a/src/models/model134.rs +++ b/src/models/model134.rs @@ -1,4 +1,5 @@ //! Freq-Watt Crv +/// Type alias for [`FreqWatt`]. pub type Model134 = FreqWatt; /// Freq-Watt Crv /// @@ -68,9 +69,11 @@ impl crate::Group for FreqWatt { const LEN: u16 = 10; } impl FreqWatt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -82,16 +85,10 @@ impl FreqWatt { hz_sf: Self::HZ_SF.from_data(data)?, w_sf: Self::W_SF.from_data(data)?, rmp_inc_dec_sf: Self::RMP_INC_DEC_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -393,9 +390,10 @@ impl crate::Group for Curve { const LEN: u16 = 58; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, hz1: Self::HZ1.from_data(data)?, @@ -451,24 +449,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &FreqWatt, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &FreqWatt, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model135.rs b/src/models/model135.rs index cc7a70a..64a3c86 100644 --- a/src/models/model135.rs +++ b/src/models/model135.rs @@ -1,4 +1,5 @@ //! LFRT +/// Type alias for [`Lfrt`]. pub type Model135 = Lfrt; /// LFRT /// @@ -69,9 +70,11 @@ impl crate::Group for Lfrt { const LEN: u16 = 10; } impl Lfrt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -82,16 +85,10 @@ impl Lfrt { n_pt: Self::N_PT.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, hz_sf: Self::HZ_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -353,9 +350,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -403,24 +401,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Lfrt, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Lfrt, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model136.rs b/src/models/model136.rs index 870c0ec..a6846af 100644 --- a/src/models/model136.rs +++ b/src/models/model136.rs @@ -1,4 +1,5 @@ //! HFRT +/// Type alias for [`Hfrt`]. pub type Model136 = Hfrt; /// HFRT /// @@ -69,9 +70,11 @@ impl crate::Group for Hfrt { const LEN: u16 = 10; } impl Hfrt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -82,16 +85,10 @@ impl Hfrt { n_pt: Self::N_PT.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, hz_sf: Self::HZ_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -353,9 +350,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -403,24 +401,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Hfrt, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Hfrt, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model137.rs b/src/models/model137.rs index cc828bf..e64e155 100644 --- a/src/models/model137.rs +++ b/src/models/model137.rs @@ -1,4 +1,5 @@ //! LVRTC +/// Type alias for [`Lvrtc`]. pub type Model137 = Lvrtc; /// LVRTC /// @@ -69,9 +70,11 @@ impl crate::Group for Lvrtc { const LEN: u16 = 10; } impl Lvrtc { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -82,16 +85,10 @@ impl Lvrtc { n_pt: Self::N_PT.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -353,9 +350,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -403,24 +401,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Lvrtc, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Lvrtc, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model138.rs b/src/models/model138.rs index f8c6ade..8a9b420 100644 --- a/src/models/model138.rs +++ b/src/models/model138.rs @@ -1,4 +1,5 @@ //! HVRTC +/// Type alias for [`Hvrtc`]. pub type Model138 = Hvrtc; /// HVRTC /// @@ -69,9 +70,11 @@ impl crate::Group for Hvrtc { const LEN: u16 = 10; } impl Hvrtc { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -82,16 +85,10 @@ impl Hvrtc { n_pt: Self::N_PT.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -353,9 +350,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -403,24 +401,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Hvrtc, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Hvrtc, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model139.rs b/src/models/model139.rs index 91d5f68..e599b63 100644 --- a/src/models/model139.rs +++ b/src/models/model139.rs @@ -1,4 +1,5 @@ //! LVRTX +/// Type alias for [`Lvrtx`]. pub type Model139 = Lvrtx; /// LVRTX /// @@ -72,9 +73,11 @@ impl crate::Group for Lvrtx { const LEN: u16 = 10; } impl Lvrtx { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -86,16 +89,10 @@ impl Lvrtx { tms_sf: Self::TMS_SF.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, crv_type: Self::CRV_TYPE.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -393,9 +390,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -443,24 +441,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Lvrtx, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Lvrtx, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model14.rs b/src/models/model14.rs index 4dafbe3..bf42829 100644 --- a/src/models/model14.rs +++ b/src/models/model14.rs @@ -53,9 +53,10 @@ impl crate::Group for Model14 { const LEN: u16 = 52; } impl Model14 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { nam: Self::NAM.from_data(data)?, cap: Self::CAP.from_data(data)?, @@ -68,11 +69,6 @@ impl Model14 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Capabilities"] #[doc = " "] #[doc = diff --git a/src/models/model140.rs b/src/models/model140.rs index 77118d8..cc0f68a 100644 --- a/src/models/model140.rs +++ b/src/models/model140.rs @@ -1,4 +1,5 @@ //! HVRTX +/// Type alias for [`Hvrtx`]. pub type Model140 = Hvrtx; /// HVRTX /// @@ -72,9 +73,11 @@ impl crate::Group for Hvrtx { const LEN: u16 = 10; } impl Hvrtx { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -86,16 +89,10 @@ impl Hvrtx { tms_sf: Self::TMS_SF.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, crv_type: Self::CRV_TYPE.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -393,9 +390,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -443,24 +441,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Hvrtx, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Hvrtx, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model141.rs b/src/models/model141.rs index 1373d62..eb3baf9 100644 --- a/src/models/model141.rs +++ b/src/models/model141.rs @@ -1,4 +1,5 @@ //! LFRTC +/// Type alias for [`Lfrtc`]. pub type Model141 = Lfrtc; /// LFRTC /// @@ -69,9 +70,11 @@ impl crate::Group for Lfrtc { const LEN: u16 = 10; } impl Lfrtc { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -82,16 +85,10 @@ impl Lfrtc { n_pt: Self::N_PT.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, hz_sf: Self::HZ_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -353,9 +350,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -403,24 +401,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Lfrtc, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Lfrtc, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model142.rs b/src/models/model142.rs index 9704749..eb9f9ea 100644 --- a/src/models/model142.rs +++ b/src/models/model142.rs @@ -1,4 +1,5 @@ //! HFRTC +/// Type alias for [`Hfrtc`]. pub type Model142 = Hfrtc; /// HFRTC /// @@ -69,9 +70,11 @@ impl crate::Group for Hfrtc { const LEN: u16 = 10; } impl Hfrtc { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -82,16 +85,10 @@ impl Hfrtc { n_pt: Self::N_PT.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, hz_sf: Self::HZ_SF.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -353,9 +350,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -403,24 +401,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Hfrtc, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Hfrtc, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model143.rs b/src/models/model143.rs index 2c246dc..e7a400c 100644 --- a/src/models/model143.rs +++ b/src/models/model143.rs @@ -1,4 +1,5 @@ //! LFRTX +/// Type alias for [`Lfrtx`]. pub type Model143 = Lfrtx; /// LFRTX /// @@ -72,9 +73,11 @@ impl crate::Group for Lfrtx { const LEN: u16 = 10; } impl Lfrtx { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -86,16 +89,10 @@ impl Lfrtx { tms_sf: Self::TMS_SF.from_data(data)?, hz_sf: Self::HZ_SF.from_data(data)?, crv_type: Self::CRV_TYPE.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -393,9 +390,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -443,24 +441,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Lfrtx, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Lfrtx, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model144.rs b/src/models/model144.rs index 79277d5..ee43b9f 100644 --- a/src/models/model144.rs +++ b/src/models/model144.rs @@ -1,4 +1,5 @@ //! HFRTX +/// Type alias for [`Hfrtx`]. pub type Model144 = Hfrtx; /// HFRTX /// @@ -72,9 +73,11 @@ impl crate::Group for Hfrtx { const LEN: u16 = 10; } impl Hfrtx { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, curve) = Curve::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_crv: Self::ACT_CRV.from_data(data)?, mod_ena: Self::MOD_ENA.from_data(data)?, @@ -86,16 +89,10 @@ impl Hfrtx { tms_sf: Self::TMS_SF.from_data(data)?, hz_sf: Self::HZ_SF.from_data(data)?, crv_type: Self::CRV_TYPE.from_data(data)?, - curve: Vec::new(), + curve, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.curve) = Curve::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " ModEna"] #[doc = " "] #[doc = @@ -393,9 +390,10 @@ impl crate::Group for Curve { const LEN: u16 = 50; } impl Curve { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, tms1: Self::TMS1.from_data(data)?, @@ -443,24 +441,21 @@ impl Curve { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Hfrtx, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Hfrtx, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Curve::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Curve::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model145.rs b/src/models/model145.rs index f397ae0..43fb811 100644 --- a/src/models/model145.rs +++ b/src/models/model145.rs @@ -1,4 +1,5 @@ //! Extended Settings +/// Type alias for [`ExtSettings`]. pub type Model145 = ExtSettings; /// Extended Settings /// @@ -54,9 +55,10 @@ impl crate::Group for ExtSettings { const LEN: u16 = 8; } impl ExtSettings { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { nom_rmp_up_rte: Self::NOM_RMP_UP_RTE.from_data(data)?, nom_rmp_dn_rte: Self::NOM_RMP_DN_RTE.from_data(data)?, @@ -69,11 +71,6 @@ impl ExtSettings { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } impl crate::Model for ExtSettings { const ID: u16 = 145; diff --git a/src/models/model15.rs b/src/models/model15.rs index 92bde6f..9509e43 100644 --- a/src/models/model15.rs +++ b/src/models/model15.rs @@ -73,9 +73,10 @@ impl crate::Group for Model15 { const LEN: u16 = 24; } impl Model15 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { clr: Self::CLR.from_data(data)?, in_cnt: Self::IN_CNT.from_data(data)?, @@ -92,11 +93,6 @@ impl Model15 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } impl crate::Model for Model15 { const ID: u16 = 15; diff --git a/src/models/model16.rs b/src/models/model16.rs index bbee6c9..6c5391e 100644 --- a/src/models/model16.rs +++ b/src/models/model16.rs @@ -63,9 +63,10 @@ impl crate::Group for Model16 { const LEN: u16 = 52; } impl Model16 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { nam: Self::NAM.from_data(data)?, cfg: Self::CFG.from_data(data)?, @@ -80,11 +81,6 @@ impl Model16 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Config /// diff --git a/src/models/model160.rs b/src/models/model160.rs index fa289fa..46eb070 100644 --- a/src/models/model160.rs +++ b/src/models/model160.rs @@ -1,4 +1,5 @@ //! Multiple MPPT Inverter Extension Model +/// Type alias for [`Mppt`]. pub type Model160 = Mppt; /// Multiple MPPT Inverter Extension Model #[derive(Debug)] @@ -35,9 +36,11 @@ impl crate::Group for Mppt { const LEN: u16 = 8; } impl Mppt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, module) = Module::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { dca_sf: Self::DCA_SF.from_data(data)?, dcv_sf: Self::DCV_SF.from_data(data)?, @@ -46,16 +49,10 @@ impl Mppt { evt: Self::EVT.from_data(data)?, n: Self::N.from_data(data)?, tms_per: Self::TMS_PER.from_data(data)?, - module: Vec::new(), + module, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.module) = Module::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Global Events"] #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -145,9 +142,10 @@ impl crate::Group for Module { const LEN: u16 = 20; } impl Module { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { id: Self::ID.from_data(data)?, id_str: Self::ID_STR.from_data(data)?, @@ -162,24 +160,21 @@ impl Module { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Mppt, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Mppt, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Module::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Module::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model17.rs b/src/models/model17.rs index a5517af..07b677c 100644 --- a/src/models/model17.rs +++ b/src/models/model17.rs @@ -53,9 +53,10 @@ impl crate::Group for Model17 { const LEN: u16 = 12; } impl Model17 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { nam: Self::NAM.from_data(data)?, rte: Self::RTE.from_data(data)?, @@ -68,11 +69,6 @@ impl Model17 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Parity /// diff --git a/src/models/model18.rs b/src/models/model18.rs index 76bc40e..0fdf87d 100644 --- a/src/models/model18.rs +++ b/src/models/model18.rs @@ -38,9 +38,10 @@ impl crate::Group for Model18 { const LEN: u16 = 22; } impl Model18 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { nam: Self::NAM.from_data(data)?, imei: Self::IMEI.from_data(data)?, @@ -50,11 +51,6 @@ impl Model18 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } impl crate::Model for Model18 { const ID: u16 = 18; diff --git a/src/models/model19.rs b/src/models/model19.rs index f0e2e2d..acf407a 100644 --- a/src/models/model19.rs +++ b/src/models/model19.rs @@ -58,9 +58,10 @@ impl crate::Group for Model19 { const LEN: u16 = 30; } impl Model19 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { nam: Self::NAM.from_data(data)?, rte: Self::RTE.from_data(data)?, @@ -74,11 +75,6 @@ impl Model19 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Parity /// diff --git a/src/models/model2.rs b/src/models/model2.rs index 153ce79..c4ddde5 100644 --- a/src/models/model2.rs +++ b/src/models/model2.rs @@ -1,4 +1,5 @@ //! Basic Aggregator +/// Type alias for [`Aggregator`]. pub type Model2 = Aggregator; /// Basic Aggregator /// @@ -64,9 +65,10 @@ impl crate::Group for Aggregator { const LEN: u16 = 14; } impl Aggregator { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { aid: Self::AID.from_data(data)?, n: Self::N.from_data(data)?, @@ -81,11 +83,6 @@ impl Aggregator { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Status /// diff --git a/src/models/model201.rs b/src/models/model201.rs index cf420de..dec384c 100644 --- a/src/models/model201.rs +++ b/src/models/model201.rs @@ -1,4 +1,5 @@ //! Meter (Single Phase) single phase (AN or AB) meter +/// Type alias for [`AcMeterAnOrAb`]. pub type Model201 = AcMeterAnOrAb; /// Meter (Single Phase) single phase (AN or AB) meter /// @@ -300,9 +301,10 @@ impl crate::Group for AcMeterAnOrAb { const LEN: u16 = 105; } impl AcMeterAnOrAb { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -379,11 +381,6 @@ impl AcMeterAnOrAb { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Events"] #[doc = " "] #[doc = " Meter Event Flags"] #[derive(Copy, Clone, diff --git a/src/models/model202.rs b/src/models/model202.rs index 863c6e6..bfa558a 100644 --- a/src/models/model202.rs +++ b/src/models/model202.rs @@ -1,4 +1,5 @@ //! split single phase (ABN) meter +/// Type alias for [`AcMeterAbn`]. pub type Model202 = AcMeterAbn; /// split single phase (ABN) meter #[derive(Debug)] @@ -292,9 +293,10 @@ impl crate::Group for AcMeterAbn { const LEN: u16 = 105; } impl AcMeterAbn { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -371,11 +373,6 @@ impl AcMeterAbn { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Events"] #[doc = " "] #[doc = " Meter Event Flags"] #[derive(Copy, Clone, diff --git a/src/models/model203.rs b/src/models/model203.rs index 2512bbb..46ca7fe 100644 --- a/src/models/model203.rs +++ b/src/models/model203.rs @@ -1,4 +1,5 @@ //! wye-connect three phase (abcn) meter +/// Type alias for [`AcMeterAbcn`]. pub type Model203 = AcMeterAbcn; /// wye-connect three phase (abcn) meter #[derive(Debug)] @@ -292,9 +293,10 @@ impl crate::Group for AcMeterAbcn { const LEN: u16 = 105; } impl AcMeterAbcn { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -371,11 +373,6 @@ impl AcMeterAbcn { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Events"] #[doc = " "] #[doc = " Meter Event Flags"] #[derive(Copy, Clone, diff --git a/src/models/model204.rs b/src/models/model204.rs index 20b7abb..e93a4bc 100644 --- a/src/models/model204.rs +++ b/src/models/model204.rs @@ -1,4 +1,5 @@ //! delta-connect three phase (abc) meter +/// Type alias for [`AcMeterAbc`]. pub type Model204 = AcMeterAbc; /// delta-connect three phase (abc) meter #[derive(Debug)] @@ -292,9 +293,10 @@ impl crate::Group for AcMeterAbc { const LEN: u16 = 105; } impl AcMeterAbc { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -371,11 +373,6 @@ impl AcMeterAbc { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Events"] #[doc = " "] #[doc = " Meter Event Flags"] #[derive(Copy, Clone, diff --git a/src/models/model211.rs b/src/models/model211.rs index e180e73..13495c8 100644 --- a/src/models/model211.rs +++ b/src/models/model211.rs @@ -1,4 +1,5 @@ //! single phase (AN or AB) meter +/// Type alias for [`AcMeterAnOrAbFloat`]. pub type Model211 = AcMeterAnOrAbFloat; /// single phase (AN or AB) meter /// @@ -264,9 +265,10 @@ impl crate::Group for AcMeterAnOrAbFloat { const LEN: u16 = 124; } impl AcMeterAnOrAbFloat { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -333,11 +335,6 @@ impl AcMeterAnOrAbFloat { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Events"] #[doc = " "] #[doc = " Meter Event Flags"] #[derive(Copy, Clone, diff --git a/src/models/model212.rs b/src/models/model212.rs index b6e0074..c8cc6ed 100644 --- a/src/models/model212.rs +++ b/src/models/model212.rs @@ -1,4 +1,5 @@ //! split single phase (ABN) meter +/// Type alias for [`AcMeterAbnFloat`]. pub type Model212 = AcMeterAbnFloat; /// split single phase (ABN) meter /// @@ -264,9 +265,10 @@ impl crate::Group for AcMeterAbnFloat { const LEN: u16 = 124; } impl AcMeterAbnFloat { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -333,11 +335,6 @@ impl AcMeterAbnFloat { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Events"] #[doc = " "] #[doc = " Meter Event Flags"] #[derive(Copy, Clone, diff --git a/src/models/model213.rs b/src/models/model213.rs index edcc124..d6b1514 100644 --- a/src/models/model213.rs +++ b/src/models/model213.rs @@ -1,4 +1,5 @@ //! wye-connect three phase (abcn) meter +/// Type alias for [`AcMeterAbcnFloat`]. pub type Model213 = AcMeterAbcnFloat; /// wye-connect three phase (abcn) meter /// @@ -264,9 +265,10 @@ impl crate::Group for AcMeterAbcnFloat { const LEN: u16 = 124; } impl AcMeterAbcnFloat { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -333,11 +335,6 @@ impl AcMeterAbcnFloat { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Events"] #[doc = " "] #[doc = " Meter Event Flags"] #[derive(Copy, Clone, diff --git a/src/models/model214.rs b/src/models/model214.rs index 19d001a..6f7bb37 100644 --- a/src/models/model214.rs +++ b/src/models/model214.rs @@ -1,4 +1,5 @@ //! delta-connect three phase (abc) meter +/// Type alias for [`AcMeterAbcFloat`]. pub type Model214 = AcMeterAbcFloat; /// delta-connect three phase (abc) meter /// @@ -264,9 +265,10 @@ impl crate::Group for AcMeterAbcFloat { const LEN: u16 = 124; } impl AcMeterAbcFloat { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, aph_a: Self::APH_A.from_data(data)?, @@ -333,11 +335,6 @@ impl AcMeterAbcFloat { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Events"] #[doc = " "] #[doc = " Meter Event Flags"] #[derive(Copy, Clone, diff --git a/src/models/model220.rs b/src/models/model220.rs index c778b41..925fb0d 100644 --- a/src/models/model220.rs +++ b/src/models/model220.rs @@ -1,4 +1,5 @@ //! Secure AC Meter Selected Readings +/// Type alias for [`AcMeterSecure`]. pub type Model220 = AcMeterSecure; /// Secure AC Meter Selected Readings /// @@ -157,9 +158,11 @@ impl crate::Group for AcMeterSecure { const LEN: u16 = 42; } impl AcMeterSecure { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a: Self::A.from_data(data)?, a_sf: Self::A_SF.from_data(data)?, @@ -192,16 +195,10 @@ impl AcMeterSecure { seq: Self::SEQ.from_data(data)?, alg: Self::ALG.from_data(data)?, n: Self::N.from_data(data)?, - repeating: Vec::new(), + repeating, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Events"] #[doc = " "] #[doc = " Meter Event Flags"] #[derive(Copy, Clone, @@ -306,32 +303,30 @@ impl crate::Group for Repeating { const LEN: u16 = 1; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ds: Self::DS.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &AcMeterSecure, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &AcMeterSecure, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model3.rs b/src/models/model3.rs index f0064f6..821ce13 100644 --- a/src/models/model3.rs +++ b/src/models/model3.rs @@ -214,9 +214,11 @@ impl crate::Group for Model3 { const LEN: u16 = 58; } impl Model3 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { x: Self::X.from_data(data)?, off1: Self::OFF1.from_data(data)?, @@ -275,16 +277,10 @@ impl Model3 { role: Self::ROLE.from_data(data)?, alg: Self::ALG.from_data(data)?, n: Self::N.from_data(data)?, - repeating: Vec::new(), + repeating, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// Algorithm /// @@ -347,32 +343,30 @@ impl crate::Group for Repeating { const LEN: u16 = 1; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ds: Self::DS.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Model3, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Model3, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model302.rs b/src/models/model302.rs index 7e34412..8355b7f 100644 --- a/src/models/model302.rs +++ b/src/models/model302.rs @@ -1,4 +1,5 @@ //! Irradiance Model +/// Type alias for [`Irradiance`]. pub type Model302 = Irradiance; /// Irradiance Model /// @@ -15,19 +16,10 @@ impl crate::Group for Irradiance { const LEN: u16 = 0; } impl Irradiance { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - Ok(( - &data[usize::from(::LEN)..], - Self { - repeating: Vec::new(), - }, - )) - } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; + Ok((nested_data, Self { repeating })) } } #[allow(missing_docs)] @@ -67,9 +59,10 @@ impl crate::Group for Repeating { const LEN: u16 = 5; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ghi: Self::GHI.from_data(data)?, poai: Self::POAI.from_data(data)?, @@ -79,24 +72,21 @@ impl Repeating { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Irradiance, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Irradiance, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model303.rs b/src/models/model303.rs index c389eb3..6739972 100644 --- a/src/models/model303.rs +++ b/src/models/model303.rs @@ -1,4 +1,5 @@ //! Back of Module Temperature Model +/// Type alias for [`BomTemp`]. pub type Model303 = BomTemp; /// Back of Module Temperature Model /// @@ -15,17 +16,10 @@ impl crate::Group for BomTemp { const LEN: u16 = 0; } impl BomTemp { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - Ok(( - &data[usize::from(::LEN)..], - Self { temp: Vec::new() }, - )) - } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.temp) = Temp::parse_multiple(data, &group)?; - Ok((data, group)) + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, temp) = Temp::parse_multiple(nested_data)?; + Ok((nested_data, Self { temp })) } } #[allow(missing_docs)] @@ -45,32 +39,30 @@ impl crate::Group for Temp { const LEN: u16 = 1; } impl Temp { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { tmp_bom: Self::TMP_BOM.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &BomTemp, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &BomTemp, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Temp::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Temp::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model304.rs b/src/models/model304.rs index 87a06bf..db8ab9e 100644 --- a/src/models/model304.rs +++ b/src/models/model304.rs @@ -1,4 +1,5 @@ //! Inclinometer Model +/// Type alias for [`Inclinometer`]. pub type Model304 = Inclinometer; /// Inclinometer Model /// @@ -15,17 +16,10 @@ impl crate::Group for Inclinometer { const LEN: u16 = 0; } impl Inclinometer { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - Ok(( - &data[usize::from(::LEN)..], - Self { incl: Vec::new() }, - )) - } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.incl) = Incl::parse_multiple(data, &group)?; - Ok((data, group)) + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, incl) = Incl::parse_multiple(nested_data)?; + Ok((nested_data, Self { incl })) } } #[allow(missing_docs)] @@ -55,9 +49,10 @@ impl crate::Group for Incl { const LEN: u16 = 6; } impl Incl { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { inclx: Self::INCLX.from_data(data)?, incly: Self::INCLY.from_data(data)?, @@ -65,24 +60,21 @@ impl Incl { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Inclinometer, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Inclinometer, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Incl::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Incl::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model305.rs b/src/models/model305.rs index a88f27a..fc9e2c4 100644 --- a/src/models/model305.rs +++ b/src/models/model305.rs @@ -1,4 +1,5 @@ //! GPS +/// Type alias for [`Location`]. pub type Model305 = Location; /// GPS /// @@ -44,9 +45,10 @@ impl crate::Group for Location { const LEN: u16 = 36; } impl Location { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { tm: Self::TM.from_data(data)?, date: Self::DATE.from_data(data)?, @@ -57,11 +59,6 @@ impl Location { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } impl crate::Model for Location { const ID: u16 = 305; diff --git a/src/models/model306.rs b/src/models/model306.rs index 1095644..d27f699 100644 --- a/src/models/model306.rs +++ b/src/models/model306.rs @@ -1,4 +1,5 @@ //! Reference Point Model +/// Type alias for [`RefPoint`]. pub type Model306 = RefPoint; /// Reference Point Model /// @@ -34,9 +35,10 @@ impl crate::Group for RefPoint { const LEN: u16 = 4; } impl RefPoint { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ghi: Self::GHI.from_data(data)?, a: Self::A.from_data(data)?, @@ -45,11 +47,6 @@ impl RefPoint { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } impl crate::Model for RefPoint { const ID: u16 = 306; diff --git a/src/models/model307.rs b/src/models/model307.rs index 6bb4d7e..813ee19 100644 --- a/src/models/model307.rs +++ b/src/models/model307.rs @@ -1,4 +1,5 @@ //! Base Met +/// Type alias for [`BaseMet`]. pub type Model307 = BaseMet; /// Base Met /// @@ -51,9 +52,10 @@ impl crate::Group for BaseMet { const LEN: u16 = 11; } impl BaseMet { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { tmp_amb: Self::TMP_AMB.from_data(data)?, rh: Self::RH.from_data(data)?, @@ -69,11 +71,6 @@ impl BaseMet { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } impl crate::Model for BaseMet { const ID: u16 = 307; diff --git a/src/models/model308.rs b/src/models/model308.rs index 903e63d..8f3d696 100644 --- a/src/models/model308.rs +++ b/src/models/model308.rs @@ -1,4 +1,5 @@ //! Mini Met Model +/// Type alias for [`MiniMet`]. pub type Model308 = MiniMet; /// Mini Met Model /// @@ -30,9 +31,10 @@ impl crate::Group for MiniMet { const LEN: u16 = 4; } impl MiniMet { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ghi: Self::GHI.from_data(data)?, tmp_bom: Self::TMP_BOM.from_data(data)?, @@ -41,11 +43,6 @@ impl MiniMet { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } impl crate::Model for MiniMet { const ID: u16 = 308; diff --git a/src/models/model4.rs b/src/models/model4.rs index 285387b..51206ac 100644 --- a/src/models/model4.rs +++ b/src/models/model4.rs @@ -222,9 +222,11 @@ impl crate::Group for Model4 { const LEN: u16 = 60; } impl Model4 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { rq_seq: Self::RQ_SEQ.from_data(data)?, sts: Self::STS.from_data(data)?, @@ -285,16 +287,10 @@ impl Model4 { alm: Self::ALM.from_data(data)?, alg: Self::ALG.from_data(data)?, n: Self::N.from_data(data)?, - repeating: Vec::new(), + repeating, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// Status /// @@ -441,32 +437,30 @@ impl crate::Group for Repeating { const LEN: u16 = 1; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ds: Self::DS.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Model4, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Model4, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model401.rs b/src/models/model401.rs index 49160a5..eb0a7d4 100644 --- a/src/models/model401.rs +++ b/src/models/model401.rs @@ -1,4 +1,5 @@ //! String Combiner (Current) +/// Type alias for [`StringCombinerCurrent`]. pub type Model401 = StringCombinerCurrent; /// String Combiner (Current) /// @@ -67,9 +68,11 @@ impl crate::Group for StringCombinerCurrent { const LEN: u16 = 14; } impl StringCombinerCurrent { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, string) = String::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { dca_sf: Self::DCA_SF.from_data(data)?, dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, @@ -82,16 +85,10 @@ impl StringCombinerCurrent { dc_ahr: Self::DC_AHR.from_data(data)?, dcv: Self::DCV.from_data(data)?, tmp: Self::TMP.from_data(data)?, - string: Vec::new(), + string, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.string) = String::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Event"] #[doc = " "] #[doc = " Bitmask value. Events"] #[derive(Copy, @@ -206,9 +203,10 @@ impl crate::Group for String { const LEN: u16 = 8; } impl String { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { in_id: Self::IN_ID.from_data(data)?, in_evt: Self::IN_EVT.from_data(data)?, @@ -218,24 +216,21 @@ impl String { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &StringCombinerCurrent, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &StringCombinerCurrent, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = String::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = String::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model402.rs b/src/models/model402.rs index 397c0dd..3938fc5 100644 --- a/src/models/model402.rs +++ b/src/models/model402.rs @@ -1,4 +1,5 @@ //! String Combiner (Advanced) +/// Type alias for [`StringCombinerAdvanced`]. pub type Model402 = StringCombinerAdvanced; /// String Combiner (Advanced) /// @@ -88,9 +89,11 @@ impl crate::Group for StringCombinerAdvanced { const LEN: u16 = 20; } impl StringCombinerAdvanced { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, string) = String::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { dca_sf: Self::DCA_SF.from_data(data)?, dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, @@ -108,16 +111,10 @@ impl StringCombinerAdvanced { dcw: Self::DCW.from_data(data)?, dcpr: Self::DCPR.from_data(data)?, dc_wh: Self::DC_WH.from_data(data)?, - string: Vec::new(), + string, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.string) = String::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Event"] #[doc = " "] #[doc = " Bitmask value. Events"] #[derive(Copy, @@ -256,9 +253,10 @@ impl crate::Group for String { const LEN: u16 = 14; } impl String { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { in_id: Self::IN_ID.from_data(data)?, in_evt: Self::IN_EVT.from_data(data)?, @@ -273,24 +271,21 @@ impl String { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &StringCombinerAdvanced, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &StringCombinerAdvanced, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = String::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = String::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model403.rs b/src/models/model403.rs index 5fe5706..fe1fe1e 100644 --- a/src/models/model403.rs +++ b/src/models/model403.rs @@ -1,4 +1,5 @@ //! String Combiner (Current) +/// Type alias for [`StringCombinerCurrentInput`]. pub type Model403 = StringCombinerCurrentInput; /// String Combiner (Current) /// @@ -73,9 +74,11 @@ impl crate::Group for StringCombinerCurrentInput { const LEN: u16 = 16; } impl StringCombinerCurrentInput { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, string) = String::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { dca_sf: Self::DCA_SF.from_data(data)?, dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, @@ -90,16 +93,10 @@ impl StringCombinerCurrentInput { tmp: Self::TMP.from_data(data)?, in_dca_sf: Self::IN_DCA_SF.from_data(data)?, in_dc_ahr_sf: Self::IN_DC_AHR_SF.from_data(data)?, - string: Vec::new(), + string, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.string) = String::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Event"] #[doc = " "] #[doc = " Bitmask value. Events"] #[derive(Copy, @@ -214,9 +211,10 @@ impl crate::Group for String { const LEN: u16 = 8; } impl String { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { in_id: Self::IN_ID.from_data(data)?, in_evt: Self::IN_EVT.from_data(data)?, @@ -226,24 +224,21 @@ impl String { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &StringCombinerCurrentInput, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &StringCombinerCurrentInput, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = String::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = String::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model404.rs b/src/models/model404.rs index b3280d6..b0b9471 100644 --- a/src/models/model404.rs +++ b/src/models/model404.rs @@ -1,4 +1,5 @@ //! String Combiner (Advanced) +/// Type alias for [`StringCombinerAdvancedInputs`]. pub type Model404 = StringCombinerAdvancedInputs; /// String Combiner (Advanced) /// @@ -103,9 +104,11 @@ impl crate::Group for StringCombinerAdvancedInputs { const LEN: u16 = 25; } impl StringCombinerAdvancedInputs { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, string) = String::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { dca_sf: Self::DCA_SF.from_data(data)?, dc_ahr_sf: Self::DC_AHR_SF.from_data(data)?, @@ -128,16 +131,10 @@ impl StringCombinerAdvancedInputs { in_dcv_sf: Self::IN_DCV_SF.from_data(data)?, in_dcw_sf: Self::IN_DCW_SF.from_data(data)?, in_dc_wh_sf: Self::IN_DC_WH_SF.from_data(data)?, - string: Vec::new(), + string, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.string) = String::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Event"] #[doc = " "] #[doc = " Bitmask value. Events"] #[derive(Copy, @@ -277,9 +274,10 @@ impl crate::Group for String { const LEN: u16 = 14; } impl String { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { in_id: Self::IN_ID.from_data(data)?, in_evt: Self::IN_EVT.from_data(data)?, @@ -294,24 +292,21 @@ impl String { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &StringCombinerAdvancedInputs, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &StringCombinerAdvancedInputs, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = String::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = String::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model5.rs b/src/models/model5.rs index 4f3062f..3df5dd5 100644 --- a/src/models/model5.rs +++ b/src/models/model5.rs @@ -304,9 +304,11 @@ impl crate::Group for Model5 { const LEN: u16 = 88; } impl Model5 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { x: Self::X.from_data(data)?, off1: Self::OFF1.from_data(data)?, @@ -395,16 +397,10 @@ impl Model5 { role: Self::ROLE.from_data(data)?, alg: Self::ALG.from_data(data)?, n: Self::N.from_data(data)?, - repeating: Vec::new(), + repeating, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// Algorithm /// @@ -467,32 +463,30 @@ impl crate::Group for Repeating { const LEN: u16 = 1; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ds: Self::DS.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Model5, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Model5, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model501.rs b/src/models/model501.rs index ca28c73..59d1d85 100644 --- a/src/models/model501.rs +++ b/src/models/model501.rs @@ -1,4 +1,5 @@ //! Solar Module +/// Type alias for [`SolarModuleFloat`]. pub type Model501 = SolarModuleFloat; /// Solar Module /// @@ -101,9 +102,10 @@ impl crate::Group for SolarModuleFloat { const LEN: u16 = 31; } impl SolarModuleFloat { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { stat: Self::STAT.from_data(data)?, stat_vend: Self::STAT_VEND.from_data(data)?, @@ -125,11 +127,6 @@ impl SolarModuleFloat { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Status /// diff --git a/src/models/model502.rs b/src/models/model502.rs index 64da9b6..d101d2c 100644 --- a/src/models/model502.rs +++ b/src/models/model502.rs @@ -1,4 +1,5 @@ //! Solar Module +/// Type alias for [`SolarModule`]. pub type Model502 = SolarModule; /// Solar Module /// @@ -113,9 +114,10 @@ impl crate::Group for SolarModule { const LEN: u16 = 28; } impl SolarModule { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { a_sf: Self::A_SF.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, @@ -141,11 +143,6 @@ impl SolarModule { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Status /// diff --git a/src/models/model6.rs b/src/models/model6.rs index 91f5484..f1f10b1 100644 --- a/src/models/model6.rs +++ b/src/models/model6.rs @@ -309,9 +309,11 @@ impl crate::Group for Model6 { const LEN: u16 = 90; } impl Model6 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { x: Self::X.from_data(data)?, off: Self::OFF.from_data(data)?, @@ -401,16 +403,10 @@ impl Model6 { role: Self::ROLE.from_data(data)?, alg: Self::ALG.from_data(data)?, n: Self::N.from_data(data)?, - repeating: Vec::new(), + repeating, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// Algorithm /// @@ -473,32 +469,30 @@ impl crate::Group for Repeating { const LEN: u16 = 1; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ds: Self::DS.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Model6, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Model6, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model601.rs b/src/models/model601.rs index 1c687a8..d8f5108 100644 --- a/src/models/model601.rs +++ b/src/models/model601.rs @@ -1,4 +1,5 @@ //! Tracker Controller DRAFT 2 +/// Type alias for [`TrackerController`]. pub type Model601 = TrackerController; /// Tracker Controller DRAFT 2 /// @@ -77,9 +78,11 @@ impl crate::Group for TrackerController { const LEN: u16 = 26; } impl TrackerController { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, tracker) = Tracker::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { nam: Self::NAM.from_data(data)?, typ: Self::TYP.from_data(data)?, @@ -92,16 +95,10 @@ impl TrackerController { glbl_alm: Self::GLBL_ALM.from_data(data)?, dgr_sf: Self::DGR_SF.from_data(data)?, n: Self::N.from_data(data)?, - tracker: Vec::new(), + tracker, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.tracker) = Tracker::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// Type /// @@ -289,9 +286,10 @@ impl crate::Group for Tracker { const LEN: u16 = 22; } impl Tracker { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { id: Self::ID.from_data(data)?, el_trgt: Self::EL_TRGT.from_data(data)?, @@ -305,24 +303,21 @@ impl Tracker { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &TrackerController, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &TrackerController, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Tracker::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Tracker::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model63001.rs b/src/models/model63001.rs index 71c2998..f8db6ab 100644 --- a/src/models/model63001.rs +++ b/src/models/model63001.rs @@ -184,9 +184,11 @@ impl crate::Group for Model63001 { const LEN: u16 = 134; } impl Model63001 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { sunssf_1: Self::SUNSSF_1.from_data(data)?, sunssf_2: Self::SUNSSF_2.from_data(data)?, @@ -243,16 +245,10 @@ impl Model63001 { sunssf_5: Self::SUNSSF_5.from_data(data)?, sunssf_6: Self::SUNSSF_6.from_data(data)?, sunssf_7: Self::SUNSSF_7.from_data(data)?, - repeating: Vec::new(), + repeating, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[allow(missing_docs)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -429,9 +425,10 @@ impl crate::Group for Repeating { const LEN: u16 = 18; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { sunssf_8: Self::SUNSSF_8.from_data(data)?, int16_11: Self::INT16_11.from_data(data)?, @@ -449,24 +446,21 @@ impl Repeating { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Model63001, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Model63001, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model63002.rs b/src/models/model63002.rs index 750819e..a105183 100644 --- a/src/models/model63002.rs +++ b/src/models/model63002.rs @@ -12,19 +12,10 @@ impl crate::Group for Model63002 { const LEN: u16 = 0; } impl Model63002 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - Ok(( - &data[usize::from(::LEN)..], - Self { - repeating: Vec::new(), - }, - )) - } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; + Ok((nested_data, Self { repeating })) } } #[allow(missing_docs)] @@ -51,9 +42,10 @@ impl crate::Group for Repeating { const LEN: u16 = 4; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { sunssf_1: Self::SUNSSF_1.from_data(data)?, int16_1: Self::INT16_1.from_data(data)?, @@ -62,24 +54,21 @@ impl Repeating { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Model63002, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Model63002, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model64001.rs b/src/models/model64001.rs index 9557f47..3f26c93 100644 --- a/src/models/model64001.rs +++ b/src/models/model64001.rs @@ -116,9 +116,10 @@ impl crate::Group for Model64001 { const LEN: u16 = 71; } impl Model64001 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { cmd: Self::CMD.from_data(data)?, hw_rev: Self::HW_REV.from_data(data)?, @@ -158,11 +159,6 @@ impl Model64001 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " DIP Switches"] #[derive(Copy, Clone, Debug, Eq, PartialEq)] diff --git a/src/models/model64020.rs b/src/models/model64020.rs index 18d4d69..1f6c9c4 100644 --- a/src/models/model64020.rs +++ b/src/models/model64020.rs @@ -137,9 +137,11 @@ impl crate::Group for Model64020 { const LEN: u16 = 30; } impl Model64020 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { aux0_tmp: Self::AUX0_TMP.from_data(data)?, aux1_tmp: Self::AUX1_TMP.from_data(data)?, @@ -171,16 +173,10 @@ impl Model64020 { relay3: Self::RELAY3.from_data(data)?, reset_accumulators: Self::RESET_ACCUMULATORS.from_data(data)?, reset: Self::RESET.from_data(data)?, - repeating: Vec::new(), + repeating, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) - } } #[allow(missing_docs)] #[derive(Debug)] @@ -207,9 +203,10 @@ impl crate::Group for Repeating { const LEN: u16 = 16; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { serial_number: Self::SERIAL_NUMBER.from_data(data)?, firmware: Self::FIRMWARE.from_data(data)?, @@ -217,24 +214,21 @@ impl Repeating { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Model64020, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Model64020, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model64101.rs b/src/models/model64101.rs index d6f06d4..ef8684c 100644 --- a/src/models/model64101.rs +++ b/src/models/model64101.rs @@ -33,9 +33,10 @@ impl crate::Group for Model64101 { const LEN: u16 = 7; } impl Model64101 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { eltek_country_code: Self::ELTEK_COUNTRY_CODE.from_data(data)?, eltek_feeding_phase: Self::ELTEK_FEEDING_PHASE.from_data(data)?, @@ -47,11 +48,6 @@ impl Model64101 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } impl crate::Model for Model64101 { const ID: u16 = 64101; diff --git a/src/models/model64111.rs b/src/models/model64111.rs index 945262a..af240c6 100644 --- a/src/models/model64111.rs +++ b/src/models/model64111.rs @@ -80,9 +80,10 @@ impl crate::Group for Model64111 { const LEN: u16 = 23; } impl Model64111 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { port: Self::PORT.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, @@ -110,11 +111,6 @@ impl Model64111 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Operating State #[derive(Copy, Clone, Debug, Eq, PartialEq, strum::FromRepr)] diff --git a/src/models/model64112.rs b/src/models/model64112.rs index e463655..311d483 100644 --- a/src/models/model64112.rs +++ b/src/models/model64112.rs @@ -229,9 +229,10 @@ impl crate::Group for Model64112 { const LEN: u16 = 64; } impl Model64112 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { port: Self::PORT.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, @@ -306,11 +307,6 @@ impl Model64112 { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Faults"] #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = diff --git a/src/models/model64410.rs b/src/models/model64410.rs index 267e89e..c808d57 100644 --- a/src/models/model64410.rs +++ b/src/models/model64410.rs @@ -1,5 +1,10 @@ //! DC Simulator Control Interface +/// Type alias for [`DcSimInterface`]. pub type Model64410 = DcSimInterface; +struct Counts { + n_pt: u16, + n_prof: u16, +} /// DC Simulator Control Interface /// /// A generic DC simulator/power supply control interface for DER electrical testing. @@ -190,9 +195,15 @@ impl crate::Group for DcSimInterface { const LEN: u16 = 68; } impl DcSimInterface { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_pt: Self::N_PT.from_data(data)?, + n_prof: Self::N_PROF.from_data(data)?, + }; + let (nested_data, prof) = Prof::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { v_max_lim: Self::V_MAX_LIM.from_data(data)?, p_max_lim: Self::P_MAX_LIM.from_data(data)?, @@ -228,16 +239,10 @@ impl DcSimInterface { p_slew_sf: Self::P_SLEW_SF.from_data(data)?, i_slew_sf: Self::I_SLEW_SF.from_data(data)?, pct_sf: Self::PCT_SF.from_data(data)?, - prof: Vec::new(), + prof, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.prof) = Prof::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// CV or CC Mode /// @@ -539,35 +544,31 @@ impl crate::Group for Prof { const LEN: u16 = 2; } impl Prof { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, dept_ref: Self::DEPT_REF.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DcSimInterface, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DcSimInterface, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_prof { - let group; - (data, group) = Prof::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_prof).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Prof::parse_group(data, counts)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -645,9 +646,10 @@ impl crate::Group for Pt { const LEN: u16 = 5; } impl Pt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { tms: Self::TMS.from_data(data)?, v: Self::V.from_data(data)?, @@ -657,24 +659,16 @@ impl Pt { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DcSimInterface, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DcSimInterface, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_pt { - let group; - (data, group) = Pt::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_pt).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Pt::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model64411.rs b/src/models/model64411.rs index 6ac1f61..82d306b 100644 --- a/src/models/model64411.rs +++ b/src/models/model64411.rs @@ -1,5 +1,10 @@ //! AC Simulator Control Interface +/// Type alias for [`AcSimInterface`]. pub type Model64411 = AcSimInterface; +struct Counts { + n_prof: u16, + n_pt: u16, +} /// AC Simulator Control Interface /// /// A generic AC simulator/power supply control interface for DER electrical testing. @@ -260,9 +265,15 @@ impl crate::Group for AcSimInterface { const LEN: u16 = 1396; } impl AcSimInterface { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_prof: Self::N_PROF.from_data(data)?, + n_pt: Self::N_PT.from_data(data)?, + }; + let (nested_data, prof) = Prof::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { phases: Self::PHASES.from_data(data)?, phase_angle: Self::PHASE_ANGLE.from_data(data)?, @@ -312,16 +323,10 @@ impl AcSimInterface { hz_slew_sf: Self::HZ_SLEW_SF.from_data(data)?, v_slew_sf: Self::V_SLEW_SF.from_data(data)?, thd_sf: Self::THD_SF.from_data(data)?, - prof: Vec::new(), + prof, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.prof) = Prof::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// Output State /// @@ -559,35 +564,31 @@ impl crate::Group for Prof { const LEN: u16 = 33; } impl Prof { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { name: Self::NAME.from_data(data)?, act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &AcSimInterface, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &AcSimInterface, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_prof { - let group; - (data, group) = Prof::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_prof).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Prof::parse_group(data, counts)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -647,9 +648,10 @@ impl crate::Group for Pt { const LEN: u16 = 8; } impl Pt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { tms: Self::TMS.from_data(data)?, va: Self::VA.from_data(data)?, @@ -662,24 +664,16 @@ impl Pt { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &AcSimInterface, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &AcSimInterface, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_pt { - let group; - (data, group) = Pt::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_pt).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Pt::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model64412.rs b/src/models/model64412.rs index d32b2c7..2a930d9 100644 --- a/src/models/model64412.rs +++ b/src/models/model64412.rs @@ -1,4 +1,5 @@ //! DER Cyber Exploitation +/// Type alias for [`DerExploitation`]. pub type Model64412 = DerExploitation; /// DER Cyber Exploitation /// @@ -261,9 +262,10 @@ impl crate::Group for DerExploitation { const LEN: u16 = 43; } impl DerExploitation { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { da_manipulation: Self::DA_MANIPULATION.from_data(data)?, falsify_device_identity: Self::FALSIFY_DEVICE_IDENTITY.from_data(data)?, @@ -311,11 +313,6 @@ impl DerExploitation { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// DA Manipulation /// diff --git a/src/models/model64413.rs b/src/models/model64413.rs index 37249fa..f98d9a4 100644 --- a/src/models/model64413.rs +++ b/src/models/model64413.rs @@ -1,5 +1,9 @@ //! PV Curves +/// Type alias for [`PvSimCurves`]. pub type Model64413 = PvSimCurves; +struct Counts { + iv_len: Option, +} /// PV Curves /// /// Current-Voltage and Power-Voltage Profiles for PV Simulation. @@ -29,23 +33,22 @@ impl crate::Group for PvSimCurves { const LEN: u16 = 3; } impl PvSimCurves { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + iv_len: Self::IV_LEN.from_data(data)?, + }; + let (nested_data, iv) = Iv::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { iv_len: Self::IV_LEN.from_data(data)?, irr: Self::IRR.from_data(data)?, irr_sf: Self::IRR_SF.from_data(data)?, - iv: Vec::new(), + iv, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.iv) = Iv::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// Comments: IV Curve Points #[derive(Debug)] @@ -74,9 +77,10 @@ impl crate::Group for Iv { const LEN: u16 = 6; } impl Iv { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { p: Self::P.from_data(data)?, i: Self::I.from_data(data)?, @@ -84,24 +88,18 @@ impl Iv { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &PvSimCurves, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &PvSimCurves, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.iv_len.unwrap_or_default() { - let group; - (data, group) = Iv::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = (0..counts.iv_len.unwrap_or_default()).try_fold( + (data, Vec::new()), + |(data, mut groups), _| { + let (data, group) = Iv::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + }, + )?; Ok((data, groups)) } } diff --git a/src/models/model64414.rs b/src/models/model64414.rs index 8d98bad..bcbcd9e 100644 --- a/src/models/model64414.rs +++ b/src/models/model64414.rs @@ -1,4 +1,5 @@ //! DER Simulation Controls +/// Type alias for [`DerSimControls`]. pub type Model64414 = DerSimControls; /// DER Simulation Controls /// @@ -45,9 +46,10 @@ impl crate::Group for DerSimControls { const LEN: u16 = 86; } impl DerSimControls { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { time: Self::TIME.from_data(data)?, temperature: Self::TEMPERATURE.from_data(data)?, @@ -61,11 +63,6 @@ impl DerSimControls { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } impl crate::Model for DerSimControls { const ID: u16 = 64414; diff --git a/src/models/model64415.rs b/src/models/model64415.rs index d9ff2da..36bd0a7 100644 --- a/src/models/model64415.rs +++ b/src/models/model64415.rs @@ -1,4 +1,5 @@ //! CSIP Client Control +/// Type alias for [`CsipControl`]. pub type Model64415 = CsipControl; /// CSIP Client Control /// @@ -30,9 +31,10 @@ impl crate::Group for CsipControl { const LEN: u16 = 3; } impl CsipControl { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { log_event_ena: Self::LOG_EVENT_ENA.from_data(data)?, http_msg: Self::HTTP_MSG.from_data(data)?, @@ -40,11 +42,6 @@ impl CsipControl { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// LogEvent Mode Enable /// diff --git a/src/models/model7.rs b/src/models/model7.rs index acb7839..f1a888f 100644 --- a/src/models/model7.rs +++ b/src/models/model7.rs @@ -63,9 +63,11 @@ impl crate::Group for Model7 { const LEN: u16 = 10; } impl Model7 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { rq_seq: Self::RQ_SEQ.from_data(data)?, sts: Self::STS.from_data(data)?, @@ -75,16 +77,10 @@ impl Model7 { alm: Self::ALM.from_data(data)?, alg: Self::ALG.from_data(data)?, n: Self::N.from_data(data)?, - repeating: Vec::new(), + repeating, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// Status /// @@ -233,32 +229,30 @@ impl crate::Group for Repeating { const LEN: u16 = 1; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ds: Self::DS.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Model7, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Model7, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model701.rs b/src/models/model701.rs index 899b3cc..d66ff5c 100644 --- a/src/models/model701.rs +++ b/src/models/model701.rs @@ -1,4 +1,5 @@ //! DER AC Measurement +/// Type alias for [`DerMeasureAc`]. pub type Model701 = DerMeasureAc; /// DER AC Measurement /// @@ -390,9 +391,10 @@ impl crate::Group for DerMeasureAc { const LEN: u16 = 153; } impl DerMeasureAc { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ac_type: Self::AC_TYPE.from_data(data)?, st: Self::ST.from_data(data)?, @@ -467,11 +469,6 @@ impl DerMeasureAc { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// AC Wiring Type /// diff --git a/src/models/model702.rs b/src/models/model702.rs index 5449bbb..6aa3eec 100644 --- a/src/models/model702.rs +++ b/src/models/model702.rs @@ -1,4 +1,5 @@ //! DER Capacity +/// Type alias for [`DerCapacity`]. pub type Model702 = DerCapacity; /// DER Capacity /// @@ -291,9 +292,10 @@ impl crate::Group for DerCapacity { const LEN: u16 = 50; } impl DerCapacity { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { w_max_rtg: Self::W_MAX_RTG.from_data(data)?, w_ovr_ext_rtg: Self::W_OVR_EXT_RTG.from_data(data)?, @@ -347,11 +349,6 @@ impl DerCapacity { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Normal Operating Category /// diff --git a/src/models/model703.rs b/src/models/model703.rs index e23e8a9..706d865 100644 --- a/src/models/model703.rs +++ b/src/models/model703.rs @@ -1,4 +1,5 @@ //! Enter Service +/// Type alias for [`DerEnterService`]. pub type Model703 = DerEnterService; /// Enter Service /// @@ -69,9 +70,10 @@ impl crate::Group for DerEnterService { const LEN: u16 = 17; } impl DerEnterService { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { es: Self::ES.from_data(data)?, esv_hi: Self::ESV_HI.from_data(data)?, @@ -87,11 +89,6 @@ impl DerEnterService { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Permit Enter Service /// diff --git a/src/models/model704.rs b/src/models/model704.rs index be44f02..ccab4f3 100644 --- a/src/models/model704.rs +++ b/src/models/model704.rs @@ -1,4 +1,5 @@ //! DER AC Controls +/// Type alias for [`DerCtlAc`]. pub type Model704 = DerCtlAc; /// DER AC Controls /// @@ -197,19 +198,19 @@ pub struct DerCtlAc { /// Power factor setpoint when injecting active power. /// /// Comments: Power Factor Settings - pub pfw_inj: Vec, + pub pfw_inj: PfwInj, /// Reversion Power Factor (W Inj) /// /// Reversion power factor setpoint when injecting active power. - pub pfw_inj_rvrt: Vec, + pub pfw_inj_rvrt: PfwInjRvrt, /// Power Factor (W Abs) /// /// Power factor setpoint when absorbing active power. - pub pfw_abs: Vec, + pub pfw_abs: PfwAbs, /// Reversion Power Factor (W Abs) /// /// Reversion power factor setpoint when absorbing active power. - pub pfw_abs_rvrt: Vec, + pub pfw_abs_rvrt: PfwAbsRvrt, } #[allow(missing_docs)] impl DerCtlAc { @@ -269,9 +270,14 @@ impl crate::Group for DerCtlAc { const LEN: u16 = 57; } impl DerCtlAc { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pfw_inj) = PfwInj::parse_group(nested_data)?; + let (nested_data, pfw_inj_rvrt) = PfwInjRvrt::parse_group(nested_data)?; + let (nested_data, pfw_abs) = PfwAbs::parse_group(nested_data)?; + let (nested_data, pfw_abs_rvrt) = PfwAbsRvrt::parse_group(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { pfw_inj_ena: Self::PFW_INJ_ENA.from_data(data)?, pfw_inj_ena_rvrt: Self::PFW_INJ_ENA_RVRT.from_data(data)?, @@ -316,22 +322,13 @@ impl DerCtlAc { w_set_pct_sf: Self::W_SET_PCT_SF.from_data(data)?, var_set_sf: Self::VAR_SET_SF.from_data(data)?, var_set_pct_sf: Self::VAR_SET_PCT_SF.from_data(data)?, - pfw_inj: Vec::new(), - pfw_inj_rvrt: Vec::new(), - pfw_abs: Vec::new(), - pfw_abs_rvrt: Vec::new(), + pfw_inj, + pfw_inj_rvrt, + pfw_abs, + pfw_abs_rvrt, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pfw_inj) = PfwInj::parse_multiple(data, &group)?; - (data, group.pfw_inj_rvrt) = PfwInjRvrt::parse_multiple(data, &group)?; - (data, group.pfw_abs) = PfwAbs::parse_multiple(data, &group)?; - (data, group.pfw_abs_rvrt) = PfwAbsRvrt::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// Power Factor Enable (W Inj) Enable /// @@ -1045,35 +1042,16 @@ impl crate::Group for PfwInj { const LEN: u16 = 2; } impl PfwInj { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { pf: Self::PF.from_data(data)?, ext: Self::EXT.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerCtlAc, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerCtlAc, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = PfwInj::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Power Factor Excitation (W Inj) /// @@ -1143,35 +1121,16 @@ impl crate::Group for PfwInjRvrt { const LEN: u16 = 2; } impl PfwInjRvrt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { pf: Self::PF.from_data(data)?, ext: Self::EXT.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerCtlAc, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerCtlAc, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = PfwInjRvrt::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Reversion PF Excitation (W Inj) /// @@ -1241,35 +1200,16 @@ impl crate::Group for PfwAbs { const LEN: u16 = 2; } impl PfwAbs { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { pf: Self::PF.from_data(data)?, ext: Self::EXT.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerCtlAc, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerCtlAc, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = PfwAbs::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Power Factor Excitation (W Abs) /// @@ -1339,35 +1279,16 @@ impl crate::Group for PfwAbsRvrt { const LEN: u16 = 2; } impl PfwAbsRvrt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { pf: Self::PF.from_data(data)?, ext: Self::EXT.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerCtlAc, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerCtlAc, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = PfwAbsRvrt::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Reversion PF Excitation (W Abs) /// diff --git a/src/models/model705.rs b/src/models/model705.rs index 15a38f8..cb7b321 100644 --- a/src/models/model705.rs +++ b/src/models/model705.rs @@ -1,5 +1,10 @@ //! DER Volt-Var +/// Type alias for [`DerVoltVar`]. pub type Model705 = DerVoltVar; +struct Counts { + n_pt: u16, + n_crv: u16, +} /// DER Volt-Var /// /// DER Volt-Var model. @@ -75,9 +80,15 @@ impl crate::Group for DerVoltVar { const LEN: u16 = 13; } impl DerVoltVar { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_pt: Self::N_PT.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + }; + let (nested_data, crv) = Crv::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ena: Self::ENA.from_data(data)?, adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, @@ -90,16 +101,10 @@ impl DerVoltVar { v_sf: Self::V_SF.from_data(data)?, dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, rsp_tms_sf: Self::RSP_TMS_SF.from_data(data)?, - crv: Vec::new(), + crv, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.crv) = Crv::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// DER Volt-Var Module Enable /// @@ -261,9 +266,14 @@ impl crate::Group for Crv { const LEN: u16 = 10; } impl Crv { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, dept_ref: Self::DEPT_REF.from_data(data)?, @@ -274,29 +284,20 @@ impl Crv { v_ref_auto_tms: Self::V_REF_AUTO_TMS.from_data(data)?, rsp_tms: Self::RSP_TMS.from_data(data)?, read_only: Self::READ_ONLY.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerVoltVar, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerVoltVar, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_crv { - let group; - (data, group) = Crv::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_crv).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Crv::parse_group(data, counts)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -510,33 +511,26 @@ impl crate::Group for Pt { const LEN: u16 = 2; } impl Pt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { v: Self::V.from_data(data)?, var: Self::VAR.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerVoltVar, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerVoltVar, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_pt { - let group; - (data, group) = Pt::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_pt).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Pt::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model706.rs b/src/models/model706.rs index b62fbf1..05d937b 100644 --- a/src/models/model706.rs +++ b/src/models/model706.rs @@ -1,5 +1,10 @@ //! DER Volt-Watt +/// Type alias for [`DerVoltWatt`]. pub type Model706 = DerVoltWatt; +struct Counts { + n_pt: u16, + n_crv: u16, +} /// DER Volt-Watt /// /// DER Volt-Watt model. @@ -75,9 +80,15 @@ impl crate::Group for DerVoltWatt { const LEN: u16 = 13; } impl DerVoltWatt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_pt: Self::N_PT.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + }; + let (nested_data, crv) = Crv::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ena: Self::ENA.from_data(data)?, adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, @@ -90,16 +101,10 @@ impl DerVoltWatt { v_sf: Self::V_SF.from_data(data)?, dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, rsp_tms_sf: Self::RSP_TMS_SF.from_data(data)?, - crv: Vec::new(), + crv, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.crv) = Crv::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// DER Volt-Watt Module Enable /// @@ -235,37 +240,33 @@ impl crate::Group for Crv { const LEN: u16 = 5; } impl Crv { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, dept_ref: Self::DEPT_REF.from_data(data)?, rsp_tms: Self::RSP_TMS.from_data(data)?, read_only: Self::READ_ONLY.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerVoltWatt, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerVoltWatt, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_crv { - let group; - (data, group) = Crv::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_crv).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Crv::parse_group(data, counts)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -383,33 +384,26 @@ impl crate::Group for Pt { const LEN: u16 = 2; } impl Pt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { v: Self::V.from_data(data)?, w: Self::W.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerVoltWatt, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerVoltWatt, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_pt { - let group; - (data, group) = Pt::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_pt).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Pt::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model707.rs b/src/models/model707.rs index 91e1c86..d2062ad 100644 --- a/src/models/model707.rs +++ b/src/models/model707.rs @@ -1,5 +1,10 @@ //! DER Trip LV +/// Type alias for [`DerTripLv`]. pub type Model707 = DerTripLv; +struct Counts { + n_pt: u16, + n_crv_set: u16, +} /// DER Trip LV /// /// DER low voltage trip model. @@ -55,9 +60,15 @@ impl crate::Group for DerTripLv { const LEN: u16 = 7; } impl DerTripLv { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_pt: Self::N_PT.from_data(data)?, + n_crv_set: Self::N_CRV_SET.from_data(data)?, + }; + let (nested_data, crv) = Crv::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ena: Self::ENA.from_data(data)?, adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, @@ -66,16 +77,10 @@ impl DerTripLv { n_crv_set: Self::N_CRV_SET.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, - crv: Vec::new(), + crv, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.crv) = Crv::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// DER Trip LV Module Enable /// @@ -186,15 +191,15 @@ pub struct Crv { /// Stored must trip curve. /// /// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt - pub must_trip: Vec, + pub must_trip: MustTrip, /// May Trip Curve /// /// Stored may trip curve. - pub may_trip: Vec, + pub may_trip: MayTrip, /// Momentary Cessation Curve /// /// Stored momentary cessation curve. - pub mom_cess: Vec, + pub mom_cess: MomCess, } #[allow(missing_docs)] impl Crv { @@ -204,38 +209,34 @@ impl crate::Group for Crv { const LEN: u16 = 1; } impl Crv { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, must_trip) = MustTrip::parse_group(nested_data, counts)?; + let (nested_data, may_trip) = MayTrip::parse_group(nested_data, counts)?; + let (nested_data, mom_cess) = MomCess::parse_group(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { read_only: Self::READ_ONLY.from_data(data)?, - must_trip: Vec::new(), - may_trip: Vec::new(), - mom_cess: Vec::new(), + must_trip, + may_trip, + mom_cess, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripLv, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.must_trip) = MustTrip::parse_multiple(data, model)?; - (data, group.may_trip) = MayTrip::parse_multiple(data, model)?; - (data, group.mom_cess) = MomCess::parse_multiple(data, model)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripLv, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_crv_set { - let group; - (data, group) = Crv::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_crv_set).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Crv::parse_group(data, counts)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -308,36 +309,20 @@ impl crate::Group for MustTrip { const LEN: u16 = 1; } impl MustTrip { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripLv, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripLv, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MustTrip::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Must Trip Curve Points /// @@ -367,33 +352,26 @@ impl crate::Group for Pt { const LEN: u16 = 3; } impl Pt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { v: Self::V.from_data(data)?, tms: Self::TMS.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripLv, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripLv, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_pt { - let group; - (data, group) = Pt::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_pt).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Pt::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -420,36 +398,20 @@ impl crate::Group for MayTrip { const LEN: u16 = 1; } impl MayTrip { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripLv, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripLv, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MayTrip::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Momentary Cessation Curve /// @@ -474,36 +436,20 @@ impl crate::Group for MomCess { const LEN: u16 = 1; } impl MomCess { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripLv, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripLv, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MomCess::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } impl crate::Model for DerTripLv { const ID: u16 = 707; diff --git a/src/models/model708.rs b/src/models/model708.rs index d65e6f1..6078717 100644 --- a/src/models/model708.rs +++ b/src/models/model708.rs @@ -1,5 +1,10 @@ //! DER Trip HV +/// Type alias for [`DerTripHv`]. pub type Model708 = DerTripHv; +struct Counts { + n_pt: u16, + n_crv_set: u16, +} /// DER Trip HV /// /// DER high voltage trip model. @@ -55,9 +60,15 @@ impl crate::Group for DerTripHv { const LEN: u16 = 7; } impl DerTripHv { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_pt: Self::N_PT.from_data(data)?, + n_crv_set: Self::N_CRV_SET.from_data(data)?, + }; + let (nested_data, crv) = Crv::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ena: Self::ENA.from_data(data)?, adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, @@ -66,16 +77,10 @@ impl DerTripHv { n_crv_set: Self::N_CRV_SET.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, - crv: Vec::new(), + crv, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.crv) = Crv::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// DER Trip HV Module Enable /// @@ -186,15 +191,15 @@ pub struct Crv { /// Stored must trip curve. /// /// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt - pub must_trip: Vec, + pub must_trip: MustTrip, /// May Trip Curve /// /// Stored may trip curve. - pub may_trip: Vec, + pub may_trip: MayTrip, /// Momentary Cessation Curve /// /// Stored momentary cessation curve. - pub mom_cess: Vec, + pub mom_cess: MomCess, } #[allow(missing_docs)] impl Crv { @@ -204,38 +209,34 @@ impl crate::Group for Crv { const LEN: u16 = 1; } impl Crv { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, must_trip) = MustTrip::parse_group(nested_data, counts)?; + let (nested_data, may_trip) = MayTrip::parse_group(nested_data, counts)?; + let (nested_data, mom_cess) = MomCess::parse_group(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { read_only: Self::READ_ONLY.from_data(data)?, - must_trip: Vec::new(), - may_trip: Vec::new(), - mom_cess: Vec::new(), + must_trip, + may_trip, + mom_cess, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripHv, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.must_trip) = MustTrip::parse_multiple(data, model)?; - (data, group.may_trip) = MayTrip::parse_multiple(data, model)?; - (data, group.mom_cess) = MomCess::parse_multiple(data, model)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripHv, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_crv_set { - let group; - (data, group) = Crv::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_crv_set).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Crv::parse_group(data, counts)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -308,36 +309,20 @@ impl crate::Group for MustTrip { const LEN: u16 = 1; } impl MustTrip { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripHv, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripHv, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MustTrip::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Must Trip Curve Points /// @@ -367,33 +352,26 @@ impl crate::Group for Pt { const LEN: u16 = 3; } impl Pt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { v: Self::V.from_data(data)?, tms: Self::TMS.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripHv, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripHv, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_pt { - let group; - (data, group) = Pt::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_pt).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Pt::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -420,36 +398,20 @@ impl crate::Group for MayTrip { const LEN: u16 = 1; } impl MayTrip { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripHv, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripHv, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MayTrip::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Momentary Cessation Curve /// @@ -474,36 +436,20 @@ impl crate::Group for MomCess { const LEN: u16 = 1; } impl MomCess { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripHv, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripHv, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MomCess::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } impl crate::Model for DerTripHv { const ID: u16 = 708; diff --git a/src/models/model709.rs b/src/models/model709.rs index 72ac57c..d02076d 100644 --- a/src/models/model709.rs +++ b/src/models/model709.rs @@ -1,5 +1,10 @@ //! DER Trip LF +/// Type alias for [`DerTripLf`]. pub type Model709 = DerTripLf; +struct Counts { + n_pt: u16, + n_crv_set: u16, +} /// DER Trip LF /// /// DER low frequency trip model. @@ -55,9 +60,15 @@ impl crate::Group for DerTripLf { const LEN: u16 = 7; } impl DerTripLf { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_pt: Self::N_PT.from_data(data)?, + n_crv_set: Self::N_CRV_SET.from_data(data)?, + }; + let (nested_data, crv) = Crv::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ena: Self::ENA.from_data(data)?, adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, @@ -66,16 +77,10 @@ impl DerTripLf { n_crv_set: Self::N_CRV_SET.from_data(data)?, hz_sf: Self::HZ_SF.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, - crv: Vec::new(), + crv, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.crv) = Crv::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// DER Trip LF Module Enable /// @@ -186,15 +191,15 @@ pub struct Crv { /// Stored must trip curve. /// /// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt - pub must_trip: Vec, + pub must_trip: MustTrip, /// May Trip Curve /// /// Stored may trip curve. - pub may_trip: Vec, + pub may_trip: MayTrip, /// Momentary Cessation Curve /// /// Stored momentary cessation curve. - pub mom_cess: Vec, + pub mom_cess: MomCess, } #[allow(missing_docs)] impl Crv { @@ -204,38 +209,34 @@ impl crate::Group for Crv { const LEN: u16 = 1; } impl Crv { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, must_trip) = MustTrip::parse_group(nested_data, counts)?; + let (nested_data, may_trip) = MayTrip::parse_group(nested_data, counts)?; + let (nested_data, mom_cess) = MomCess::parse_group(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { read_only: Self::READ_ONLY.from_data(data)?, - must_trip: Vec::new(), - may_trip: Vec::new(), - mom_cess: Vec::new(), + must_trip, + may_trip, + mom_cess, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripLf, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.must_trip) = MustTrip::parse_multiple(data, model)?; - (data, group.may_trip) = MayTrip::parse_multiple(data, model)?; - (data, group.mom_cess) = MomCess::parse_multiple(data, model)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripLf, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_crv_set { - let group; - (data, group) = Crv::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_crv_set).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Crv::parse_group(data, counts)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -308,36 +309,20 @@ impl crate::Group for MustTrip { const LEN: u16 = 1; } impl MustTrip { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripLf, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripLf, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MustTrip::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Must Trip Curve Points /// @@ -367,33 +352,26 @@ impl crate::Group for Pt { const LEN: u16 = 4; } impl Pt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { hz: Self::HZ.from_data(data)?, tms: Self::TMS.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripLf, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripLf, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_pt { - let group; - (data, group) = Pt::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_pt).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Pt::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -420,36 +398,20 @@ impl crate::Group for MayTrip { const LEN: u16 = 1; } impl MayTrip { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripLf, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripLf, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MayTrip::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Momentary Cessation Curve /// @@ -474,36 +436,20 @@ impl crate::Group for MomCess { const LEN: u16 = 1; } impl MomCess { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripLf, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripLf, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MomCess::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } impl crate::Model for DerTripLf { const ID: u16 = 709; diff --git a/src/models/model710.rs b/src/models/model710.rs index cc45c8e..a1406ac 100644 --- a/src/models/model710.rs +++ b/src/models/model710.rs @@ -1,5 +1,10 @@ //! DER Trip HF +/// Type alias for [`DerTripHf`]. pub type Model710 = DerTripHf; +struct Counts { + n_pt: u16, + n_crv_set: u16, +} /// DER Trip HF /// /// DER high frequency trip model. @@ -55,9 +60,15 @@ impl crate::Group for DerTripHf { const LEN: u16 = 7; } impl DerTripHf { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_pt: Self::N_PT.from_data(data)?, + n_crv_set: Self::N_CRV_SET.from_data(data)?, + }; + let (nested_data, crv) = Crv::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ena: Self::ENA.from_data(data)?, adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, @@ -66,16 +77,10 @@ impl DerTripHf { n_crv_set: Self::N_CRV_SET.from_data(data)?, hz_sf: Self::HZ_SF.from_data(data)?, tms_sf: Self::TMS_SF.from_data(data)?, - crv: Vec::new(), + crv, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.crv) = Crv::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// DER Trip HF Module Enable /// @@ -186,15 +191,15 @@ pub struct Crv { /// Stored must trip curve. /// /// Comments: Stored curve set containing a Must Trip, May Trip, and Momentary Cessation Curve - Number of curve points contained in NPt - pub must_trip: Vec, + pub must_trip: MustTrip, /// May Trip Curve /// /// Stored may trip curve. - pub may_trip: Vec, + pub may_trip: MayTrip, /// Momentary Cessation Curve /// /// Stored momentary cessation curve. - pub mom_cess: Vec, + pub mom_cess: MomCess, } #[allow(missing_docs)] impl Crv { @@ -204,38 +209,34 @@ impl crate::Group for Crv { const LEN: u16 = 1; } impl Crv { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, must_trip) = MustTrip::parse_group(nested_data, counts)?; + let (nested_data, may_trip) = MayTrip::parse_group(nested_data, counts)?; + let (nested_data, mom_cess) = MomCess::parse_group(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { read_only: Self::READ_ONLY.from_data(data)?, - must_trip: Vec::new(), - may_trip: Vec::new(), - mom_cess: Vec::new(), + must_trip, + may_trip, + mom_cess, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripHf, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.must_trip) = MustTrip::parse_multiple(data, model)?; - (data, group.may_trip) = MayTrip::parse_multiple(data, model)?; - (data, group.mom_cess) = MomCess::parse_multiple(data, model)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripHf, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_crv_set { - let group; - (data, group) = Crv::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_crv_set).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Crv::parse_group(data, counts)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -308,36 +309,20 @@ impl crate::Group for MustTrip { const LEN: u16 = 1; } impl MustTrip { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripHf, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripHf, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MustTrip::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Must Trip Curve Points /// @@ -367,33 +352,26 @@ impl crate::Group for Pt { const LEN: u16 = 4; } impl Pt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { hz: Self::HZ.from_data(data)?, tms: Self::TMS.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripHf, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripHf, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_pt { - let group; - (data, group) = Pt::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_pt).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Pt::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -420,36 +398,20 @@ impl crate::Group for MayTrip { const LEN: u16 = 1; } impl MayTrip { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripHf, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripHf, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MayTrip::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } /// Momentary Cessation Curve /// @@ -474,36 +436,20 @@ impl crate::Group for MomCess { const LEN: u16 = 1; } impl MomCess { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerTripHf, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerTripHf, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..1 { - let group; - (data, group) = MomCess::parse_group(data, model)?; - groups.push(group); - } - Ok((data, groups)) - } } impl crate::Model for DerTripHf { const ID: u16 = 710; diff --git a/src/models/model711.rs b/src/models/model711.rs index 966f9b3..72f9f83 100644 --- a/src/models/model711.rs +++ b/src/models/model711.rs @@ -1,5 +1,9 @@ //! DER Frequency Droop +/// Type alias for [`DerFreqDroop`]. pub type Model711 = DerFreqDroop; +struct Counts { + n_ctl: u16, +} /// DER Frequency Droop /// /// DER Frequency Droop model. @@ -70,9 +74,14 @@ impl crate::Group for DerFreqDroop { const LEN: u16 = 12; } impl DerFreqDroop { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_ctl: Self::N_CTL.from_data(data)?, + }; + let (nested_data, ctl) = Ctl::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ena: Self::ENA.from_data(data)?, adpt_ctl_req: Self::ADPT_CTL_REQ.from_data(data)?, @@ -84,16 +93,10 @@ impl DerFreqDroop { db_sf: Self::DB_SF.from_data(data)?, k_sf: Self::K_SF.from_data(data)?, rsp_tms_sf: Self::RSP_TMS_SF.from_data(data)?, - ctl: Vec::new(), + ctl, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.ctl) = Ctl::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// DER Frequency Droop Module Enable /// @@ -238,9 +241,10 @@ impl crate::Group for Ctl { const LEN: u16 = 10; } impl Ctl { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { db_of: Self::DB_OF.from_data(data)?, db_uf: Self::DB_UF.from_data(data)?, @@ -252,24 +256,16 @@ impl Ctl { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerFreqDroop, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerFreqDroop, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_ctl { - let group; - (data, group) = Ctl::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_ctl).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Ctl::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model712.rs b/src/models/model712.rs index d62e0d0..943bcfa 100644 --- a/src/models/model712.rs +++ b/src/models/model712.rs @@ -1,5 +1,10 @@ //! DER Watt-Var +/// Type alias for [`DerWattVar`]. pub type Model712 = DerWattVar; +struct Counts { + n_pt: u16, + n_crv: u16, +} /// DER Watt-Var /// /// DER Watt-Var model. @@ -70,9 +75,15 @@ impl crate::Group for DerWattVar { const LEN: u16 = 12; } impl DerWattVar { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_pt: Self::N_PT.from_data(data)?, + n_crv: Self::N_CRV.from_data(data)?, + }; + let (nested_data, crv) = Crv::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ena: Self::ENA.from_data(data)?, adpt_crv_req: Self::ADPT_CRV_REQ.from_data(data)?, @@ -84,16 +95,10 @@ impl DerWattVar { rvrt_crv: Self::RVRT_CRV.from_data(data)?, w_sf: Self::W_SF.from_data(data)?, dept_ref_sf: Self::DEPT_REF_SF.from_data(data)?, - crv: Vec::new(), + crv, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.crv) = Crv::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// DER Watt-Var Module Enable /// @@ -229,37 +234,33 @@ impl crate::Group for Crv { const LEN: u16 = 4; } impl Crv { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group<'a>( + data: &'a [u16], + counts: &Counts, + ) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, pt) = Pt::parse_multiple(nested_data, counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { act_pt: Self::ACT_PT.from_data(data)?, dept_ref: Self::DEPT_REF.from_data(data)?, pri: Self::PRI.from_data(data)?, read_only: Self::READ_ONLY.from_data(data)?, - pt: Vec::new(), + pt, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerWattVar, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.pt) = Pt::parse_multiple(data, model)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerWattVar, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_crv { - let group; - (data, group) = Crv::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_crv).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Crv::parse_group(data, counts)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } @@ -425,33 +426,26 @@ impl crate::Group for Pt { const LEN: u16 = 2; } impl Pt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { w: Self::W.from_data(data)?, var: Self::VAR.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerWattVar, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerWattVar, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_pt { - let group; - (data, group) = Pt::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_pt).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Pt::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model713.rs b/src/models/model713.rs index 0ae5a2f..b6c98dc 100644 --- a/src/models/model713.rs +++ b/src/models/model713.rs @@ -1,4 +1,5 @@ //! DER Storage Capacity +/// Type alias for [`DerStorageCapacity`]. pub type Model713 = DerStorageCapacity; /// DER Storage Capacity /// @@ -51,9 +52,10 @@ impl crate::Group for DerStorageCapacity { const LEN: u16 = 7; } impl DerStorageCapacity { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { wh_rtg: Self::WH_RTG.from_data(data)?, wh_avail: Self::WH_AVAIL.from_data(data)?, @@ -65,11 +67,6 @@ impl DerStorageCapacity { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Status /// diff --git a/src/models/model714.rs b/src/models/model714.rs index 2ac5912..c3298fa 100644 --- a/src/models/model714.rs +++ b/src/models/model714.rs @@ -1,5 +1,9 @@ //! DER DC Measurement +/// Type alias for [`DerMeasureDc`]. pub type Model714 = DerMeasureDc; +struct Counts { + n_prt: Option, +} /// DER DC Measurement /// /// DER DC measurement. @@ -73,9 +77,14 @@ impl crate::Group for DerMeasureDc { const LEN: u16 = 18; } impl DerMeasureDc { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_prt: Self::N_PRT.from_data(data)?, + }; + let (nested_data, prt) = Prt::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { prt_alrms: Self::PRT_ALRMS.from_data(data)?, n_prt: Self::N_PRT.from_data(data)?, @@ -88,16 +97,10 @@ impl DerMeasureDc { dcw_sf: Self::DCW_SF.from_data(data)?, dcwh_sf: Self::DCWH_SF.from_data(data)?, tmp_sf: Self::TMP_SF.from_data(data)?, - prt: Vec::new(), + prt, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.prt) = Prt::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " Port Alarms"] #[doc = " "] #[doc = @@ -199,9 +202,10 @@ impl crate::Group for Prt { const LEN: u16 = 25; } impl Prt { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { prt_typ: Self::PRT_TYP.from_data(data)?, id: Self::ID.from_data(data)?, @@ -217,24 +221,18 @@ impl Prt { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &DerMeasureDc, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &DerMeasureDc, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_prt.unwrap_or_default() { - let group; - (data, group) = Prt::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = (0..counts.n_prt.unwrap_or_default()).try_fold( + (data, Vec::new()), + |(data, mut groups), _| { + let (data, group) = Prt::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + }, + )?; Ok((data, groups)) } } diff --git a/src/models/model715.rs b/src/models/model715.rs index 1c9bce2..1a0d6d7 100644 --- a/src/models/model715.rs +++ b/src/models/model715.rs @@ -1,4 +1,5 @@ //! DERCtl +/// Type alias for [`DerCtl`]. pub type Model715 = DerCtl; /// DERCtl /// @@ -41,9 +42,10 @@ impl crate::Group for DerCtl { const LEN: u16 = 7; } impl DerCtl { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { loc_rem_ctl: Self::LOC_REM_CTL.from_data(data)?, der_hb: Self::DER_HB.from_data(data)?, @@ -53,11 +55,6 @@ impl DerCtl { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Control Mode /// diff --git a/src/models/model8.rs b/src/models/model8.rs index 3aa1643..6c42b24 100644 --- a/src/models/model8.rs +++ b/src/models/model8.rs @@ -25,22 +25,18 @@ impl crate::Group for Model8 { const LEN: u16 = 2; } impl Model8 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { fmt: Self::FMT.from_data(data)?, n: Self::N.from_data(data)?, - repeating: Vec::new(), + repeating, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// Format /// @@ -101,32 +97,30 @@ impl crate::Group for Repeating { const LEN: u16 = 1; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { cert: Self::CERT.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Model8, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Model8, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model801.rs b/src/models/model801.rs index 38ebb5b..1ff187d 100644 --- a/src/models/model801.rs +++ b/src/models/model801.rs @@ -1,4 +1,5 @@ //! Energy Storage Base Model (DEPRECATED) +/// Type alias for [`Storage`]. pub type Model801 = Storage; /// Energy Storage Base Model (DEPRECATED) /// @@ -19,19 +20,15 @@ impl crate::Group for Storage { const LEN: u16 = 1; } impl Storage { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { deprecated: Self::DEPRECATED.from_data(data)?, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } impl crate::Model for Storage { const ID: u16 = 801; diff --git a/src/models/model802.rs b/src/models/model802.rs index 9493a36..d5edfbe 100644 --- a/src/models/model802.rs +++ b/src/models/model802.rs @@ -1,4 +1,5 @@ //! Battery Base Model +/// Type alias for [`Battery`]. pub type Model802 = Battery; /// Battery Base Model #[derive(Debug)] @@ -311,9 +312,10 @@ impl crate::Group for Battery { const LEN: u16 = 62; } impl Battery { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { ah_rtg: Self::AH_RTG.from_data(data)?, wh_rtg: Self::WH_RTG.from_data(data)?, @@ -374,11 +376,6 @@ impl Battery { }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } } /// Charge Status /// diff --git a/src/models/model803.rs b/src/models/model803.rs index 399fef4..6fb86f8 100644 --- a/src/models/model803.rs +++ b/src/models/model803.rs @@ -1,5 +1,9 @@ //! Lithium-Ion Battery Bank Model +/// Type alias for [`LithiumIonBank`]. pub type Model803 = LithiumIonBank; +struct Counts { + n_str: u16, +} /// Lithium-Ion Battery Bank Model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] @@ -150,9 +154,14 @@ impl crate::Group for LithiumIonBank { const LEN: u16 = 26; } impl LithiumIonBank { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_str: Self::N_STR.from_data(data)?, + }; + let (nested_data, string) = String::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { n_str: Self::N_STR.from_data(data)?, n_str_con: Self::N_STR_CON.from_data(data)?, @@ -180,16 +189,10 @@ impl LithiumIonBank { soh_sf: Self::SOH_SF.from_data(data)?, soc_sf: Self::SOC_SF.from_data(data)?, v_sf: Self::V_SF.from_data(data)?, - string: Vec::new(), + string, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.string) = String::parse_multiple(data, &group)?; - Ok((data, group)) - } } #[allow(missing_docs)] #[derive(Debug)] @@ -330,9 +333,10 @@ impl crate::Group for String { const LEN: u16 = 32; } impl String { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { str_n_mod: Self::STR_N_MOD.from_data(data)?, str_st: Self::STR_ST.from_data(data)?, @@ -361,24 +365,16 @@ impl String { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &LithiumIonBank, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &LithiumIonBank, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_str { - let group; - (data, group) = String::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_str).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = String::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model804.rs b/src/models/model804.rs index 5ac5dd3..261eff7 100644 --- a/src/models/model804.rs +++ b/src/models/model804.rs @@ -1,5 +1,9 @@ //! Lithium-Ion String Model +/// Type alias for [`LithiumIonString`]. pub type Model804 = LithiumIonString; +struct Counts { + n_mod: u16, +} /// Lithium-Ion String Model #[derive(Debug)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] @@ -201,9 +205,15 @@ impl crate::Group for LithiumIonString { const LEN: u16 = 46; } impl LithiumIonString { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let counts = Counts { + n_mod: Self::N_MOD.from_data(data)?, + }; + let (nested_data, lithium_ion_string_module) = + LithiumIonStringModule::parse_multiple(nested_data, &counts)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { idx: Self::IDX.from_data(data)?, n_mod: Self::N_MOD.from_data(data)?, @@ -240,17 +250,10 @@ impl LithiumIonString { v_sf: Self::V_SF.from_data(data)?, cell_v_sf: Self::CELL_V_SF.from_data(data)?, mod_tmp_sf: Self::MOD_TMP_SF.from_data(data)?, - lithium_ion_string_module: Vec::new(), + lithium_ion_string_module, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.lithium_ion_string_module) = - LithiumIonStringModule::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " String Status"] #[doc = " "] #[doc = " Current status of the string."] @@ -662,9 +665,10 @@ impl crate::Group for LithiumIonStringModule { const LEN: u16 = 16; } impl LithiumIonStringModule { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { mod_n_cell: Self::MOD_N_CELL.from_data(data)?, mod_soc: Self::MOD_SOC.from_data(data)?, @@ -682,24 +686,16 @@ impl LithiumIonStringModule { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &LithiumIonString, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } fn parse_multiple<'a>( - mut data: &'a [u16], - model: &LithiumIonString, + data: &'a [u16], + counts: &Counts, ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..model.n_mod { - let group; - (data, group) = LithiumIonStringModule::parse_group(data, model)?; - groups.push(group); - } + let (data, groups) = + (0..counts.n_mod).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = LithiumIonStringModule::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model805.rs b/src/models/model805.rs index 84b074c..37783d6 100644 --- a/src/models/model805.rs +++ b/src/models/model805.rs @@ -1,4 +1,5 @@ //! Lithium-Ion Module Model +/// Type alias for [`LithiumIonModule`]. pub type Model805 = LithiumIonModule; /// Lithium-Ion Module Model #[derive(Debug)] @@ -152,9 +153,12 @@ impl crate::Group for LithiumIonModule { const LEN: u16 = 42; } impl LithiumIonModule { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, lithium_ion_module_cell) = + LithiumIonModuleCell::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { str_idx: Self::STR_IDX.from_data(data)?, mod_idx: Self::MOD_IDX.from_data(data)?, @@ -182,16 +186,10 @@ impl LithiumIonModule { v_sf: Self::V_SF.from_data(data)?, cell_v_sf: Self::CELL_V_SF.from_data(data)?, tmp_sf: Self::TMP_SF.from_data(data)?, - lithium_ion_module_cell: Vec::new(), + lithium_ion_module_cell, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.lithium_ion_module_cell) = LithiumIonModuleCell::parse_multiple(data, &group)?; - Ok((data, group)) - } } #[allow(missing_docs)] #[derive(Debug)] @@ -221,9 +219,10 @@ impl crate::Group for LithiumIonModuleCell { const LEN: u16 = 4; } impl LithiumIonModuleCell { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { cell_v: Self::CELL_V.from_data(data)?, cell_tmp: Self::CELL_TMP.from_data(data)?, @@ -231,24 +230,21 @@ impl LithiumIonModuleCell { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &LithiumIonModule, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &LithiumIonModule, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = LithiumIonModuleCell::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = LithiumIonModuleCell::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model806.rs b/src/models/model806.rs index 5543777..35e2755 100644 --- a/src/models/model806.rs +++ b/src/models/model806.rs @@ -1,4 +1,5 @@ //! Flow Battery Model +/// Type alias for [`FlowBattery`]. pub type Model806 = FlowBattery; /// Flow Battery Model #[derive(Debug)] @@ -17,21 +18,17 @@ impl crate::Group for FlowBattery { const LEN: u16 = 1; } impl FlowBattery { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, battery_string) = BatteryString::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { bat_tbd: Self::BAT_TBD.from_data(data)?, - battery_string: Vec::new(), + battery_string, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.battery_string) = BatteryString::parse_multiple(data, &group)?; - Ok((data, group)) - } } #[allow(missing_docs)] #[derive(Debug)] @@ -48,32 +45,30 @@ impl crate::Group for BatteryString { const LEN: u16 = 1; } impl BatteryString { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { bat_st_tbd: Self::BAT_ST_TBD.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &FlowBattery, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &FlowBattery, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = BatteryString::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = BatteryString::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model807.rs b/src/models/model807.rs index 406a726..5a8e569 100644 --- a/src/models/model807.rs +++ b/src/models/model807.rs @@ -1,4 +1,5 @@ //! Flow Battery String Model +/// Type alias for [`FlowBatteryString`]. pub type Model807 = FlowBatteryString; /// Flow Battery String Model #[derive(Debug)] @@ -169,9 +170,11 @@ impl crate::Group for FlowBatteryString { const LEN: u16 = 34; } impl FlowBatteryString { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, module) = Module::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { idx: Self::IDX.from_data(data)?, n_mod: Self::N_MOD.from_data(data)?, @@ -202,16 +205,10 @@ impl FlowBatteryString { tmp_sf: Self::TMP_SF.from_data(data)?, soc_sf: Self::SOC_SF.from_data(data)?, ocv_sf: Self::OCV_SF.from_data(data)?, - module: Vec::new(), + module, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.module) = Module::parse_multiple(data, &group)?; - Ok((data, group)) - } } bitflags::bitflags! { #[doc = " String Event 1"] #[doc = " "] #[doc = @@ -477,9 +474,10 @@ impl crate::Group for Module { const LEN: u16 = 24; } impl Module { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { mod_idx: Self::MOD_IDX.from_data(data)?, mod_n_stk: Self::MOD_N_STK.from_data(data)?, @@ -504,24 +502,21 @@ impl Module { }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &FlowBatteryString, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &FlowBatteryString, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Module::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Module::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model808.rs b/src/models/model808.rs index 7611810..6c2ac67 100644 --- a/src/models/model808.rs +++ b/src/models/model808.rs @@ -1,4 +1,5 @@ //! Flow Battery Module Model +/// Type alias for [`FlowBatteryModule`]. pub type Model808 = FlowBatteryModule; /// Flow Battery Module Model #[derive(Debug)] @@ -17,21 +18,17 @@ impl crate::Group for FlowBatteryModule { const LEN: u16 = 1; } impl FlowBatteryModule { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, stack) = Stack::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { module_tbd: Self::MODULE_TBD.from_data(data)?, - stack: Vec::new(), + stack, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.stack) = Stack::parse_multiple(data, &group)?; - Ok((data, group)) - } } #[allow(missing_docs)] #[derive(Debug)] @@ -48,32 +45,30 @@ impl crate::Group for Stack { const LEN: u16 = 1; } impl Stack { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { stack_tbd: Self::STACK_TBD.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &FlowBatteryModule, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &FlowBatteryModule, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Stack::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Stack::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model809.rs b/src/models/model809.rs index 8a8fb23..a5f8dc6 100644 --- a/src/models/model809.rs +++ b/src/models/model809.rs @@ -1,4 +1,5 @@ //! Flow Battery Stack Model +/// Type alias for [`FlowBatteryStack`]. pub type Model809 = FlowBatteryStack; /// Flow Battery Stack Model #[derive(Debug)] @@ -17,21 +18,17 @@ impl crate::Group for FlowBatteryStack { const LEN: u16 = 1; } impl FlowBatteryStack { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, cell) = Cell::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { stack_tbd: Self::STACK_TBD.from_data(data)?, - cell: Vec::new(), + cell, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.cell) = Cell::parse_multiple(data, &group)?; - Ok((data, group)) - } } #[allow(missing_docs)] #[derive(Debug)] @@ -48,32 +45,30 @@ impl crate::Group for Cell { const LEN: u16 = 1; } impl Cell { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { cell_tbd: Self::CELL_TBD.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &FlowBatteryStack, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &FlowBatteryStack, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Cell::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Cell::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/src/models/model9.rs b/src/models/model9.rs index fe37068..5ef1610 100644 --- a/src/models/model9.rs +++ b/src/models/model9.rs @@ -328,9 +328,11 @@ impl crate::Group for Model9 { const LEN: u16 = 92; } impl Model9 { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + let (nested_data, repeating) = Repeating::parse_multiple(nested_data)?; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { cert_uid: Self::CERT_UID.from_data(data)?, cert_role: Self::CERT_ROLE.from_data(data)?, @@ -423,16 +425,10 @@ impl Model9 { role: Self::ROLE.from_data(data)?, alg: Self::ALG.from_data(data)?, n: Self::N.from_data(data)?, - repeating: Vec::new(), + repeating, }, )) } - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - (data, group.repeating) = Repeating::parse_multiple(data, &group)?; - Ok((data, group)) - } } /// Format /// @@ -581,32 +577,30 @@ impl crate::Group for Repeating { const LEN: u16 = 1; } impl Repeating { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; Ok(( - &data[usize::from(::LEN)..], + nested_data, Self { cert: Self::CERT.from_data(data)?, }, )) } - fn parse_group<'a>( - mut data: &'a [u16], - model: &Model9, - ) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - Ok((data, group)) - } - fn parse_multiple<'a>( - mut data: &'a [u16], - model: &Model9, - ) -> Result<(&'a [u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..0 { - let group; - (data, group) = Repeating::parse_group(data, model)?; - groups.push(group); + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); } + let group_count = data.len() / group_len; + let (data, groups) = + (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = Repeating::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; Ok((data, groups)) } } diff --git a/sunspec-gen/src/gen.rs b/sunspec-gen/src/gen.rs index f51dc3a..03e927c 100644 --- a/sunspec-gen/src/gen.rs +++ b/sunspec-gen/src/gen.rs @@ -1,4 +1,7 @@ -use std::{collections::HashMap, ptr}; +use std::{ + collections::{HashMap, HashSet}, + ptr, +}; use proc_macro2::{Literal, TokenStream}; use quote::{format_ident, quote, ToTokens}; @@ -124,13 +127,25 @@ pub fn gen_model(model: &Model) -> Result { let m_name = format_ident!("m{}", model.id); let model_id = Literal::u16_unsuffixed(model.id); let group_name = group_ident(&model.group); + let count_point_names = find_count_points(model); + let has_counts = !count_point_names.is_empty(); + let model_alias_doc = doc_to_ts(&format!("Type alias for [`{group_name}`].")); let type_alias = if model_name != group_name { - quote! { pub type #model_name = #group_name; } + quote! { + #model_alias_doc + pub type #model_name = #group_name; + } } else { quote! {} }; let mut state = GenState::default(); - let group = gen_group(&model, &model.group, &mut state)?; + let group = gen_group( + &model, + &model.group, + &count_point_names, + has_counts, + &mut state, + )?; let trait_impl = quote! { impl crate::Model for #group_name { const ID: u16 = #model_id; @@ -154,6 +169,8 @@ pub fn gen_model(model: &Model) -> Result { fn gen_group( xmodel: &Model, group: &Group, + count_point_names: &[String], + has_counts: bool, state: &mut GenState, ) -> Result { let is_root = ptr::eq(&xmodel.group, group); @@ -216,22 +233,20 @@ fn gen_group( } }); - let groups = group - .groups - .iter() - // XXX It's quite unfortunate but groups with a count of 0 - // aren't defined properly in the sunspec JSON files. - // XXX - //.filter(|group| group.count != GroupCount::Integer(0)) - .collect::>(); + let groups = group.groups.iter().collect::>(); let group_fields = groups.iter().map(|group| { let field_name = format_ident!("{}", snake_case(&group.name)); let group_type = group_ident(group); let group_doc = doc_to_ts(&group.doc.to_doc_string()); + let field_type = if group.count.is_one() { + quote! { #group_type } + } else { + quote! { Vec<#group_type> } + }; quote! { #group_doc - pub #field_name: Vec<#group_type>, + pub #field_name: #field_type, } }); @@ -272,7 +287,7 @@ fn gen_group( } }; - let from_data_fields = points + let point_field_inits = points .iter() .filter(|point| !point.is_padding()) .map(|point| { @@ -282,50 +297,132 @@ fn gen_group( #field_name: Self::#const_name.from_data(data)?, } }); - - let from_data_groups_default = groups.iter().map(|group| { - let field_name = format_ident!("{}", snake_case(&group.name)); + let count_inits = count_point_names.iter().map(|count_field_name| { + let field_name = format_ident!("{}", snake_case(count_field_name)); + let const_name = format_ident!("{}", shouty_snake_case(count_field_name)); + quote! { + #field_name: Self::#const_name.from_data(data)?, + } + }); + let count_fields = count_point_names.iter().map(|count_field_name| { + let field_name = format_ident!("{}", snake_case(count_field_name)); + let point = find_point(&xmodel.group, count_field_name) + .unwrap_or_else(|| panic!("missing root count point: {}", count_field_name)); + let field_type = rust_type(point, &String::new()); quote! { - #field_name: Vec::new(), + #field_name: #field_type, } }); - let root_group_name = group_ident(&xmodel.group); + let counts_struct = if is_root && has_counts { + quote! { + struct Counts { + #(#count_fields)* + } + } + } else { + quote! {} + }; + let counts_init = if is_root && has_counts { + quote! { + let counts = Counts { + #(#count_inits)* + }; + } + } else { + quote! {} + }; let parse_groups = groups.iter().map(|sub_group| { let field_name = format_ident!("{}", snake_case(&sub_group.name)); let group_type = group_ident(sub_group); + let parse_fn = if sub_group.count.is_one() { + quote! { parse_group } + } else { + quote! { parse_multiple } + }; + let needs_counts = if sub_group.count.is_one() { + group_parse_group_needs_counts(sub_group, has_counts) + } else { + group_parse_multiple_needs_counts(sub_group, has_counts) + }; if is_root { - quote! { - (data, group.#field_name) = #group_type::parse_multiple(data, &group)?; + if needs_counts { + quote! { + let (nested_data, #field_name) = #group_type::#parse_fn(nested_data, &counts)?; + } + } else { + quote! { + let (nested_data, #field_name) = #group_type::#parse_fn(nested_data)?; + } } } else { - quote! { - (data, group.#field_name) = #group_type::parse_multiple(data, model)?; + if needs_counts { + quote! { + let (nested_data, #field_name) = #group_type::#parse_fn(nested_data, counts)?; + } + } else { + quote! { + let (nested_data, #field_name) = #group_type::#parse_fn(nested_data)?; + } } } }); + let group_field_inits = groups.iter().map(|group| { + let field_name = format_ident!("{}", snake_case(&group.name)); + quote! { + #field_name, + } + }); let group_len = Literal::u16_unsuffixed(points.iter().map(|point| point.size).sum()); - let fn_parse_multiple = if !is_root { - gen_group_fn_parse_multiple(group, xmodel) + let fn_parse_multiple = if !is_root && !group.count.is_one() { + gen_group_fn_parse_multiple(group, xmodel, has_counts) } else { quote! {} }; + let parse_group_needs_counts = group_parse_group_needs_counts(group, has_counts); let parse_group = if is_root { quote! { - fn parse_group(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + #counts_init #(#parse_groups)* - Ok((data, group)) + Ok(( + nested_data, + Self { + #(#point_field_inits)* + #(#group_field_inits)* + } + )) } } } else { - quote! { - fn parse_group<'a>(mut data: &'a [u16], model: &#root_group_name) -> Result<(&'a [u16], Self), crate::DecodeError> { - let mut group; - (data, group) = Self::parse_points(data)?; - #(#parse_groups)* - Ok((data, group)) + if parse_group_needs_counts { + quote! { + fn parse_group<'a>(data: &'a [u16], counts: &Counts) -> Result<(&'a [u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + #(#parse_groups)* + Ok(( + nested_data, + Self { + #(#point_field_inits)* + #(#group_field_inits)* + } + )) + } + } + } else { + quote! { + fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { + let nested_data = &data[usize::from(::LEN)..]; + #(#parse_groups)* + Ok(( + nested_data, + Self { + #(#point_field_inits)* + #(#group_field_inits)* + } + )) + } } } }; @@ -334,15 +431,6 @@ fn gen_group( const LEN: u16 = #group_len; } impl #group_name { - fn parse_points(mut data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> { - Ok(( - &data[usize::from(::LEN)..], - Self { - #(#from_data_fields)* - #(#from_data_groups_default)* - } - )) - } #parse_group #fn_parse_multiple } @@ -362,11 +450,18 @@ fn gen_group( } for sub_group in groups { - extra.extend(gen_group(xmodel, sub_group, state)?); + extra.extend(gen_group( + xmodel, + sub_group, + count_point_names, + has_counts, + state, + )?); } Ok(quote! { + #counts_struct #model_struct #model_impl #trait_impl @@ -374,20 +469,27 @@ fn gen_group( }) } -fn gen_group_fn_parse_multiple(group: &Group, model: &Model) -> TokenStream { - let model_name = group_ident(&model.group); +fn gen_group_fn_parse_multiple(group: &Group, model: &Model, has_counts: bool) -> TokenStream { + let model_name = format_ident!("Counts"); let group_name = group_ident(group); + let parse_group_needs_counts = group_parse_group_needs_counts(group, has_counts); + let parse_multiple_needs_counts = group_parse_multiple_needs_counts(group, has_counts); + let parse_group_call_with_counts = if parse_group_needs_counts { + quote! { #group_name::parse_group(data, counts)? } + } else { + quote! { #group_name::parse_group(data)? } + }; let group_count = match &group.count { GroupCount::String(count_field_name) => { let count_field = format_ident!("{}", snake_case(&count_field_name)); if let Some(point) = find_point(&model.group, count_field_name) { if point.mandatory == PointMandatory::M { - quote! { model.#count_field } + quote! { counts.#count_field } } else { - quote! { model.#count_field.unwrap_or_default() } + quote! { counts.#count_field.unwrap_or_default() } } } else { - quote! { model.#count_field.unwrap_or_default() } + quote! { counts.#count_field.unwrap_or_default() } } } GroupCount::Integer(count_value) => { @@ -395,19 +497,96 @@ fn gen_group_fn_parse_multiple(group: &Group, model: &Model) -> TokenStream { quote! { #count_value } } }; - quote! { - fn parse_multiple<'a>(mut data: &'a[u16], model: &#model_name) -> Result<(&'a[u16], Vec), crate::DecodeError> { - let mut groups = Vec::new(); - for _ in 0..#group_count { - let group; - (data, group) = #group_name::parse_group(data, model)?; - groups.push(group); + if group.count.is_zero() { + return quote! { + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let group_len = usize::from(<#group_name as crate::Group>::LEN); + if group_len == 0 { + return Ok((data, Vec::new())); + } + if data.len() % group_len != 0 { + return Err(crate::DecodeError::OutOfBounds); + } + let group_count = data.len() / group_len; + let (data, groups) = (0..group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = #group_name::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; + Ok((data, groups)) + } + }; + } + if parse_multiple_needs_counts { + quote! { + fn parse_multiple<'a>(data: &'a[u16], counts: &#model_name) -> Result<(&'a[u16], Vec), crate::DecodeError> { + let (data, groups) = (0..#group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = #parse_group_call_with_counts; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; + Ok((data, groups)) + } + } + } else { + quote! { + fn parse_multiple(data: &[u16]) -> Result<(&[u16], Vec), crate::DecodeError> { + let (data, groups) = (0..#group_count).try_fold((data, Vec::new()), |(data, mut groups), _| { + let (data, group) = #group_name::parse_group(data)?; + groups.push(group); + Ok::<_, crate::DecodeError>((data, groups)) + })?; + Ok((data, groups)) } - Ok((data, groups)) } } } +fn collect_count_field_names(group: &Group, names: &mut HashSet) { + for sub_group in &group.groups { + if let GroupCount::String(name) = &sub_group.count { + names.insert(name.clone()); + } + collect_count_field_names(sub_group, names); + } +} + +/// Collect all root-level point names referenced by `count: "PointName"` in any nested +/// group and return them ordered by their declaration order in the root group. +fn find_count_points(model: &Model) -> Vec { + let mut count_field_names = HashSet::new(); + collect_count_field_names(&model.group, &mut count_field_names); + model + .group + .points + .iter() + .skip(2) + .filter(|point| !point.is_padding()) + .map(|point| point.name.clone()) + .filter(|name| count_field_names.contains(name)) + .collect::>() +} + +fn group_parse_group_needs_counts(group: &Group, has_counts: bool) -> bool { + has_counts + && group.groups.iter().any(|sub_group| { + if sub_group.count.is_one() { + group_parse_group_needs_counts(sub_group, has_counts) + } else { + group_parse_multiple_needs_counts(sub_group, has_counts) + } + }) +} + +fn group_parse_multiple_needs_counts(group: &Group, has_counts: bool) -> bool { + has_counts + && match group.count { + GroupCount::String(_) => true, + GroupCount::Integer(0) => false, + GroupCount::Integer(_) => group_parse_group_needs_counts(group, has_counts), + } +} + fn group_ident(group: &Group) -> proc_macro2::Ident { format_ident!("{}", upper_camel_case(&group.name)) } diff --git a/sunspec-gen/src/json.rs b/sunspec-gen/src/json.rs index a09bb29..7674c9c 100644 --- a/sunspec-gen/src/json.rs +++ b/sunspec-gen/src/json.rs @@ -71,6 +71,20 @@ pub enum GroupCount { String(String), } +impl GroupCount { + /// A group count of zero indicates that the number of groups + /// must be deduced from the remaining data after reading the + /// points of the model itself. + pub fn is_zero(&self) -> bool { + matches!(self, Self::Integer(0)) + } + /// A group count of one indicates that the group is nested + /// and not repeating. + pub fn is_one(&self) -> bool { + matches!(self, Self::Integer(1)) + } +} + #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Point { From 8871464fd3734d1816a04d441b5bf797a33974d2 Mon Sep 17 00:00:00 2001 From: "Michael P. Jung" Date: Tue, 31 Mar 2026 00:29:02 +0200 Subject: [PATCH 3/3] Update README --- README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 47207c5..0408da4 100644 --- a/README.md +++ b/README.md @@ -16,23 +16,21 @@ in a safe and convenient way. - [x] All communication is abstracted via traits making it runtime agnostic - [x] Supports Modbus TCP and RTU (via [tokio-modbus](https://crates.io/crates/tokio-modbus)). - [x] Implements "Device Information Model Discovery" as - defined in the SunSpec specification. + defined in the SunSpec specification. - [x] Fully typed models generated from the JSON files contained in the - [SunSpec models repository](https://github.com/sunspec/models/) + [SunSpec models repository](https://github.com/sunspec/models/) - [x] Fully typed enums - [x] Fully typed bitfields - [x] Fully documented. Even the generated models. - [x] Reading of complete models in a single request. - -| ⚠️ Nested and repeating groups are not supported, yet. | -| ---- | +- [x] Supports nested and repeating groups. ## Features -| Feature | Description | Extra dependencies | Default | -| ------- | ----------------------------- | ----------------------------- | ------- | -| `tokio` | Enable `tokio_modbus` support | `tokio-modbus`, `tokio/time` | yes | -| `serde` | Enable `serde` support | `serde`, `bitflags/serde` | yes | +| Feature | Description | Extra dependencies | Default | +| ------- | ----------------------------- | ---------------------------- | ------- | +| `tokio` | Enable `tokio_modbus` support | `tokio-modbus`, `tokio/time` | yes | +| `serde` | Enable `serde` support | `serde`, `bitflags/serde` | yes | ## Examples