Skip to content

Commit 4ee1ad8

Browse files
committed
Allow for fetching measurements while matching LogicPortPins
1 parent c1f9f01 commit 4ee1ad8

File tree

4 files changed

+117
-25
lines changed

4 files changed

+117
-25
lines changed

cli/src/main.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use anyhow::Result;
22
use clap::Parser;
33
use ppk2::{
4-
types::{DevicePower, MeasurementMode, SourceVoltage},
4+
types::{DevicePower, MeasurementMode, SourceVoltage, LogicPortPins, Level},
55
Ppk2, try_find_ppk2_port,
66
};
77

88
use std::{
99
sync::mpsc::RecvTimeoutError,
1010
time::{Duration, Instant},
1111
};
12-
use tracing::{debug, error, info, Level};
12+
use tracing::{debug, error, info, Level as LogLevel};
1313
use tracing_subscriber::FmtSubscriber;
1414

1515
#[derive(Parser)]
@@ -50,7 +50,7 @@ struct Args {
5050
mode: MeasurementMode,
5151

5252
#[clap(env, short = 'l', long, help = "The log level", default_value = "info")]
53-
log_level: Level,
53+
log_level: LogLevel,
5454

5555
#[clap(
5656
env,
@@ -79,7 +79,10 @@ fn main() -> Result<()> {
7979

8080
ppk2.set_source_voltage(args.voltage)?;
8181
ppk2.set_device_power(args.power)?;
82-
let (rx, kill) = ppk2.start_measuring(args.sps)?;
82+
let mut levels = [Level::Either; 8];
83+
levels[0] = Level::Low;
84+
let pins = LogicPortPins::with_levels(levels);
85+
let (rx, kill) = ppk2.start_measuring_while_matches(pins, args.sps)?;
8386

8487
let mut kill = Some(kill);
8588

ppk2/src/lib.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::{
1414
time::Duration,
1515
};
1616
use thiserror::Error;
17-
use types::{DevicePower, MeasurementMode, Metadata, SourceVoltage};
17+
use types::{DevicePower, LogicPortPins, MeasurementMode, Metadata, SourceVoltage};
1818

1919
use crate::cmd::Command;
2020

@@ -110,10 +110,14 @@ impl Ppk2 {
110110
/// - [Receiver] of [measurement::Result], and
111111
/// - A closure that can be called to stop the measurement parsing pipeline and return the
112112
/// device.
113-
pub fn start_measuring(
113+
pub fn start_measuring_while_matches(
114114
mut self,
115+
pins: LogicPortPins,
115116
sps: usize,
116-
) -> Result<(Receiver<measurement::Measurement>, impl FnOnce() -> Result<Self>)> {
117+
) -> Result<(
118+
Receiver<measurement::Measurement>,
119+
impl FnOnce() -> Result<Self>,
120+
)> {
117121
// Stuff needed to communicate with the main thread
118122
// ready allows main thread to signal worker when serial input buf is cleared.
119123
let ready = Arc::new((Mutex::new(false), Condvar::new()));
@@ -141,6 +145,7 @@ impl Ppk2 {
141145
let mut buf = [0u8; 1024];
142146
let mut measurement_buf = VecDeque::with_capacity(SPS_MAX);
143147
let mut missed = 0;
148+
let mut did_get_matches = false;
144149
loop {
145150
// Check whether the main thread has signaled
146151
// us to stop
@@ -155,8 +160,18 @@ impl Ppk2 {
155160
missed += accumulator.feed_into(&buf[..n], &mut measurement_buf);
156161
let len = measurement_buf.len();
157162
if len >= SPS_MAX / sps {
158-
let measurement = measurement_buf.drain(..).combine(missed);
159-
meas_tx.send(measurement)?;
163+
let measurement = measurement_buf.drain(..).combine_matching(missed, pins);
164+
match measurement {
165+
Some(m) => {
166+
meas_tx.send(m)?;
167+
did_get_matches = true;
168+
}
169+
None if did_get_matches => {
170+
break Ok(());
171+
},
172+
_ => {/* No matching measurements yet, wait for them to come up */},
173+
}
174+
160175
missed = 0;
161176
}
162177
}
@@ -210,4 +225,4 @@ pub fn try_find_ppk2_port() -> Result<String> {
210225
})
211226
.ok_or(Error::Ppk2NotFound)?
212227
.port_name)
213-
}
228+
}

ppk2/src/measurement.rs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::collections::VecDeque;
44

5-
use crate::types::{Metadata, LogicPortPins};
5+
use crate::types::{LogicPortPins, Metadata};
66

77
const ADC_MULTIPLIER: f32 = 1.8 / 163840.;
88
const SPIKE_FILTER_ALPHA: f32 = 0.18;
@@ -97,7 +97,10 @@ impl MeasurementAccumulator {
9797
self.state.expected_counter.replace(counter);
9898
}
9999

100-
buf.push_back(Measurement { micro_amps, pins: bits })
100+
buf.push_back(Measurement {
101+
micro_amps,
102+
pins: bits,
103+
})
101104
}
102105
self.buf.drain(..end);
103106
samples_missed
@@ -164,12 +167,15 @@ fn get_adc_result(
164167

165168
/// Extension trait for VecDeque<Measurement>
166169
pub trait MeasurementIterExt {
167-
/// Combine items into a single [Measurement]. T
168-
fn combine(self, missed: usize) -> Measurement;
170+
/// Combine items into a single [Measurement], if there are items.
171+
fn combine(self, missed: usize) -> Option<Measurement>;
172+
173+
/// Combine items with matching logic port pins into a single [Measurement], if any.
174+
fn combine_matching(self, missed: usize, matching_pins: LogicPortPins) -> Option<Measurement>;
169175
}
170176

171177
impl<I: Iterator<Item = Measurement>> MeasurementIterExt for I {
172-
fn combine(self, missed: usize) -> Measurement {
178+
fn combine(self, missed: usize) -> Option<Measurement> {
173179
let mut pin_high_count = [0usize; 8];
174180
let mut count = 0;
175181
let mut sum = 0f32;
@@ -180,10 +186,15 @@ impl<I: Iterator<Item = Measurement>> MeasurementIterExt for I {
180186
.inner()
181187
.iter()
182188
.enumerate()
183-
.filter(|(_, &p)| p)
189+
.filter(|(_, &p)| p.is_high())
184190
.for_each(|(i, _)| pin_high_count[i] += 1);
185191
});
186192

193+
if count == 0 {
194+
// No measurements
195+
return None;
196+
}
197+
187198
let mut pins = [false; 8];
188199
pin_high_count
189200
.into_iter()
@@ -192,10 +203,21 @@ impl<I: Iterator<Item = Measurement>> MeasurementIterExt for I {
192203
.for_each(|(i, _)| pins[i] = true);
193204
let avg = sum / (count - missed) as f32;
194205

195-
Measurement {
206+
Some(Measurement {
196207
micro_amps: avg,
197208
pins: pins.into(),
198-
}
209+
})
210+
}
211+
212+
fn combine_matching(self, missed: usize, matching_pins: LogicPortPins) -> Option<Measurement> {
213+
let iter = self.filter(|m| {
214+
m.pins
215+
.inner()
216+
.iter()
217+
.enumerate()
218+
.all(|(i, l)| l.matches(matching_pins.inner()[i]))
219+
});
220+
iter.combine(missed)
199221
}
200222
}
201223

ppk2/src/types.rs

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,17 +136,65 @@ impl FromStr for DevicePower {
136136
}
137137
}
138138

139+
/// Logic level for logic port pins
140+
#[derive(Debug, Clone, Copy)]
141+
pub enum Level {
142+
/// Low level
143+
Low,
144+
/// High level
145+
High,
146+
/// Either level. Used for matching only.
147+
Either,
148+
}
149+
150+
impl From<bool> for Level {
151+
fn from(level: bool) -> Self {
152+
use Level::*;
153+
match level {
154+
true => High,
155+
false => Low,
156+
}
157+
}
158+
}
159+
160+
impl Level {
161+
/// Check whether the level is high.
162+
pub fn is_high(&self) -> bool {
163+
matches!(self, Level::High)
164+
}
165+
166+
/// Check whether the level is low.
167+
pub fn is_low(&self) -> bool {
168+
matches!(self, Level::Low)
169+
}
170+
171+
/// Check whether the [Level] matches another.
172+
pub fn matches(&self, other: Level) -> bool {
173+
match (self, other) {
174+
(_, Level::Either) => true,
175+
(Level::Either, _) => true,
176+
(Level::Low, Level::Low) => true,
177+
(Level::High, Level::High) => true,
178+
_ => false,
179+
}
180+
}
181+
}
182+
139183
/// Logic port state
140184
#[derive(Debug, Clone, Copy)]
141185
pub struct LogicPortPins {
142-
pins: [bool; 8],
186+
pin_levels: [Level; 8],
143187
}
144188

145189
impl LogicPortPins {
190+
/// Set up a new [LogicPortPins] with given [Level]s
191+
pub fn with_levels(pin_levels: [Level; 8]) -> Self {
192+
Self { pin_levels }
193+
}
194+
146195
/// Check whether a pin level is high
147196
pub fn pin_is_high(&self, pin: usize) -> bool {
148-
assert!(pin < 8);
149-
self.pins[pin]
197+
self.pin_levels[pin].is_high()
150198
}
151199

152200
/// Check whether a pin level is low
@@ -155,14 +203,18 @@ impl LogicPortPins {
155203
}
156204

157205
/// Get a reference to the internal pin array
158-
pub fn inner(&self) -> &[bool; 8] {
159-
&self.pins
206+
pub fn inner(&self) -> &[Level; 8] {
207+
&self.pin_levels
160208
}
161209
}
162210

163211
impl From<[bool; 8]> for LogicPortPins {
164-
fn from(pins: [bool; 8]) -> Self {
165-
Self { pins }
212+
fn from(pin_bools: [bool; 8]) -> Self {
213+
let mut pins = [Level::Low; 8];
214+
pin_bools.iter().enumerate().for_each(|(i, &p)| {
215+
pins[i] = p.into();
216+
});
217+
Self { pin_levels: pins }
166218
}
167219
}
168220

0 commit comments

Comments
 (0)