stm32builder/
gpio_bank.rs1use crate::{
4 api::{Convertible, PeripheralOnBus, Validatable},
5 device::DeviceIn,
6 gpio_pin::{GpioPinIn, GpioPinOut},
7 peripheral_bus::{PeripheralBusIn, PeripheralBusOut},
8 types::{DeviceId, Valid},
9};
10use serde::de::{Deserialize, Deserializer};
11use serde_derive::{Deserialize, Serialize};
12
13#[derive(Debug, Deserialize)]
15pub struct GpioBankIn {
16 pub name: String,
18 #[serde(deserialize_with = "seq_of_pins_as_string_or_struct")]
20 pub pins: Vec<GpioPinIn>,
21 #[serde(flatten)]
23 pub valid: Valid,
24 pub bus: PeripheralBusIn,
26}
27
28#[allow(non_snake_case)]
30#[derive(Debug, PartialEq, Serialize)]
31pub struct GpioBankOut {
32 pub GPIO: String,
34 pub gpio: String,
36 pub pins: Vec<GpioPinOut>,
38}
39
40impl Convertible for GpioBankIn {
41 type Output = GpioBankOut;
42
43 fn to_output(&self, id: &DeviceId, device: &DeviceIn) -> GpioBankOut {
45 GpioBankOut {
46 GPIO: self.name.clone().to_uppercase(),
47 gpio: self.name.clone().to_lowercase(),
48 pins: self
49 .pins
50 .iter()
51 .filter(|pin| pin.is_valid_for(&id, &device))
52 .map(|pin| pin.to_output(&id, &device))
53 .collect(),
54 }
55 }
56}
57
58impl Validatable for GpioBankIn {
59 fn is_valid_for(&self, id: &DeviceId, device: &DeviceIn) -> bool {
60 self.valid.is_valid_for(&id, &device)
61 }
62}
63
64impl PeripheralOnBus for GpioBankIn {
65 fn peripheral_bus(&self) -> PeripheralBusOut {
66 PeripheralBusOut {
67 peripheral: self.name.clone().to_lowercase(),
68 bus: self.bus.name.clone(),
69 field: self.bus.field.clone(),
70 resetable: self.bus.resetable,
71 }
72 }
73}
74
75fn seq_of_pins_as_string_or_struct<'de, D>(deserializer: D) -> Result<Vec<GpioPinIn>, D::Error>
76where
77 D: Deserializer<'de>,
78{
79 #[derive(Deserialize)]
80 struct Wrapper(
81 #[serde(deserialize_with = "crate::helpers::serde::string_or_struct")] GpioPinIn,
82 );
83
84 let v = Vec::deserialize(deserializer)?;
85 Ok(v.into_iter().map(|Wrapper(a)| a).collect())
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::tests::*;
92 use crate::types::*;
93
94 fn bank_under_test() -> GpioBankOut {
95 GpioBankIn {
96 name: "gpioa".to_owned(),
97 pins: vec![
98 GpioPinIn {
99 name: "pa0".to_owned(),
100 initial_mode: None,
101 valid: Valid::default(),
102 },
103 GpioPinIn {
104 name: "pa1".to_owned(),
105 initial_mode: None,
106 valid: Valid::default(),
107 },
108 ],
109 valid: Valid::default(),
110 bus: PeripheralBusIn {
111 name: Bus::AHB,
112 field: "IOPA".to_string(),
113 resetable: true,
114 },
115 }
116 .to_output(&valid_device_id(), &valid_device_in())
117 }
118
119 #[test]
120 fn has_a_type() {
121 assert_eq!(bank_under_test().GPIO, "GPIOA");
122 }
123 #[test]
124 fn has_a_name() {
125 assert_eq!(bank_under_test().gpio, "gpioa");
126 }
127 #[test]
128 fn has_some_pins() {
129 let pins = bank_under_test().pins;
130 let mut pins = pins.iter();
131 assert_eq!(pins.next().unwrap().PIN, "PA0");
132 assert_eq!(pins.next().unwrap().PIN, "PA1");
133 assert!(pins.next().is_none());
134 }
135}