1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(not(feature = "std"))]
4use defmt::Format;
5
6#[cfg(not(feature = "std"))]
7extern crate core as std;
8
9pub const DEVICE_FIRMWARE_VERSION: u8 = 14;
10
11#[derive(Clone, PartialEq, Debug)]
12#[cfg_attr(not(feature = "std"), derive(Format))]
13pub enum SyncVal {
14 Sync0,
15 Sync1,
16 Sync2,
17}
18
19#[derive(Clone, PartialEq, Debug)]
20#[cfg_attr(not(feature = "std"), derive(Format))]
21pub struct TopAndPrescaler {
22 avr_icr1: u16,
23 prescaler_key: u8,
24}
25
26impl TopAndPrescaler {
27 pub fn new_avr(top: u16, prescaler: Prescaler) -> Self {
28 let prescaler_key = match prescaler {
29 Prescaler::Scale8 => b'1',
30 Prescaler::Scale64 => b'2',
31 };
32
33 Self {
34 avr_icr1: top,
35 prescaler_key,
36 }
37 }
38 #[inline]
39 pub fn avr_icr1(&self) -> u16 {
40 self.avr_icr1
41 }
42
43 #[inline]
44 pub fn prescaler_key(&self) -> u8 {
45 self.prescaler_key
46 }
47}
48
49#[derive(Debug, Clone)]
50pub enum Prescaler {
51 Scale8,
52 Scale64,
53}
54
55impl Prescaler {
56 pub fn as_f64(&self) -> f64 {
57 match self {
58 Prescaler::Scale8 => 8.0,
59 Prescaler::Scale64 => 64.0,
60 }
61 }
62}
63
64#[derive(Clone, PartialEq, Debug)]
65#[cfg_attr(not(feature = "std"), derive(Format))]
66pub struct NewAOut {
67 pub aout0: u16,
68 pub aout1: u16,
69 pub aout_sequence: u8,
70}
71
72#[derive(Clone, PartialEq, Debug)]
73#[cfg_attr(not(feature = "std"), derive(Format))]
74pub enum UdevMsg {
75 Query,
76 Set([u8; 8]),
77}
78
79#[derive(Clone, PartialEq, Debug)]
80#[cfg_attr(not(feature = "std"), derive(Format))]
81pub enum UsbEvent {
82 TimestampQuery(u8),
83 VersionRequest,
84 Sync(SyncVal),
85 SetTop(TopAndPrescaler),
86 SetAOut(NewAOut),
87 Udev(UdevMsg),
88 SetLed(LedInfo),
89}
90
91#[derive(Clone, PartialEq, Debug)]
92#[cfg_attr(not(feature = "std"), derive(Format))]
93pub struct LedInfo {
94 pub max_duration_usec: u32,
100 pub max_overall_duty_cycle: f32,
108 pub nth_frame: u8,
116}
117
118impl Default for LedInfo {
119 fn default() -> Self {
120 Self {
121 max_duration_usec: 5_000,
122 max_overall_duty_cycle: 1.0,
123 nth_frame: 2,
124 }
125 }
126}
127
128const LED_MSG_BYTES: usize = 11;
129
130impl LedInfo {
131 #[cfg(feature = "std")]
132 pub fn encode(&self) -> [u8; LED_MSG_BYTES] {
133 let mut result: [u8; LED_MSG_BYTES] = [0; LED_MSG_BYTES];
134
135 result[0..2].copy_from_slice(b"L=");
136 result[2..6].copy_from_slice(&self.max_duration_usec.to_le_bytes());
137 result[6..10].copy_from_slice(&self.max_overall_duty_cycle.to_le_bytes());
138 result[10] = self.nth_frame;
139
140 result
141 }
142
143 pub fn raw_decode(buf: &[u8]) -> Result<LedInfo, Error> {
144 assert_eq!(buf.len(), LED_MSG_BYTES);
145 let arr = buf[2..6].try_into().unwrap();
146 let max_duration_usec = u32::from_le_bytes(arr);
147
148 let arr = buf[6..10].try_into().unwrap();
149 let max_overall_duty_cycle = f32::from_le_bytes(arr);
150
151 let nth_frame = buf[10];
152 Ok(LedInfo {
153 max_duration_usec,
154 max_overall_duty_cycle,
155 nth_frame,
156 })
157 }
158}
159
160#[derive(Clone, PartialEq, Debug)]
161#[cfg_attr(not(feature = "std"), derive(Format))]
162struct AccumState {
163 last_update: u64,
164}
165
166impl Default for AccumState {
167 fn default() -> Self {
168 Self { last_update: 0 }
169 }
170}
171
172pub const BUF_MAX_SZ: usize = 32;
173
174const MAX_AGE_USEC: u64 = 500_000;
176
177#[derive(Debug, Clone, PartialEq)]
178#[cfg_attr(not(feature = "std"), derive(Format))]
179pub enum Error {
180 AwaitingMoreData,
181 UnknownSyncValue,
182 UnknownData,
183}
184
185enum PState {
186 Empty,
187 Accumulating(AccumState),
188}
189
190pub struct PacketParser<'bb> {
191 prod: bbqueue::Producer<'bb, BUF_MAX_SZ>,
193 cons: bbqueue::Consumer<'bb, BUF_MAX_SZ>,
194 state: PState,
195}
196
197impl<'bb> PacketParser<'bb> {
198 pub fn new(backing_store: &'bb bbqueue::BBBuffer<BUF_MAX_SZ>) -> Self {
199 let (prod, cons) = backing_store.try_split().unwrap();
201
202 Self {
203 prod,
204 cons,
205 state: PState::Empty,
206 }
207 }
208
209 pub fn got_buf(&mut self, now_usec: u64, buf: &[u8]) -> Result<UsbEvent, Error> {
211 let mut accum_state = match &self.state {
212 PState::Empty => AccumState::default(),
213 PState::Accumulating(old_accum_state) => {
214 if (now_usec - old_accum_state.last_update) <= MAX_AGE_USEC {
215 old_accum_state.clone()
216 } else {
217 match self.cons.read() {
218 Ok(rgrant) => {
219 let sz = rgrant.len();
220 rgrant.release(sz);
221 }
222 Err(bbqueue::Error::InsufficientSize) => { }
223 Err(e) => {
224 panic!("error: {:?}", e);
225 }
226 }
227 AccumState::default()
228 }
229 }
230 };
231
232 let mut wgrant = self.prod.grant_exact(buf.len()).unwrap();
233 wgrant.clone_from_slice(buf);
234 wgrant.commit(buf.len());
235 accum_state.last_update = now_usec;
236
237 self.state = PState::Accumulating(accum_state);
238
239 let rgrant = self.cons.read().unwrap();
240 let buf = rgrant.buf();
241
242 let mut consumed_bytes = 0;
243
244 let mut result = Err(Error::AwaitingMoreData);
245
246 if buf.len() >= 2 {
247 if buf == b"V?" {
248 result = Ok(UsbEvent::VersionRequest);
249 consumed_bytes = 2;
250 } else if buf[0] == b'P' {
251 result = Ok(UsbEvent::TimestampQuery(buf[1]));
252 consumed_bytes = 2;
253 } else if buf == b"N?" {
254 result = Ok(UsbEvent::Udev(UdevMsg::Query));
255 consumed_bytes = 2;
256 } else if buf[0] == b'S' {
257 result = match buf[1] {
258 b'0' => Ok(UsbEvent::Sync(SyncVal::Sync0)),
259 b'1' => Ok(UsbEvent::Sync(SyncVal::Sync1)),
260 b'2' => Ok(UsbEvent::Sync(SyncVal::Sync2)),
261 _ => Err(Error::UnknownSyncValue),
262 };
263 consumed_bytes = 2;
264 } else if buf[0] == b'T' && buf[1] == b'=' {
265 if buf.len() < 5 {
266 } else {
268 let value0 = buf[2];
269 let value1 = buf[3];
270 let prescaler_key = buf[4];
271
272 let avr_icr1 = u16::from_le_bytes([value0, value1]);
273 result = Ok(UsbEvent::SetTop(TopAndPrescaler {
274 avr_icr1,
275 prescaler_key,
276 }));
277 consumed_bytes = 5;
278 }
279 } else if buf[0] == b'L' && buf[1] == b'=' {
280 if buf.len() < LED_MSG_BYTES {
281 } else {
283 let x2 = LedInfo::raw_decode(&buf[..LED_MSG_BYTES]).unwrap();
284 result = Ok(UsbEvent::SetLed(x2));
285 consumed_bytes = LED_MSG_BYTES;
286 }
287 } else if buf[0] == b'O' && buf[1] == b'=' {
288 if buf.len() < 7 {
289 } else {
291 let aout0_0 = buf[2];
292 let aout0_1 = buf[3];
293 let aout0 = u16::from_le_bytes([aout0_0, aout0_1]);
294
295 let aout1_0 = buf[4];
296 let aout1_1 = buf[5];
297 let aout1 = u16::from_le_bytes([aout1_0, aout1_1]);
298
299 let aout_sequence = buf[6];
300
301 result = Ok(UsbEvent::SetAOut(NewAOut {
302 aout0,
303 aout1,
304 aout_sequence,
305 }));
306 consumed_bytes = 7;
307 }
308 } else {
309 result = Err(Error::UnknownData);
310 consumed_bytes = 2;
311 }
314 }
315
316 rgrant.release(consumed_bytes);
317 result
318 }
319}
320
321#[cfg(test)]
323mod tests {
324 use super::*;
325
326 fn check_simple(buf: &[u8], expected: &UsbEvent) {
327 let bb: bbqueue::BBBuffer<BUF_MAX_SZ> = bbqueue::BBBuffer::new();
329 let mut pp = PacketParser::new(&bb);
330 let parsed = pp.got_buf(0, buf);
331 assert_eq!(parsed, Ok(expected.clone()));
332 }
333
334 fn check_stale(buf: &[u8], expected: &UsbEvent) {
335 let bb: bbqueue::BBBuffer<BUF_MAX_SZ> = bbqueue::BBBuffer::new();
337 let mut pp = PacketParser::new(&bb);
338 pp.got_buf(0, b"P").ok();
339 let parsed = pp.got_buf(MAX_AGE_USEC + 1, buf);
340 assert_eq!(parsed, Ok(expected.clone()));
341 }
342
343 fn check_multiple(buf: &[u8], expected: &UsbEvent) {
344 let bb: bbqueue::BBBuffer<BUF_MAX_SZ> = bbqueue::BBBuffer::new();
346 let mut pp = PacketParser::new(&bb);
347 assert_eq!(Ok(UsbEvent::TimestampQuery(b'2')), pp.got_buf(0, b"P2"));
348 let parsed = pp.got_buf(0, buf);
349 assert_eq!(parsed, Ok(expected.clone()));
350 assert_eq!(Ok(UsbEvent::TimestampQuery(b'3')), pp.got_buf(0, b"P3"));
351 }
352
353 #[test]
354 fn manual_serialization() {
355 for (buf, expected) in &[
356 (&b"V?"[..], UsbEvent::VersionRequest),
357 (&b"P1"[..], UsbEvent::TimestampQuery(b'1')),
358 (&b"S0"[..], UsbEvent::Sync(SyncVal::Sync0)),
359 (&b"S1"[..], UsbEvent::Sync(SyncVal::Sync1)),
360 (&b"S2"[..], UsbEvent::Sync(SyncVal::Sync2)),
361 ][..]
368 {
369 check_simple(buf, &expected);
370 check_stale(buf, &expected);
371 check_multiple(buf, &expected);
372 }
373 }
374
375 #[test]
376 fn set_led_roundtrip() {
377 let x1 = LedInfo::default();
378 let buf = x1.encode();
379 let x2 = LedInfo::raw_decode(&buf[..]).unwrap();
380 assert_eq!(x1, x2);
381 }
382}