m_bus_parser/user_data/
data_information.rs

1use super::data_information::{self};
2use super::variable_user_data::DataRecordError;
3use super::FixedDataHeader;
4
5#[cfg_attr(feature = "serde", derive(serde::Serialize))]
6#[derive(Debug, PartialEq, Clone)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub struct DataInformationBlock<'a> {
9    pub data_information_field: DataInformationField,
10    pub data_information_field_extension: Option<DataInformationFieldExtensions<'a>>,
11}
12
13impl DataInformationBlock<'_> {
14    #[must_use]
15    pub fn get_size(&self) -> usize {
16        let mut size = 1;
17        if let Some(dife) = &self.data_information_field_extension {
18            size += dife.len();
19        }
20        size
21    }
22}
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24#[derive(Debug, PartialEq, Clone)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub struct DataInformationField {
27    pub data: u8,
28}
29
30impl From<data_information::DataInformationError> for DataRecordError {
31    fn from(error: data_information::DataInformationError) -> Self {
32        Self::DataInformationError(error)
33    }
34}
35
36impl From<u8> for DataInformationField {
37    fn from(data: u8) -> Self {
38        Self { data }
39    }
40}
41
42impl From<u8> for DataInformationFieldExtension {
43    fn from(data: u8) -> Self {
44        Self { data }
45    }
46}
47
48#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
49#[derive(Debug, PartialEq)]
50#[repr(transparent)]
51pub struct DataInformationFieldExtension {
52    pub data: u8,
53}
54
55#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56#[derive(Clone, Debug, PartialEq)]
57#[cfg_attr(feature = "defmt", derive(defmt::Format))]
58pub struct DataInformationFieldExtensions<'a>(&'a [u8]);
59impl<'a> DataInformationFieldExtensions<'a> {
60    const fn new(data: &'a [u8]) -> Self {
61        Self(data)
62    }
63}
64
65impl Iterator for DataInformationFieldExtensions<'_> {
66    type Item = DataInformationFieldExtension;
67    fn next(&mut self) -> Option<Self::Item> {
68        let (head, tail) = self.0.split_first()?;
69        self.0 = tail;
70        Some(DataInformationFieldExtension { data: *head })
71    }
72    fn size_hint(&self) -> (usize, Option<usize>) {
73        (self.0.len(), Some(self.0.len()))
74    }
75}
76impl ExactSizeIterator for DataInformationFieldExtensions<'_> {}
77impl DoubleEndedIterator for DataInformationFieldExtensions<'_> {
78    fn next_back(&mut self) -> Option<Self::Item> {
79        let (end, start) = self.0.split_last()?;
80        self.0 = start;
81        Some(DataInformationFieldExtension { data: *end })
82    }
83}
84
85impl<'a> TryFrom<&'a [u8]> for DataInformationBlock<'a> {
86    type Error = DataInformationError;
87
88    fn try_from(data: &'a [u8]) -> Result<Self, DataInformationError> {
89        let Some((dif_byte, data)) = data.split_first() else {
90            return Err(DataInformationError::NoData);
91        };
92        let dif = DataInformationField::from(*dif_byte);
93
94        let length = data.iter().take_while(|&&u8| u8 & 0x80 != 0).count();
95        let offset = length + 1;
96        match () {
97            () if dif.has_extension() && offset > MAXIMUM_DATA_INFORMATION_SIZE => {
98                Err(DataInformationError::DataTooLong)
99            }
100            () if dif.has_extension() && offset > data.len() => {
101                Err(DataInformationError::DataTooShort)
102            }
103            () if dif.has_extension() => Ok(DataInformationBlock {
104                data_information_field: dif,
105                data_information_field_extension: Some(DataInformationFieldExtensions::new(
106                    data.get(..offset)
107                        .ok_or(DataInformationError::DataTooShort)?,
108                )),
109            }),
110            () => Ok(DataInformationBlock {
111                data_information_field: dif,
112                data_information_field_extension: None,
113            }),
114        }
115    }
116}
117
118impl DataInformationField {
119    const fn has_extension(&self) -> bool {
120        self.data & 0x80 != 0
121    }
122}
123
124impl DataInformationFieldExtension {
125    const fn special_function(&self) -> SpecialFunctions {
126        match self.data {
127            0x0F => SpecialFunctions::ManufacturerSpecific,
128            0x1F => SpecialFunctions::MoreRecordsFollow,
129            0x2F => SpecialFunctions::IdleFiller,
130            0x7F => SpecialFunctions::GlobalReadoutRequest,
131            _ => SpecialFunctions::Reserved,
132        }
133    }
134}
135#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
136#[derive(Debug, Clone, PartialEq)]
137#[cfg_attr(feature = "defmt", derive(defmt::Format))]
138pub struct DataInformation {
139    pub storage_number: u64,
140    pub tariff: u64,
141    pub device: u64,
142    pub function_field: FunctionField,
143    pub data_field_coding: DataFieldCoding,
144    pub data_information_extension: Option<DataInformationExtensionField>,
145    pub size: usize,
146}
147
148#[cfg(feature = "std")]
149impl std::fmt::Display for DataInformation {
150    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151        write!(
152            f,
153            "{},{},{}",
154            self.storage_number, self.function_field, self.data_field_coding
155        )
156    }
157}
158
159const MAXIMUM_DATA_INFORMATION_SIZE: usize = 11;
160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
161#[derive(Debug, Clone, PartialEq)]
162#[cfg_attr(feature = "defmt", derive(defmt::Format))]
163pub struct DataInformationExtensionField {}
164
165#[derive(Debug, Clone, PartialEq)]
166#[cfg_attr(feature = "defmt", derive(defmt::Format))]
167pub enum DataInformationError {
168    NoData,
169    DataTooLong,
170    DataTooShort,
171    InvalidValueInformation,
172}
173
174impl TryFrom<&DataInformationBlock<'_>> for DataInformation {
175    type Error = DataInformationError;
176
177    fn try_from(
178        data_information_block: &DataInformationBlock,
179    ) -> Result<Self, DataInformationError> {
180        let dif = data_information_block.data_information_field.data;
181        let possible_difes = &data_information_block.data_information_field_extension;
182        let mut storage_number = u64::from((dif & 0b0100_0000) >> 6);
183
184        let mut extension_bit = dif & 0x80 != 0;
185        let mut extension_index = 1;
186        let mut tariff = 0;
187        let mut device = 0;
188        let mut first_dife = None;
189
190        if let Some(difes) = possible_difes {
191            first_dife = difes.clone().next();
192            let mut tariff_index = 0;
193            for (device_index, dife) in difes.clone().enumerate() {
194                if extension_index > MAXIMUM_DATA_INFORMATION_SIZE {
195                    return Err(DataInformationError::DataTooLong);
196                }
197                let dife = dife.data;
198                storage_number += u64::from(dife & 0x0f) << ((extension_index * 4) + 1);
199                tariff |= u64::from((dife & 0x30) >> 4) << (tariff_index);
200                tariff_index += 2;
201                device |= u64::from((dife & 0x40) >> 6) << device_index;
202                extension_bit = dife & 0x80 != 0;
203                extension_index += 1;
204            }
205        }
206
207        let function_field = match (dif & 0b0011_0000) >> 4 {
208            0b00 => FunctionField::InstantaneousValue,
209            0b01 => FunctionField::MaximumValue,
210            0b10 => FunctionField::MinimumValue,
211            _ => FunctionField::ValueDuringErrorState,
212        };
213        let data_field_coding = match dif & 0b0000_1111 {
214            0b0000 => DataFieldCoding::NoData,
215            0b0001 => DataFieldCoding::Integer8Bit,
216            0b0010 => DataFieldCoding::Integer16Bit,
217            0b0011 => DataFieldCoding::Integer24Bit,
218            0b0100 => DataFieldCoding::Integer32Bit,
219            0b0101 => DataFieldCoding::Real32Bit,
220            0b0110 => DataFieldCoding::Integer48Bit,
221            0b0111 => DataFieldCoding::Integer64Bit,
222            0b1000 => DataFieldCoding::SelectionForReadout,
223            0b1001 => DataFieldCoding::BCD2Digit,
224            0b1010 => DataFieldCoding::BCD4Digit,
225            0b1011 => DataFieldCoding::BCD6Digit,
226            0b1100 => DataFieldCoding::BCD8Digit,
227            0b1101 => DataFieldCoding::VariableLength,
228            0b1110 => DataFieldCoding::BCDDigit12,
229            0b1111 => DataFieldCoding::SpecialFunctions(
230                first_dife
231                    .ok_or(DataInformationError::DataTooShort)?
232                    .special_function(),
233            ),
234            _ => unreachable!(), // This case should never occur due to the 4-bit width
235        };
236
237        Ok(Self {
238            storage_number,
239            tariff,
240            device,
241            function_field,
242            data_field_coding,
243            data_information_extension: if extension_bit {
244                Some(DataInformationExtensionField {})
245            } else {
246                None
247            },
248            size: extension_index,
249        })
250    }
251}
252
253#[cfg_attr(feature = "serde", derive(serde::Serialize))]
254#[cfg_attr(feature = "serde", serde(into = "String"))]
255#[derive(Clone, Copy, Debug, PartialEq, Eq)]
256#[cfg_attr(feature = "defmt", derive(defmt::Format))]
257pub struct TextUnit<'a>(&'a [u8]);
258impl<'a> TextUnit<'a> {
259    pub const fn new(input: &'a [u8]) -> Self {
260        Self(input)
261    }
262}
263
264impl PartialEq<str> for TextUnit<'_> {
265    fn eq(&self, other: &str) -> bool {
266        self.0.iter().eq(other.as_bytes().iter().rev())
267    }
268}
269
270#[cfg(feature = "std")]
271impl std::fmt::Display for TextUnit<'_> {
272    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273        let value: Vec<u8> = self.0.iter().copied().rev().collect();
274        let value = String::from_utf8(value).unwrap_or_default();
275        write!(f, "{}", value)
276    }
277}
278
279#[cfg(any(feature = "serde", feature = "std"))]
280impl From<TextUnit<'_>> for String {
281    fn from(value: TextUnit<'_>) -> Self {
282        let value: Vec<u8> = value.0.iter().copied().rev().collect();
283        String::from_utf8(value).unwrap_or_default()
284    }
285}
286
287#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
288#[derive(Debug, PartialEq, Clone)]
289#[cfg_attr(feature = "defmt", derive(defmt::Format))]
290pub enum Month {
291    January,
292    February,
293    March,
294    April,
295    May,
296    June,
297    July,
298    August,
299    September,
300    October,
301    November,
302    December,
303}
304
305#[cfg(feature = "std")]
306impl std::fmt::Display for Month {
307    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
308        match self {
309            Month::January => write!(f, "Jan"),
310            Month::February => write!(f, "Feb"),
311            Month::March => write!(f, "Mar"),
312            Month::April => write!(f, "Apr"),
313            Month::May => write!(f, "May"),
314            Month::June => write!(f, "Jun"),
315            Month::July => write!(f, "Jul"),
316            Month::August => write!(f, "Aug"),
317            Month::September => write!(f, "Sep"),
318            Month::October => write!(f, "Oct"),
319            Month::November => write!(f, "Nov"),
320            Month::December => write!(f, "Dec"),
321        }
322    }
323}
324
325pub type Year = u16;
326pub type DayOfMonth = u8;
327pub type Hour = u8;
328pub type Minute = u8;
329pub type Second = u8;
330
331#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
332#[derive(Debug, PartialEq, Clone)]
333#[cfg_attr(feature = "defmt", derive(defmt::Format))]
334pub enum SingleEveryOrInvalid<T> {
335    Single(T),
336    Every(),
337    Invalid(),
338}
339
340#[cfg_attr(feature = "serde", derive(serde::Serialize))]
341#[derive(Debug, PartialEq, Clone)]
342#[cfg_attr(feature = "defmt", derive(defmt::Format))]
343pub enum DataType<'a> {
344    Text(TextUnit<'a>),
345    Number(f64),
346    LossyNumber(f64),
347    Date(
348        SingleEveryOrInvalid<DayOfMonth>,
349        SingleEveryOrInvalid<Month>,
350        SingleEveryOrInvalid<Year>,
351    ),
352    Time(
353        SingleEveryOrInvalid<Second>,
354        SingleEveryOrInvalid<Minute>,
355        SingleEveryOrInvalid<Hour>,
356    ),
357    DateTime(
358        SingleEveryOrInvalid<DayOfMonth>,
359        SingleEveryOrInvalid<Month>,
360        SingleEveryOrInvalid<Year>,
361        SingleEveryOrInvalid<Hour>,
362        SingleEveryOrInvalid<Minute>,
363    ),
364    DateTimeWithSeconds(
365        SingleEveryOrInvalid<DayOfMonth>,
366        SingleEveryOrInvalid<Month>,
367        SingleEveryOrInvalid<Year>,
368        SingleEveryOrInvalid<Hour>,
369        SingleEveryOrInvalid<Minute>,
370        SingleEveryOrInvalid<Second>,
371    ),
372    ManufacturerSpecific(&'a [u8]),
373}
374#[cfg_attr(feature = "serde", derive(serde::Serialize))]
375#[derive(PartialEq, Debug, Clone)]
376#[cfg_attr(feature = "defmt", derive(defmt::Format))]
377pub struct Data<'a> {
378    pub value: Option<DataType<'a>>,
379    pub size: usize,
380}
381
382#[cfg(feature = "std")]
383impl<T: std::fmt::Display> std::fmt::Display for SingleEveryOrInvalid<T> {
384    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
385        match self {
386            SingleEveryOrInvalid::Single(value) => write!(f, "{}", value),
387            SingleEveryOrInvalid::Every() => write!(f, "Every"),
388            SingleEveryOrInvalid::Invalid() => write!(f, "Invalid"),
389        }
390    }
391}
392
393#[cfg(feature = "std")]
394impl std::fmt::Display for Data<'_> {
395    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
396        match &self.value {
397            Some(value) => match value {
398                DataType::Number(value) => write!(f, "{}", value),
399                DataType::LossyNumber(value) => write!(f, "{}", value),
400                DataType::Date(day, month, year) => write!(f, "{}/{}/{}", day, month, year),
401                DataType::DateTime(day, month, year, hour, minute) => {
402                    write!(f, "{}/{}/{} {}:{}:00", day, month, year, hour, minute)
403                }
404                DataType::DateTimeWithSeconds(day, month, year, hour, minute, second) => {
405                    write!(
406                        f,
407                        "{}/{}/{} {}:{}:{}",
408                        day, month, year, hour, minute, second
409                    )
410                }
411                DataType::Time(seconds, minutes, hours) => {
412                    write!(f, "{}:{}:{}", hours, minutes, seconds)
413                }
414                DataType::Text(text_unit) => {
415                    let text: String = (*text_unit).into();
416                    write!(f, "{}", text)
417                }
418                DataType::ManufacturerSpecific(data) => {
419                    write!(f, "Manufacturer Specific: {:?}", data)
420                }
421            },
422            None => write!(f, "No Data"),
423        }
424    }
425}
426
427impl Data<'_> {
428    #[must_use]
429    pub const fn get_size(&self) -> usize {
430        self.size
431    }
432}
433
434macro_rules! parse_single_or_every {
435    ($input:expr, $mask:expr, $all_value:expr, $shift:expr) => {
436        if $input & $mask == $all_value {
437            SingleEveryOrInvalid::Every()
438        } else {
439            SingleEveryOrInvalid::Single(($input & $mask) >> $shift)
440        }
441    };
442}
443
444macro_rules! parse_month {
445    ($input:expr) => {
446        match $input & 0xF {
447            0x1 => SingleEveryOrInvalid::Single(Month::January),
448            0x2 => SingleEveryOrInvalid::Single(Month::February),
449            0x3 => SingleEveryOrInvalid::Single(Month::March),
450            0x4 => SingleEveryOrInvalid::Single(Month::April),
451            0x5 => SingleEveryOrInvalid::Single(Month::May),
452            0x6 => SingleEveryOrInvalid::Single(Month::June),
453            0x7 => SingleEveryOrInvalid::Single(Month::July),
454            0x8 => SingleEveryOrInvalid::Single(Month::August),
455            0x9 => SingleEveryOrInvalid::Single(Month::September),
456            0xA => SingleEveryOrInvalid::Single(Month::October),
457            0xB => SingleEveryOrInvalid::Single(Month::November),
458            0xC => SingleEveryOrInvalid::Single(Month::December),
459            _ => SingleEveryOrInvalid::Invalid(),
460        }
461    };
462}
463
464macro_rules! parse_year {
465    ($input:expr, $mask_byte1:expr, $mask_byte2:expr, $all_value:expr) => {{
466        let byte1 = u16::from($input.get(1).copied().unwrap_or(0) & $mask_byte1);
467        let byte2 = u16::from($input.get(0).copied().unwrap_or(0) & $mask_byte2);
468        let year = byte1.wrapping_shr(1) | byte2.wrapping_shr(5);
469        if year == $all_value {
470            SingleEveryOrInvalid::Every()
471        } else {
472            SingleEveryOrInvalid::Single(year)
473        }
474    }};
475}
476fn bcd_to_value_internal(
477    data: &[u8],
478    num_digits: usize,
479    sign: i32,
480    lsb_order: bool,
481) -> Result<Data, DataRecordError> {
482    if data.len() < num_digits.div_ceil(2) {
483        return Err(DataRecordError::InsufficientData);
484    }
485
486    let mut data_value = 0.0;
487    let mut current_weight = 1.0;
488
489    for i in 0..num_digits {
490        let index = if lsb_order {
491            (num_digits - i - 1) / 2
492        } else {
493            i / 2
494        };
495        let byte = data.get(index).ok_or(DataRecordError::InsufficientData)?;
496
497        let digit = if i % 2 == 0 {
498            byte & 0x0F
499        } else {
500            (byte >> 4) & 0x0F
501        };
502
503        if digit > 9 {
504            return Err(DataRecordError::DataInformationError(
505                DataInformationError::InvalidValueInformation,
506            ));
507        }
508
509        data_value += f64::from(digit) * current_weight;
510        current_weight *= 10.0;
511    }
512
513    let signed_value = data_value * sign as f64;
514
515    Ok(Data {
516        value: Some(DataType::Number(signed_value)),
517        size: num_digits.div_ceil(2),
518    })
519}
520
521fn integer_to_value_internal(data: &[u8], byte_size: usize) -> Data<'_> {
522    let mut data_value = 0i64;
523    let mut shift = 0;
524    for byte in data.iter().take(if byte_size > 8 { 8 } else { byte_size }) {
525        data_value |= (*byte as i64) << shift;
526        shift += 8;
527    }
528
529    let msb = (data_value >> (shift - 1)) & 1;
530    let data_value = if byte_size < 8 && msb == 1 {
531        -((data_value ^ (2i64.pow(shift) - 1)) + 1)
532    } else {
533        data_value
534    };
535
536    let output = if byte_size > 8 {
537        DataType::LossyNumber(data_value as f64)
538    } else {
539        DataType::Number(data_value as f64)
540    };
541    Data {
542        value: Some(output),
543        size: byte_size,
544    }
545}
546
547impl DataFieldCoding {
548    pub fn parse<'a>(
549        &self,
550        input: &'a [u8],
551        fixed_data_header: Option<&'a FixedDataHeader>,
552    ) -> Result<Data<'a>, DataRecordError> {
553        let lsb_order = fixed_data_header.map(|x| x.lsb_order).unwrap_or(false);
554
555        macro_rules! bcd_to_value {
556            ($data:expr, $num_digits:expr) => {{
557                bcd_to_value_internal($data, $num_digits, 1, lsb_order)
558            }};
559
560            ($data:expr, $num_digits:expr, $sign:expr) => {{
561                bcd_to_value_internal($data, $num_digits, $sign, lsb_order)
562            }};
563        }
564
565        macro_rules! integer_to_value {
566            ($data:expr, $byte_size:expr) => {{
567                if $data.len() < $byte_size {
568                    return Err(DataRecordError::InsufficientData);
569                }
570                Ok(integer_to_value_internal($data, $byte_size))
571            }};
572        }
573        match self {
574            Self::NoData => Ok(Data {
575                value: None,
576                size: 0,
577            }),
578            Self::Integer8Bit => integer_to_value!(input, 1),
579            Self::Integer16Bit => integer_to_value!(input, 2),
580            Self::Integer24Bit => integer_to_value!(input, 3),
581            Self::Integer32Bit => integer_to_value!(input, 4),
582            Self::Integer48Bit => integer_to_value!(input, 6),
583            Self::Integer64Bit => integer_to_value!(input, 8),
584
585            Self::Real32Bit => {
586                if input.len() < 4 {
587                    return Err(DataRecordError::InsufficientData);
588                }
589                if let Ok(x) = input
590                    .get(0..4)
591                    .ok_or(DataRecordError::InsufficientData)?
592                    .try_into()
593                {
594                    let x: [u8; 4] = x;
595                    Ok(Data {
596                        value: Some(DataType::Number(f64::from(f32::from_le_bytes(x)))),
597                        size: 4,
598                    })
599                } else {
600                    Err(DataRecordError::InsufficientData)
601                }
602            }
603
604            Self::SelectionForReadout => Ok(Data {
605                value: None,
606                size: 0,
607            }),
608
609            Self::BCD2Digit => bcd_to_value!(input, 2),
610            Self::BCD4Digit => bcd_to_value!(input, 4),
611            Self::BCD6Digit => bcd_to_value!(input, 6),
612            Self::BCD8Digit => bcd_to_value!(input, 8),
613            Self::BCDDigit12 => bcd_to_value!(input, 12),
614
615            Self::VariableLength => {
616                let mut length = *input.first().ok_or(DataRecordError::InsufficientData)?;
617                match length {
618                    0x00..=0xBF => Ok(Data {
619                        value: Some(DataType::Text(TextUnit::new(
620                            input
621                                .get(1..(1 + length as usize))
622                                .ok_or(DataRecordError::InsufficientData)?,
623                        ))),
624                        size: length as usize + 1,
625                    }),
626                    0xC0..=0xC9 => {
627                        length -= 0xC0;
628                        let bytes = input
629                            .get(1..(1 + length as usize))
630                            .ok_or(DataRecordError::InsufficientData)?;
631                        match bcd_to_value!(bytes, 2 * length as usize) {
632                            Ok(data) => Ok(Data {
633                                value: data.value,
634                                size: data.size + 1,
635                            }),
636                            Err(err) => Err(err),
637                        }
638                    }
639                    0xD0..=0xD9 => {
640                        length -= 0xD0;
641                        let bytes = input
642                            .get(1..(1 + length as usize))
643                            .ok_or(DataRecordError::InsufficientData)?;
644                        match bcd_to_value!(bytes, 2 * length as usize, -1) {
645                            Ok(data) => Ok(Data {
646                                value: data.value,
647                                size: data.size + 1,
648                            }),
649                            Err(err) => Err(err),
650                        }
651                    }
652                    0xE0..=0xEF => {
653                        length -= 0xE0;
654                        let bytes = input
655                            .get(1..(1 + length as usize))
656                            .ok_or(DataRecordError::InsufficientData)?;
657                        match integer_to_value!(bytes, length as usize) {
658                            Ok(data) => Ok(Data {
659                                value: data.value,
660                                size: data.size + 1,
661                            }),
662                            Err(err) => Err(err),
663                        }
664                    }
665                    0xF0..=0xF4 => {
666                        length -= 0xEC;
667                        let bytes = input
668                            .get(1..(1 + 4 * length as usize))
669                            .ok_or(DataRecordError::InsufficientData)?;
670                        match integer_to_value!(bytes, 4 * length as usize) {
671                            Ok(data) => Ok(Data {
672                                value: data.value,
673                                size: data.size + 1,
674                            }),
675                            Err(err) => Err(err),
676                        }
677                    }
678                    0xF5 => {
679                        let bytes = input
680                            .get(1..(1 + 48_usize))
681                            .ok_or(DataRecordError::InsufficientData)?;
682                        match integer_to_value!(bytes, 48_usize) {
683                            Ok(data) => Ok(Data {
684                                value: data.value,
685                                size: data.size + 1,
686                            }),
687                            Err(err) => Err(err),
688                        }
689                    }
690                    0xF6 => {
691                        let bytes = input
692                            .get(1..(1 + 64_usize))
693                            .ok_or(DataRecordError::InsufficientData)?;
694                        match integer_to_value!(bytes, 64_usize) {
695                            Ok(data) => Ok(Data {
696                                value: data.value,
697                                size: data.size + 1,
698                            }),
699                            Err(err) => Err(err),
700                        }
701                    }
702                    _ => {
703                        todo!(
704                            "Variable length parsing for length: {} is a reserved value",
705                            length
706                        );
707                    }
708                }
709            }
710
711            Self::SpecialFunctions(_code) => {
712                // Special functions parsing based on the code
713                todo!()
714            }
715
716            Self::DateTypeG => {
717                let day = parse_single_or_every!(
718                    input.first().ok_or(DataRecordError::InsufficientData)?,
719                    0x1F,
720                    0,
721                    0
722                );
723                let month = parse_month!(input.get(1).ok_or(DataRecordError::InsufficientData)?);
724                let year = parse_year!(input, 0xF0, 0xE0, 0x7F);
725
726                Ok(Data {
727                    value: Some(DataType::Date(day, month, year)),
728                    size: 2,
729                })
730            }
731            Self::DateTimeTypeF => {
732                let minutes = parse_single_or_every!(
733                    input.first().ok_or(DataRecordError::InsufficientData)?,
734                    0x3F,
735                    0x3F,
736                    0
737                );
738                let hour = parse_single_or_every!(
739                    input.get(1).ok_or(DataRecordError::InsufficientData)?,
740                    0x1F,
741                    0x1F,
742                    0
743                );
744                let day = parse_single_or_every!(
745                    input.get(2).ok_or(DataRecordError::InsufficientData)?,
746                    0x1F,
747                    0x1F,
748                    0
749                );
750                let month = parse_month!(input.get(3).ok_or(DataRecordError::InsufficientData)?);
751                let year = parse_year!(input, 0xF0, 0xE0, 0x7F);
752
753                Ok(Data {
754                    value: Some(DataType::DateTime(day, month, year, hour, minutes)),
755                    size: 4,
756                })
757            }
758            Self::DateTimeTypeJ => {
759                let seconds = parse_single_or_every!(
760                    input.first().ok_or(DataRecordError::InsufficientData)?,
761                    0x3F,
762                    0x3F,
763                    0
764                );
765                let minutes = parse_single_or_every!(
766                    input.get(1).ok_or(DataRecordError::InsufficientData)?,
767                    0x3F,
768                    0x3F,
769                    0
770                );
771                let hours = parse_single_or_every!(
772                    input.get(2).ok_or(DataRecordError::InsufficientData)?,
773                    0x1F,
774                    0x1F,
775                    0
776                );
777
778                Ok(Data {
779                    value: Some(DataType::Time(seconds, minutes, hours)),
780                    size: 4,
781                })
782            }
783            Self::DateTimeTypeI => {
784                // note: more information can be extracted from the data,
785                // however, because this data can be derived from the other data that is
786                // that is extracted, it is not necessary to extract it.
787
788                let seconds = parse_single_or_every!(
789                    input.first().ok_or(DataRecordError::InsufficientData)?,
790                    0x3F,
791                    0x3F,
792                    0
793                );
794
795                let minutes = parse_single_or_every!(
796                    input.get(1).ok_or(DataRecordError::InsufficientData)?,
797                    0x3F,
798                    0x3F,
799                    0
800                );
801
802                let hours = parse_single_or_every!(
803                    input.get(2).ok_or(DataRecordError::InsufficientData)?,
804                    0x1F,
805                    0x1F,
806                    0
807                );
808                let days = parse_single_or_every!(
809                    input.get(3).ok_or(DataRecordError::InsufficientData)?,
810                    0x1F,
811                    0x1F,
812                    0
813                );
814                let months = parse_month!(input.get(4).ok_or(DataRecordError::InsufficientData)?);
815                let year = parse_year!(input, 0xF0, 0xE0, 0x7F);
816
817                Ok(Data {
818                    value: Some(DataType::DateTimeWithSeconds(
819                        days, months, year, hours, minutes, seconds,
820                    )),
821                    size: 6,
822                })
823            }
824        }
825    }
826}
827
828impl DataInformation {
829    #[must_use]
830    pub const fn get_size(&self) -> usize {
831        self.size
832    }
833}
834#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
835#[derive(Debug, Clone, Copy, PartialEq)]
836#[cfg_attr(feature = "defmt", derive(defmt::Format))]
837pub enum FunctionField {
838    InstantaneousValue,
839    MaximumValue,
840    MinimumValue,
841    ValueDuringErrorState,
842}
843
844#[cfg(feature = "std")]
845impl std::fmt::Display for FunctionField {
846    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
847        match self {
848            FunctionField::InstantaneousValue => write!(f, "Inst"),
849            FunctionField::MaximumValue => write!(f, "Max"),
850            FunctionField::MinimumValue => write!(f, "Min"),
851            FunctionField::ValueDuringErrorState => write!(f, "Value During Error State"),
852        }
853    }
854}
855#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
856#[derive(Debug, Clone, Copy, PartialEq)]
857#[cfg_attr(feature = "defmt", derive(defmt::Format))]
858pub enum SpecialFunctions {
859    ManufacturerSpecific,
860    MoreRecordsFollow,
861    IdleFiller,
862    Reserved,
863    GlobalReadoutRequest,
864}
865
866#[cfg_attr(feature = "defmt", derive(defmt::Format))]
867pub struct Value {
868    pub data: f64,
869    pub byte_size: usize,
870}
871
872#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
873#[derive(Debug, Clone, Copy, PartialEq)]
874#[cfg_attr(feature = "defmt", derive(defmt::Format))]
875pub enum DataFieldCoding {
876    NoData,
877    Integer8Bit,
878    Integer16Bit,
879    Integer24Bit,
880    Integer32Bit,
881    Real32Bit,
882    Integer48Bit,
883    Integer64Bit,
884    SelectionForReadout,
885    BCD2Digit,
886    BCD4Digit,
887    BCD6Digit,
888    BCD8Digit,
889    VariableLength,
890    BCDDigit12,
891    SpecialFunctions(SpecialFunctions),
892    DateTypeG,
893    DateTimeTypeF,
894    DateTimeTypeJ,
895    DateTimeTypeI,
896}
897
898#[cfg(feature = "std")]
899impl std::fmt::Display for DataFieldCoding {
900    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
901        match self {
902            DataFieldCoding::NoData => write!(f, "No Data"),
903            DataFieldCoding::Integer8Bit => write!(f, "8-bit Integer"),
904            DataFieldCoding::Integer16Bit => write!(f, "16-bit Integer"),
905            DataFieldCoding::Integer24Bit => write!(f, "24-bit Integer"),
906            DataFieldCoding::Integer32Bit => write!(f, "32-bit Integer"),
907            DataFieldCoding::Real32Bit => write!(f, "32-bit Real"),
908            DataFieldCoding::Integer48Bit => write!(f, "48-bit Integer"),
909            DataFieldCoding::Integer64Bit => write!(f, "64-bit Integer"),
910            DataFieldCoding::SelectionForReadout => write!(f, "Selection for Readout"),
911            DataFieldCoding::BCD2Digit => write!(f, "BCD 2-digit"),
912            DataFieldCoding::BCD4Digit => write!(f, "BCD 4-digit"),
913            DataFieldCoding::BCD6Digit => write!(f, "BCD 6-digit"),
914            DataFieldCoding::BCD8Digit => write!(f, "BCD 8-digit"),
915            DataFieldCoding::VariableLength => write!(f, "Variable Length"),
916            DataFieldCoding::BCDDigit12 => write!(f, "BCD 12-digit"),
917            DataFieldCoding::DateTypeG => write!(f, "Date Type G"),
918            DataFieldCoding::DateTimeTypeF => write!(f, "Date Time Type F"),
919            DataFieldCoding::DateTimeTypeJ => write!(f, "Date Time Type J"),
920            DataFieldCoding::DateTimeTypeI => write!(f, "Date Time Type I"),
921            DataFieldCoding::SpecialFunctions(code) => write!(f, "Special Functions ({:?})", code),
922        }
923    }
924}
925
926#[cfg(test)]
927mod tests {
928
929    use super::*;
930    #[test]
931    fn test_data_information() {
932        let data = [0x13_u8];
933        let result = DataInformationBlock::try_from(data.as_slice());
934        let result = DataInformation::try_from(&result.unwrap());
935        assert_eq!(
936            result,
937            Ok(DataInformation {
938                storage_number: 0,
939                device: 0,
940                tariff: 0,
941                function_field: FunctionField::MaximumValue,
942                data_field_coding: DataFieldCoding::Integer24Bit,
943                data_information_extension: None,
944                size: 1,
945            })
946        );
947    }
948
949    #[test]
950    fn test_complex_data_information() {
951        let data = [0xc4, 0x80, 0x40];
952        let result = DataInformationBlock::try_from(data.as_slice());
953        let result = DataInformation::try_from(&result.unwrap());
954        assert_eq!(
955            result,
956            Ok(DataInformation {
957                storage_number: 1,
958                device: 2,
959                tariff: 0,
960                function_field: FunctionField::InstantaneousValue,
961                data_field_coding: DataFieldCoding::Integer32Bit,
962                data_information_extension: None,
963                size: 3,
964            })
965        );
966    }
967
968    #[test]
969    fn reverse_text_unit() {
970        let original_value = [0x6c, 0x61, 0x67, 0x69];
971        let parsed = TextUnit::new(&original_value);
972        assert_eq!(&parsed, "igal");
973    }
974
975    #[test]
976    fn test_invalid_data_information() {
977        let data = [
978            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
979        ];
980        let result = DataInformationBlock::try_from(data.as_slice());
981        assert_eq!(result, Err(DataInformationError::DataTooLong));
982    }
983
984    #[test]
985    fn test_longest_data_information_not_too_long() {
986        let data = [
987            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01,
988        ];
989        let result = DataInformationBlock::try_from(data.as_slice());
990        assert_ne!(result, Err(DataInformationError::DataTooLong));
991    }
992
993    #[test]
994    fn test_short_data_information() {
995        let data = [0xFF];
996        let result = DataInformationBlock::try_from(data.as_slice());
997        assert_eq!(result, Err(DataInformationError::DataTooShort));
998    }
999
1000    #[test]
1001    fn test_data_inforamtion1() {
1002        let data = [178, 1];
1003        let result = DataInformationBlock::try_from(data.as_slice());
1004        assert!(result.is_ok());
1005        assert_eq!(result.unwrap().get_size(), 2);
1006    }
1007
1008    #[test]
1009    fn test_bcd_to_value_unsigned() {
1010        let data = [0x54, 0x76, 0x98];
1011        let result = bcd_to_value_internal(&data, 6, 1, false);
1012        assert_eq!(
1013            result.unwrap(),
1014            Data {
1015                value: Some(DataType::Number(987654.0)),
1016                size: 3
1017            }
1018        );
1019    }
1020
1021    #[test]
1022    fn test_bcd_to_value_invalid() {
1023        let data = [0x5A, 0x76, 0x98];
1024        let result = bcd_to_value_internal(&data, 6, 1, false);
1025        assert!(matches!(
1026            result,
1027            Err(DataRecordError::DataInformationError(
1028                DataInformationError::InvalidValueInformation
1029            ))
1030        ));
1031    }
1032
1033    #[test]
1034    fn test_integer_to_value_8_bit_positive() {
1035        let data = [0x7F];
1036        let result = integer_to_value_internal(&data, 1);
1037        assert_eq!(
1038            result,
1039            Data {
1040                value: Some(DataType::Number(127.0)),
1041                size: 1
1042            }
1043        );
1044    }
1045
1046    #[test]
1047    fn test_integer_to_value_8_bit_negative() {
1048        let data = [0xFF];
1049        let result = integer_to_value_internal(&data, 1);
1050        assert_eq!(
1051            result,
1052            Data {
1053                value: Some(DataType::Number(-1.0)),
1054                size: 1
1055            }
1056        );
1057    }
1058
1059    #[test]
1060    fn test_integer_to_value_64_bit_positive() {
1061        let data = [0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1062        let result = integer_to_value_internal(&data, 8);
1063        assert_eq!(
1064            result,
1065            Data {
1066                value: Some(DataType::Number(250.0)),
1067                size: 8
1068            }
1069        );
1070    }
1071
1072    #[test]
1073    fn test_integer_to_value_64_bit_negative() {
1074        let data = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
1075        let result = integer_to_value_internal(&data, 8);
1076        assert_eq!(
1077            result,
1078            Data {
1079                value: Some(DataType::Number(-1.0)),
1080                size: 8
1081            }
1082        );
1083    }
1084}