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        data_value += f64::from(digit) * current_weight;
504        current_weight *= 10.0;
505    }
506
507    let signed_value = data_value * sign as f64;
508
509    Ok(Data {
510        value: Some(DataType::Number(signed_value)),
511        size: num_digits.div_ceil(2),
512    })
513}
514
515fn integer_to_value_internal(data: &[u8], byte_size: usize) -> Data<'_> {
516    let mut data_value = 0i64;
517    let mut shift = 0;
518    for byte in data.iter().take(if byte_size > 8 { 8 } else { byte_size }) {
519        data_value |= (*byte as i64) << shift;
520        shift += 8;
521    }
522
523    let msb = (data_value >> (shift - 1)) & 1;
524    let data_value = if byte_size < 8 && msb == 1 {
525        -((data_value ^ (2i64.pow(shift) - 1)) + 1)
526    } else {
527        data_value
528    };
529
530    let output = if byte_size > 8 {
531        DataType::LossyNumber(data_value as f64)
532    } else {
533        DataType::Number(data_value as f64)
534    };
535    Data {
536        value: Some(output),
537        size: byte_size,
538    }
539}
540
541impl DataFieldCoding {
542    pub fn parse<'a>(
543        &self,
544        input: &'a [u8],
545        fixed_data_header: Option<&'a FixedDataHeader>,
546    ) -> Result<Data<'a>, DataRecordError> {
547        let lsb_order = fixed_data_header.map(|x| x.lsb_order).unwrap_or(false);
548
549        macro_rules! bcd_to_value {
550            ($data:expr, $num_digits:expr) => {{
551                bcd_to_value_internal($data, $num_digits, 1, lsb_order)
552            }};
553
554            ($data:expr, $num_digits:expr, $sign:expr) => {{
555                bcd_to_value_internal($data, $num_digits, $sign, lsb_order)
556            }};
557        }
558
559        macro_rules! integer_to_value {
560            ($data:expr, $byte_size:expr) => {{
561                if $data.len() < $byte_size {
562                    return Err(DataRecordError::InsufficientData);
563                }
564                Ok(integer_to_value_internal($data, $byte_size))
565            }};
566        }
567        match self {
568            Self::NoData => Ok(Data {
569                value: None,
570                size: 0,
571            }),
572            Self::Integer8Bit => integer_to_value!(input, 1),
573            Self::Integer16Bit => integer_to_value!(input, 2),
574            Self::Integer24Bit => integer_to_value!(input, 3),
575            Self::Integer32Bit => integer_to_value!(input, 4),
576            Self::Integer48Bit => integer_to_value!(input, 6),
577            Self::Integer64Bit => integer_to_value!(input, 8),
578
579            Self::Real32Bit => {
580                if input.len() < 4 {
581                    return Err(DataRecordError::InsufficientData);
582                }
583                if let Ok(x) = input
584                    .get(0..4)
585                    .ok_or(DataRecordError::InsufficientData)?
586                    .try_into()
587                {
588                    let x: [u8; 4] = x;
589                    Ok(Data {
590                        value: Some(DataType::Number(f64::from(f32::from_le_bytes(x)))),
591                        size: 4,
592                    })
593                } else {
594                    Err(DataRecordError::InsufficientData)
595                }
596            }
597
598            Self::SelectionForReadout => Ok(Data {
599                value: None,
600                size: 0,
601            }),
602
603            Self::BCD2Digit => bcd_to_value!(input, 2),
604            Self::BCD4Digit => bcd_to_value!(input, 4),
605            Self::BCD6Digit => bcd_to_value!(input, 6),
606            Self::BCD8Digit => bcd_to_value!(input, 8),
607            Self::BCDDigit12 => bcd_to_value!(input, 12),
608
609            Self::VariableLength => {
610                let mut length = *input.first().ok_or(DataRecordError::InsufficientData)?;
611                match length {
612                    0x00..=0xBF => Ok(Data {
613                        value: Some(DataType::Text(TextUnit::new(
614                            input
615                                .get(1..(1 + length as usize))
616                                .ok_or(DataRecordError::InsufficientData)?,
617                        ))),
618                        size: length as usize + 1,
619                    }),
620                    0xC0..=0xC9 => {
621                        length -= 0xC0;
622                        let bytes = input
623                            .get(1..(1 + length as usize))
624                            .ok_or(DataRecordError::InsufficientData)?;
625                        match bcd_to_value!(bytes, 2 * length as usize) {
626                            Ok(data) => Ok(Data {
627                                value: data.value,
628                                size: data.size + 1,
629                            }),
630                            Err(err) => Err(err),
631                        }
632                    }
633                    0xD0..=0xD9 => {
634                        length -= 0xD0;
635                        let bytes = input
636                            .get(1..(1 + length as usize))
637                            .ok_or(DataRecordError::InsufficientData)?;
638                        match bcd_to_value!(bytes, 2 * length as usize, -1) {
639                            Ok(data) => Ok(Data {
640                                value: data.value,
641                                size: data.size + 1,
642                            }),
643                            Err(err) => Err(err),
644                        }
645                    }
646                    0xE0..=0xEF => {
647                        length -= 0xE0;
648                        let bytes = input
649                            .get(1..(1 + length as usize))
650                            .ok_or(DataRecordError::InsufficientData)?;
651                        match integer_to_value!(bytes, length as usize) {
652                            Ok(data) => Ok(Data {
653                                value: data.value,
654                                size: data.size + 1,
655                            }),
656                            Err(err) => Err(err),
657                        }
658                    }
659                    0xF0..=0xF4 => {
660                        length -= 0xEC;
661                        let bytes = input
662                            .get(1..(1 + 4 * length as usize))
663                            .ok_or(DataRecordError::InsufficientData)?;
664                        match integer_to_value!(bytes, 4 * length as usize) {
665                            Ok(data) => Ok(Data {
666                                value: data.value,
667                                size: data.size + 1,
668                            }),
669                            Err(err) => Err(err),
670                        }
671                    }
672                    0xF5 => {
673                        let bytes = input
674                            .get(1..(1 + 48_usize))
675                            .ok_or(DataRecordError::InsufficientData)?;
676                        match integer_to_value!(bytes, 48_usize) {
677                            Ok(data) => Ok(Data {
678                                value: data.value,
679                                size: data.size + 1,
680                            }),
681                            Err(err) => Err(err),
682                        }
683                    }
684                    0xF6 => {
685                        let bytes = input
686                            .get(1..(1 + 64_usize))
687                            .ok_or(DataRecordError::InsufficientData)?;
688                        match integer_to_value!(bytes, 64_usize) {
689                            Ok(data) => Ok(Data {
690                                value: data.value,
691                                size: data.size + 1,
692                            }),
693                            Err(err) => Err(err),
694                        }
695                    }
696                    _ => {
697                        todo!(
698                            "Variable length parsing for length: {} is a reserved value",
699                            length
700                        );
701                    }
702                }
703            }
704
705            Self::SpecialFunctions(_code) => {
706                // Special functions parsing based on the code
707                todo!()
708            }
709
710            Self::DateTypeG => {
711                let day = parse_single_or_every!(
712                    input.first().ok_or(DataRecordError::InsufficientData)?,
713                    0x1F,
714                    0,
715                    0
716                );
717                let month = parse_month!(input.get(1).ok_or(DataRecordError::InsufficientData)?);
718                let year = parse_year!(input, 0xF0, 0xE0, 0x7F);
719
720                Ok(Data {
721                    value: Some(DataType::Date(day, month, year)),
722                    size: 2,
723                })
724            }
725            Self::DateTimeTypeF => {
726                let minutes = parse_single_or_every!(
727                    input.first().ok_or(DataRecordError::InsufficientData)?,
728                    0x3F,
729                    0x3F,
730                    0
731                );
732                let hour = parse_single_or_every!(
733                    input.get(1).ok_or(DataRecordError::InsufficientData)?,
734                    0x1F,
735                    0x1F,
736                    0
737                );
738                let day = parse_single_or_every!(
739                    input.get(2).ok_or(DataRecordError::InsufficientData)?,
740                    0x1F,
741                    0x1F,
742                    0
743                );
744                let month = parse_month!(input.get(3).ok_or(DataRecordError::InsufficientData)?);
745                let year = parse_year!(input, 0xF0, 0xE0, 0x7F);
746
747                Ok(Data {
748                    value: Some(DataType::DateTime(day, month, year, hour, minutes)),
749                    size: 4,
750                })
751            }
752            Self::DateTimeTypeJ => {
753                let seconds = parse_single_or_every!(
754                    input.first().ok_or(DataRecordError::InsufficientData)?,
755                    0x3F,
756                    0x3F,
757                    0
758                );
759                let minutes = parse_single_or_every!(
760                    input.get(1).ok_or(DataRecordError::InsufficientData)?,
761                    0x3F,
762                    0x3F,
763                    0
764                );
765                let hours = parse_single_or_every!(
766                    input.get(2).ok_or(DataRecordError::InsufficientData)?,
767                    0x1F,
768                    0x1F,
769                    0
770                );
771
772                Ok(Data {
773                    value: Some(DataType::Time(seconds, minutes, hours)),
774                    size: 4,
775                })
776            }
777            Self::DateTimeTypeI => {
778                // note: more information can be extracted from the data,
779                // however, because this data can be derived from the other data that is
780                // that is extracted, it is not necessary to extract it.
781
782                let seconds = parse_single_or_every!(
783                    input.first().ok_or(DataRecordError::InsufficientData)?,
784                    0x3F,
785                    0x3F,
786                    0
787                );
788
789                let minutes = parse_single_or_every!(
790                    input.get(1).ok_or(DataRecordError::InsufficientData)?,
791                    0x3F,
792                    0x3F,
793                    0
794                );
795
796                let hours = parse_single_or_every!(
797                    input.get(2).ok_or(DataRecordError::InsufficientData)?,
798                    0x1F,
799                    0x1F,
800                    0
801                );
802                let days = parse_single_or_every!(
803                    input.get(3).ok_or(DataRecordError::InsufficientData)?,
804                    0x1F,
805                    0x1F,
806                    0
807                );
808                let months = parse_month!(input.get(4).ok_or(DataRecordError::InsufficientData)?);
809                let year = parse_year!(input, 0xF0, 0xE0, 0x7F);
810
811                Ok(Data {
812                    value: Some(DataType::DateTimeWithSeconds(
813                        days, months, year, hours, minutes, seconds,
814                    )),
815                    size: 6,
816                })
817            }
818        }
819    }
820}
821
822impl DataInformation {
823    #[must_use]
824    pub const fn get_size(&self) -> usize {
825        self.size
826    }
827}
828#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
829#[derive(Debug, Clone, Copy, PartialEq)]
830#[cfg_attr(feature = "defmt", derive(defmt::Format))]
831pub enum FunctionField {
832    InstantaneousValue,
833    MaximumValue,
834    MinimumValue,
835    ValueDuringErrorState,
836}
837
838#[cfg(feature = "std")]
839impl std::fmt::Display for FunctionField {
840    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
841        match self {
842            FunctionField::InstantaneousValue => write!(f, "Inst"),
843            FunctionField::MaximumValue => write!(f, "Max"),
844            FunctionField::MinimumValue => write!(f, "Min"),
845            FunctionField::ValueDuringErrorState => write!(f, "Value During Error State"),
846        }
847    }
848}
849#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
850#[derive(Debug, Clone, Copy, PartialEq)]
851#[cfg_attr(feature = "defmt", derive(defmt::Format))]
852pub enum SpecialFunctions {
853    ManufacturerSpecific,
854    MoreRecordsFollow,
855    IdleFiller,
856    Reserved,
857    GlobalReadoutRequest,
858}
859
860#[cfg_attr(feature = "defmt", derive(defmt::Format))]
861pub struct Value {
862    pub data: f64,
863    pub byte_size: usize,
864}
865
866#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
867#[derive(Debug, Clone, Copy, PartialEq)]
868#[cfg_attr(feature = "defmt", derive(defmt::Format))]
869pub enum DataFieldCoding {
870    NoData,
871    Integer8Bit,
872    Integer16Bit,
873    Integer24Bit,
874    Integer32Bit,
875    Real32Bit,
876    Integer48Bit,
877    Integer64Bit,
878    SelectionForReadout,
879    BCD2Digit,
880    BCD4Digit,
881    BCD6Digit,
882    BCD8Digit,
883    VariableLength,
884    BCDDigit12,
885    SpecialFunctions(SpecialFunctions),
886    DateTypeG,
887    DateTimeTypeF,
888    DateTimeTypeJ,
889    DateTimeTypeI,
890}
891
892#[cfg(feature = "std")]
893impl std::fmt::Display for DataFieldCoding {
894    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
895        match self {
896            DataFieldCoding::NoData => write!(f, "No Data"),
897            DataFieldCoding::Integer8Bit => write!(f, "8-bit Integer"),
898            DataFieldCoding::Integer16Bit => write!(f, "16-bit Integer"),
899            DataFieldCoding::Integer24Bit => write!(f, "24-bit Integer"),
900            DataFieldCoding::Integer32Bit => write!(f, "32-bit Integer"),
901            DataFieldCoding::Real32Bit => write!(f, "32-bit Real"),
902            DataFieldCoding::Integer48Bit => write!(f, "48-bit Integer"),
903            DataFieldCoding::Integer64Bit => write!(f, "64-bit Integer"),
904            DataFieldCoding::SelectionForReadout => write!(f, "Selection for Readout"),
905            DataFieldCoding::BCD2Digit => write!(f, "BCD 2-digit"),
906            DataFieldCoding::BCD4Digit => write!(f, "BCD 4-digit"),
907            DataFieldCoding::BCD6Digit => write!(f, "BCD 6-digit"),
908            DataFieldCoding::BCD8Digit => write!(f, "BCD 8-digit"),
909            DataFieldCoding::VariableLength => write!(f, "Variable Length"),
910            DataFieldCoding::BCDDigit12 => write!(f, "BCD 12-digit"),
911            DataFieldCoding::DateTypeG => write!(f, "Date Type G"),
912            DataFieldCoding::DateTimeTypeF => write!(f, "Date Time Type F"),
913            DataFieldCoding::DateTimeTypeJ => write!(f, "Date Time Type J"),
914            DataFieldCoding::DateTimeTypeI => write!(f, "Date Time Type I"),
915            DataFieldCoding::SpecialFunctions(code) => write!(f, "Special Functions ({:?})", code),
916        }
917    }
918}
919
920#[cfg(test)]
921mod tests {
922
923    use super::*;
924    #[test]
925    fn test_data_information() {
926        let data = [0x13_u8];
927        let result = DataInformationBlock::try_from(data.as_slice());
928        let result = DataInformation::try_from(&result.unwrap());
929        assert_eq!(
930            result,
931            Ok(DataInformation {
932                storage_number: 0,
933                device: 0,
934                tariff: 0,
935                function_field: FunctionField::MaximumValue,
936                data_field_coding: DataFieldCoding::Integer24Bit,
937                data_information_extension: None,
938                size: 1,
939            })
940        );
941    }
942
943    #[test]
944    fn test_complex_data_information() {
945        let data = [0xc4, 0x80, 0x40];
946        let result = DataInformationBlock::try_from(data.as_slice());
947        let result = DataInformation::try_from(&result.unwrap());
948        assert_eq!(
949            result,
950            Ok(DataInformation {
951                storage_number: 1,
952                device: 2,
953                tariff: 0,
954                function_field: FunctionField::InstantaneousValue,
955                data_field_coding: DataFieldCoding::Integer32Bit,
956                data_information_extension: None,
957                size: 3,
958            })
959        );
960    }
961
962    #[test]
963    fn reverse_text_unit() {
964        let original_value = [0x6c, 0x61, 0x67, 0x69];
965        let parsed = TextUnit::new(&original_value);
966        assert_eq!(&parsed, "igal");
967    }
968
969    #[test]
970    fn test_invalid_data_information() {
971        let data = [
972            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
973        ];
974        let result = DataInformationBlock::try_from(data.as_slice());
975        assert_eq!(result, Err(DataInformationError::DataTooLong));
976    }
977
978    #[test]
979    fn test_longest_data_information_not_too_long() {
980        let data = [
981            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01,
982        ];
983        let result = DataInformationBlock::try_from(data.as_slice());
984        assert_ne!(result, Err(DataInformationError::DataTooLong));
985    }
986
987    #[test]
988    fn test_short_data_information() {
989        let data = [0xFF];
990        let result = DataInformationBlock::try_from(data.as_slice());
991        assert_eq!(result, Err(DataInformationError::DataTooShort));
992    }
993
994    #[test]
995    fn test_data_inforamtion1() {
996        let data = [178, 1];
997        let result = DataInformationBlock::try_from(data.as_slice());
998        assert!(result.is_ok());
999        assert_eq!(result.unwrap().get_size(), 2);
1000    }
1001
1002    #[test]
1003    fn test_bcd_to_value_unsigned() {
1004        let data = [0x54, 0x76, 0x98];
1005        let result = bcd_to_value_internal(&data, 6, 1, false);
1006        assert_eq!(
1007            result.unwrap(),
1008            Data {
1009                value: Some(DataType::Number(987654.0)),
1010                size: 3
1011            }
1012        );
1013    }
1014
1015    #[test]
1016    fn test_integer_to_value_8_bit_positive() {
1017        let data = [0x7F];
1018        let result = integer_to_value_internal(&data, 1);
1019        assert_eq!(
1020            result,
1021            Data {
1022                value: Some(DataType::Number(127.0)),
1023                size: 1
1024            }
1025        );
1026    }
1027
1028    #[test]
1029    fn test_integer_to_value_8_bit_negative() {
1030        let data = [0xFF];
1031        let result = integer_to_value_internal(&data, 1);
1032        assert_eq!(
1033            result,
1034            Data {
1035                value: Some(DataType::Number(-1.0)),
1036                size: 1
1037            }
1038        );
1039    }
1040
1041    #[test]
1042    fn test_integer_to_value_64_bit_positive() {
1043        let data = [0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1044        let result = integer_to_value_internal(&data, 8);
1045        assert_eq!(
1046            result,
1047            Data {
1048                value: Some(DataType::Number(250.0)),
1049                size: 8
1050            }
1051        );
1052    }
1053
1054    #[test]
1055    fn test_integer_to_value_64_bit_negative() {
1056        let data = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
1057        let result = integer_to_value_internal(&data, 8);
1058        assert_eq!(
1059            result,
1060            Data {
1061                value: Some(DataType::Number(-1.0)),
1062                size: 8
1063            }
1064        );
1065    }
1066}