m_bus_parser/user_data/
mod.rs

1//! is a part of the application layer
2#[cfg(feature = "std")]
3use std::fmt;
4
5use variable_user_data::DataRecordError;
6
7use self::data_record::DataRecord;
8
9pub mod data_information;
10pub mod data_record;
11pub mod value_information;
12pub mod variable_user_data;
13
14#[cfg_attr(feature = "serde", derive(serde::Serialize))]
15#[cfg_attr(feature = "serde", serde(into = "Vec<DataRecord>"))]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17#[derive(Clone, Debug, PartialEq)]
18pub struct DataRecords<'a> {
19    offset: usize,
20    data: &'a [u8],
21    fixed_data_header: Option<&'a FixedDataHeader>,
22}
23
24#[cfg(feature = "serde")]
25impl<'a> From<DataRecords<'a>> for Vec<DataRecord<'a>> {
26    fn from(value: DataRecords<'a>) -> Self {
27        let value: Result<Vec<_>, _> = value.collect();
28        value.unwrap_or_default()
29    }
30}
31
32impl<'a> Iterator for DataRecords<'a> {
33    type Item = Result<DataRecord<'a>, DataRecordError>;
34
35    fn next(&mut self) -> Option<Self::Item> {
36        let mut _more_records_follow = false;
37
38        while self.offset < self.data.len() {
39            match self.data.get(self.offset)? {
40                0x1F => {
41                    /* TODO: parse manufacturer specific */
42                    _more_records_follow = true;
43                    self.offset = self.data.len();
44                }
45                0x2F => {
46                    self.offset += 1;
47                }
48                _ => {
49                    let record = if let Some(fixed_data_header) = self.fixed_data_header {
50                        DataRecord::try_from((self.data.get(self.offset..)?, fixed_data_header))
51                    } else {
52                        DataRecord::try_from(self.data.get(self.offset..)?)
53                    };
54                    if let Ok(record) = record {
55                        self.offset += record.get_size();
56                        return Some(Ok(record));
57                    } else {
58                        self.offset = self.data.len();
59                    }
60                }
61            }
62        }
63        None
64    }
65}
66
67impl<'a> DataRecords<'a> {
68    #[must_use]
69    pub const fn new(data: &'a [u8], fixed_data_header: Option<&'a FixedDataHeader>) -> Self {
70        DataRecords {
71            offset: 0,
72            data,
73            fixed_data_header,
74        }
75    }
76}
77
78bitflags::bitflags! {
79    #[repr(transparent)]
80    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
81    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82    pub struct StatusField: u8 {
83        const COUNTER_BINARY_SIGNED     = 0b0000_0001;
84        const COUNTER_FIXED_DATE        = 0b0000_0010;
85        const POWER_LOW                 = 0b0000_0100;
86        const PERMANENT_ERROR           = 0b0000_1000;
87        const TEMPORARY_ERROR           = 0b0001_0000;
88        const MANUFACTURER_SPECIFIC_1   = 0b0010_0000;
89        const MANUFACTURER_SPECIFIC_2   = 0b0100_0000;
90        const MANUFACTURER_SPECIFIC_3   = 0b1000_0000;
91    }
92}
93
94#[cfg(feature = "defmt")]
95impl defmt::Format for StatusField {
96    fn format(&self, f: defmt::Formatter) {
97        defmt::write!(f, "{:?}", self);
98    }
99}
100
101#[cfg(feature = "std")]
102impl fmt::Display for StatusField {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        let mut status = String::new();
105        if self.contains(StatusField::COUNTER_BINARY_SIGNED) {
106            status.push_str("Counter binary signed, ");
107        }
108        if self.contains(StatusField::COUNTER_FIXED_DATE) {
109            status.push_str("Counter fixed date, ");
110        }
111        if self.contains(StatusField::POWER_LOW) {
112            status.push_str("Power low, ");
113        }
114        if self.contains(StatusField::PERMANENT_ERROR) {
115            status.push_str("Permanent error, ");
116        }
117        if self.contains(StatusField::TEMPORARY_ERROR) {
118            status.push_str("Temporary error, ");
119        }
120        if self.contains(StatusField::MANUFACTURER_SPECIFIC_1) {
121            status.push_str("Manufacturer specific 1, ");
122        }
123        if self.contains(StatusField::MANUFACTURER_SPECIFIC_2) {
124            status.push_str("Manufacturer specific 2, ");
125        }
126        if self.contains(StatusField::MANUFACTURER_SPECIFIC_3) {
127            status.push_str("Manufacturer specific 3, ");
128        }
129        if status.is_empty() {
130            status.push_str("No Error(s)");
131        }
132        write!(f, "{}", status.trim_end_matches(", "))
133    }
134}
135
136#[derive(Debug, PartialEq)]
137#[cfg_attr(feature = "defmt", derive(defmt::Format))]
138pub enum Direction {
139    SlaveToMaster,
140    MasterToSlave,
141}
142
143// implement from trait for direction
144impl From<ControlInformation> for Direction {
145    fn from(single_byte: ControlInformation) -> Self {
146        match single_byte {
147            ControlInformation::ResetAtApplicationLevel => Self::MasterToSlave,
148            ControlInformation::SendData => Self::MasterToSlave,
149            ControlInformation::SelectSlave => Self::MasterToSlave,
150            ControlInformation::SynchronizeSlave => Self::MasterToSlave,
151            ControlInformation::SetBaudRate300 => Self::MasterToSlave,
152            ControlInformation::SetBaudRate600 => Self::MasterToSlave,
153            ControlInformation::SetBaudRate1200 => Self::MasterToSlave,
154            ControlInformation::SetBaudRate2400 => Self::MasterToSlave,
155            ControlInformation::SetBaudRate4800 => Self::MasterToSlave,
156            ControlInformation::SetBaudRate9600 => Self::MasterToSlave,
157            ControlInformation::SetBaudRate19200 => Self::MasterToSlave,
158            ControlInformation::SetBaudRate38400 => Self::MasterToSlave,
159            ControlInformation::OutputRAMContent => Self::MasterToSlave,
160            ControlInformation::WriteRAMContent => Self::MasterToSlave,
161            ControlInformation::StartCalibrationTestMode => Self::MasterToSlave,
162            ControlInformation::ReadEEPROM => Self::MasterToSlave,
163            ControlInformation::StartSoftwareTest => Self::MasterToSlave,
164            ControlInformation::HashProcedure(_) => Self::MasterToSlave,
165            ControlInformation::SendErrorStatus => Self::SlaveToMaster,
166            ControlInformation::SendAlarmStatus => Self::SlaveToMaster,
167            ControlInformation::ResponseWithVariableDataStructure { lsb_order: _ } => {
168                Self::SlaveToMaster
169            }
170            ControlInformation::ResponseWithFixedDataStructure => Self::SlaveToMaster,
171        }
172    }
173}
174
175#[derive(Debug, PartialEq)]
176#[cfg_attr(feature = "defmt", derive(defmt::Format))]
177pub enum ControlInformation {
178    SendData,
179    SelectSlave,
180    ResetAtApplicationLevel,
181    SynchronizeSlave,
182    SetBaudRate300,
183    SetBaudRate600,
184    SetBaudRate1200,
185    SetBaudRate2400,
186    SetBaudRate4800,
187    SetBaudRate9600,
188    SetBaudRate19200,
189    SetBaudRate38400,
190    OutputRAMContent,
191    WriteRAMContent,
192    StartCalibrationTestMode,
193    ReadEEPROM,
194    StartSoftwareTest,
195    HashProcedure(u8),
196    SendErrorStatus,
197    SendAlarmStatus,
198    ResponseWithVariableDataStructure { lsb_order: bool },
199    ResponseWithFixedDataStructure,
200}
201
202impl ControlInformation {
203    const fn from(byte: u8) -> Result<Self, ApplicationLayerError> {
204        match byte {
205            0x50 => Ok(Self::ResetAtApplicationLevel),
206            0x51 => Ok(Self::SendData),
207            0x52 => Ok(Self::SelectSlave),
208            0x54 => Ok(Self::SynchronizeSlave),
209            0xB8 => Ok(Self::SetBaudRate300),
210            0xB9 => Ok(Self::SetBaudRate600),
211            0xBA => Ok(Self::SetBaudRate1200),
212            0xBB => Ok(Self::SetBaudRate2400),
213            0xBC => Ok(Self::SetBaudRate4800),
214            0xBD => Ok(Self::SetBaudRate9600),
215            0xBE => Ok(Self::SetBaudRate19200),
216            0xBF => Ok(Self::SetBaudRate38400),
217            0xB1 => Ok(Self::OutputRAMContent),
218            0xB2 => Ok(Self::WriteRAMContent),
219            0xB3 => Ok(Self::StartCalibrationTestMode),
220            0xB4 => Ok(Self::ReadEEPROM),
221            0xB6 => Ok(Self::StartSoftwareTest),
222            0x90..=0x97 => Ok(Self::HashProcedure(byte - 0x90)),
223            0x70 => Ok(Self::SendErrorStatus),
224            0x71 => Ok(Self::SendAlarmStatus),
225            0x72 | 0x76 => Ok(Self::ResponseWithVariableDataStructure {
226                lsb_order: byte & 0x04 != 0,
227            }),
228            0x73 | 0x77 => Ok(Self::ResponseWithFixedDataStructure),
229            _ => Err(ApplicationLayerError::InvalidControlInformation { byte }),
230        }
231    }
232}
233
234#[derive(Debug, PartialEq)]
235#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
236#[cfg_attr(feature = "defmt", derive(defmt::Format))]
237pub enum ApplicationLayerError {
238    MissingControlInformation,
239    InvalidControlInformation { byte: u8 },
240    IdentificationNumberError { digits: [u8; 4], number: u32 },
241    InvalidManufacturerCode { code: u16 },
242    InsufficientData,
243}
244
245#[cfg(feature = "std")]
246impl fmt::Display for ApplicationLayerError {
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        match self {
249            ApplicationLayerError::MissingControlInformation => {
250                write!(f, "Missing control information")
251            }
252            ApplicationLayerError::InvalidControlInformation { byte } => {
253                write!(f, "Invalid control information: {}", byte)
254            }
255            ApplicationLayerError::InvalidManufacturerCode { code } => {
256                write!(f, "Invalid manufacturer code: {}", code)
257            }
258            ApplicationLayerError::IdentificationNumberError { digits, number } => {
259                write!(
260                    f,
261                    "Invalid identification number: {:?}, number: {}",
262                    digits, number
263                )
264            }
265            ApplicationLayerError::InsufficientData => {
266                write!(f, "Insufficient data")
267            }
268        }
269    }
270}
271
272#[cfg(feature = "std")]
273impl std::error::Error for ApplicationLayerError {}
274
275#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
276#[derive(Debug, PartialEq)]
277#[cfg_attr(feature = "defmt", derive(defmt::Format))]
278pub enum ApplicationResetSubcode {
279    All(u8),
280    UserData(u8),
281    SimpleBilling(u8),
282    EnhancedBilling(u8),
283    MultiTariffBilling(u8),
284    InstantaneousValues(u8),
285    LoadManagementValues(u8),
286    Reserved1(u8),
287    InstallationStartup(u8),
288    Testing(u8),
289    Calibration(u8),
290    ConfigurationUpdates(u8),
291    Manufacturing(u8),
292    Development(u8),
293    Selftest(u8),
294    Reserved2(u8),
295}
296
297#[cfg(feature = "std")]
298impl fmt::Display for ApplicationResetSubcode {
299    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300        let subcode = match self {
301            Self::All(_) => "All",
302            Self::UserData(_) => "User data",
303            Self::SimpleBilling(_) => "Simple billing",
304            Self::EnhancedBilling(_) => "Enhanced billing",
305            Self::MultiTariffBilling(_) => "Multi-tariff billing",
306            Self::InstantaneousValues(_) => "Instantaneous values",
307            Self::LoadManagementValues(_) => "Load management values",
308            Self::Reserved1(_) => "Reserved",
309            Self::InstallationStartup(_) => "Installation startup",
310            Self::Testing(_) => "Testing",
311            Self::Calibration(_) => "Calibration",
312            Self::ConfigurationUpdates(_) => "Configuration updates",
313            Self::Manufacturing(_) => "Manufacturing",
314            Self::Development(_) => "Development",
315            Self::Selftest(_) => "Self-test",
316            Self::Reserved2(_) => "Reserved",
317        };
318        write!(f, "{}", subcode)
319    }
320}
321
322impl ApplicationResetSubcode {
323    #[must_use]
324    pub const fn from(value: u8) -> Self {
325        match value & 0b1111 {
326            // Extracting the lower 4 bits
327            0b0000 => Self::All(value),
328            0b0001 => Self::UserData(value),
329            0b0010 => Self::SimpleBilling(value),
330            0b0011 => Self::EnhancedBilling(value),
331            0b0100 => Self::MultiTariffBilling(value),
332            0b0101 => Self::InstantaneousValues(value),
333            0b0110 => Self::LoadManagementValues(value),
334            0b0111 => Self::Reserved1(value),
335            0b1000 => Self::InstallationStartup(value),
336            0b1001 => Self::Testing(value),
337            0b1010 => Self::Calibration(value),
338            0b1011 => Self::ConfigurationUpdates(value),
339            0b1100 => Self::Manufacturing(value),
340            0b1101 => Self::Development(value),
341            0b1110 => Self::Selftest(value),
342            _ => Self::Reserved2(value),
343        }
344    }
345}
346
347fn bcd_hex_digits_to_u32(digits: [u8; 4]) -> Result<u32, ApplicationLayerError> {
348    let mut number = 0u32;
349
350    for &digit in digits.iter().rev() {
351        let lower = digit & 0x0F;
352        let upper = digit >> 4;
353        if lower > 9 || upper > 9 {
354            return Err(ApplicationLayerError::IdentificationNumberError { digits, number });
355        }
356        number = number * 100 + (u32::from(upper) * 10) + u32::from(lower);
357    }
358
359    Ok(number)
360}
361#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
362#[derive(Debug, PartialEq)]
363#[cfg_attr(feature = "defmt", derive(defmt::Format))]
364pub struct Counter {
365    count: u32,
366}
367
368#[cfg(feature = "std")]
369impl fmt::Display for Counter {
370    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371        write!(f, "{:08}", self.count)
372    }
373}
374#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
375#[derive(Debug, PartialEq)]
376#[cfg_attr(feature = "defmt", derive(defmt::Format))]
377pub struct IdentificationNumber {
378    pub number: u32,
379}
380
381#[cfg(feature = "std")]
382impl fmt::Display for IdentificationNumber {
383    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384        write!(f, "{:08}", self.number)
385    }
386}
387
388impl From<IdentificationNumber> for u32 {
389    fn from(id: IdentificationNumber) -> Self {
390        id.number
391    }
392}
393
394impl IdentificationNumber {
395    pub fn from_bcd_hex_digits(digits: [u8; 4]) -> Result<Self, ApplicationLayerError> {
396        let number = bcd_hex_digits_to_u32(digits)?;
397        Ok(Self { number })
398    }
399}
400
401impl Counter {
402    pub fn from_bcd_hex_digits(digits: [u8; 4]) -> Result<Self, ApplicationLayerError> {
403        let count = bcd_hex_digits_to_u32(digits)?;
404        Ok(Self { count })
405    }
406}
407
408#[derive(Debug, PartialEq)]
409#[allow(dead_code)]
410#[cfg_attr(feature = "defmt", derive(defmt::Format))]
411pub struct FixedDataHeder {
412    identification_number: IdentificationNumber,
413    manufacturer_code: ManufacturerCode,
414    version: u8,
415    medium: Medium,
416    access_number: u8,
417    status: StatusField,
418    signature: u16,
419}
420#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
421#[allow(clippy::large_enum_variant)]
422#[derive(Debug, PartialEq)]
423#[cfg_attr(feature = "defmt", derive(defmt::Format))]
424pub enum UserDataBlock<'a> {
425    ResetAtApplicationLevel {
426        subcode: ApplicationResetSubcode,
427    },
428    FixedDataStructure {
429        identification_number: IdentificationNumber,
430        access_number: u8,
431        status: StatusField,
432        medium_ad_unit: u16,
433        counter1: Counter,
434        counter2: Counter,
435    },
436    VariableDataStructure {
437        fixed_data_header: FixedDataHeader,
438        #[cfg_attr(feature = "serde", serde(skip_serializing))]
439        variable_data_block: &'a [u8],
440    },
441}
442#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
443#[derive(Debug, PartialEq)]
444#[cfg_attr(feature = "defmt", derive(defmt::Format))]
445pub enum Medium {
446    Other,
447    Oil,
448    Electricity,
449    Gas,
450    Heat,
451    Steam,
452    HotWater,
453    Water,
454    HeatCostAllocator,
455    Reserved,
456    GasMode2,
457    HeatMode2,
458    HotWaterMode2,
459    WaterMode2,
460    HeatCostAllocator2,
461    ReservedMode2,
462    Unknown,
463    ColdWater,
464    DualWater,
465    Pressure,
466    ADConverter,
467}
468
469impl Medium {
470    #[must_use]
471    pub const fn from_byte(byte: u8) -> Self {
472        match byte {
473            0x00 => Self::Other,
474            0x01 => Self::Oil,
475            0x02 => Self::Electricity,
476            0x03 => Self::Gas,
477            0x04 => Self::Heat,
478            0x05 => Self::Steam,
479            0x06 => Self::HotWater,
480            0x07 => Self::Water,
481            0x08 => Self::HeatCostAllocator,
482            0x09 => Self::Reserved, // Note: Reserved for 0x09 from the first set
483            0x0A => Self::GasMode2,
484            0x0B => Self::HeatMode2,
485            0x0C => Self::HotWaterMode2,
486            0x0D => Self::WaterMode2,
487            0x0E => Self::HeatCostAllocator2,
488            0x0F => Self::ReservedMode2,
489            // Unique mediums from the second set
490            0x10 => Self::Reserved, // Reserved range
491            0x11 => Self::Reserved, // Reserved range
492            0x12 => Self::Reserved, // Reserved range
493            0x13 => Self::Reserved, // Reserved range
494            0x14 => Self::Reserved, // Reserved range
495            0x15 => Self::Reserved, // Reserved range
496            0x16 => Self::ColdWater,
497            0x17 => Self::DualWater,
498            0x18 => Self::Pressure,
499            0x19 => Self::ADConverter,
500            // Extended reserved range from the second set
501            0x20..=0xFF => Self::Reserved,
502            _ => Self::Unknown,
503        }
504    }
505}
506
507#[cfg(feature = "std")]
508impl fmt::Display for Medium {
509    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
510        let medium = match self {
511            Self::Other => "Other",
512            Self::Oil => "Oil",
513            Self::Electricity => "Electricity",
514            Self::Gas => "Gas",
515            Self::Heat => "Heat",
516            Self::Steam => "Steam",
517            Self::HotWater => "Hot water",
518            Self::Water => "Water",
519            Self::HeatCostAllocator => "Heat Cost Allocator",
520            Self::Reserved => "Reserved",
521            Self::GasMode2 => "Gas Mode 2",
522            Self::HeatMode2 => "Heat Mode 2",
523            Self::HotWaterMode2 => "Hot Water Mode 2",
524            Self::WaterMode2 => "Water Mode 2",
525            Self::HeatCostAllocator2 => "Heat Cost Allocator 2",
526            Self::ReservedMode2 => "Reserved",
527            Self::Unknown => "Unknown",
528            Self::ColdWater => "Cold Water",
529            Self::DualWater => "Dual Water",
530            Self::Pressure => "Pressure",
531            Self::ADConverter => "AD Converter",
532        };
533        write!(f, "{}", medium)
534    }
535}
536#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
537#[derive(Debug, PartialEq)]
538#[cfg_attr(feature = "defmt", derive(defmt::Format))]
539pub struct FixedDataHeader {
540    pub identification_number: IdentificationNumber,
541    pub manufacturer: Result<ManufacturerCode, ApplicationLayerError>,
542    pub version: u8,
543    pub medium: Medium,
544    pub access_number: u8,
545    pub status: StatusField,
546    pub signature: u16,
547    pub lsb_order: bool,
548}
549#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
550#[derive(Debug, PartialEq)]
551#[cfg_attr(feature = "defmt", derive(defmt::Format))]
552pub struct ManufacturerCode {
553    pub code: [char; 3],
554}
555
556impl ManufacturerCode {
557    pub const fn from_id(id: u16) -> Result<Self, ApplicationLayerError> {
558        let first_letter = ((id / (32 * 32)) + 64) as u8 as char;
559        let second_letter = (((id % (32 * 32)) / 32) + 64) as u8 as char;
560        let third_letter = ((id % 32) + 64) as u8 as char;
561
562        if first_letter.is_ascii_uppercase()
563            && second_letter.is_ascii_uppercase()
564            && third_letter.is_ascii_uppercase()
565        {
566            Ok(Self {
567                code: [first_letter, second_letter, third_letter],
568            })
569        } else {
570            Err(ApplicationLayerError::InvalidManufacturerCode { code: id })
571        }
572    }
573}
574
575#[cfg(feature = "std")]
576impl fmt::Display for ManufacturerCode {
577    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578        write!(f, "{}{}{}", self.code[0], self.code[1], self.code[2])
579    }
580}
581
582#[derive(Debug, PartialEq)]
583#[cfg_attr(feature = "defmt", derive(defmt::Format))]
584pub struct MeasuredMedium {
585    pub medium: Medium,
586}
587
588impl MeasuredMedium {
589    #[must_use]
590    pub const fn new(byte: u8) -> Self {
591        Self {
592            medium: Medium::from_byte(byte),
593        }
594    }
595}
596
597impl<'a> TryFrom<&'a [u8]> for UserDataBlock<'a> {
598    type Error = ApplicationLayerError;
599
600    fn try_from(data: &'a [u8]) -> Result<Self, ApplicationLayerError> {
601        if data.is_empty() {
602            return Err(ApplicationLayerError::MissingControlInformation);
603        }
604
605        let control_information = ControlInformation::from(
606            *data
607                .first()
608                .ok_or(ApplicationLayerError::InsufficientData)?,
609        )?;
610
611        match control_information {
612            ControlInformation::ResetAtApplicationLevel => {
613                let subcode = ApplicationResetSubcode::from(
614                    *data.get(1).ok_or(ApplicationLayerError::InsufficientData)?,
615                );
616                Ok(UserDataBlock::ResetAtApplicationLevel { subcode })
617            }
618            ControlInformation::SendData => todo!(),
619            ControlInformation::SelectSlave => todo!(),
620            ControlInformation::SynchronizeSlave => todo!(),
621            ControlInformation::SetBaudRate300 => todo!(),
622            ControlInformation::SetBaudRate600 => todo!(),
623            ControlInformation::SetBaudRate1200 => todo!(),
624            ControlInformation::SetBaudRate2400 => todo!(),
625            ControlInformation::SetBaudRate4800 => todo!(),
626            ControlInformation::SetBaudRate9600 => todo!(),
627            ControlInformation::SetBaudRate19200 => todo!(),
628            ControlInformation::SetBaudRate38400 => todo!(),
629            ControlInformation::OutputRAMContent => todo!(),
630            ControlInformation::WriteRAMContent => todo!(),
631            ControlInformation::StartCalibrationTestMode => todo!(),
632            ControlInformation::ReadEEPROM => todo!(),
633            ControlInformation::StartSoftwareTest => todo!(),
634            ControlInformation::HashProcedure(_) => todo!(),
635            ControlInformation::SendErrorStatus => todo!(),
636            ControlInformation::SendAlarmStatus => todo!(),
637            ControlInformation::ResponseWithVariableDataStructure { lsb_order } => {
638                let mut iter = data.iter().skip(1);
639                let mut identification_number_bytes = [
640                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
641                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
642                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
643                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
644                ];
645                if lsb_order {
646                    identification_number_bytes.reverse();
647                }
648
649                Ok(UserDataBlock::VariableDataStructure {
650                    fixed_data_header: FixedDataHeader {
651                        identification_number: IdentificationNumber::from_bcd_hex_digits(
652                            identification_number_bytes,
653                        )?,
654                        manufacturer: ManufacturerCode::from_id(u16::from_le_bytes([
655                            *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
656                            *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
657                        ])),
658                        version: *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
659                        medium: MeasuredMedium::new(
660                            *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
661                        )
662                        .medium,
663                        access_number: *iter
664                            .next()
665                            .ok_or(ApplicationLayerError::InsufficientData)?,
666                        status: StatusField::from_bits_truncate(
667                            *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
668                        ),
669                        signature: u16::from_le_bytes([
670                            *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
671                            *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
672                        ]),
673                        lsb_order,
674                    },
675                    variable_data_block: data
676                        .get(13..data.len())
677                        .ok_or(ApplicationLayerError::InsufficientData)?,
678                })
679            }
680            ControlInformation::ResponseWithFixedDataStructure => {
681                let mut iter = data.iter().skip(1);
682                let identification_number = IdentificationNumber::from_bcd_hex_digits([
683                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
684                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
685                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
686                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
687                ])?;
688
689                let access_number = *iter.next().ok_or(ApplicationLayerError::InsufficientData)?;
690
691                let status = StatusField::from_bits_truncate(
692                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
693                );
694                let medium_and_unit = u16::from_be_bytes([
695                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
696                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
697                ]);
698                let counter1 = Counter::from_bcd_hex_digits([
699                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
700                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
701                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
702                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
703                ])?;
704                let counter2 = Counter::from_bcd_hex_digits([
705                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
706                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
707                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
708                    *iter.next().ok_or(ApplicationLayerError::InsufficientData)?,
709                ])?;
710                Ok(UserDataBlock::FixedDataStructure {
711                    identification_number,
712                    access_number,
713                    status,
714                    medium_ad_unit: medium_and_unit,
715                    counter1,
716                    counter2,
717                })
718            }
719        }
720    }
721}
722
723#[cfg(all(test, feature = "std"))]
724mod tests {
725
726    use super::*;
727
728    #[test]
729    fn test_control_information() {
730        assert_eq!(
731            ControlInformation::from(0x50),
732            Ok(ControlInformation::ResetAtApplicationLevel)
733        );
734        assert_eq!(
735            ControlInformation::from(0x51),
736            Ok(ControlInformation::SendData)
737        );
738        assert_eq!(
739            ControlInformation::from(0x52),
740            Ok(ControlInformation::SelectSlave)
741        );
742        assert_eq!(
743            ControlInformation::from(0x54),
744            Ok(ControlInformation::SynchronizeSlave)
745        );
746        assert_eq!(
747            ControlInformation::from(0xB8),
748            Ok(ControlInformation::SetBaudRate300)
749        );
750        assert_eq!(
751            ControlInformation::from(0xB9),
752            Ok(ControlInformation::SetBaudRate600)
753        );
754        assert_eq!(
755            ControlInformation::from(0xBA),
756            Ok(ControlInformation::SetBaudRate1200)
757        );
758        assert_eq!(
759            ControlInformation::from(0xBB),
760            Ok(ControlInformation::SetBaudRate2400)
761        );
762        assert_eq!(
763            ControlInformation::from(0xBC),
764            Ok(ControlInformation::SetBaudRate4800)
765        );
766        assert_eq!(
767            ControlInformation::from(0xBD),
768            Ok(ControlInformation::SetBaudRate9600)
769        );
770        assert_eq!(
771            ControlInformation::from(0xBE),
772            Ok(ControlInformation::SetBaudRate19200)
773        );
774        assert_eq!(
775            ControlInformation::from(0xBF),
776            Ok(ControlInformation::SetBaudRate38400)
777        );
778        assert_eq!(
779            ControlInformation::from(0xB1),
780            Ok(ControlInformation::OutputRAMContent)
781        );
782        assert_eq!(
783            ControlInformation::from(0xB2),
784            Ok(ControlInformation::WriteRAMContent)
785        );
786        assert_eq!(
787            ControlInformation::from(0xB3),
788            Ok(ControlInformation::StartCalibrationTestMode)
789        );
790        assert_eq!(
791            ControlInformation::from(0xB4),
792            Ok(ControlInformation::ReadEEPROM)
793        );
794        assert_eq!(
795            ControlInformation::from(0xB6),
796            Ok(ControlInformation::StartSoftwareTest)
797        );
798        assert_eq!(
799            ControlInformation::from(0x90),
800            Ok(ControlInformation::HashProcedure(0,))
801        );
802        assert_eq!(
803            ControlInformation::from(0x91),
804            Ok(ControlInformation::HashProcedure(1,))
805        );
806    }
807
808    #[test]
809    fn test_reset_subcode() {
810        // Application layer of frame | 68 04 04 68 | 53 FE 50 | 10 | B1 16
811        let data = [0x50, 0x10];
812        let result = UserDataBlock::try_from(data.as_slice());
813        assert_eq!(
814            result,
815            Ok(UserDataBlock::ResetAtApplicationLevel {
816                subcode: ApplicationResetSubcode::All(0x10)
817            })
818        );
819    }
820
821    #[test]
822    fn test_identification_number() -> Result<(), ApplicationLayerError> {
823        let data = [0x78, 0x56, 0x34, 0x12];
824        let result = IdentificationNumber::from_bcd_hex_digits(data)?;
825        assert_eq!(result, IdentificationNumber { number: 12345678 });
826        Ok(())
827    }
828
829    #[test]
830    fn test_fixed_data_structure() {
831        let data = [
832            0x73, 0x78, 0x56, 0x34, 0x12, 0x0A, 0x00, 0xE9, 0x7E, 0x01, 0x00, 0x00, 0x00, 0x35,
833            0x01, 0x00, 0x00,
834        ];
835
836        let result = UserDataBlock::try_from(data.as_slice());
837
838        assert_eq!(
839            result,
840            Ok(UserDataBlock::FixedDataStructure {
841                identification_number: IdentificationNumber { number: 12345678 },
842                access_number: 0x0A,
843                status: StatusField::from_bits_truncate(0x00),
844                medium_ad_unit: 0xE97E,
845                counter1: Counter { count: 1 },
846                counter2: Counter { count: 135 },
847            })
848        );
849    }
850
851    #[test]
852    fn test_manufacturer_code() -> Result<(), ApplicationLayerError> {
853        let code = ManufacturerCode::from_id(0x1ee6)?;
854        assert_eq!(
855            code,
856            ManufacturerCode {
857                code: ['G', 'W', 'F']
858            }
859        );
860        Ok(())
861    }
862
863    #[test]
864    fn test_lsb_frame() {
865        use crate::frames::Frame;
866        use crate::user_data::data_information::DataType;
867
868        let lsb_frame: &[u8] = &[
869            0x68, 0x64, 0x64, 0x68, 0x8, 0x7f, 0x76, 0x9, 0x67, 0x1, 0x6, 0x0, 0x0, 0x51, 0x4,
870            0x50, 0x0, 0x0, 0x0, 0x2, 0x6c, 0x38, 0x1c, 0xc, 0xf, 0x0, 0x80, 0x87, 0x32, 0x8c,
871            0x20, 0xf, 0x0, 0x0, 0x0, 0x0, 0xc, 0x14, 0x13, 0x32, 0x82, 0x58, 0xbc, 0x10, 0x15,
872            0x0, 0x25, 0x81, 0x25, 0x8c, 0x20, 0x13, 0x0, 0x0, 0x0, 0x0, 0x8c, 0x30, 0x13, 0x0,
873            0x0, 0x1, 0x61, 0x8c, 0x40, 0x13, 0x0, 0x0, 0x16, 0x88, 0xa, 0x3c, 0x1, 0x10, 0xa,
874            0x2d, 0x0, 0x80, 0xa, 0x5a, 0x7, 0x18, 0xa, 0x5e, 0x6, 0x53, 0xc, 0x22, 0x0, 0x16, 0x7,
875            0x26, 0x3c, 0x22, 0x0, 0x0, 0x33, 0x81, 0x4, 0x7e, 0x0, 0x0, 0x67, 0xc, 0xc, 0x16,
876        ];
877        let non_lsb_frame: &[u8] = &[
878            0x68, 0xc7, 0xc7, 0x68, 0x8, 0x38, 0x72, 0x56, 0x73, 0x23, 0x72, 0x2d, 0x2c, 0x34, 0x4,
879            0x87, 0x0, 0x0, 0x0, 0x4, 0xf, 0x7f, 0x1c, 0x1, 0x0, 0x4, 0xff, 0x7, 0x8a, 0xad, 0x8,
880            0x0, 0x4, 0xff, 0x8, 0x6, 0xfe, 0x5, 0x0, 0x4, 0x14, 0x4e, 0x55, 0xb, 0x0, 0x84, 0x40,
881            0x14, 0x0, 0x0, 0x0, 0x0, 0x84, 0x80, 0x40, 0x14, 0x0, 0x0, 0x0, 0x0, 0x4, 0x22, 0x76,
882            0x7f, 0x0, 0x0, 0x34, 0x22, 0x8b, 0x2c, 0x0, 0x0, 0x2, 0x59, 0x61, 0x1b, 0x2, 0x5d,
883            0x5f, 0x10, 0x2, 0x61, 0x2, 0xb, 0x4, 0x2d, 0x55, 0x0, 0x0, 0x0, 0x14, 0x2d, 0x83, 0x0,
884            0x0, 0x0, 0x4, 0x3b, 0x6, 0x1, 0x0, 0x0, 0x14, 0x3b, 0xaa, 0x1, 0x0, 0x0, 0x4, 0xff,
885            0x22, 0x0, 0x0, 0x0, 0x0, 0x4, 0x6d, 0x6, 0x2c, 0x1f, 0x3a, 0x44, 0xf, 0xcf, 0x11, 0x1,
886            0x0, 0x44, 0xff, 0x7, 0xb, 0x69, 0x8, 0x0, 0x44, 0xff, 0x8, 0x54, 0xd3, 0x5, 0x0, 0x44,
887            0x14, 0x11, 0xf3, 0xa, 0x0, 0xc4, 0x40, 0x14, 0x0, 0x0, 0x0, 0x0, 0xc4, 0x80, 0x40,
888            0x14, 0x0, 0x0, 0x0, 0x0, 0x54, 0x2d, 0x3a, 0x0, 0x0, 0x0, 0x54, 0x3b, 0x28, 0x1, 0x0,
889            0x0, 0x42, 0x6c, 0x1, 0x3a, 0x2, 0xff, 0x1a, 0x1, 0x1a, 0xc, 0x78, 0x56, 0x73, 0x23,
890            0x72, 0x4, 0xff, 0x16, 0xe6, 0x84, 0x1e, 0x0, 0x4, 0xff, 0x17, 0xc1, 0xd5, 0xb4, 0x0,
891            0x12, 0x16,
892        ];
893
894        let frames = [
895            (lsb_frame, 9670106, Some(DataType::Number(808732.0))),
896            (non_lsb_frame, 72237356, Some(DataType::Number(568714.0))),
897        ];
898
899        for (frame, expected_iden_nr, data_record_value) in frames {
900            let frame = Frame::try_from(frame).unwrap();
901
902            if let Frame::LongFrame {
903                function: _,
904                address: _,
905                data,
906            } = frame
907            {
908                let user_data_block = UserDataBlock::try_from(data).unwrap();
909                if let UserDataBlock::VariableDataStructure {
910                    fixed_data_header,
911                    variable_data_block,
912                } = user_data_block
913                {
914                    assert_eq!(
915                        fixed_data_header.identification_number.number,
916                        expected_iden_nr
917                    );
918
919                    let mut data_records =
920                        DataRecords::try_from((variable_data_block, &fixed_data_header))
921                            .unwrap()
922                            .flatten();
923                    data_records.next().unwrap();
924                    assert_eq!(data_records.next().unwrap().data.value, data_record_value);
925                } else {
926                    panic!("UserDataBlock is not a variable data structure");
927                }
928            } else {
929                panic!("Frame is not a long frame");
930            }
931        }
932    }
933
934    #[test]
935    fn test_manufacturer_specific_data() {
936        use crate::frames::Frame;
937        use crate::user_data::data_information::DataType;
938
939        let manufacturer_specific_data_frame: &[u8] = &[
940            0x68, 0x55, 0x55, 0x68, 0x8, 0x1e, 0x72, 0x34, 0x35, 0x58, 0x12, 0x92, 0x26, 0x18, 0x4,
941            0x14, 0x0, 0x0, 0x0, 0xc, 0x78, 0x34, 0x35, 0x58, 0x12, 0x4, 0xe, 0x57, 0x64, 0x3, 0x0,
942            0xc, 0x14, 0x73, 0x58, 0x44, 0x0, 0xb, 0x2d, 0x6, 0x0, 0x0, 0xb, 0x3b, 0x55, 0x0, 0x0,
943            0xa, 0x5a, 0x87, 0x6, 0xa, 0x5e, 0x77, 0x5, 0xb, 0x61, 0x1, 0x11, 0x0, 0x4, 0x6d, 0x10,
944            0x2, 0x4, 0x3c, 0x2, 0x27, 0x79, 0x11, 0x9, 0xfd, 0xe, 0x6, 0x9, 0xfd, 0xf, 0x6, 0x8c,
945            0xc0, 0x0, 0x15, 0x71, 0x25, 0x0, 0x0, 0xf, 0x0, 0x0, 0x86, 0x16,
946        ];
947
948        let frame = Frame::try_from(manufacturer_specific_data_frame).unwrap();
949
950        if let Frame::LongFrame {
951            function: _,
952            address: _,
953            data,
954        } = frame
955        {
956            let user_data_block = UserDataBlock::try_from(data).unwrap();
957            if let UserDataBlock::VariableDataStructure {
958                fixed_data_header,
959                variable_data_block,
960            } = user_data_block
961            {
962                let mut data_records: Vec<_> =
963                    DataRecords::try_from((variable_data_block, &fixed_data_header))
964                        .unwrap()
965                        .flatten()
966                        .collect();
967
968                assert_eq!(data_records.len(), 14);
969
970                assert_eq!(
971                    data_records.pop().unwrap().data.value,
972                    Some(DataType::ManufacturerSpecific(&[15, 0, 0]))
973                );
974                assert_eq!(
975                    data_records.pop().unwrap().data.value,
976                    Some(DataType::Number(2571.0))
977                );
978            }
979        }
980    }
981
982    #[test]
983    fn real32bit() {
984        use crate::frames::Frame;
985        use crate::user_data::data_information::DataType;
986        use crate::user_data::value_information::ValueLabel;
987
988        let real32bit: &[u8] = &[
989            0x68, 0xa7, 0xa7, 0x68, 0x8, 0x4d, 0x72, 0x82, 0x4, 0x75, 0x30, 0xee, 0x4d, 0x19, 0x4,
990            0xc2, 0x0, 0x0, 0x0, 0x4, 0xe, 0x1b, 0xe, 0x0, 0x0, 0x84, 0xa, 0xe, 0x4c, 0x6, 0x0,
991            0x0, 0x4, 0x13, 0x7, 0x81, 0x0, 0x0, 0x84, 0xa, 0x13, 0x9d, 0x37, 0x0, 0x0, 0xb, 0xfd,
992            0xf, 0x0, 0x7, 0x1, 0xa, 0xfd, 0xd, 0x0, 0x11, 0x8c, 0x40, 0x79, 0x1, 0x0, 0x0, 0x0,
993            0x84, 0x40, 0x14, 0x31, 0x5, 0x0, 0x0, 0x84, 0x4a, 0x14, 0xfd, 0x4, 0x0, 0x0, 0x8c,
994            0x80, 0x40, 0x79, 0x2, 0x0, 0x0, 0x0, 0x84, 0x80, 0x40, 0x14, 0x27, 0x50, 0x0, 0x0,
995            0x84, 0x8a, 0x40, 0x14, 0x8, 0x31, 0x0, 0x0, 0x5, 0xff, 0x1, 0xdf, 0xa3, 0xb1, 0x3e,
996            0x5, 0xff, 0x2, 0xa8, 0x59, 0x6b, 0x3f, 0xc, 0x78, 0x82, 0x4, 0x75, 0x30, 0x4, 0x6d,
997            0x5, 0xb, 0x2f, 0x31, 0x82, 0xa, 0x6c, 0xe1, 0xf1, 0x5, 0x5b, 0x40, 0x7a, 0x63, 0x42,
998            0x5, 0x5f, 0x80, 0xc3, 0x25, 0x42, 0x5, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x5, 0x2b, 0x0, 0x0,
999            0x0, 0x0, 0x1, 0xff, 0x2b, 0x0, 0x3, 0x22, 0x17, 0x3b, 0x0, 0x2, 0xff, 0x2c, 0x0, 0x0,
1000            0x1f, 0xa4, 0x16,
1001        ];
1002
1003        let frame = Frame::try_from(real32bit).unwrap();
1004
1005        if let Frame::LongFrame {
1006            function: _,
1007            address: _,
1008            data,
1009        } = frame
1010        {
1011            let user_data_block = UserDataBlock::try_from(data).unwrap();
1012            if let UserDataBlock::VariableDataStructure {
1013                fixed_data_header,
1014                variable_data_block,
1015            } = user_data_block
1016            {
1017                let data_records: Vec<DataRecord> =
1018                    DataRecords::try_from((variable_data_block, &fixed_data_header))
1019                        .unwrap()
1020                        .flatten()
1021                        .collect();
1022
1023                assert_eq!(data_records.len(), 24);
1024
1025                for data_record in data_records {
1026                    let labels = data_record
1027                        .data_record_header
1028                        .processed_data_record_header
1029                        .value_information
1030                        .as_ref()
1031                        .unwrap()
1032                        .labels
1033                        .clone();
1034                    if labels.contains(&ValueLabel::ReturnTemperature) {
1035                        assert_eq!(
1036                            data_record.data.value,
1037                            Some(DataType::Number(41.44091796875))
1038                        );
1039                    }
1040                    if labels.contains(&ValueLabel::FlowTemperature) {
1041                        assert_eq!(
1042                            data_record.data.value,
1043                            Some(DataType::Number(56.869384765625))
1044                        );
1045                    }
1046                }
1047            }
1048        }
1049    }
1050}