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(
404 #[cfg_attr(
405 feature = "serde",
406 serde(serialize_with = "m_bus_core::serde_hex::serialize")
407 )]
408 &'a [u8],
409 ),
410}
411#[cfg_attr(feature = "serde", derive(serde::Serialize))]
412#[derive(PartialEq, Debug, Clone)]
413#[cfg_attr(feature = "defmt", derive(defmt::Format))]
414pub struct Data<'a> {
415 pub value: Option<DataType<'a>>,
416 pub size: usize,
417}
418
419#[cfg(feature = "std")]
420impl<T: std::fmt::Display> std::fmt::Display for SingleEveryOrInvalid<T> {
421 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
422 match self {
423 SingleEveryOrInvalid::Single(value) => write!(f, "{}", value),
424 SingleEveryOrInvalid::Every() => write!(f, "Every"),
425 SingleEveryOrInvalid::Invalid() => write!(f, "Invalid"),
426 }
427 }
428}
429
430#[cfg(feature = "std")]
431impl std::fmt::Display for Data<'_> {
432 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
433 match &self.value {
434 Some(value) => match value {
435 DataType::Number(value) => write!(f, "{}", value),
436 DataType::LossyNumber(value) => write!(f, "{}", value),
437 DataType::Date(day, month, year) => write!(f, "{}/{}/{}", day, month, year),
438 DataType::DateTime(day, month, year, hour, minute) => {
439 write!(f, "{}/{}/{} {}:{}:00", day, month, year, hour, minute)
440 }
441 DataType::DateTimeWithSeconds(day, month, year, hour, minute, second) => {
442 write!(
443 f,
444 "{}/{}/{} {}:{}:{}",
445 day, month, year, hour, minute, second
446 )
447 }
448 DataType::Time(seconds, minutes, hours) => {
449 write!(f, "{}:{}:{}", hours, minutes, seconds)
450 }
451 DataType::Text(text_unit) => {
452 let text: String = (*text_unit).into();
453 write!(f, "{}", text)
454 }
455 DataType::ManufacturerSpecific(data) => {
456 write!(f, "Manufacturer Specific: {:?}", data)
457 }
458 },
459 None => write!(f, "No Data"),
460 }
461 }
462}
463
464impl Data<'_> {
465 #[must_use]
466 pub const fn get_size(&self) -> usize {
467 self.size
468 }
469}
470
471macro_rules! parse_single_or_every {
472 ($input:expr, $mask:expr, $all_value:expr, $shift:expr) => {
473 if $input & $mask == $all_value {
474 SingleEveryOrInvalid::Every()
475 } else {
476 SingleEveryOrInvalid::Single(($input & $mask) >> $shift)
477 }
478 };
479}
480
481macro_rules! parse_month {
482 ($input:expr) => {
483 match $input & 0xF {
484 0x1 => SingleEveryOrInvalid::Single(Month::January),
485 0x2 => SingleEveryOrInvalid::Single(Month::February),
486 0x3 => SingleEveryOrInvalid::Single(Month::March),
487 0x4 => SingleEveryOrInvalid::Single(Month::April),
488 0x5 => SingleEveryOrInvalid::Single(Month::May),
489 0x6 => SingleEveryOrInvalid::Single(Month::June),
490 0x7 => SingleEveryOrInvalid::Single(Month::July),
491 0x8 => SingleEveryOrInvalid::Single(Month::August),
492 0x9 => SingleEveryOrInvalid::Single(Month::September),
493 0xA => SingleEveryOrInvalid::Single(Month::October),
494 0xB => SingleEveryOrInvalid::Single(Month::November),
495 0xC => SingleEveryOrInvalid::Single(Month::December),
496 _ => SingleEveryOrInvalid::Invalid(),
497 }
498 };
499}
500
501macro_rules! parse_year {
502 ($input:expr, $mask_byte1:expr, $mask_byte2:expr, $all_value:expr) => {{
503 let byte1 = u16::from($input.get(1).copied().unwrap_or(0) & $mask_byte1);
504 let byte2 = u16::from($input.get(0).copied().unwrap_or(0) & $mask_byte2);
505 let year = byte1.wrapping_shr(1) | byte2.wrapping_shr(5);
506 if year == $all_value {
507 SingleEveryOrInvalid::Every()
508 } else {
509 SingleEveryOrInvalid::Single(year)
510 }
511 }};
512}
513fn bcd_to_value_internal(
514 data: &[u8],
515 num_digits: usize,
516 sign: i32,
517 lsb_order: bool,
518) -> Result<Data<'_>, DataRecordError> {
519 if data.len() < num_digits.div_ceil(2) {
520 return Err(DataRecordError::InsufficientData);
521 }
522
523 let mut data_value = 0.0;
524 let mut current_weight = 1.0;
525
526 for i in 0..num_digits {
527 let index = if lsb_order {
528 (num_digits - i - 1) / 2
529 } else {
530 i / 2
531 };
532 let byte = data.get(index).ok_or(DataRecordError::InsufficientData)?;
533
534 let digit = if i % 2 == 0 {
535 byte & 0x0F
536 } else {
537 (byte >> 4) & 0x0F
538 };
539
540 if digit > 9 {
541 return Err(DataRecordError::DataInformationError(
542 DataInformationError::InvalidValueInformation,
543 ));
544 }
545
546 data_value += f64::from(digit) * current_weight;
547 current_weight *= 10.0;
548 }
549
550 let signed_value = data_value * sign as f64;
551
552 Ok(Data {
553 value: Some(DataType::Number(signed_value)),
554 size: num_digits.div_ceil(2),
555 })
556}
557
558fn integer_to_value_internal(data: &[u8], byte_size: usize) -> Data<'_> {
559 let mut data_value = 0i64;
560 let mut shift = 0;
561 for byte in data.iter().take(if byte_size > 8 { 8 } else { byte_size }) {
562 data_value |= (*byte as i64) << shift;
563 shift += 8;
564 }
565
566 let msb = (data_value >> (shift - 1)) & 1;
567 let data_value = if byte_size < 8 && msb == 1 {
568 -((data_value ^ (2i64.pow(shift) - 1)) + 1)
569 } else {
570 data_value
571 };
572
573 let output = if byte_size > 8 {
574 DataType::LossyNumber(data_value as f64)
575 } else {
576 DataType::Number(data_value as f64)
577 };
578 Data {
579 value: Some(output),
580 size: byte_size,
581 }
582}
583
584impl DataFieldCoding {
585 pub fn parse<'a>(
586 &self,
587 input: &'a [u8],
588 fixed_data_header: Option<&'a LongTplHeader>,
589 ) -> Result<Data<'a>, DataRecordError> {
590 let lsb_order = fixed_data_header.map(|x| x.lsb_order).unwrap_or(false);
591
592 macro_rules! bcd_to_value {
593 ($data:expr, $num_digits:expr) => {{
594 bcd_to_value_internal($data, $num_digits, 1, lsb_order)
595 }};
596
597 ($data:expr, $num_digits:expr, $sign:expr) => {{
598 bcd_to_value_internal($data, $num_digits, $sign, lsb_order)
599 }};
600 }
601
602 macro_rules! integer_to_value {
603 ($data:expr, $byte_size:expr) => {{
604 if $data.len() < $byte_size {
605 return Err(DataRecordError::InsufficientData);
606 }
607 Ok(integer_to_value_internal($data, $byte_size))
608 }};
609 }
610 match self {
611 Self::NoData => Ok(Data {
612 value: None,
613 size: 0,
614 }),
615 Self::Integer8Bit => integer_to_value!(input, 1),
616 Self::Integer16Bit => integer_to_value!(input, 2),
617 Self::Integer24Bit => integer_to_value!(input, 3),
618 Self::Integer32Bit => integer_to_value!(input, 4),
619 Self::Integer48Bit => integer_to_value!(input, 6),
620 Self::Integer64Bit => integer_to_value!(input, 8),
621
622 Self::Real32Bit => {
623 if input.len() < 4 {
624 return Err(DataRecordError::InsufficientData);
625 }
626 if let Ok(x) = input
627 .get(0..4)
628 .ok_or(DataRecordError::InsufficientData)?
629 .try_into()
630 {
631 let x: [u8; 4] = x;
632 Ok(Data {
633 value: Some(DataType::Number(f64::from(f32::from_le_bytes(x)))),
634 size: 4,
635 })
636 } else {
637 Err(DataRecordError::InsufficientData)
638 }
639 }
640
641 Self::SelectionForReadout => Ok(Data {
642 value: None,
643 size: 0,
644 }),
645
646 Self::BCD2Digit => bcd_to_value!(input, 2),
647 Self::BCD4Digit => bcd_to_value!(input, 4),
648 Self::BCD6Digit => bcd_to_value!(input, 6),
649 Self::BCD8Digit => bcd_to_value!(input, 8),
650 Self::BCDDigit12 => bcd_to_value!(input, 12),
651
652 Self::VariableLength => {
653 let mut length = *input.first().ok_or(DataRecordError::InsufficientData)?;
654 match length {
655 0x00..=0xBF => Ok(Data {
656 value: Some(DataType::Text(TextUnit::new(
657 input
658 .get(1..(1 + length as usize))
659 .ok_or(DataRecordError::InsufficientData)?,
660 ))),
661 size: length as usize + 1,
662 }),
663 0xC0..=0xC9 => {
664 length -= 0xC0;
665 let bytes = input
666 .get(1..(1 + length as usize))
667 .ok_or(DataRecordError::InsufficientData)?;
668 match bcd_to_value!(bytes, 2 * length as usize) {
669 Ok(data) => Ok(Data {
670 value: data.value,
671 size: data.size + 1,
672 }),
673 Err(err) => Err(err),
674 }
675 }
676 0xD0..=0xD9 => {
677 length -= 0xD0;
678 let bytes = input
679 .get(1..(1 + length as usize))
680 .ok_or(DataRecordError::InsufficientData)?;
681 match bcd_to_value!(bytes, 2 * length as usize, -1) {
682 Ok(data) => Ok(Data {
683 value: data.value,
684 size: data.size + 1,
685 }),
686 Err(err) => Err(err),
687 }
688 }
689 0xE0..=0xEF => {
690 length -= 0xE0;
691 let bytes = input
692 .get(1..(1 + length as usize))
693 .ok_or(DataRecordError::InsufficientData)?;
694 match integer_to_value!(bytes, length as usize) {
695 Ok(data) => Ok(Data {
696 value: data.value,
697 size: data.size + 1,
698 }),
699 Err(err) => Err(err),
700 }
701 }
702 0xF0..=0xF4 => {
703 length -= 0xEC;
704 let bytes = input
705 .get(1..(1 + 4 * length as usize))
706 .ok_or(DataRecordError::InsufficientData)?;
707 match integer_to_value!(bytes, 4 * length as usize) {
708 Ok(data) => Ok(Data {
709 value: data.value,
710 size: data.size + 1,
711 }),
712 Err(err) => Err(err),
713 }
714 }
715 0xF5 => {
716 let bytes = input
717 .get(1..(1 + 48_usize))
718 .ok_or(DataRecordError::InsufficientData)?;
719 match integer_to_value!(bytes, 48_usize) {
720 Ok(data) => Ok(Data {
721 value: data.value,
722 size: data.size + 1,
723 }),
724 Err(err) => Err(err),
725 }
726 }
727 0xF6 => {
728 let bytes = input
729 .get(1..(1 + 64_usize))
730 .ok_or(DataRecordError::InsufficientData)?;
731 match integer_to_value!(bytes, 64_usize) {
732 Ok(data) => Ok(Data {
733 value: data.value,
734 size: data.size + 1,
735 }),
736 Err(err) => Err(err),
737 }
738 }
739 _ => Err(DataRecordError::DataInformationError(
740 DataInformationError::Unimplemented {
741 feature: "Variable length parsing for reserved length values",
742 },
743 )),
744 }
745 }
746
747 Self::SpecialFunctions(code) => match code {
748 SpecialFunctions::ManufacturerSpecific | SpecialFunctions::MoreRecordsFollow => {
749 Ok(Data {
750 value: Some(DataType::ManufacturerSpecific(input)),
751 size: input.len(),
752 })
753 }
754 SpecialFunctions::IdleFiller => Ok(Data {
755 value: None,
756 size: 0,
757 }),
758 SpecialFunctions::GlobalReadoutRequest => Ok(Data {
759 value: None,
760 size: 0,
761 }),
762 SpecialFunctions::Reserved => Err(DataRecordError::DataInformationError(
763 DataInformationError::InvalidValueInformation,
764 )),
765 },
766
767 Self::DateTypeG => {
768 let day = parse_single_or_every!(
769 input.first().ok_or(DataRecordError::InsufficientData)?,
770 0x1F,
771 0,
772 0
773 );
774 let month = parse_month!(input.get(1).ok_or(DataRecordError::InsufficientData)?);
775 let year = parse_year!(input, 0xF0, 0xE0, 0x7F);
776
777 Ok(Data {
778 value: Some(DataType::Date(day, month, year)),
779 size: 2,
780 })
781 }
782 Self::DateTimeTypeF => {
783 let minutes = parse_single_or_every!(
784 input.first().ok_or(DataRecordError::InsufficientData)?,
785 0x3F,
786 0x3F,
787 0
788 );
789 let hour = parse_single_or_every!(
790 input.get(1).ok_or(DataRecordError::InsufficientData)?,
791 0x1F,
792 0x1F,
793 0
794 );
795 let day = parse_single_or_every!(
796 input.get(2).ok_or(DataRecordError::InsufficientData)?,
797 0x1F,
798 0x1F,
799 0
800 );
801 let month = parse_month!(input.get(3).ok_or(DataRecordError::InsufficientData)?);
802 let year = parse_year!(input, 0xF0, 0xE0, 0x7F);
803
804 Ok(Data {
805 value: Some(DataType::DateTime(day, month, year, hour, minutes)),
806 size: 4,
807 })
808 }
809 Self::DateTimeTypeJ => {
810 let seconds = parse_single_or_every!(
811 input.first().ok_or(DataRecordError::InsufficientData)?,
812 0x3F,
813 0x3F,
814 0
815 );
816 let minutes = parse_single_or_every!(
817 input.get(1).ok_or(DataRecordError::InsufficientData)?,
818 0x3F,
819 0x3F,
820 0
821 );
822 let hours = parse_single_or_every!(
823 input.get(2).ok_or(DataRecordError::InsufficientData)?,
824 0x1F,
825 0x1F,
826 0
827 );
828
829 Ok(Data {
830 value: Some(DataType::Time(seconds, minutes, hours)),
831 size: 4,
832 })
833 }
834 Self::DateTimeTypeI => {
835 let seconds = parse_single_or_every!(
840 input.first().ok_or(DataRecordError::InsufficientData)?,
841 0x3F,
842 0x3F,
843 0
844 );
845
846 let minutes = parse_single_or_every!(
847 input.get(1).ok_or(DataRecordError::InsufficientData)?,
848 0x3F,
849 0x3F,
850 0
851 );
852
853 let hours = parse_single_or_every!(
854 input.get(2).ok_or(DataRecordError::InsufficientData)?,
855 0x1F,
856 0x1F,
857 0
858 );
859 let days = parse_single_or_every!(
860 input.get(3).ok_or(DataRecordError::InsufficientData)?,
861 0x1F,
862 0x1F,
863 0
864 );
865 let months = parse_month!(input.get(4).ok_or(DataRecordError::InsufficientData)?);
866 let year = parse_year!(input, 0xF0, 0xE0, 0x7F);
867
868 Ok(Data {
869 value: Some(DataType::DateTimeWithSeconds(
870 days, months, year, hours, minutes, seconds,
871 )),
872 size: 6,
873 })
874 }
875 }
876 }
877}
878
879impl DataInformation {
880 #[must_use]
881 pub const fn get_size(&self) -> usize {
882 self.size
883 }
884}
885#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
886#[derive(Debug, Clone, Copy, PartialEq)]
887#[cfg_attr(feature = "defmt", derive(defmt::Format))]
888#[non_exhaustive]
889pub enum FunctionField {
890 InstantaneousValue,
891 MaximumValue,
892 MinimumValue,
893 ValueDuringErrorState,
894}
895
896#[cfg(feature = "std")]
897impl std::fmt::Display for FunctionField {
898 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
899 match self {
900 FunctionField::InstantaneousValue => write!(f, "Inst"),
901 FunctionField::MaximumValue => write!(f, "Max"),
902 FunctionField::MinimumValue => write!(f, "Min"),
903 FunctionField::ValueDuringErrorState => write!(f, "Value During Error State"),
904 }
905 }
906}
907#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
908#[derive(Debug, Clone, Copy, PartialEq)]
909#[cfg_attr(feature = "defmt", derive(defmt::Format))]
910#[non_exhaustive]
911pub enum SpecialFunctions {
912 ManufacturerSpecific,
913 MoreRecordsFollow,
914 IdleFiller,
915 Reserved,
916 GlobalReadoutRequest,
917}
918
919#[cfg_attr(feature = "defmt", derive(defmt::Format))]
920pub struct Value {
921 pub data: f64,
922 pub byte_size: usize,
923}
924
925#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
926#[derive(Debug, Clone, Copy, PartialEq)]
927#[cfg_attr(feature = "defmt", derive(defmt::Format))]
928#[non_exhaustive]
929pub enum DataFieldCoding {
930 NoData,
931 Integer8Bit,
932 Integer16Bit,
933 Integer24Bit,
934 Integer32Bit,
935 Real32Bit,
936 Integer48Bit,
937 Integer64Bit,
938 SelectionForReadout,
939 BCD2Digit,
940 BCD4Digit,
941 BCD6Digit,
942 BCD8Digit,
943 VariableLength,
944 BCDDigit12,
945 SpecialFunctions(SpecialFunctions),
946 DateTypeG,
947 DateTimeTypeF,
948 DateTimeTypeJ,
949 DateTimeTypeI,
950}
951
952#[cfg(feature = "std")]
953impl std::fmt::Display for DataFieldCoding {
954 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
955 match self {
956 DataFieldCoding::NoData => write!(f, "No Data"),
957 DataFieldCoding::Integer8Bit => write!(f, "8-bit Integer"),
958 DataFieldCoding::Integer16Bit => write!(f, "16-bit Integer"),
959 DataFieldCoding::Integer24Bit => write!(f, "24-bit Integer"),
960 DataFieldCoding::Integer32Bit => write!(f, "32-bit Integer"),
961 DataFieldCoding::Real32Bit => write!(f, "32-bit Real"),
962 DataFieldCoding::Integer48Bit => write!(f, "48-bit Integer"),
963 DataFieldCoding::Integer64Bit => write!(f, "64-bit Integer"),
964 DataFieldCoding::SelectionForReadout => write!(f, "Selection for Readout"),
965 DataFieldCoding::BCD2Digit => write!(f, "BCD 2-digit"),
966 DataFieldCoding::BCD4Digit => write!(f, "BCD 4-digit"),
967 DataFieldCoding::BCD6Digit => write!(f, "BCD 6-digit"),
968 DataFieldCoding::BCD8Digit => write!(f, "BCD 8-digit"),
969 DataFieldCoding::VariableLength => write!(f, "Variable Length"),
970 DataFieldCoding::BCDDigit12 => write!(f, "BCD 12-digit"),
971 DataFieldCoding::DateTypeG => write!(f, "Date Type G"),
972 DataFieldCoding::DateTimeTypeF => write!(f, "Date Time Type F"),
973 DataFieldCoding::DateTimeTypeJ => write!(f, "Date Time Type J"),
974 DataFieldCoding::DateTimeTypeI => write!(f, "Date Time Type I"),
975 DataFieldCoding::SpecialFunctions(code) => write!(f, "Special Functions ({:?})", code),
976 }
977 }
978}
979
980#[cfg(test)]
981mod tests {
982
983 use super::*;
984 #[test]
985 fn test_data_information() {
986 let data = [0x13_u8];
987 let result = DataInformationBlock::try_from(data.as_slice());
988 let result = DataInformation::try_from(&result.unwrap());
989 assert_eq!(
990 result,
991 Ok(DataInformation {
992 storage_number: 0,
993 device: 0,
994 tariff: 0,
995 function_field: FunctionField::MaximumValue,
996 data_field_coding: DataFieldCoding::Integer24Bit,
997 data_information_extension: None,
998 size: 1,
999 })
1000 );
1001 }
1002
1003 #[test]
1004 fn test_complex_data_information() {
1005 let data = [0xc4, 0x80, 0x40];
1006 let result = DataInformationBlock::try_from(data.as_slice());
1007 let result = DataInformation::try_from(&result.unwrap());
1008 assert_eq!(
1009 result,
1010 Ok(DataInformation {
1011 storage_number: 1,
1012 device: 2,
1013 tariff: 0,
1014 function_field: FunctionField::InstantaneousValue,
1015 data_field_coding: DataFieldCoding::Integer32Bit,
1016 data_information_extension: None,
1017 size: 3,
1018 })
1019 );
1020 }
1021
1022 #[test]
1023 fn reverse_text_unit() {
1024 let original_value = [0x6c, 0x61, 0x67, 0x69];
1025 let parsed = TextUnit::new(&original_value);
1026 assert_eq!(&parsed, "igal");
1027 }
1028
1029 #[cfg(feature = "std")]
1030 #[test]
1031 fn text_unit_latin1_swedish_characters() {
1032 let bytes = [0xF6, 0x6D, 0x6C, 0x61, 0x4D]; let text = TextUnit::new(&bytes);
1035 assert_eq!(String::from(text), "Malmö");
1036 }
1037
1038 #[cfg(feature = "std")]
1039 #[test]
1040 fn text_unit_latin1_superscript_three() {
1041 let bytes = [0x68, 0x2F, 0xB3, 0x6D]; let text = TextUnit::new(&bytes);
1044 assert_eq!(String::from(text), "m³/h");
1045 }
1046
1047 #[cfg(feature = "std")]
1048 #[test]
1049 fn text_unit_utf8_superscript_three() {
1050 let bytes = [0x68, 0x2F, 0xB3, 0xC2, 0x6D]; let text = TextUnit::new(&bytes);
1053 assert_eq!(String::from(text), "m³/h");
1054 }
1055
1056 #[test]
1057 fn test_invalid_data_information() {
1058 let data = [
1059 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1060 ];
1061 let result = DataInformationBlock::try_from(data.as_slice());
1062 assert_eq!(result, Err(DataInformationError::DataTooLong));
1063 }
1064
1065 #[test]
1066 fn test_longest_data_information_not_too_long() {
1067 let data = [
1068 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01,
1069 ];
1070 let result = DataInformationBlock::try_from(data.as_slice());
1071 assert_ne!(result, Err(DataInformationError::DataTooLong));
1072 }
1073
1074 #[test]
1075 fn test_short_data_information() {
1076 let data = [0xFF];
1077 let result = DataInformationBlock::try_from(data.as_slice());
1078 assert_eq!(result, Err(DataInformationError::DataTooShort));
1079 }
1080
1081 #[test]
1082 fn test_data_inforamtion1() {
1083 let data = [178, 1];
1084 let result = DataInformationBlock::try_from(data.as_slice());
1085 assert!(result.is_ok());
1086 assert_eq!(result.unwrap().get_size(), 2);
1087 }
1088
1089 #[test]
1090 fn test_bcd_to_value_unsigned() {
1091 let data = [0x54, 0x76, 0x98];
1092 let result = bcd_to_value_internal(&data, 6, 1, false);
1093 assert_eq!(
1094 result.unwrap(),
1095 Data {
1096 value: Some(DataType::Number(987654.0)),
1097 size: 3
1098 }
1099 );
1100 }
1101
1102 #[test]
1103 fn test_bcd_to_value_invalid() {
1104 let data = [0x5A, 0x76, 0x98];
1105 let result = bcd_to_value_internal(&data, 6, 1, false);
1106 assert!(matches!(
1107 result,
1108 Err(DataRecordError::DataInformationError(
1109 DataInformationError::InvalidValueInformation
1110 ))
1111 ));
1112 }
1113
1114 #[test]
1115 fn test_integer_to_value_8_bit_positive() {
1116 let data = [0x7F];
1117 let result = integer_to_value_internal(&data, 1);
1118 assert_eq!(
1119 result,
1120 Data {
1121 value: Some(DataType::Number(127.0)),
1122 size: 1
1123 }
1124 );
1125 }
1126
1127 #[test]
1128 fn test_integer_to_value_8_bit_negative() {
1129 let data = [0xFF];
1130 let result = integer_to_value_internal(&data, 1);
1131 assert_eq!(
1132 result,
1133 Data {
1134 value: Some(DataType::Number(-1.0)),
1135 size: 1
1136 }
1137 );
1138 }
1139
1140 #[test]
1141 fn test_integer_to_value_64_bit_positive() {
1142 let data = [0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1143 let result = integer_to_value_internal(&data, 8);
1144 assert_eq!(
1145 result,
1146 Data {
1147 value: Some(DataType::Number(250.0)),
1148 size: 8
1149 }
1150 );
1151 }
1152
1153 #[test]
1154 fn test_integer_to_value_64_bit_negative() {
1155 let data = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
1156 let result = integer_to_value_internal(&data, 8);
1157 assert_eq!(
1158 result,
1159 Data {
1160 value: Some(DataType::Number(-1.0)),
1161 size: 8
1162 }
1163 );
1164 }
1165}