Skip to content

Commit e660f9d

Browse files
committed
parse metadata
1 parent dc707fa commit e660f9d

File tree

6 files changed

+162
-42
lines changed

6 files changed

+162
-42
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ Cargo.lock
1313
# Added by cargo
1414

1515
/target
16+
17+
# Editor stuff
18+
.vscode

Cargo.toml

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ authors = ["Henk Oordt <[email protected]>"]
88

99
[dependencies]
1010
anyhow = { version = "1.0.60", features = ["backtrace"] }
11+
num_enum = "0.5.7"
1112
serialport = "4.2.0"
1213
thiserror = "1.0.32"
13-
14-
[[bin]]
15-
name = "ppk2"

setup-udev.sh

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
echo "Updating udev rules..."
2+
sudo echo 'ATTRS{idVendor}=="1915", ATTRS{idProduct}=="c00a", MODE="660", GROUP="plugdev", TAG+="uaccess"' > /etc/udev/rules.d/99-ppk2.rules;
3+
sudo udevadm control --reload-rules;
4+
echo "Done! Please disconnect and reconnect your device!"

src/cmd.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,18 @@ impl Command {
4949
Command::ResUserSet => 0,
5050
Command::SpikeFilteringOn => 0,
5151
Command::SpikeFilteringOff => 0,
52-
Command::GetMetaData => 0,
52+
Command::GetMetaData => 1000,
5353
Command::Reset => 0,
5454
Command::SetUserGains => 0,
5555
}
5656
}
57+
58+
pub fn response_complete(&self, response: &[u8]) -> bool {
59+
match self {
60+
Command::GetMetaData => response.ends_with(b"END\n"),
61+
_ => todo!(),
62+
}
63+
}
5764
}
5865

