Skip to content

Commit 789af8f

Browse files
authored
Merge pull request #42 from Switch2-OliverW/variable_length_data
Extend Variable Length Data parsing
2 parents c144e84 + b9f43f5 commit 789af8f

File tree

2 files changed

+110
-17
lines changed

2 files changed

+110
-17
lines changed

src/user_data/data_information.rs

+46-17
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ impl DataInformationBlock<'_> {
1414
#[must_use]
1515
pub fn get_size(&self) -> usize {
1616
let mut size = 1;
17-
if let Some(vife) = &self.data_information_field_extension {
18-
size += vife.len();
17+
if let Some(dife) = &self.data_information_field_extension {
18+
size += dife.len();
1919
}
2020
size
2121
}
@@ -605,37 +605,66 @@ impl DataFieldCoding {
605605
0x00..=0xBF => Ok(Data {
606606
value: Some(DataType::Text(TextUnit::new(
607607
input
608-
.get(1..(length as usize))
608+
.get(1..(1 + length as usize))
609609
.ok_or(DataRecordError::InsufficientData)?,
610610
))),
611611
size: length as usize + 1,
612612
}),
613-
0xC0..=0xD9 => {
613+
0xC0..=0xC9 => {
614614
length -= 0xC0;
615-
let is_negative =
616-
*input.first().ok_or(DataRecordError::InsufficientData)? > 0xC9;
617-
let sign = if is_negative { -1 } else { 1 };
618-
bcd_to_value!(input, length as usize, sign)
615+
let bytes = input
616+
.get(1..(1 + length as usize))
617+
.ok_or(DataRecordError::InsufficientData)?;
618+
match bcd_to_value!(bytes, 2 * length as usize) {
619+
Ok(data) => Ok(Data {
620+
value: data.value,
621+
size: data.size + 1,
622+
}),
623+
Err(err) => Err(err),
624+
}
619625
}
620-
0xE0..=0xE9 => {
626+
0xD0..=0xD9 => {
627+
length -= 0xD0;
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, -1) {
632+
Ok(data) => Ok(Data {
633+
value: data.value,
634+
size: data.size + 1,
635+
}),
636+
Err(err) => Err(err),
637+
}
638+
}
639+
0xE0..=0xEF => {
621640
length -= 0xE0;
622-
todo!("0xE0-0xE9 not implemented for length {}", length);
641+
let bytes = input
642+
.get(1..(1 + length as usize))
643+
.ok_or(DataRecordError::InsufficientData)?;
644+
match integer_to_value!(bytes, length as usize) {
645+
Ok(data) => Ok(Data {
646+
value: data.value,
647+
size: data.size + 1,
648+
}),
649+
Err(err) => Err(err),
650+
}
623651
}
624652
0xF0..=0xF4 => {
625-
length -= 0xF0;
626-
todo!("0xF0-0xF4 not implemented for length {}", length);
653+
length -= 0xEC;
654+
// integer_to_value!(input, 4 * length as usize)
655+
todo!("Variable length handle 64 -> 128 bit numbers: {}", length);
627656
}
628657
0xF5 => {
629-
length = 6;
630-
todo!("0xF5 not implemented for length {}", length);
658+
// integer_to_value!(input, 48)
659+
todo!("Variable length handle 192 bit number: {}", length);
631660
}
632661
0xF6 => {
633-
length = 8;
634-
todo!("0xF6 not implemented for length {}", length);
662+
// integer_to_value!(input, 64)
663+
todo!("Variable length handle 256 bit number: {}", length);
635664
}
636665
_ => {
637666
todo!(
638-
"Variable length parsing for length: {} is a resreved value",
667+
"Variable length parsing for length: {} is a reserved value",
639668
length
640669
);
641670
}

src/user_data/variable_user_data.rs

+64
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,61 @@ impl<'a> From<(&'a [u8], &'a FixedDataHeader)> for DataRecords<'a> {
3232
}
3333
}
3434

35+
#[cfg(all(test, feature = "std"))]
3536
mod tests {
37+
use crate::user_data::{data_information::DataFieldCoding, data_record::DataRecord};
38+
39+
#[test]
40+
fn test_parse_variable_data_length() {
41+
use crate::user_data::data_information::DataFieldCoding;
42+
use crate::user_data::data_information::DataType;
43+
use crate::user_data::data_information::TextUnit;
44+
use crate::user_data::DataRecords;
45+
46+
let data: &[u8] = &[
47+
0x0D, 0x06, 0xC1, 0x12, 0x0D, 0x06, 0xD3, 0x12, 0x34, 0x56, 0x0D, 0x06, 0x02, 0x31,
48+
0x32, 0x0D, 0x06, 0xE1, 0xFF, 0x0D, 0x06, 0x00,
49+
];
50+
51+
let records: Vec<DataRecord<'_>> = DataRecords::from(data).flatten().collect();
52+
53+
assert_eq!(records.len(), 5);
54+
{
55+
let record = records.get(0).unwrap();
56+
let code = get_data_field_coding(record);
57+
assert_eq!(code, DataFieldCoding::VariableLength);
58+
let value = record.data.value.clone().unwrap();
59+
assert_eq!(value, DataType::Number(12.0))
60+
}
61+
{
62+
let record = records.get(1).unwrap();
63+
let code = get_data_field_coding(record);
64+
assert_eq!(code, DataFieldCoding::VariableLength);
65+
let value = record.data.value.clone().unwrap();
66+
assert_eq!(value, DataType::Number(-563412.0))
67+
}
68+
{
69+
let record = records.get(2).unwrap();
70+
let code = get_data_field_coding(record);
71+
assert_eq!(code, DataFieldCoding::VariableLength);
72+
let value = record.data.value.clone().unwrap();
73+
assert_eq!(value, DataType::Text(TextUnit::new(&[0x31, 0x32])))
74+
}
75+
{
76+
let record = records.get(3).unwrap();
77+
let code = get_data_field_coding(record);
78+
assert_eq!(code, DataFieldCoding::VariableLength);
79+
let value = record.data.value.clone().unwrap();
80+
assert_eq!(value, DataType::Number(-1.0))
81+
}
82+
{
83+
let record = records.get(4).unwrap();
84+
let code = get_data_field_coding(record);
85+
assert_eq!(code, DataFieldCoding::VariableLength);
86+
let value = record.data.value.clone().unwrap();
87+
assert_eq!(value, DataType::Text(TextUnit::new(&[])))
88+
}
89+
}
3690

3791
#[test]
3892
fn test_parse_variable_data() {
@@ -82,4 +136,14 @@ mod tests {
82136
/* Data block 3: unit 1, storage No 0, tariff 2, instantaneous energy, 218,37 kWh (6 digit BCD) */
83137
let _data = &[0x8B, 0x60, 0x04, 0x37, 0x18, 0x02];
84138
}
139+
140+
fn get_data_field_coding(record: &DataRecord) -> DataFieldCoding {
141+
record
142+
.data_record_header
143+
.processed_data_record_header
144+
.data_information
145+
.clone()
146+
.unwrap()
147+
.data_field_coding
148+
}
85149
}

0 commit comments

Comments
 (0)