scrapyard_core/
pin.rs

1#[derive(Debug)]
2pub struct PinBuilder<'a> {
3    pin_type: &'a str,
4    position: Position,
5    name: &'a str,
6    signals: Option<Vec<String>>,
7    current: Option<usize>,
8}
9
10impl<'a> PinBuilder<'a> {
11    pub fn new(pin_type: &'a str, position: Position, name: &'a str) -> PinBuilder<'a> {
12        PinBuilder {
13            pin_type: pin_type,
14            name: name,
15            position: position,
16            signals: None,
17            current: None,
18        }
19    }
20
21    pub fn signals(&mut self, signals: Vec<String>, current: usize) -> PinBuilder<'a> {
22        PinBuilder {
23            pin_type: self.pin_type,
24            name: self.name,
25            position: self.position,
26            signals: Some(signals),
27            current: Some(current),
28        }
29    }
30
31    pub fn finish(self) -> Pin {
32        let current = match self.current {
33            Some(idx) => match &self.signals {
34                &Some(ref signals) => {
35                    if idx < signals.len() {
36                        Some(idx)
37                    } else {
38                        None
39                    }
40                }
41                &None => None,
42            },
43            None => None,
44        };
45
46        // TODO: Return also error
47        match self.pin_type {
48            "NC" => Pin::NC {
49                name: String::from(self.name),
50                position: self.position,
51            },
52            "BOOT" => Pin::BOOT {
53                name: String::from(self.name),
54                position: self.position,
55            },
56            "Reset" => Pin::NRST {
57                name: String::from(self.name),
58                position: self.position,
59            },
60            "Power" => Pin::POWER {
61                name: String::from(self.name),
62                position: self.position,
63            },
64            "I/O" => {
65                return Pin::IO {
66                    name: String::from(self.name),
67                    position: self.position,
68                    params: Box::new(IOPin {
69                        reset: true,
70                        label: String::new(),
71                        signals: match self.signals {
72                            Some(s) => s,
73                            None => Vec::new(),
74                        },
75                        current: current,
76                    }),
77                }
78            }
79            &_ => Pin::NC {
80                name: String::from(self.name),
81                position: self.position,
82            },
83        }
84    }
85}
86
87#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
88pub enum Position {
89    Linear(u16),
90    Grid(u8, u8),
91}
92
93#[derive(Serialize, Deserialize, Debug)]
94pub struct IOPin {
95    reset: bool,
96    label: String,
97    signals: Vec<String>,
98    current: Option<usize>,
99}
100
101impl IOPin {
102    pub fn reset(&mut self) {
103        self.reset = true;
104    }
105
106    pub fn is_reset(&self) -> bool {
107        self.reset
108    }
109
110    pub fn set_label(&mut self, label: &str) {
111        self.label = label.to_string();
112    }
113
114    pub fn label(&self) -> &str {
115        &self.label
116    }
117
118    pub fn signals(&self) -> &Vec<String> {
119        &self.signals
120    }
121
122    pub fn select_signal(&mut self, signal: &str) -> bool {
123        let item = self.signals.iter().position(|r| r.as_str() == signal);
124
125        match item {
126            Some(idx) => {
127                self.current = Some(idx);
128                true
129            }
130            None => {
131                self.current = None;
132                false
133            }
134        }
135    }
136
137    pub fn current_signal(&self) -> Option<&str> {
138        match self.current {
139            Some(idx) => Some(&self.signals[idx]),
140            None => None,
141        }
142    }
143}
144
145#[derive(Serialize, Deserialize, Debug)]
146pub enum Pin {
147    NC {
148        name: String,
149        position: Position,
150    },
151    IO {
152        name: String,
153        position: Position,
154        params: Box<IOPin>,
155    },
156    BOOT {
157        name: String,
158        position: Position,
159    },
160    NRST {
161        name: String,
162        position: Position,
163    },
164    POWER {
165        name: String,
166        position: Position,
167    },
168}
169
170impl Pin {
171    pub fn name(&self) -> &str {
172        match *self {
173            Pin::NC { ref name, .. } => &name,
174            Pin::IO { ref name, .. } => &name,
175            Pin::BOOT { ref name, .. } => &name,
176            Pin::NRST { ref name, .. } => &name,
177            Pin::POWER { ref name, .. } => &name,
178        }
179    }
180
181    pub fn position(&self) -> &Position {
182        match *self {
183            Pin::NC { ref position, .. } => &position,
184            Pin::IO { ref position, .. } => &position,
185            Pin::BOOT { ref position, .. } => &position,
186            Pin::NRST { ref position, .. } => &position,
187            Pin::POWER { ref position, .. } => &position,
188        }
189    }
190
191    pub fn params(&self) -> Option<&IOPin> {
192        match *self {
193            Pin::IO { ref params, .. } => Some(params),
194            _ => None,
195        }
196    }
197
198    pub fn params_mut(&mut self) -> Option<&mut IOPin> {
199        match *self {
200            Pin::IO { ref mut params, .. } => Some(params),
201            _ => None,
202        }
203    }
204}
205
206#[cfg(test)]
207mod tests {
208
209    use super::*;
210
211    #[test]
212    fn pin_ok() {
213        let pin = Pin::POWER {
214            name: "VDD".to_string(),
215            position: Position::Grid(4, 3),
216        };
217
218        assert_eq!(pin.name(), "VDD");
219        assert_eq!(*pin.position(), Position::Grid(4, 3));
220    }
221
222    #[test]
223    fn pin_reset() {
224        let pin = Pin::IO {
225            name: "PA3".to_string(),
226            position: Position::Grid(4, 3),
227            params: Box::new(IOPin {
228                reset: true,
229                label: "".to_string(),
230                signals: vec![],
231                current: None,
232            }),
233        };
234
235        let params = pin.params().unwrap();
236        assert_eq!(params.is_reset(), true);
237    }
238
239    #[test]
240    fn pin_label() {
241        let mut pin = Pin::IO {
242            name: "PA3".to_string(),
243            position: Position::Grid(4, 3),
244            params: Box::new(IOPin {
245                reset: true,
246                label: "".to_string(),
247                signals: vec![],
248                current: None,
249            }),
250        };
251
252        let params = pin.params_mut().unwrap();
253        params.set_label("PWM");
254
255        assert_eq!(params.label(), "PWM");
256    }
257
258    #[test]
259    fn pin_signals() {
260        let mut pin = Pin::IO {
261            name: "PA3".to_string(),
262            position: Position::Grid(4, 3),
263            params: Box::new(IOPin {
264                reset: true,
265                label: "".to_string(),
266                signals: vec![
267                    "Input".to_string(),
268                    "Output".to_string(),
269                    "EXTI".to_string(),
270                ],
271                current: Some(0),
272            }),
273        };
274
275        let params = pin.params_mut().unwrap();
276        let signals = params.signals();
277
278        assert_eq!(
279            *signals,
280            vec![
281                "Input".to_string(),
282                "Output".to_string(),
283                "EXTI".to_string(),
284            ]
285        );
286    }
287
288    #[test]
289    fn pin_select_signal_present() {
290        let mut pin = Pin::IO {
291            name: "PA3".to_string(),
292            position: Position::Grid(4, 3),
293            params: Box::new(IOPin {
294                reset: true,
295                label: "".to_string(),
296                signals: vec![
297                    "Input".to_string(),
298                    "Output".to_string(),
299                    "EXTI".to_string(),
300                ],
301                current: Some(1),
302            }),
303        };
304
305        let params = pin.params_mut().unwrap();
306        let ret = params.select_signal("Output");
307
308        assert_eq!(ret, true);
309        assert_eq!(params.current_signal().unwrap(), "Output");
310    }
311
312    #[test]
313    fn pin_select_signal_missing() {
314        let mut pin = Pin::IO {
315            name: "PA3".to_string(),
316            position: Position::Grid(4, 3),
317            params: Box::new(IOPin {
318                reset: true,
319                label: "".to_string(),
320                signals: vec![
321                    "Input".to_string(),
322                    "Output".to_string(),
323                    "EXTI".to_string(),
324                ],
325                current: Some(0),
326            }),
327        };
328
329        let params = pin.params_mut().unwrap();
330        let ret = params.select_signal("Missing");
331
332        assert_eq!(ret, false);
333        assert_eq!(params.current_signal().is_none(), true);
334    }
335
336    // TODO: Create unknown Pin type and fail
337    #[test]
338    fn build_nc_pin() {
339        let pinbuilder = PinBuilder::new("NC", Position::Linear(10), "NotConnected");
340        let pin = pinbuilder.finish();
341
342        match pin {
343            Pin::NC { .. } => assert!(true),
344            _ => assert!(false),
345        }
346    }
347
348    #[test]
349    fn build_boot_pin() {
350        let pinbuilder = PinBuilder::new("BOOT", Position::Linear(10), "WakeUp");
351        let pin = pinbuilder.finish();
352
353        match pin {
354            Pin::BOOT { .. } => assert!(true),
355            _ => assert!(false),
356        }
357    }
358
359    #[test]
360    fn build_power_pin() {
361        let pinbuilder = PinBuilder::new("Power", Position::Linear(10), "VCC");
362        let pin = pinbuilder.finish();
363
364        match pin {
365            Pin::POWER { .. } => assert!(true),
366            _ => assert!(false),
367        }
368    }
369
370    #[test]
371    fn build_nrst_pin() {
372        let pinbuilder = PinBuilder::new("Reset", Position::Linear(10), "NRST");
373        let pin = pinbuilder.finish();
374
375        match pin {
376            Pin::NRST { .. } => assert!(true),
377            _ => assert!(false),
378        }
379    }
380
381    // TODO: Check signals
382    #[test]
383    fn build_io_pin() {
384        let pinbuilder = PinBuilder::new("I/O", Position::Linear(10), "PA1")
385            .signals(vec![String::from("Input"), String::from("Output")], 0);
386        let pin = pinbuilder.finish();
387
388        match pin {
389            Pin::IO { .. } => assert!(true),
390            _ => assert!(false),
391        }
392    }
393}