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