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