5966
impl Command {
@@ -75,7 +82,7 @@ impl<'c> Iterator for CommandBytes<'c> {
7582

7683
fn next(&mut self) -> Option<Self::Item> {
7784
use Command::*;
78-
match (self.cmd, self.index) {
85+
let b = match (self.cmd, self.index) {
7986
(NoOp, 0) => Some(0x00),
8087
(TriggerSet, 0) => Some(0x01),
8188
(AvgNumSet, 0) => Some(0x02),
@@ -101,6 +108,8 @@ impl<'c> Iterator for CommandBytes<'c> {
101108
(Reset, 0) => Some(0x20),
102109
(SetUserGains, 0) => Some(0x25),
103110
_ => None,
104-
}
111+
};
112+
self.index += 1;
113+
b
105114
}
106115
}

src/lib.rs

+142-36
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![doc = include_str!("../README.md")]
2+
use num_enum::{IntoPrimitive, TryFromPrimitive};
23
use serialport::SerialPort;
34
use std::{borrow::Cow, io, ops::Range, string::FromUtf8Error, time::Duration};
45
use thiserror::Error;
@@ -22,7 +23,7 @@ pub enum Error {
2223
Io(#[from] io::Error),
2324
#[error("Utf8 error {0}")]
2425
Utf8(#[from] FromUtf8Error),
25-
#[error("Parse")]
26+
#[error("Parse error in \"{0}\"")]
2627
Parse(String),
2728
}
2829

@@ -35,15 +36,15 @@ pub struct Ppk2 {
3536
impl Ppk2 {
3637
pub fn new<'a>(path: impl Into<Cow<'a, str>>) -> Result<Self> {
3738
let port = serialport::new(path, 9600)
38-
.timeout(Duration::from_millis(500))
39+
.timeout(Duration::from_millis(10000))
3940
.open()?;
4041
Ok(Self { port })
4142
}
4243

43-
pub fn get_metadata(&mut self) -> Result<Modifiers> {
44+
pub fn get_metadata(&mut self) -> Result<Metadata> {
4445
let response = self.send_command(Command::GetMetaData)?;
4546

46-
Modifiers::parse(response, None)
47+
Metadata::parse(response, None)
4748
}
4849

4950
pub fn reset(&mut self) -> Result<()> {
@@ -54,59 +55,164 @@ impl Ppk2 {
5455
pub fn send_command(&mut self, command: Command) -> Result<Vec<u8>> {
5556
self.port.write_all(&Vec::from_iter(command.bytes()))?;
5657
// Doesn't allocate if expected response length is 0
57-
let mut buf = Vec::with_capacity(command.expected_response_len());
58-
self.port.read_exact(&mut buf)?;
59-
Ok(buf)
58+
let mut response = Vec::with_capacity(command.expected_response_len());
59+
let mut buf = [0u8; 128];
60+
while !command.response_complete(&response) {
61+
let n = self.port.read(&mut buf)?;
62+
response.extend_from_slice(&buf[..n]);
63+
}
64+
65+
Ok(response)
6066
}
6167
}
6268

6369
#[derive(Debug)]
6470
pub struct Modifiers {
6571
r: [f32; 5],
66-
gs: [u8; 5],
67-
gi: [u8; 5],
68-
o: [u8; 5],
69-
s: [u8; 5],
70-
i: [u8; 5],
71-
ug: [u8; 5],
72-
}
73-
74-
impl Modifiers {
75-
pub fn merge(&mut self, incomplete: IncompleteModifiers) {
76-
merge!(r, incomplete);
77-
}
72+
gs: [f32; 5],
73+
gi: [f32; 5],
74+
o: [f32; 5],
75+
s: [f32; 5],
76+
i: [f32; 5],
77+
ug: [f32; 5],
7878
}
7979

8080
impl Default for Modifiers {
8181
fn default() -> Self {
8282
Self {
8383
r: [1031.64, 101.65, 10.15, 0.94, 0.043],
84-
gs: [1, 1, 1, 1, 1],
85-
gi: [1, 1, 1, 1, 1],
86-
o: [0, 0, 0, 0, 0],
87-
s: [0, 0, 0, 0, 0],
88-
i: [0, 0, 0, 0, 0],
89-
ug: [1, 1, 1, 1, 1],
84+
gs: [1., 1., 1., 1., 1.],
85+
gi: [1., 1., 1., 1., 1.],
86+
o: [0., 0., 0., 0., 0.],
87+
s: [0., 0., 0., 0., 0.],
88+
i: [0., 0., 0., 0., 0.],
89+
ug: [1., 1., 1., 1., 1.],
9090
}
9191
}
9292
}
9393

94-
impl Modifiers {
95-
pub fn parse(bytes: Vec<u8>, modifiers: Option<Modifiers>) -> Result<Self> {
96-
use Error::Parse;
94+
#[repr(u8)]
95+
#[derive(TryFromPrimitive, IntoPrimitive, Default, Debug)]
96+
pub enum Mode {
97+
#[default]
98+
Source = 0x01,
99+
Ampere = 0x02,
100+
}
97101

98-
let mut modifiers = modifiers.unwrap_or_default();
102+
#[derive(Default, Debug)]
103+
pub struct Metadata {
104+
modifiers: Modifiers,
105+
calibrated: bool,
106+
vdd: u16,
107+
hw: u32,
108+
mode: Mode,
109+
ia: u32,
110+
}
99111

100-
let metadata = String::from_utf8(bytes)?;
101-
dbg!(&metadata); // TODO may be JSON
102-
if !metadata.ends_with("END") {
103-
return Err(Parse(metadata));
112+
impl Metadata {
113+
/// Example metadata:
114+
/// ```
115+
/// Calibrated: 0
116+
/// R0: 1003.3506
117+
/// R1: 101.5865
118+
/// R2: 10.3027
119+
/// R3: 0.9636
120+
/// R4: 0.0564
121+
/// GS0: 0.0000
122+
/// GS1: 112.7890
123+
/// GS2: 18.0115
124+
/// GS3: 2.4217
125+
/// GS4: 0.0729
126+
/// GI0: 1.0000
127+
/// GI1: 0.9695
128+
/// GI2: 0.9609
129+
/// GI3: 0.9519
130+
/// GI4: 0.9582
131+
/// O0: 112.9420
132+
/// O1: 75.4627
133+
/// O2: 64.6020
134+
/// O3: 50.4983
135+
/// O4: 87.2177
136+
/// VDD: 3000
137+
/// HW: 9173
138+
/// mode: 2
139+
/// S0: 0.000000048
140+
/// S1: 0.000000596
141+
/// S2: 0.000005281
142+
/// S3: 0.000062577
143+
/// S4: 0.002940743
144+
/// I0: -0.000000104
145+
/// I1: -0.000001443
146+
/// I2: 0.000036439
147+
/// I3: -0.000374119
148+
/// I4: -0.009388455
149+
/// UG0: 1.00
150+
/// UG1: 1.00
151+
/// UG2: 1.00
152+
/// UG3: 1.00
153+
/// UG4: 1.00
154+
/// IA: 56
155+
/// END
156+
/// ```
157+
#[rustfmt::skip]
158+
pub fn parse(bytes: Vec<u8>, metadata: Option<Metadata>) -> Result<Self> {
159+
use Error::Parse;
160+
161+
let mut metadata = metadata.unwrap_or_default();
162+
let raw_metadata = String::from_utf8(bytes)?;
163+
if !raw_metadata.ends_with("END\n") {
164+
return Err(Parse(raw_metadata));
104165
}
105-
let lines = metadata.lines();
166+
167+
let lines = raw_metadata.lines();
106168
for line in lines {
107-
todo!("PArse line by line")
169+
// TODO kill this beast
170+
match line.split_once(": ") {
171+
Some(("Calibrated", calibrated)) => metadata.calibrated = calibrated != "0",
172+
Some(("R0", r0)) => metadata.modifiers.r[0] = r0.parse().map_err(|_| Parse(line.to_owned()))?,
173+
Some(("R1", r1)) => metadata.modifiers.r[1] = r1.parse().map_err(|_| Parse(line.to_owned()))?,
174+
Some(("R2", r2)) => metadata.modifiers.r[2] = r2.parse().map_err(|_| Parse(line.to_owned()))?,
175+
Some(("R3", r3)) => metadata.modifiers.r[3] = r3.parse().map_err(|_| Parse(line.to_owned()))?,
176+
Some(("R4", r4)) => metadata.modifiers.r[4] = r4.parse().map_err(|_| Parse(line.to_owned()))?,
177+
Some(("GS0", gs0)) => metadata.modifiers.gs[0] = gs0.parse().map_err(|_| Parse(line.to_owned()))?,
178+
Some(("GS1", gs1)) => metadata.modifiers.gs[1] = gs1.parse().map_err(|_| Parse(line.to_owned()))?,
179+
Some(("GS2", gs2)) => metadata.modifiers.gs[2] = gs2.parse().map_err(|_| Parse(line.to_owned()))?,
180+
Some(("GS3", gs3)) => metadata.modifiers.gs[3] = gs3.parse().map_err(|_| Parse(line.to_owned()))?,
181+
Some(("GS4", gs4)) => metadata.modifiers.gs[4] = gs4.parse().map_err(|_| Parse(line.to_owned()))?,
182+
Some(("GI0", gi0)) => metadata.modifiers.gi[0] = gi0.parse().map_err(|_| Parse(line.to_owned()))?,
183+
Some(("GI1", gi1)) => metadata.modifiers.gi[1] = gi1.parse().map_err(|_| Parse(line.to_owned()))?,
184+
Some(("GI2", gi2)) => metadata.modifiers.gi[2] = gi2.parse().map_err(|_| Parse(line.to_owned()))?,
185+
Some(("GI3", gi3)) => metadata.modifiers.gi[3] = gi3.parse().map_err(|_| Parse(line.to_owned()))?,
186+
Some(("GI4", gi4)) => metadata.modifiers.gi[4] = gi4.parse().map_err(|_| Parse(line.to_owned()))?,
187+
Some(("O0", o0)) => metadata.modifiers.o[0] = o0.parse().map_err(|_| Parse(line.to_owned()))?,
188+
Some(("O1", o1)) => metadata.modifiers.o[1] = o1.parse().map_err(|_| Parse(line.to_owned()))?,
189+
Some(("O2", o2)) => metadata.modifiers.o[2] = o2.parse().map_err(|_| Parse(line.to_owned()))?,
190+
Some(("O3", o3)) => metadata.modifiers.o[3] = o3.parse().map_err(|_| Parse(line.to_owned()))?,
191+
Some(("O4", o4)) => metadata.modifiers.o[4] = o4.parse().map_err(|_| Parse(line.to_owned()))?,
192+
Some(("VDD", vdd)) => metadata.vdd = vdd.parse().map_err(|_| Parse(line.to_owned()))?,
193+
Some(("HW", hw)) => metadata.hw = hw.parse().map_err(|_| Parse(line.to_owned()))?,
194+
Some(("mode", mode)) => metadata.mode = mode.parse::<u8>().map_err(|_| Parse(line.to_owned()))?.try_into().map_err(|_| Parse(line.to_owned()))?,
195+
Some(("S0", s0)) => metadata.modifiers.s[0] = s0.parse().map_err(|_| Parse(line.to_owned()))?,
196+
Some(("S1", s1)) => metadata.modifiers.s[0] = s1.parse().map_err(|_| Parse(line.to_owned()))?,
197+
Some(("S2", s2)) => metadata.modifiers.s[0] = s2.parse().map_err(|_| Parse(line.to_owned()))?,
198+
Some(("S3", s3)) => metadata.modifiers.s[0] = s3.parse().map_err(|_| Parse(line.to_owned()))?,
199+
Some(("S4", s4)) => metadata.modifiers.s[0] = s4.parse().map_err(|_| Parse(line.to_owned()))?,
200+
Some(("I0", i0)) => metadata.modifiers.i[0] = i0.parse().map_err(|_| Parse(line.to_owned()))?,
201+
Some(("I1", i1)) => metadata.modifiers.i[0] = i1.parse().map_err(|_| Parse(line.to_owned()))?,
202+
Some(("I2", i2)) => metadata.modifiers.i[0] = i2.parse().map_err(|_| Parse(line.to_owned()))?,
203+
Some(("I3", i3)) => metadata.modifiers.i[0] = i3.parse().map_err(|_| Parse(line.to_owned()))?,
204+
Some(("I4", i4)) => metadata.modifiers.i[0] = i4.parse().map_err(|_| Parse(line.to_owned()))?,
205+
Some(("UG0", ug0)) => metadata.modifiers.ug[0] = ug0.parse().map_err(|_| Parse(line.to_owned()))?,
206+
Some(("UG1", ug1)) => metadata.modifiers.ug[0] = ug1.parse().map_err(|_| Parse(line.to_owned()))?,
207+
Some(("UG2", ug2)) => metadata.modifiers.ug[0] = ug2.parse().map_err(|_| Parse(line.to_owned()))?,
208+
Some(("UG3", ug3)) => metadata.modifiers.ug[0] = ug3.parse().map_err(|_| Parse(line.to_owned()))?,
209+
Some(("UG4", ug4)) => metadata.modifiers.ug[0] = ug4.parse().map_err(|_| Parse(line.to_owned()))?,
210+
Some(("IA", ia)) => metadata.ia = ia.parse().map_err(|_| Parse(line.to_owned()))?,
211+
None if line == "END" => return Ok(metadata),
212+
_ => return Err(Parse(line.to_owned())),
213+
}
108214
}
109215

110-
todo!();
216+
Ok(metadata)
111217
}
112218
}

src/bin/ppk2.rs src/main.rs

File renamed without changes.

0 commit comments

Comments
 (0)