1pub mod responses;
3
4pub mod command;
6
7pub mod config;
9
10pub mod acquisition;
12
13pub mod calibration;
15
16use serialport::SerialPort;
17use std::{error::Error, hash::Hasher, string::FromUtf8Error, time::Duration};
18#[macro_use]
19extern crate derive_more;
20
21use command::Command;
22use responses::{Get, ModInfoResp};
23
24
25#[derive(Debug, Display)]
27pub enum ReadError {
28 PipeError(std::io::Error),
30
31 ParseError(String),
33
34 #[display(
36 fmt = "ChecksumMismatch {{ expected: {}, actual: {} }}",
37 expected,
38 actual
39 )]
40 ChecksumMismatch { expected: u16, actual: u16 }, #[display(fmt = "SizeMismatch {{ expected: {}, actual: {} }}", expected, actual)]
46 SizeMismatch { expected: u16, actual: u16 },
47}
48
49impl Error for ReadError {}
50
51impl From<std::io::Error> for ReadError {
52 fn from(value: std::io::Error) -> Self {
53 Self::PipeError(value)
54 }
55}
56
57impl From<FromUtf8Error> for ReadError {
58 fn from(e: FromUtf8Error) -> Self {
59 Self::ParseError(format!("UTF8 String couldn't be parsed: {}", e))
60 }
61}
62
63#[derive(Debug, Display)]
65pub enum WriteError {
66 PipeError(std::io::Error),
68}
69
70impl Error for WriteError {}
71
72impl From<std::io::Error> for WriteError {
73 fn from(value: std::io::Error) -> Self {
74 Self::PipeError(value)
75 }
76}
77
78#[derive(Debug, Display)]
79pub enum RWError {
80 ReadError(ReadError),
82
83 WriteError(WriteError),
85
86 DeviceError(String),
88}
89
90impl Error for RWError {}
91
92impl From<WriteError> for RWError {
93 fn from(value: WriteError) -> Self {
94 Self::WriteError(value)
95 }
96}
97
98impl From<ReadError> for RWError {
99 fn from(value: ReadError) -> Self {
100 Self::ReadError(value)
101 }
102}
103
104pub struct Device {
117 serialport: Box<dyn SerialPort>,
118
119 read_checksum: crc16::State<crc16::XMODEM>,
121
122 read_bytes: u16,
124}
125
126impl Device {
127 pub fn new(serialport: impl Into<Box<dyn SerialPort>>) -> Self {
129 Self {
130 serialport: serialport.into(),
131 read_checksum: crc16::State::<crc16::XMODEM>::new(),
132 read_bytes: 0,
133 }
134 }
135
136 pub fn connect(port: Option<String>) -> Result<Self, Box<dyn Error>> {
151 let ports = serialport::available_ports()?;
152
153 let port = if let Some(provided_port) = port {
154 provided_port
155 } else {
156 match ports.into_iter().fold(None, |chosen, port| {
157 if port.port_name.contains("usb") {
158 Some(port)
159 } else {
160 chosen
161 }
162 }) {
163 Some(port) => port.port_name,
164 None => {
165 return Err(Box::new(serialport::Error::new(
166 serialport::ErrorKind::NoDevice,
167 "Could not auto-detect serial port",
168 )))
169 }
170 }
171 };
172
173 println!("Using port {}", port);
174
175 Ok(Device::new(
176 serialport::new(port, 38400)
177 .data_bits(serialport::DataBits::Eight)
178 .stop_bits(serialport::StopBits::One)
179 .parity(serialport::Parity::None)
180 .timeout(Duration::new(1, 0))
181 .open()?,
182 ))
183 }
184
185 pub fn write_frame(
187 &mut self,
188 command: Command,
189 payload: Option<&[u8]>,
190 ) -> Result<(), WriteError> {
191 let payload_length = if let Some(payload) = payload {
192 payload.len() as u16
193 } else {
194 0
195 };
196
197 let size = (payload_length + 5u16).to_be_bytes();
199 let command = command.discriminant().to_be_bytes();
200
201 let mut crc = crc16::State::<crc16::XMODEM>::new();
204
205 self.serialport.write(&size)?;
207 crc.update(&size);
208
209 self.serialport.write(&command)?;
211 crc.update(&command);
212
213 if let Some(payload_bytes) = payload {
214 self.serialport.write(payload_bytes)?;
216 crc.update(payload_bytes);
217 }
218
219 let crc = &(crc.finish() as u16).to_be_bytes();
221 self.serialport.write(crc)?;
222
223 Ok(())
224 }
225
226 fn end_frame(&mut self, expected_frame_len: u16) -> Result<(), ReadError> {
229 let expected_sum = self.read_checksum.finish() as u16;
232 let checksum: u16 = Get::<u16>::get(self)?;
233
234 self.read_checksum = crc16::State::<crc16::XMODEM>::new();
236
237 if expected_sum == checksum && self.read_bytes == expected_frame_len {
238 self.read_bytes = 0;
239 Ok(())
240 } else if self.read_bytes != expected_frame_len {
241 let read_bytes = self.read_bytes;
242 self.read_bytes = 0;
243 Err(ReadError::SizeMismatch {
244 expected: expected_frame_len,
245 actual: read_bytes,
246 })
247 } else {
248 self.read_bytes = 0;
249 Err(ReadError::ChecksumMismatch {
250 expected: expected_sum,
251 actual: checksum,
252 })
253 }
254 }
255
256 pub fn get_mod_info(&mut self) -> Result<ModInfoResp, RWError> {
258 self.write_frame(Command::GetModInfo, None)?;
259 let expected_size = Get::<u16>::get(self)?;
260 if Get::<u8>::get(self)? == Command::GetModInfoResp.discriminant() {
261 let device_type = Get::<u32>::get_string(self)?;
262 let revision = Get::<u32>::get_string(self)?;
263 self.end_frame(expected_size)?;
264 Ok(ModInfoResp {
265 device_type,
266 revision,
267 })
268 } else {
269 let _ = self.end_frame(expected_size);
270 Err(RWError::ReadError(ReadError::ParseError(
271 "Unexpected response type".to_string(),
272 )))
273 }
274 }
275
276 pub fn serial_number(&mut self) -> Result<u32, RWError> {
278 self.write_frame(Command::SerialNumber, None)?;
279 let expected_size = Get::<u16>::get(self)?;
280 if Get::<u8>::get(self)? == Command::SerialNumberResp.discriminant() {
281 let serial_number = Get::<u32>::get(self)?;
282 self.end_frame(expected_size)?;
283 Ok(serial_number)
284 } else {
285 let _ = self.end_frame(expected_size);
286 Err(RWError::ReadError(ReadError::ParseError(
287 "Unexpected response type".to_string(),
288 )))
289 }
290 }
291
292 pub fn save(&mut self) -> Result<(), RWError> {
295 self.write_frame(Command::Save, None)?;
296
297 let expected_size = Get::<u16>::get(self)?;
298 if Get::<u8>::get(self)? == Command::SaveDone.discriminant() {
299 let error_code = Get::<u16>::get(self)?;
300 self.end_frame(expected_size)?;
301 if error_code != 0 {
302 return Err(RWError::DeviceError(
303 "Recieved error code from device, settings not saved succesfully".to_string(),
304 ));
305 }
306 Ok(())
307 } else {
308 let _ = self.end_frame(expected_size);
309 Err(RWError::ReadError(ReadError::ParseError(
310 "Unexpected response type".to_string(),
311 )))
312 }
313 }
314
315 pub fn power_up(&mut self) -> Result<(), RWError> {
318 self.write_frame(Command::SerialNumber, None)?;
319
320 let expected_size = Get::<u16>::get(self)?;
321 let resp_command = Get::<u8>::get(self)?;
322
323 if resp_command == Command::PowerUpDone.discriminant() {
324 self.end_frame(expected_size)?;
325 Ok(())
326 } else if resp_command == Command::SerialNumberResp.discriminant() {
327 Get::<u32>::get(self)?;
330 self.end_frame(expected_size)?;
331 Ok(())
332 } else {
333 let _ = self.end_frame(expected_size);
334 Err(RWError::ReadError(ReadError::ParseError(
335 "Unexpected response type".to_string(),
336 )))
337 }
338 }
339
340 fn power_down_impl(&mut self) -> Result<(), RWError> {
344 self.write_frame(Command::PowerDown, None)?;
345
346 let expected_size = Get::<u16>::get(self)?;
347 if Get::<u8>::get(self)? == Command::PowerDownDone.discriminant() {
348 self.end_frame(expected_size)?;
349 Ok(())
350 } else {
351 let _ = self.end_frame(expected_size);
352 Err(RWError::ReadError(ReadError::ParseError(
353 "Unexpected response type".to_string(),
354 )))
355 }
356 }
357
358 #[cfg(feature = "reserved")]
365 pub fn power_down_raw(&mut self) -> Result<(), RWError> {
366 self.power_down_impl()
367 }
368
369 pub fn power_down(mut self) -> Result<(), RWError> {
377 let ret = match self.power_down_impl() {
378 Ok(_) => Ok(()),
379 Err(RWError::ReadError(_)) => Ok(()),
380 Err(e) => Err(e),
381 };
382 ret
383 }
384}
385
386#[cfg(test)]
389mod tests {
390 use crate::acquisition::*;
391 use crate::*;
392
393 #[test]
394 fn continuous_mode() {
395 let tp3 = Device::connect(None).expect("connects to device");
396 let mut tp3 = tp3
397 .continuous_mode_easy(0.25, vec![DataID::AccelX])
398 .expect("got into cont mode");
399 {
400 let mut iter = tp3.iter();
401 for _ in 0..16 {
402 assert!(match iter.next() { Some(Ok(Data { accel_x: Some(_accel_measurement), ..})) => true, _ => false }, "Calling next on interator in continuous mode should yield the data we asked for");
403 }
404 }
405
406 let mut tp3 = tp3.stop_continuous_mode_easy().unwrap();
407 {
408 let mut iter = tp3.iter();
409 assert!(
410 match iter.next() {
411 None => true,
412 _ => false,
413 },
414 "Stop continious mode should leave continuous mode"
415 )
416 }
417 }
418}