Skip to main content

sunspec/models/
model804.rs

1//! Lithium-Ion String Model
2/// Type alias for [`LithiumIonString`].
3pub type Model804 = LithiumIonString;
4struct Counts {
5    n_mod: u16,
6}
7/// Lithium-Ion String Model
8#[derive(Debug)]
9#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
10pub struct LithiumIonString {
11    /// String Index
12    ///
13    /// Index of the string within the bank.
14    ///
15    /// Detail: Indices are one-based.
16    pub idx: u16,
17    /// Module Count
18    ///
19    /// Count of modules in the string.
20    pub n_mod: u16,
21    /// String Status
22    ///
23    /// Current status of the string.
24    pub st: St,
25    /// Connection Failure Reason
26    pub con_fail: Option<ConFail>,
27    /// String Cell Balancing Count
28    ///
29    /// Number of cells currently being balanced in the string.
30    pub n_cell_bal: Option<u16>,
31    /// String State of Charge
32    ///
33    /// Battery string state of charge, expressed as a percentage.
34    ///
35    /// Detail: Measurement.
36    pub soc: u16,
37    /// String Depth of Discharge
38    ///
39    /// Depth of discharge for the string, expressed as a percentage.
40    ///
41    /// Detail: Measurement.
42    pub do_d: Option<u16>,
43    /// String Cycle Count
44    ///
45    /// Number of discharge cycles executed upon the string.
46    pub n_cyc: Option<u32>,
47    /// String State of Health
48    ///
49    /// Battery string state of health, expressed as a percentage.
50    ///
51    /// Detail: Measurement.
52    pub soh: Option<u16>,
53    /// String Current
54    ///
55    /// String current measurement.
56    ///
57    /// Detail: Measurement.
58    pub a: i16,
59    /// String Voltage
60    ///
61    /// String voltage measurement.
62    ///
63    /// Detail: Measurement.
64    pub v: Option<u16>,
65    /// Max Cell Voltage
66    ///
67    /// Maximum voltage for all cells in the string.
68    ///
69    /// Detail: Measurement.
70    pub cell_v_max: u16,
71    /// Max Cell Voltage Module
72    ///
73    /// Module containing the cell with maximum cell voltage.
74    pub cell_v_max_mod: Option<u16>,
75    /// Min Cell Voltage
76    ///
77    /// Minimum voltage for all cells in the string.
78    ///
79    /// Detail: Measurement.
80    pub cell_v_min: u16,
81    /// Min Cell Voltage Module
82    ///
83    /// Module containing the cell with minimum cell voltage.
84    pub cell_v_min_mod: Option<u16>,
85    /// Average Cell Voltage
86    ///
87    /// Average voltage for all cells in the string.
88    ///
89    /// Detail: Calculation based on measurements.
90    pub cell_v_avg: u16,
91    /// Max Module Temperature
92    ///
93    /// Maximum temperature for all modules in the string.
94    ///
95    /// Detail: Measurement.
96    pub mod_tmp_max: i16,
97    /// Max Module Temperature Module
98    ///
99    /// Module with the maximum temperature.
100    pub mod_tmp_max_mod: u16,
101    /// Min Module Temperature
102    ///
103    /// Minimum temperature for all modules in the string.
104    ///
105    /// Detail: Measurement.
106    pub mod_tmp_min: i16,
107    /// Min Module Temperature Module
108    ///
109    /// Module with the minimum temperature.
110    pub mod_tmp_min_mod: u16,
111    /// Average Module Temperature
112    ///
113    /// Average temperature for all modules in the string.
114    ///
115    /// Detail: Calculation based on measurements.
116    pub mod_tmp_avg: i16,
117    /// Contactor Status
118    ///
119    /// Status of the contactor(s) for the string.
120    pub con_st: Option<ConSt>,
121    /// String Event 1
122    ///
123    /// Alarms, warnings and status values.  Bit flags.
124    pub evt1: Evt1,
125    /// String Event 2
126    ///
127    /// Alarms, warnings and status values.  Bit flags.
128    ///
129    /// Detail: Reserved for future use.
130    pub evt2: Option<Evt2>,
131    /// Vendor Event Bitfield 1
132    ///
133    /// Vendor defined events.
134    pub evt_vnd1: Option<EvtVnd1>,
135    /// Vendor Event Bitfield 2
136    ///
137    /// Vendor defined events.
138    pub evt_vnd2: Option<EvtVnd2>,
139    /// Enable/Disable String
140    ///
141    /// Enables and disables the string.  Should reset to 0 upon completion.
142    pub set_ena: Option<u16>,
143    /// Connect/Disconnect String
144    ///
145    /// Connects and disconnects the string.
146    ///
147    /// Detail: Should reset to 0 upon completion.
148    pub set_con: Option<SetCon>,
149    /// Scale factor for string state of charge.
150    pub soc_sf: i16,
151    /// Scale factor for string state of health.
152    pub soh_sf: Option<i16>,
153    /// Scale factor for string depth of discharge.
154    pub do_d_sf: Option<i16>,
155    /// Scale factor for string current.
156    pub a_sf: i16,
157    /// Scale factor for string voltage.
158    pub v_sf: Option<i16>,
159    /// Scale factor for cell voltage.
160    pub cell_v_sf: i16,
161    /// Scale factor for module temperature.
162    pub mod_tmp_sf: i16,
163    #[allow(missing_docs)]
164    pub lithium_ion_string_module: Vec<LithiumIonStringModule>,
165}
166#[allow(missing_docs)]
167impl LithiumIonString {
168    pub const IDX: crate::Point<Self, u16> = crate::Point::new(0, 1, false);
169    pub const N_MOD: crate::Point<Self, u16> = crate::Point::new(1, 1, false);
170    pub const ST: crate::Point<Self, St> = crate::Point::new(2, 2, false);
171    pub const CON_FAIL: crate::Point<Self, Option<ConFail>> = crate::Point::new(4, 1, false);
172    pub const N_CELL_BAL: crate::Point<Self, Option<u16>> = crate::Point::new(5, 1, false);
173    pub const SOC: crate::Point<Self, u16> = crate::Point::new(6, 1, false);
174    pub const DO_D: crate::Point<Self, Option<u16>> = crate::Point::new(7, 1, false);
175    pub const N_CYC: crate::Point<Self, Option<u32>> = crate::Point::new(8, 2, false);
176    pub const SOH: crate::Point<Self, Option<u16>> = crate::Point::new(10, 1, false);
177    pub const A: crate::Point<Self, i16> = crate::Point::new(11, 1, false);
178    pub const V: crate::Point<Self, Option<u16>> = crate::Point::new(12, 1, false);
179    pub const CELL_V_MAX: crate::Point<Self, u16> = crate::Point::new(13, 1, false);
180    pub const CELL_V_MAX_MOD: crate::Point<Self, Option<u16>> = crate::Point::new(14, 1, false);
181    pub const CELL_V_MIN: crate::Point<Self, u16> = crate::Point::new(15, 1, false);
182    pub const CELL_V_MIN_MOD: crate::Point<Self, Option<u16>> = crate::Point::new(16, 1, false);
183    pub const CELL_V_AVG: crate::Point<Self, u16> = crate::Point::new(17, 1, false);
184    pub const MOD_TMP_MAX: crate::Point<Self, i16> = crate::Point::new(18, 1, false);
185    pub const MOD_TMP_MAX_MOD: crate::Point<Self, u16> = crate::Point::new(19, 1, false);
186    pub const MOD_TMP_MIN: crate::Point<Self, i16> = crate::Point::new(20, 1, false);
187    pub const MOD_TMP_MIN_MOD: crate::Point<Self, u16> = crate::Point::new(21, 1, false);
188    pub const MOD_TMP_AVG: crate::Point<Self, i16> = crate::Point::new(22, 1, false);
189    pub const CON_ST: crate::Point<Self, Option<ConSt>> = crate::Point::new(24, 2, false);
190    pub const EVT1: crate::Point<Self, Evt1> = crate::Point::new(26, 2, false);
191    pub const EVT2: crate::Point<Self, Option<Evt2>> = crate::Point::new(28, 2, false);
192    pub const EVT_VND1: crate::Point<Self, Option<EvtVnd1>> = crate::Point::new(30, 2, false);
193    pub const EVT_VND2: crate::Point<Self, Option<EvtVnd2>> = crate::Point::new(32, 2, false);
194    pub const SET_ENA: crate::Point<Self, Option<u16>> = crate::Point::new(34, 1, true);
195    pub const SET_CON: crate::Point<Self, Option<SetCon>> = crate::Point::new(35, 1, true);
196    pub const SOC_SF: crate::Point<Self, i16> = crate::Point::new(36, 1, false);
197    pub const SOH_SF: crate::Point<Self, Option<i16>> = crate::Point::new(37, 1, false);
198    pub const DO_D_SF: crate::Point<Self, Option<i16>> = crate::Point::new(38, 1, false);
199    pub const A_SF: crate::Point<Self, i16> = crate::Point::new(39, 1, false);
200    pub const V_SF: crate::Point<Self, Option<i16>> = crate::Point::new(40, 1, false);
201    pub const CELL_V_SF: crate::Point<Self, i16> = crate::Point::new(41, 1, false);
202    pub const MOD_TMP_SF: crate::Point<Self, i16> = crate::Point::new(42, 1, false);
203}
204impl crate::Group for LithiumIonString {
205    const LEN: u16 = 46;
206}
207impl LithiumIonString {
208    fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> {
209        let nested_data = data
210            .get(usize::from(<Self as crate::Group>::LEN)..)
211            .unwrap_or(&[]);
212        let counts = Counts {
213            n_mod: Self::N_MOD.from_data(data)?,
214        };
215        let (nested_data, lithium_ion_string_module) =
216            LithiumIonStringModule::parse_multiple(nested_data, &counts)?;
217        Ok((
218            nested_data,
219            Self {
220                idx: Self::IDX.from_data(data)?,
221                n_mod: Self::N_MOD.from_data(data)?,
222                st: Self::ST.from_data(data)?,
223                con_fail: Self::CON_FAIL.from_data(data)?,
224                n_cell_bal: Self::N_CELL_BAL.from_data(data)?,
225                soc: Self::SOC.from_data(data)?,
226                do_d: Self::DO_D.from_data(data)?,
227                n_cyc: Self::N_CYC.from_data(data)?,
228                soh: Self::SOH.from_data(data)?,
229                a: Self::A.from_data(data)?,
230                v: Self::V.from_data(data)?,
231                cell_v_max: Self::CELL_V_MAX.from_data(data)?,
232                cell_v_max_mod: Self::CELL_V_MAX_MOD.from_data(data)?,
233                cell_v_min: Self::CELL_V_MIN.from_data(data)?,
234                cell_v_min_mod: Self::CELL_V_MIN_MOD.from_data(data)?,
235                cell_v_avg: Self::CELL_V_AVG.from_data(data)?,
236                mod_tmp_max: Self::MOD_TMP_MAX.from_data(data)?,
237                mod_tmp_max_mod: Self::MOD_TMP_MAX_MOD.from_data(data)?,
238                mod_tmp_min: Self::MOD_TMP_MIN.from_data(data)?,
239                mod_tmp_min_mod: Self::MOD_TMP_MIN_MOD.from_data(data)?,
240                mod_tmp_avg: Self::MOD_TMP_AVG.from_data(data)?,
241                con_st: Self::CON_ST.from_data(data)?,
242                evt1: Self::EVT1.from_data(data)?,
243                evt2: Self::EVT2.from_data(data)?,
244                evt_vnd1: Self::EVT_VND1.from_data(data)?,
245                evt_vnd2: Self::EVT_VND2.from_data(data)?,
246                set_ena: Self::SET_ENA.from_data(data)?,
247                set_con: Self::SET_CON.from_data(data)?,
248                soc_sf: Self::SOC_SF.from_data(data)?,
249                soh_sf: Self::SOH_SF.from_data(data)?,
250                do_d_sf: Self::DO_D_SF.from_data(data)?,
251                a_sf: Self::A_SF.from_data(data)?,
252                v_sf: Self::V_SF.from_data(data)?,
253                cell_v_sf: Self::CELL_V_SF.from_data(data)?,
254                mod_tmp_sf: Self::MOD_TMP_SF.from_data(data)?,
255                lithium_ion_string_module,
256            },
257        ))
258    }
259}
260bitflags::bitflags! {
261    #[doc = " String Status"] #[doc = " "] #[doc = " Current status of the string."]
262    #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde",
263    derive(::serde::Serialize, ::serde::Deserialize))] pub struct St : u32 {
264    #[allow(missing_docs)] const StringEnabled = 1; #[doc =
265    " Detail: If string has multiple contactors, indicates that all contactors are closed."]
266    const ContactorStatus = 2; }
267}
268impl crate::Value for St {
269    fn decode(data: &[u16]) -> Result<Self, crate::DecodeError> {
270        let value = u32::decode(data)?;
271        Ok(Self::from_bits_retain(value))
272    }
273    fn encode(self) -> Box<[u16]> {
274        self.bits().encode()
275    }
276}
277impl crate::FixedSize for St {
278    const SIZE: u16 = 2u16;
279    const INVALID: Self = Self::from_bits_retain(4294967295u32);
280    fn is_invalid(&self) -> bool {
281        self.bits() == 4294967295u32
282    }
283}
284/// Connection Failure Reason
285#[derive(Copy, Clone, Debug, Eq, PartialEq)]
286#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
287pub enum ConFail {
288    #[allow(missing_docs)]
289    NoFailure,
290    #[allow(missing_docs)]
291    ButtonPushed,
292    #[allow(missing_docs)]
293    StrGroundFault,
294    #[allow(missing_docs)]
295    OutsideVoltageRange,
296    #[allow(missing_docs)]
297    StringNotEnabled,
298    #[allow(missing_docs)]
299    FuseOpen,
300    #[allow(missing_docs)]
301    ContactorFailure,
302    #[allow(missing_docs)]
303    PrechargeFailure,
304    /// Detail: See Evt1 for more information.
305    StringFault,
306    /// Raw enum value not defined by the SunSpec model.
307    Invalid(u16),
308}
309impl crate::EnumValue for ConFail {
310    type Repr = u16;
311    const INVALID: Self::Repr = 65535;
312    fn from_repr(value: Self::Repr) -> Self {
313        match value {
314            0 => Self::NoFailure,
315            1 => Self::ButtonPushed,
316            2 => Self::StrGroundFault,
317            3 => Self::OutsideVoltageRange,
318            4 => Self::StringNotEnabled,
319            5 => Self::FuseOpen,
320            6 => Self::ContactorFailure,
321            7 => Self::PrechargeFailure,
322            8 => Self::StringFault,
323            value => Self::Invalid(value),
324        }
325    }
326    fn to_repr(self) -> Self::Repr {
327        match self {
328            Self::NoFailure => 0,
329            Self::ButtonPushed => 1,
330            Self::StrGroundFault => 2,
331            Self::OutsideVoltageRange => 3,
332            Self::StringNotEnabled => 4,
333            Self::FuseOpen => 5,
334            Self::ContactorFailure => 6,
335            Self::PrechargeFailure => 7,
336            Self::StringFault => 8,
337            Self::Invalid(value) => value,
338        }
339    }
340}
341impl crate::FixedSize for ConFail {
342    const SIZE: u16 = 1u16;
343    const INVALID: Self = Self::Invalid(65535);
344    fn is_invalid(&self) -> bool {
345        matches!(self, Self::Invalid(_))
346    }
347}
348bitflags::bitflags! {
349    #[doc = " Contactor Status"] #[doc = " "] #[doc =
350    " Status of the contactor(s) for the string."] #[derive(Copy, Clone, Debug, Eq,
351    PartialEq)] #[cfg_attr(feature = "serde", derive(::serde::Serialize,
352    ::serde::Deserialize))] pub struct ConSt : u32 { #[allow(missing_docs)] const
353    Contactor0 = 1; #[allow(missing_docs)] const Contactor1 = 2; #[allow(missing_docs)]
354    const Contactor2 = 4; #[allow(missing_docs)] const Contactor3 = 8;
355    #[allow(missing_docs)] const Contactor4 = 16; #[allow(missing_docs)] const Contactor5
356    = 32; #[allow(missing_docs)] const Contactor6 = 64; #[allow(missing_docs)] const
357    Contactor7 = 128; #[allow(missing_docs)] const Contactor8 = 256;
358    #[allow(missing_docs)] const Contactor9 = 512; #[allow(missing_docs)] const
359    Contactor10 = 1024; #[allow(missing_docs)] const Contactor11 = 2048;
360    #[allow(missing_docs)] const Contactor12 = 4096; #[allow(missing_docs)] const
361    Contactor13 = 8192; #[allow(missing_docs)] const Contactor14 = 16384;
362    #[allow(missing_docs)] const Contactor15 = 32768; #[allow(missing_docs)] const
363    Contactor16 = 65536; #[allow(missing_docs)] const Contactor17 = 131072;
364    #[allow(missing_docs)] const Contactor18 = 262144; #[allow(missing_docs)] const
365    Contactor19 = 524288; #[allow(missing_docs)] const Contactor20 = 1048576;
366    #[allow(missing_docs)] const Contactor21 = 2097152; #[allow(missing_docs)] const
367    Contactor22 = 4194304; #[allow(missing_docs)] const Contactor23 = 8388608;
368    #[allow(missing_docs)] const Contactor24 = 16777216; #[allow(missing_docs)] const
369    Contactor25 = 33554432; #[allow(missing_docs)] const Contactor26 = 67108864;
370    #[allow(missing_docs)] const Contactor27 = 134217728; #[allow(missing_docs)] const
371    Contactor28 = 268435456; #[allow(missing_docs)] const Contactor29 = 536870912;
372    #[allow(missing_docs)] const Contactor30 = 1073741824; }
373}
374impl crate::Value for ConSt {
375    fn decode(data: &[u16]) -> Result<Self, crate::DecodeError> {
376        let value = u32::decode(data)?;
377        Ok(Self::from_bits_retain(value))
378    }
379    fn encode(self) -> Box<[u16]> {
380        self.bits().encode()
381    }
382}
383impl crate::FixedSize for ConSt {
384    const SIZE: u16 = 2u16;
385    const INVALID: Self = Self::from_bits_retain(4294967295u32);
386    fn is_invalid(&self) -> bool {
387        self.bits() == 4294967295u32
388    }
389}
390bitflags::bitflags! {
391    #[doc = " String Event 1"] #[doc = " "] #[doc =
392    " Alarms, warnings and status values.  Bit flags."] #[derive(Copy, Clone, Debug, Eq,
393    PartialEq)] #[cfg_attr(feature = "serde", derive(::serde::Serialize,
394    ::serde::Deserialize))] pub struct Evt1 : u32 { #[allow(missing_docs)] const
395    CommunicationError = 1; #[allow(missing_docs)] const OverTempAlarm = 2;
396    #[allow(missing_docs)] const OverTempWarning = 4; #[allow(missing_docs)] const
397    UnderTempAlarm = 8; #[allow(missing_docs)] const UnderTempWarning = 16; #[doc =
398    " Detail: See AChaMax in model S 802."] const OverChargeCurrentAlarm = 32; #[doc =
399    " Detail: See AChaMax in model S 802."] const OverChargeCurrentWarning = 64; #[doc =
400    " Detail: See ADisChaMax in model S 802."] const OverDischargeCurrentAlarm = 128;
401    #[doc = " Detail: See ADisChaMax in model S 802."] const OverDischargeCurrentWarning
402    = 256; #[allow(missing_docs)] const OverVoltAlarm = 512; #[allow(missing_docs)] const
403    OverVoltWarning = 1024; #[allow(missing_docs)] const UnderVoltAlarm = 2048;
404    #[allow(missing_docs)] const UnderVoltWarning = 4096; #[allow(missing_docs)] const
405    UnderSocMinAlarm = 8192; #[allow(missing_docs)] const UnderSocMinWarning = 16384;
406    #[allow(missing_docs)] const OverSocMaxAlarm = 32768; #[allow(missing_docs)] const
407    OverSocMaxWarning = 65536; #[allow(missing_docs)] const VoltageImbalanceWarning =
408    131072; #[allow(missing_docs)] const TemperatureImbalanceAlarm = 262144;
409    #[allow(missing_docs)] const TemperatureImbalanceWarning = 524288;
410    #[allow(missing_docs)] const ContactorError = 1048576; #[allow(missing_docs)] const
411    FanError = 2097152; #[allow(missing_docs)] const GroundFault = 4194304;
412    #[allow(missing_docs)] const OpenDoorError = 8388608; #[doc =
413    " Detail: Do not implement."] const Reserved1 = 16777216; #[doc =
414    " Detail: See EvtVnd1 and EvtVnd2 for more information."] const OtherAlarm =
415    33554432; #[doc = " Detail: See EvtVnd1 and EvtVnd2 for more information."] const
416    OtherWarning = 67108864; #[doc = " Detail: Do not implement."] const Reserved2 =
417    134217728; #[allow(missing_docs)] const ConfigurationAlarm = 268435456;
418    #[allow(missing_docs)] const ConfigurationWarning = 536870912; }
419}
420impl crate::Value for Evt1 {
421    fn decode(data: &[u16]) -> Result<Self, crate::DecodeError> {
422        let value = u32::decode(data)?;
423        Ok(Self::from_bits_retain(value))
424    }
425    fn encode(self) -> Box<[u16]> {
426        self.bits().encode()
427    }
428}
429impl crate::FixedSize for Evt1 {
430    const SIZE: u16 = 2u16;
431    const INVALID: Self = Self::from_bits_retain(4294967295u32);
432    fn is_invalid(&self) -> bool {
433        self.bits() == 4294967295u32
434    }
435}
436bitflags::bitflags! {
437    #[doc = " String Event 2"] #[doc = " "] #[doc =
438    " Alarms, warnings and status values.  Bit flags."] #[doc = " "] #[doc =
439    " Detail: Reserved for future use."] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
440    #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub
441    struct Evt2 : u32 {}
442}
443impl crate::Value for Evt2 {
444    fn decode(data: &[u16]) -> Result<Self, crate::DecodeError> {
445        let value = u32::decode(data)?;
446        Ok(Self::from_bits_retain(value))
447    }
448    fn encode(self) -> Box<[u16]> {
449        self.bits().encode()
450    }
451}
452impl crate::FixedSize for Evt2 {
453    const SIZE: u16 = 2u16;
454    const INVALID: Self = Self::from_bits_retain(4294967295u32);
455    fn is_invalid(&self) -> bool {
456        self.bits() == 4294967295u32
457    }
458}
459bitflags::bitflags! {
460    #[doc = " Vendor Event Bitfield 1"] #[doc = " "] #[doc = " Vendor defined events."]
461    #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde",
462    derive(::serde::Serialize, ::serde::Deserialize))] pub struct EvtVnd1 : u32 {}
463}
464impl crate::Value for EvtVnd1 {
465    fn decode(data: &[u16]) -> Result<Self, crate::DecodeError> {
466        let value = u32::decode(data)?;
467        Ok(Self::from_bits_retain(value))
468    }
469    fn encode(self) -> Box<[u16]> {
470        self.bits().encode()
471    }
472}
473impl crate::FixedSize for EvtVnd1 {
474    const SIZE: u16 = 2u16;
475    const INVALID: Self = Self::from_bits_retain(4294967295u32);
476    fn is_invalid(&self) -> bool {
477        self.bits() == 4294967295u32
478    }
479}
480bitflags::bitflags! {
481    #[doc = " Vendor Event Bitfield 2"] #[doc = " "] #[doc = " Vendor defined events."]
482    #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde",
483    derive(::serde::Serialize, ::serde::Deserialize))] pub struct EvtVnd2 : u32 {}
484}
485impl crate::Value for EvtVnd2 {
486    fn decode(data: &[u16]) -> Result<Self, crate::DecodeError> {
487        let value = u32::decode(data)?;
488        Ok(Self::from_bits_retain(value))
489    }
490    fn encode(self) -> Box<[u16]> {
491        self.bits().encode()
492    }
493}
494impl crate::FixedSize for EvtVnd2 {
495    const SIZE: u16 = 2u16;
496    const INVALID: Self = Self::from_bits_retain(4294967295u32);
497    fn is_invalid(&self) -> bool {
498        self.bits() == 4294967295u32
499    }
500}
501/// Connect/Disconnect String
502///
503/// Connects and disconnects the string.
504///
505/// Detail: Should reset to 0 upon completion.
506#[derive(Copy, Clone, Debug, Eq, PartialEq)]
507#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
508pub enum SetCon {
509    #[allow(missing_docs)]
510    ConnectString,
511    #[allow(missing_docs)]
512    DisconnectString,
513    /// Raw enum value not defined by the SunSpec model.
514    Invalid(u16),
515}
516impl crate::EnumValue for SetCon {
517    type Repr = u16;
518    const INVALID: Self::Repr = 65535;
519    fn from_repr(value: Self::Repr) -> Self {
520        match value {
521            1 => Self::ConnectString,
522            2 => Self::DisconnectString,
523            value => Self::Invalid(value),
524        }
525    }
526    fn to_repr(self) -> Self::Repr {
527        match self {
528            Self::ConnectString => 1,
529            Self::DisconnectString => 2,
530            Self::Invalid(value) => value,
531        }
532    }
533}
534impl crate::FixedSize for SetCon {
535    const SIZE: u16 = 1u16;
536    const INVALID: Self = Self::Invalid(65535);
537    fn is_invalid(&self) -> bool {
538        matches!(self, Self::Invalid(_))
539    }
540}
541#[allow(missing_docs)]
542#[derive(Debug)]
543#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
544pub struct LithiumIonStringModule {
545    /// Module Cell Count
546    ///
547    /// Count of all cells in the module.
548    pub mod_n_cell: u16,
549    /// Module SoC
550    ///
551    /// Module state of charge, expressed as a percentage.
552    pub mod_soc: Option<u16>,
553    /// Module SoH
554    ///
555    /// Module state of health, expressed as a percentage.
556    pub mod_soh: Option<u16>,
557    /// Max Cell Voltage
558    ///
559    /// Maximum voltage for all cells in the module.
560    pub mod_cell_v_max: u16,
561    /// Max Cell Voltage Cell
562    ///
563    /// Cell with maximum voltage.
564    pub mod_cell_v_max_cell: Option<u16>,
565    /// Min Cell Voltage
566    ///
567    /// Minimum voltage for all cells in the module.
568    pub mod_cell_v_min: u16,
569    /// Min Cell Voltage Cell
570    ///
571    /// Cell with minimum voltage.
572    pub mod_cell_v_min_cell: Option<u16>,
573    /// Average Cell Voltage
574    ///
575    /// Average voltage for all cells in the module.
576    pub mod_cell_v_avg: u16,
577    /// Max Cell Temperature
578    ///
579    /// Maximum temperature for all cells in the module.
580    pub mod_cell_tmp_max: i16,
581    /// Max Cell Temperature Cell
582    ///
583    /// Cell with maximum temperature.
584    pub mod_cell_tmp_max_cell: Option<u16>,
585    /// Min Cell Temperature
586    ///
587    /// Minimum temperature for all cells in the module.
588    pub mod_cell_tmp_min: i16,
589    /// Min Cell Temperature Cell
590    ///
591    /// Cell with minimum temperature.
592    pub mod_cell_tmp_min_cell: Option<u16>,
593    /// Average Cell Temperature
594    ///
595    /// Average temperature for all cells in the module.
596    pub mod_cell_tmp_avg: i16,
597}
598#[allow(missing_docs)]
599impl LithiumIonStringModule {
600    pub const MOD_N_CELL: crate::Point<Self, u16> = crate::Point::new(0, 1, false);
601    pub const MOD_SOC: crate::Point<Self, Option<u16>> = crate::Point::new(1, 1, false);
602    pub const MOD_SOH: crate::Point<Self, Option<u16>> = crate::Point::new(2, 1, false);
603    pub const MOD_CELL_V_MAX: crate::Point<Self, u16> = crate::Point::new(3, 1, false);
604    pub const MOD_CELL_V_MAX_CELL: crate::Point<Self, Option<u16>> = crate::Point::new(4, 1, false);
605    pub const MOD_CELL_V_MIN: crate::Point<Self, u16> = crate::Point::new(5, 1, false);
606    pub const MOD_CELL_V_MIN_CELL: crate::Point<Self, Option<u16>> = crate::Point::new(6, 1, false);
607    pub const MOD_CELL_V_AVG: crate::Point<Self, u16> = crate::Point::new(7, 1, false);
608    pub const MOD_CELL_TMP_MAX: crate::Point<Self, i16> = crate::Point::new(8, 1, false);
609    pub const MOD_CELL_TMP_MAX_CELL: crate::Point<Self, Option<u16>> =
610        crate::Point::new(9, 1, false);
611    pub const MOD_CELL_TMP_MIN: crate::Point<Self, i16> = crate::Point::new(10, 1, false);
612    pub const MOD_CELL_TMP_MIN_CELL: crate::Point<Self, Option<u16>> =
613        crate::Point::new(11, 1, false);
614    pub const MOD_CELL_TMP_AVG: crate::Point<Self, i16> = crate::Point::new(12, 1, false);
615}
616impl crate::Group for LithiumIonStringModule {
617    const LEN: u16 = 16;
618}
619impl LithiumIonStringModule {
620    fn parse_group(data: &[u16]) -> Result<(&[u16], Self), crate::DecodeError> {
621        let nested_data = data
622            .get(usize::from(<Self as crate::Group>::LEN)..)
623            .unwrap_or(&[]);
624        Ok((
625            nested_data,
626            Self {
627                mod_n_cell: Self::MOD_N_CELL.from_data(data)?,
628                mod_soc: Self::MOD_SOC.from_data(data)?,
629                mod_soh: Self::MOD_SOH.from_data(data)?,
630                mod_cell_v_max: Self::MOD_CELL_V_MAX.from_data(data)?,
631                mod_cell_v_max_cell: Self::MOD_CELL_V_MAX_CELL.from_data(data)?,
632                mod_cell_v_min: Self::MOD_CELL_V_MIN.from_data(data)?,
633                mod_cell_v_min_cell: Self::MOD_CELL_V_MIN_CELL.from_data(data)?,
634                mod_cell_v_avg: Self::MOD_CELL_V_AVG.from_data(data)?,
635                mod_cell_tmp_max: Self::MOD_CELL_TMP_MAX.from_data(data)?,
636                mod_cell_tmp_max_cell: Self::MOD_CELL_TMP_MAX_CELL.from_data(data)?,
637                mod_cell_tmp_min: Self::MOD_CELL_TMP_MIN.from_data(data)?,
638                mod_cell_tmp_min_cell: Self::MOD_CELL_TMP_MIN_CELL.from_data(data)?,
639                mod_cell_tmp_avg: Self::MOD_CELL_TMP_AVG.from_data(data)?,
640            },
641        ))
642    }
643    fn parse_multiple<'a>(
644        data: &'a [u16],
645        counts: &Counts,
646    ) -> Result<(&'a [u16], Vec<Self>), crate::DecodeError> {
647        let (data, groups) =
648            (0..counts.n_mod).try_fold((data, Vec::new()), |(data, mut groups), _| {
649                let (data, group) = LithiumIonStringModule::parse_group(data)?;
650                groups.push(group);
651                Ok::<_, crate::DecodeError>((data, groups))
652            })?;
653        Ok((data, groups))
654    }
655}
656impl crate::Model for LithiumIonString {
657    const ID: u16 = 804;
658    fn addr(models: &crate::Models) -> crate::ModelAddr<Self> {
659        models.m804
660    }
661    fn parse(data: &[u16]) -> Result<Self, crate::ParseError<Self>> {
662        let (_, model) = Self::parse_group(data)?;
663        Ok(model)
664    }
665}