1use super::Signal;
2use crate::{Error, Result};
3
4#[inline]
7fn round(x: f64) -> f64 {
8 if x >= 0.0 {
10 (x + 0.5) as i64 as f64
11 } else {
12 (x - 0.5) as i64 as f64
13 }
14}
15
16impl Signal {
17 #[inline]
38 pub fn encode_raw(&self, physical_value: f64) -> Result<u64> {
39 if !physical_value.is_finite() {
42 return Err(Error::Encoding(Error::ENCODING_VALUE_OUT_OF_RANGE));
43 }
44
45 if physical_value < self.min || physical_value > self.max {
47 return Err(Error::Encoding(Error::ENCODING_VALUE_OUT_OF_RANGE));
48 }
49
50 let raw_float = if self.factor != 0.0 {
53 (physical_value - self.offset) / self.factor
54 } else {
55 0.0
57 };
58
59 let raw_signed = round(raw_float) as i64;
61
62 let raw_bits = if self.unsigned {
64 if raw_signed < 0 {
66 return Err(Error::Encoding(Error::ENCODING_VALUE_OVERFLOW));
67 }
68 let raw_unsigned = raw_signed as u64;
69 let max_value = if self.length >= 64 {
70 u64::MAX
71 } else {
72 (1u64 << self.length) - 1
73 };
74 if raw_unsigned > max_value {
75 return Err(Error::Encoding(Error::ENCODING_VALUE_OVERFLOW));
76 }
77 raw_unsigned
78 } else {
79 let (min_signed, max_signed) = if self.length >= 64 {
84 (i64::MIN, i64::MAX)
85 } else {
86 let half_range = 1i64 << (self.length - 1);
87 (-half_range, half_range - 1)
88 };
89
90 if raw_signed < min_signed || raw_signed > max_signed {
91 return Err(Error::Encoding(Error::ENCODING_VALUE_OVERFLOW));
92 }
93
94 if raw_signed >= 0 {
97 raw_signed as u64
98 } else {
99 let mask = if self.length >= 64 {
101 u64::MAX
102 } else {
103 (1u64 << self.length) - 1
104 };
105 (raw_signed as u64) & mask
106 }
107 };
108
109 Ok(raw_bits)
110 }
111
112 #[inline]
128 pub fn encode_to(&self, physical_value: f64, payload: &mut [u8]) -> Result<()> {
129 let start_bit = self.start_bit as usize;
130 let length = self.length as usize;
131
132 if self.required_len() > payload.len() {
135 return Err(Error::Encoding(Error::SIGNAL_EXTENDS_BEYOND_DATA));
136 }
137
138 let raw_bits = self.encode_raw(physical_value)?;
139 self.byte_order.insert_bits(payload, start_bit, length, raw_bits);
140 Ok(())
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::Signal;
147 use crate::Parser;
148
149 #[test]
150 fn test_encode_raw_unsigned() {
151 let signal = Signal::parse(
154 &mut Parser::new(b"SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
155 )
156 .unwrap();
157
158 let raw = signal.encode_raw(2000.0).unwrap();
159 assert_eq!(raw, 8000);
160 }
161
162 #[test]
163 fn test_encode_raw_with_offset() {
164 let signal =
167 Signal::parse(&mut Parser::new(b"SG_ Temp : 16|8@1- (1,-40) [-40|87] \"\"").unwrap())
168 .unwrap();
169
170 let raw = signal.encode_raw(50.0).unwrap();
171 assert_eq!(raw, 90);
172 }
173
174 #[test]
175 fn test_encode_raw_signed_negative() {
176 let signal = Signal::parse(
179 &mut Parser::new(b"SG_ Torque : 0|16@1- (0.01,0) [-327.68|327.67] \"Nm\"").unwrap(),
180 )
181 .unwrap();
182
183 let raw = signal.encode_raw(-10.0).unwrap();
184 assert_eq!(raw, 0xFC18);
186 }
187
188 #[test]
189 fn test_encode_raw_out_of_range() {
190 let signal = Signal::parse(
191 &mut Parser::new(b"SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
192 )
193 .unwrap();
194
195 let result = signal.encode_raw(9000.0);
197 assert!(result.is_err());
198
199 let result = signal.encode_raw(-100.0);
201 assert!(result.is_err());
202 }
203
204 #[test]
205 fn test_encode_decode_roundtrip() {
206 let signal = Signal::parse(
208 &mut Parser::new(b"SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] \"km/h\"").unwrap(),
209 )
210 .unwrap();
211
212 let raw = signal.encode_raw(100.0).unwrap();
214 assert_eq!(raw, 1000); let data = [0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let (decoded_raw, decoded_physical) = signal.decode_raw(&data).unwrap();
219 assert_eq!(decoded_raw, 1000);
220 assert!((decoded_physical - 100.0).abs() < 0.001);
221 }
222
223 #[test]
224 fn test_encode_to_little_endian() {
225 let signal = Signal::parse(
226 &mut Parser::new(b"SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] \"km/h\"").unwrap(),
227 )
228 .unwrap();
229
230 let mut payload = [0x00; 8];
231 signal.encode_to(100.0, &mut payload).unwrap();
232
233 assert_eq!(payload[0], 0xE8);
235 assert_eq!(payload[1], 0x03);
236 }
237
238 #[test]
239 fn test_encode_to_big_endian() {
240 let signal = Signal::parse(
241 &mut Parser::new(b"SG_ Pressure : 7|16@0+ (0.01,0) [0|655.35] \"kPa\"").unwrap(),
242 )
243 .unwrap();
244
245 let mut payload = [0x00; 8];
246 signal.encode_to(10.0, &mut payload).unwrap();
247
248 assert_eq!(payload[0], 0x03);
250 assert_eq!(payload[1], 0xE8);
251 }
252
253 #[test]
254 fn test_encode_to_at_offset() {
255 let signal =
256 Signal::parse(&mut Parser::new(b"SG_ Throttle : 24|8@1+ (1,0) [0|100] \"%\"").unwrap())
257 .unwrap();
258
259 let mut payload = [0x00; 8];
260 signal.encode_to(75.0, &mut payload).unwrap();
261
262 assert_eq!(payload[3], 75);
264 }
265
266 #[test]
267 fn test_encode_to_preserves_other_bits() {
268 let signal =
269 Signal::parse(&mut Parser::new(b"SG_ Gear : 8|8@1+ (1,0) [0|5] \"\"").unwrap())
270 .unwrap();
271
272 let mut payload = [0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
273 signal.encode_to(3.0, &mut payload).unwrap();
274
275 assert_eq!(payload[0], 0xFF);
277 assert_eq!(payload[1], 3);
278 assert_eq!(payload[2], 0xFF);
279 }
280}