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