1#![doc = include_str!("../README.md")]
2#![deny(missing_docs)]
3
4use measurement::{MeasurementAccumulator, MeasurementIterExt, MeasurementMatch};
5use serialport::{ClearBuffer::Input, FlowControl, SerialPort};
6use std::str::Utf8Error;
7use std::sync::mpsc::{self, Receiver, SendError, TryRecvError};
8use std::{
9 borrow::Cow,
10 collections::VecDeque,
11 io,
12 sync::{Arc, Condvar, Mutex},
13 thread,
14 time::Duration,
15};
16use thiserror::Error;
17use types::{DevicePower, LogicPortPins, MeasurementMode, Metadata, SourceVoltage};
18
19use crate::cmd::Command;
20
21pub mod cmd;
22pub mod measurement;
23pub mod types;
24
25const SPS_MAX: usize = 100_000;
26
27#[derive(Error, Debug)]
28#[allow(missing_docs)]
30pub enum Error {
31 #[error("Serial port error: {0}")]
32 SerialPort(#[from] serialport::Error),
33 #[error("PPK2 not found. Is the device connected and are permissions set correctly?")]
34 Ppk2NotFound,
35 #[error("IO error: {0}")]
36 Io(#[from] io::Error),
37 #[error("Utf8 error {0}")]
38 Utf8(#[from] Utf8Error),
39 #[error("Parse error in \"{0}\"")]
40 Parse(String),
41 #[error("Error sending measurement: {0}")]
42 SendMeasurement(#[from] SendError<MeasurementMatch>),
43 #[error("Error sending stop signal: {0}")]
44 SendStopSignal(#[from] SendError<()>),
45 #[error("Worker thread signal error: {0}")]
46 WorkerSignalError(#[from] TryRecvError),
47 #[error("Error deserializeing a measurement: {0:?}")]
48 DeserializeMeasurement(Vec<u8>),
49}
50
51#[allow(missing_docs)]
52pub type Result<T> = std::result::Result<T, Error>;
53
54pub struct Ppk2 {
56 port: Box<dyn SerialPort>,
57 metadata: Metadata,
58}
59
60impl Ppk2 {
61 pub fn new<'a>(path: impl Into<Cow<'a, str>>, mode: MeasurementMode) -> Result<Self> {
63 let mut port = serialport::new(path, 9600)
64 .timeout(Duration::from_millis(500))
65 .flow_control(FlowControl::Hardware)
66 .open()?;
67
68 if let Err(e) = port.clear(serialport::ClearBuffer::All) {
69 tracing::warn!("failed to clear buffers: {:?}", e);
70 }
71
72 if let Err(e) = port.write_data_terminal_ready(true) {
74 tracing::warn!("failed to set DTR: {:?}", e);
75 }
76
77 let mut ppk2 = Self {
78 port,
79 metadata: Metadata::default(),
80 };
81
82 ppk2.metadata = ppk2.get_metadata()?;
83 ppk2.set_power_mode(mode)?;
84 Ok(ppk2)
85 }
86
87 pub fn send_command(&mut self, command: Command) -> Result<Vec<u8>> {
89 self.port.write_all(&Vec::from_iter(command.bytes()))?;
90 let mut response = Vec::with_capacity(command.expected_response_len());
92 let mut buf = [0u8; 128];
93 while !command.response_complete(&response) {
94 let n = self.port.read(&mut buf)?;
95 response.extend_from_slice(&buf[..n]);
96 }
97 Ok(response)
98 }
99
100 fn try_get_metadata(&mut self) -> Result<Metadata> {
101 let response = self.send_command(Command::GetMetaData)?;
102 Metadata::from_bytes(&response)
103 }
104
105 pub fn get_metadata(&mut self) -> Result<Metadata> {
107 let mut result: Result<Metadata> = Err(Error::Parse("Metadata".to_string()));
108
109 for _ in 0..3 {
111 match self.try_get_metadata() {
112 Ok(metadata) => {
113 result = Ok(metadata);
114 break;
115 }
116 Err(e) => {
117 tracing::warn!("Error fetching metadata: {:?}. Retrying..", e);
118 }
119 }
120 }
121
122 result
123 }
124
125 pub fn set_device_power(&mut self, power: DevicePower) -> Result<()> {
127 self.send_command(Command::DeviceRunningSet(power))?;
128 Ok(())
129 }
130
131 pub fn set_source_voltage(&mut self, vdd: SourceVoltage) -> Result<()> {
133 self.send_command(Command::RegulatorSet(vdd))?;
134 Ok(())
135 }
136
137 pub fn start_measurement(
143 self,
144 sps: usize,
145 ) -> Result<(Receiver<MeasurementMatch>, impl FnOnce() -> Result<Self>)> {
146 self.start_measurement_matching(LogicPortPins::default(), sps)
147 }
148
149 pub fn start_measurement_matching(
155 mut self,
156 pins: LogicPortPins,
157 sps: usize,
158 ) -> Result<(Receiver<MeasurementMatch>, impl FnOnce() -> Result<Self>)> {
159 let ready = Arc::new((Mutex::new(false), Condvar::new()));
162 let (meas_tx, meas_rx) = mpsc::channel::<MeasurementMatch>();
164 let (sig_tx, sig_rx) = mpsc::channel::<()>();
167
168 let task_ready = ready.clone();
169 let mut port = self.port.try_clone()?;
170 let metadata = self.metadata.clone();
171
172 let t = thread::spawn(move || {
173 let r = || -> Result<()> {
174 let mut accumulator = MeasurementAccumulator::new(metadata);
176 let (lock, cvar) = &*task_ready;
179 let _l = cvar
180 .wait_while(lock.lock().unwrap(), |ready| !*ready)
181 .unwrap();
182
183 let mut buf = [0u8; 4];
190 let mut measurement_buf = VecDeque::with_capacity(SPS_MAX);
191 let mut missed = 0;
192 loop {
193 match sig_rx.try_recv() {
196 Ok(_) => return Ok(()),
197 Err(TryRecvError::Empty) => {}
198 Err(e) => return Err(e.into()),
199 }
200
201 let n = port.read(&mut buf)?;
203 missed += accumulator.feed_into(&buf[..n], &mut measurement_buf);
204 let len = measurement_buf.len();
205 if len >= SPS_MAX / sps {
206 let measurement = measurement_buf.drain(..).combine_matching(missed, pins);
207 meas_tx.send(measurement)?;
208 missed = 0;
209 }
210 }
211 };
212 let res = r();
213 if let Err(e) = &res {
214 tracing::error!("Error fetching measurements: {:?}", e);
215 };
216 res
217 });
218 self.port.clear(Input)?;
219
220 let (lock, cvar) = &*ready;
221 let mut ready = lock.lock().unwrap();
222 *ready = true;
223 cvar.notify_all();
224
225 self.send_command(Command::AverageStart)?;
226
227 let stop = move || {
228 sig_tx.send(())?;
229 t.join().expect("Data receive thread panicked")?;
230 self.send_command(Command::AverageStop)?;
231 Ok(self)
232 };
233
234 Ok((meas_rx, stop))
235 }
236
237 pub fn reset(mut self) -> Result<()> {
239 self.send_command(Command::Reset)?;
240 Ok(())
241 }
242
243 fn set_power_mode(&mut self, mode: MeasurementMode) -> Result<()> {
244 self.send_command(Command::SetPowerMode(mode))?;
245 Ok(())
246 }
247}
248
249pub fn try_find_ppk2_port() -> Result<String> {
251 use serialport::SerialPortType::UsbPort;
252
253 Ok(serialport::available_ports()?
254 .into_iter()
255 .find(|p| match &p.port_type {
256 UsbPort(usb) => usb.vid == 0x1915 && usb.pid == 0xc00a,
257 _ => false,
258 })
259 .ok_or(Error::Ppk2NotFound)?
260 .port_name)
261}