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 < self.min || physical_value > self.max {
41 return Err(Error::Encoding(Error::ENCODING_VALUE_OUT_OF_RANGE));
42 }
43
44 let raw_float = if self.factor != 0.0 {
47 (physical_value - self.offset) / self.factor
48 } else {
49 0.0
51 };
52
53 let raw_signed = round(raw_float) as i64;
55
56 let raw_bits = if self.unsigned {
58 if raw_signed < 0 {
60 return Err(Error::Encoding(Error::ENCODING_VALUE_OVERFLOW));
61 }
62 let raw_unsigned = raw_signed as u64;
63 let max_value = if self.length >= 64 {
64 u64::MAX
65 } else {
66 (1u64 << self.length) - 1
67 };
68 if raw_unsigned > max_value {
69 return Err(Error::Encoding(Error::ENCODING_VALUE_OVERFLOW));
70 }
71 raw_unsigned
72 } else {
73 let half_range = 1i64 << (self.length - 1);
76 let min_signed = -half_range;
77 let max_signed = half_range - 1;
78
79 if raw_signed < min_signed || raw_signed > max_signed {
80 return Err(Error::Encoding(Error::ENCODING_VALUE_OVERFLOW));
81 }
82
83 if raw_signed >= 0 {
86 raw_signed as u64
87 } else {
88 let mask = if self.length >= 64 {
90 u64::MAX
91 } else {
92 (1u64 << self.length) - 1
93 };
94 (raw_signed as u64) & mask
95 }
96 };
97
98 Ok(raw_bits)
99 }
100
101 #[inline]
117 pub fn encode_to(&self, physical_value: f64, payload: &mut [u8]) -> Result<()> {
118 let start_bit = self.start_bit as usize;
119 let length = self.length as usize;
120 let end_byte = (start_bit + length - 1) / 8;
121
122 if end_byte >= payload.len() {
123 return Err(Error::Encoding(Error::SIGNAL_EXTENDS_BEYOND_DATA));
124 }
125
126 let raw_bits = self.encode_raw(physical_value)?;
127 self.byte_order.insert_bits(payload, start_bit, length, raw_bits);
128 Ok(())
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::Signal;
135 use crate::Parser;
136
137 #[test]
138 fn test_encode_raw_unsigned() {
139 let signal = Signal::parse(
142 &mut Parser::new(b"SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
143 )
144 .unwrap();
145
146 let raw = signal.encode_raw(2000.0).unwrap();
147 assert_eq!(raw, 8000);
148 }
149
150 #[test]
151 fn test_encode_raw_with_offset() {
152 let signal =
155 Signal::parse(&mut Parser::new(b"SG_ Temp : 16|8@1- (1,-40) [-40|87] \"\"").unwrap())
156 .unwrap();
157
158 let raw = signal.encode_raw(50.0).unwrap();
159 assert_eq!(raw, 90);
160 }
161
162 #[test]
163 fn test_encode_raw_signed_negative() {
164 let signal = Signal::parse(
167 &mut Parser::new(b"SG_ Torque : 0|16@1- (0.01,0) [-327.68|327.67] \"Nm\"").unwrap(),
168 )
169 .unwrap();
170
171 let raw = signal.encode_raw(-10.0).unwrap();
172 assert_eq!(raw, 0xFC18);
174 }
175
176 #[test]
177 fn test_encode_raw_out_of_range() {
178 let signal = Signal::parse(
179 &mut Parser::new(b"SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
180 )
181 .unwrap();
182
183 let result = signal.encode_raw(9000.0);
185 assert!(result.is_err());
186
187 let result = signal.encode_raw(-100.0);
189 assert!(result.is_err());
190 }
191
192 #[test]
193 fn test_encode_decode_roundtrip() {
194 let signal = Signal::parse(
196 &mut Parser::new(b"SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] \"km/h\"").unwrap(),
197 )
198 .unwrap();
199
200 let raw = signal.encode_raw(100.0).unwrap();
202 assert_eq!(raw, 1000); let data = [0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let (decoded_raw, decoded_physical) = signal.decode_raw(&data).unwrap();
207 assert_eq!(decoded_raw, 1000);
208 assert!((decoded_physical - 100.0).abs() < 0.001);
209 }
210
211 #[test]
212 fn test_encode_to_little_endian() {
213 let signal = Signal::parse(
214 &mut Parser::new(b"SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] \"km/h\"").unwrap(),
215 )
216 .unwrap();
217
218 let mut payload = [0x00; 8];
219 signal.encode_to(100.0, &mut payload).unwrap();
220
221 assert_eq!(payload[0], 0xE8);
223 assert_eq!(payload[1], 0x03);
224 }
225
226 #[test]
227 fn test_encode_to_big_endian() {
228 let signal = Signal::parse(
229 &mut Parser::new(b"SG_ Pressure : 7|16@0+ (0.01,0) [0|655.35] \"kPa\"").unwrap(),
230 )
231 .unwrap();
232
233 let mut payload = [0x00; 8];
234 signal.encode_to(10.0, &mut payload).unwrap();
235
236 assert_eq!(payload[0], 0x03);
238 assert_eq!(payload[1], 0xE8);
239 }
240
241 #[test]
242 fn test_encode_to_at_offset() {
243 let signal =
244 Signal::parse(&mut Parser::new(b"SG_ Throttle : 24|8@1+ (1,0) [0|100] \"%\"").unwrap())
245 .unwrap();
246
247 let mut payload = [0x00; 8];
248 signal.encode_to(75.0, &mut payload).unwrap();
249
250 assert_eq!(payload[3], 75);
252 }
253
254 #[test]
255 fn test_encode_to_preserves_other_bits() {
256 let signal =
257 Signal::parse(&mut Parser::new(b"SG_ Gear : 8|8@1+ (1,0) [0|5] \"\"").unwrap())
258 .unwrap();
259
260 let mut payload = [0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
261 signal.encode_to(3.0, &mut payload).unwrap();
262
263 assert_eq!(payload[0], 0xFF);
265 assert_eq!(payload[1], 3);
266 assert_eq!(payload[2], 0xFF);
267 }
268}