1use crate::{utils::*, Error, Result, Time, MAX_BITS};
2use std::{fmt, str};
3
4pub type LineId = u32;
6
7pub type BitId = u8;
9
10#[derive(Debug, Clone)]
12pub struct LineMap {
13 map: Vec<BitId>,
14}
15
16impl LineMap {
17 const NOT_LINE: BitId = MAX_BITS;
18
19 pub fn new(lines: &[LineId]) -> Self {
21 let mut map: Vec<BitId> = (0..=lines.iter().max().copied().unwrap_or(0))
22 .map(|_| Self::NOT_LINE)
23 .collect();
24 for i in 0..lines.len() {
25 map[lines[i] as usize] = i as _;
26 }
27 Self { map }
28 }
29
30 pub fn get(&self, line: LineId) -> Result<BitId> {
32 let line = line as usize;
33 if line < self.map.len() {
34 let val = self.map[line];
35 if val != Self::NOT_LINE {
36 return Ok(val as _);
37 }
38 }
39 Err(invalid_data("Unknown line offset"))
40 }
41}
42
43#[derive(Debug, Clone)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
46pub struct LineInfo {
47 pub direction: Direction,
49
50 pub active: Active,
52
53 pub edge: EdgeDetect,
55
56 pub used: bool,
60
61 pub bias: Bias,
63
64 pub drive: Drive,
66
67 pub name: String,
69
70 pub consumer: String,
72}
73
74impl fmt::Display for LineInfo {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 if self.name.is_empty() {
77 write!(f, "\t unnamed")?;
78 } else {
79 write!(f, "\t {:?}", self.name)?;
80 }
81 if self.consumer.is_empty() {
82 write!(f, "\t unused")?;
83 } else {
84 write!(f, "\t {:?}", self.consumer)?;
85 }
86 write!(f, "\t {}", self.direction)?;
87 write!(f, "\t active-{}", self.active)?;
88 if !matches!(self.edge, EdgeDetect::Disable) {
89 write!(f, "\t {}-edge", self.edge)?;
90 }
91 if !matches!(self.bias, Bias::Disable) {
92 write!(f, "\t {}", self.edge)?;
93 }
94 if !matches!(self.drive, Drive::PushPull) {
95 write!(f, "\t {}", self.drive)?;
96 }
97 if self.used {
98 write!(f, "\t [used]")?;
99 }
100 Ok(())
101 }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
107#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
108#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
109#[repr(u8)]
110pub enum Direction {
111 #[cfg_attr(feature = "clap", clap(aliases = ["i", "in"]))]
113 Input,
114 #[cfg_attr(feature = "clap", clap(aliases = ["o", "out"]))]
116 Output,
117}
118
119impl Default for Direction {
120 fn default() -> Self {
121 Self::Input
122 }
123}
124
125impl AsRef<str> for Direction {
126 fn as_ref(&self) -> &str {
127 match self {
128 Self::Input => "input",
129 Self::Output => "output",
130 }
131 }
132}
133
134impl fmt::Display for Direction {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 self.as_ref().fmt(f)
137 }
138}
139
140impl str::FromStr for Direction {
141 type Err = Error;
142
143 fn from_str(s: &str) -> Result<Self> {
144 Ok(match s {
145 "i" | "in" | "input" => Self::Input,
146 "o" | "out" | "output" => Self::Output,
147 _ => return Err(invalid_input("Not recognized direction")),
148 })
149 }
150}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
159#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
161#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
162#[repr(u8)]
163pub enum Active {
164 #[cfg_attr(feature = "clap", clap(aliases = ["l", "lo"]))]
166 Low,
167 #[cfg_attr(feature = "clap", clap(aliases = ["h", "hi"]))]
169 High,
170}
171
172impl Default for Active {
173 fn default() -> Self {
174 Self::High
175 }
176}
177
178impl AsRef<str> for Active {
179 fn as_ref(&self) -> &str {
180 match self {
181 Self::Low => "low",
182 Self::High => "high",
183 }
184 }
185}
186
187impl fmt::Display for Active {
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 self.as_ref().fmt(f)
190 }
191}
192
193impl str::FromStr for Active {
194 type Err = Error;
195
196 fn from_str(s: &str) -> Result<Self> {
197 Ok(match s {
198 "l" | "lo" | "low" | "active-low" => Self::Low,
199 "h" | "hi" | "high" | "active-high" => Self::High,
200 _ => return Err(invalid_input("Not recognized active state")),
201 })
202 }
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
207#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
208#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
209#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
210#[repr(u8)]
211pub enum Edge {
212 #[cfg_attr(feature = "clap", clap(aliases = ["r", "rise"]))]
214 Rising,
215 #[cfg_attr(feature = "clap", clap(aliases = ["f", "fall"]))]
217 Falling,
218}
219
220impl AsRef<str> for Edge {
221 fn as_ref(&self) -> &str {
222 match self {
223 Self::Rising => "rising",
224 Self::Falling => "falling",
225 }
226 }
227}
228
229impl fmt::Display for Edge {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 self.as_ref().fmt(f)
232 }
233}
234
235impl str::FromStr for Edge {
236 type Err = Error;
237
238 fn from_str(s: &str) -> Result<Self> {
239 Ok(match s {
240 "r" | "rise" | "rising" => Self::Rising,
241 "f" | "fall" | "falling" => Self::Falling,
242 _ => return Err(invalid_input("Not recognized edge")),
243 })
244 }
245}
246
247#[derive(Debug, Clone, Copy)]
249#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
250pub struct Event {
251 pub line: BitId,
253 pub edge: Edge,
255 pub time: Time,
257}
258
259impl fmt::Display for Event {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 '#'.fmt(f)?;
262 self.line.fmt(f)?;
263 ' '.fmt(f)?;
264 self.edge.fmt(f)?;
265 ' '.fmt(f)?;
266 self.time.as_nanos().fmt(f)
267 }
268}
269
270#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
272#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
273#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
274#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
275#[repr(u8)]
276pub enum EdgeDetect {
277 #[cfg_attr(feature = "clap", clap(aliases = ["d", "dis"]))]
279 Disable,
280 #[cfg_attr(feature = "clap", clap(aliases = ["r", "rise"]))]
282 Rising,
283 #[cfg_attr(feature = "clap", clap(aliases = ["f", "fall"]))]
285 Falling,
286 #[cfg_attr(feature = "clap", clap(aliases = ["b"]))]
288 Both,
289}
290
291impl Default for EdgeDetect {
292 fn default() -> Self {
293 Self::Disable
294 }
295}
296
297impl AsRef<str> for EdgeDetect {
298 fn as_ref(&self) -> &str {
299 match self {
300 Self::Disable => "disable",
301 Self::Rising => "rising",
302 Self::Falling => "falling",
303 Self::Both => "both",
304 }
305 }
306}
307
308impl fmt::Display for EdgeDetect {
309 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310 self.as_ref().fmt(f)
311 }
312}
313
314impl str::FromStr for EdgeDetect {
315 type Err = Error;
316
317 fn from_str(s: &str) -> Result<Self> {
318 Ok(match s {
319 "d" | "dis" | "disable" => Self::Disable,
320 "r" | "rise" | "rising" => Self::Rising,
321 "f" | "fall" | "falling" => Self::Falling,
322 "b" | "both" | "rise-fall" | "rising-falling" => Self::Both,
323 _ => return Err(invalid_input("Not recognized edge-detect")),
324 })
325 }
326}
327
328#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
333#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
334#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
335#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
336#[repr(u8)]
337pub enum Bias {
338 #[cfg_attr(feature = "clap", clap(aliases = ["d", "dis"]))]
340 Disable,
341 #[cfg_attr(feature = "clap", clap(aliases = ["pu"]))]
343 PullUp,
344 #[cfg_attr(feature = "clap", clap(aliases = ["pd"]))]
346 PullDown,
347}
348
349impl Default for Bias {
350 fn default() -> Self {
351 Self::Disable
352 }
353}
354
355impl AsRef<str> for Bias {
356 fn as_ref(&self) -> &str {
357 match self {
358 Self::Disable => "disable",
359 Self::PullUp => "pull-up",
360 Self::PullDown => "pull-down",
361 }
362 }
363}
364
365impl fmt::Display for Bias {
366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 self.as_ref().fmt(f)
368 }
369}
370
371impl str::FromStr for Bias {
372 type Err = Error;
373
374 fn from_str(s: &str) -> Result<Self> {
375 Ok(match s {
376 "d" | "dis" | "disable" => Self::Disable,
377 "pu" | "pull-up" => Self::PullUp,
378 "pd" | "pull-down" => Self::PullUp,
379 _ => return Err(invalid_input("Not recognized input bias")),
380 })
381 }
382}
383
384#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
388#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
389#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
390#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
391#[repr(u8)]
392pub enum Drive {
393 #[cfg_attr(feature = "clap", clap(aliases = ["pp"]))]
395 PushPull,
396 #[cfg_attr(feature = "clap", clap(aliases = ["od"]))]
398 OpenDrain,
399 #[cfg_attr(feature = "clap", clap(aliases = ["os"]))]
401 OpenSource,
402}
403
404impl Default for Drive {
405 fn default() -> Self {
406 Self::PushPull
407 }
408}
409
410impl AsRef<str> for Drive {
411 fn as_ref(&self) -> &str {
412 match self {
413 Self::PushPull => "push-pull",
414 Self::OpenDrain => "open-drain",
415 Self::OpenSource => "open-source",
416 }
417 }
418}
419
420impl fmt::Display for Drive {
421 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
422 self.as_ref().fmt(f)
423 }
424}
425
426impl str::FromStr for Drive {
427 type Err = Error;
428
429 fn from_str(s: &str) -> Result<Self> {
430 Ok(match s {
431 "pp" | "push-pull" => Self::PushPull,
432 "od" | "open-drain" => Self::OpenDrain,
433 "os" | "open-source" => Self::OpenSource,
434 _ => return Err(invalid_input("Not recognized output drive")),
435 })
436 }
437}