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!(), };
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 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 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}