Skip to main content

m_bus_application_layer/
data_information.rs

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