use anyhow::Result;
use clap::Parser;
use ppk2::{
types::{DevicePower, MeasurementMode, SourceVoltage, LogicPortPins, Level},
Ppk2, try_find_ppk2_port, measurement::MeasurementMatch,
};
use std::{
sync::mpsc::RecvTimeoutError,
time::{Duration, Instant},
};
use tracing::{debug, error, info, Level as LogLevel};
use tracing_subscriber::FmtSubscriber;
#[derive(Parser)]
struct Args {
#[clap(
env,
short = 'p',
long,
help = "The serial port the PPK2 is connected to. If unspecified, will try to find the PPK2 automatically"
)]
serial_port: Option<String>,
#[clap(
env,
short = 'v',
long,
help = "The voltage of the device source in mV",
default_value = "0"
)]
voltage: SourceVoltage,
#[clap(
env,
short = 'e',
long,
help = "Enable power",
default_value = "disabled"
)]
power: DevicePower,
#[clap(
env,
short = 'm',
long,
help = "Measurement mode",
default_value = "source"
)]
mode: MeasurementMode,
#[clap(env, short = 'l', long, help = "The log level", default_value = "info")]
log_level: LogLevel,
#[clap(
env,
short = 's',
long,
help = "The maximum number of samples to be taken per second. Uses averaging of device samples Samples are analyzed in chunks, and as such the actual number of samples per second will deviate",
default_value = "100"
)]
sps: usize,
}
fn main() -> Result<()> {
let args = Args::parse();
let subscriber = FmtSubscriber::builder()
.with_max_level(args.log_level)
.finish();
tracing::subscriber::set_global_default(subscriber)?;
let ppk2_port = match args.serial_port {
Some(p) => p,
None => try_find_ppk2_port()?,
};
let mut ppk2 = Ppk2::new(ppk2_port, args.mode)?;
ppk2.set_source_voltage(args.voltage)?;
ppk2.set_device_power(args.power)?;
let mut levels = [Level::Either; 8];
levels[0] = Level::Low;
let pins = LogicPortPins::with_levels(levels);
let (rx, kill) = ppk2.start_measurement_matching(pins, args.sps)?;
let mut kill = Some(kill);
ctrlc::set_handler(move || {
kill.take().unwrap()().unwrap();
})?;
let mut count = 0usize;
let start = Instant::now();
let r: Result<()> = loop {
let rcv_res = rx.recv_timeout(Duration::from_millis(2000));
count += 1;
use MeasurementMatch::*;
match rcv_res {
Ok(Match(m)) => {
debug!("Last chunk average: {:.4} μA", m.micro_amps);
}
Ok(NoMatch) => {
debug!("No match in the last chunk of measurements");
}
Err(RecvTimeoutError::Disconnected) => break Ok(()),
Err(e) => {
error!("Error receiving data: {e:?}");
break Err(e)?;
}
}
};
let sample_time = Instant::now().duration_since(start).as_secs() as usize;
info!("Samples per second: {}", count / sample_time);
info!("Stopping measurements and resetting");
info!("Goodbye!");
r
}