1use super::Signal;
2use crate::{Error, Result};
3
4impl Signal {
5 #[inline]
20 pub(crate) fn decode_raw(&self, data: &[u8]) -> Result<(i64, f64)> {
21 let start_bit = self.start_bit as usize;
22 let length = self.length as usize;
23 let end_byte = (start_bit + length - 1) / 8;
24
25 if end_byte >= data.len() {
26 return Err(Error::Decoding(Error::SIGNAL_EXTENDS_BEYOND_DATA));
27 }
28
29 let raw_bits = self.byte_order.extract_bits(data, start_bit, length);
30
31 let raw_value = if self.unsigned {
32 raw_bits as i64
33 } else {
34 let sign_bit_mask = 1u64 << (length - 1);
35 if (raw_bits & sign_bit_mask) != 0 {
36 let mask = !((1u64 << length) - 1);
37 (raw_bits | mask) as i64
38 } else {
39 raw_bits as i64
40 }
41 };
42
43 let physical_value = (raw_value as f64) * self.factor + self.offset;
44 Ok((raw_value, physical_value))
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::Signal;
51 use crate::Parser;
52
53 #[test]
54 fn test_decode_little_endian() {
55 let signal = Signal::parse(
56 &mut Parser::new(b"SG_ TestSignal : 0|16@1+ (1,0) [0|65535] \"\"").unwrap(),
57 )
58 .unwrap();
59 let data = [0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
61 let (_raw, value) = signal.decode_raw(&data).unwrap();
62 assert_eq!(value, 258.0);
63 }
64
65 #[test]
66 fn test_decode_big_endian() {
67 let signal = Signal::parse(
68 &mut Parser::new(b"SG_ TestSignal : 0|16@0+ (1,0) [0|65535] \"\"").unwrap(),
69 )
70 .unwrap();
71 let data = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
73 let (_raw, value) = signal.decode_raw(&data).unwrap();
74 assert!((0.0..=65535.0).contains(&value));
76 }
77
78 #[test]
79 fn test_decode_little_endian_with_offset() {
80 let signal =
81 Signal::parse(&mut Parser::new(b"SG_ Temp : 0|8@1- (1,-40) [-40|215] \"\"").unwrap())
82 .unwrap();
83 let data = [0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
85 let (_raw, value) = signal.decode_raw(&data).unwrap();
86 assert_eq!(value, 50.0);
87 }
88
89 #[test]
90 fn test_decode_big_endian_with_factor() {
91 let signal =
92 Signal::parse(&mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"\"").unwrap())
93 .unwrap();
94 let data = [0x1F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
97 let (_raw, value) = signal.decode_raw(&data).unwrap();
98 assert!((0.0..=16383.75).contains(&value)); }
101
102 #[test]
114 fn test_spec_section_10_3_little_endian_example() {
115 let signal = Signal::parse(
116 &mut Parser::new(b"SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] \"km/h\"").unwrap(),
117 )
118 .unwrap();
119
120 let data = [0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
122 let (_raw, value) = signal.decode_raw(&data).unwrap();
123
124 assert_eq!(
126 value, 10.0,
127 "Spec Section 10.3: Little-endian 0x64 should decode to 10.0 km/h"
128 );
129 }
130
131 #[test]
138 fn test_spec_section_10_4_big_endian_example() {
139 let signal = Signal::parse(
140 &mut Parser::new(b"SG_ Pressure : 7|16@0+ (0.01,0) [0|655.35] \"kPa\"").unwrap(),
141 )
142 .unwrap();
143
144 let data = [0x03, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
146 let (_raw, value) = signal.decode_raw(&data).unwrap();
147
148 assert_eq!(
150 value, 10.0,
151 "Spec Section 10.4: Big-endian 0x03E8 should decode to 10.0 kPa"
152 );
153 }
154
155 #[test]
161 fn test_spec_section_10_5_temperature_offset_example() {
162 let signal = Signal::parse(
163 &mut Parser::new(b"SG_ Temperature : 16|8@1- (1,-40) [-40|87] \"\"").unwrap(),
164 )
165 .unwrap();
166
167 let data1 = [0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00];
170 let (_raw, value1) = signal.decode_raw(&data1).unwrap();
171 assert_eq!(
172 value1, 87.0,
173 "Spec Section 10.5: raw=127 should decode to 87°C"
174 );
175
176 let data2 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
178 let (_raw, value2) = signal.decode_raw(&data2).unwrap();
179 assert_eq!(
180 value2, -40.0,
181 "Spec Section 10.5: raw=0 should decode to -40°C"
182 );
183 }
184
185 #[test]
189 fn test_spec_section_10_2_byte_order_values() {
190 use crate::ByteOrder;
191
192 assert_eq!(
194 ByteOrder::BigEndian as u8,
195 0,
196 "Spec Section 10.2: @0 = Big-Endian"
197 );
198 assert_eq!(
199 ByteOrder::LittleEndian as u8,
200 1,
201 "Spec Section 10.2: @1 = Little-Endian"
202 );
203 }
204
205 #[test]
208 fn test_spec_section_10_5_value_conversion_formula() {
209 let signal = Signal::parse(
211 &mut Parser::new(b"SG_ Test : 0|16@1+ (0.25,100) [0|1000] \"\"").unwrap(),
212 )
213 .unwrap();
214
215 let data = [0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
218 let (_raw, value) = signal.decode_raw(&data).unwrap();
219 assert_eq!(value, 200.0, "Spec Section 10.5: 400 * 0.25 + 100 = 200");
220 }
221}