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