cube2rust/
gpio.rs

1use std::convert::TryFrom;
2
3use regex::Regex;
4
5use crate::*;
6
7#[derive(Debug)]
8pub struct GpioPin {
9    pub port: String,
10    pub register: String,
11    pub signal: SignalType,
12    pub label: Option<String>,
13    pub pin_state: Option<PinStateType>,
14    pub speed: Option<SpeedType>,
15    pub pu_pd: Option<PullType>,
16    pub mode_default_output_pp: Option<ModeOutputType>,
17}
18
19pub fn get_gpios(config: &ConfigParams<'_>) -> anyhow::Result<(Vec<char>, Vec<GpioPin>)> {
20    // regex matches PA11, PB4, etc
21    let re = Regex::new(r"^P[A-K]\d{1,2}").unwrap();
22
23    // collect regex matches into a params Vec<(match, params)>
24    let mut gpio_params = Vec::new();
25    for (name, params) in config {
26        if let Some(name_match) = re.find(name) {
27            gpio_params.push((name_match.as_str(), params));
28        }
29    }
30
31    // sort vec alphanumerically, e.g. PA1, PA2, PA11, PB1
32    gpio_params.sort_by(|(a, _), (b, _)| human_sort::compare(a, b));
33
34    // map params to GpioPins
35    let mut gpios = Vec::new();
36    let mut ports = Vec::new();
37    for (name, parameters) in gpio_params {
38        let gpio: GpioPin = GpioPin::new(name, parameters).context(format!("Pin: {}", name))?;
39
40        // Don't count external clock sources as GPIOs
41        if let SignalType::Peripheral(ref signal) = gpio.signal {
42            if signal == "RCC_OSC_OUT" || signal == "RCC_OSC_IN" {
43                continue;
44            }
45        };
46
47        ports.push(gpio.port.chars().last().unwrap());
48        gpios.push(gpio);
49    }
50
51    ports.dedup();
52
53    Ok((ports, gpios))
54}
55
56impl GpioPin {
57    pub fn new(name: &str, parameters: &HashMap<&str, &str>) -> anyhow::Result<Self> {
58        let (port, register) = parse_name(name)?;
59
60        let signal = parse_mandatory_param(parameters, "Signal")?;
61        let label = parameters.get("GPIO_Label").map(|&s| String::from(s));
62
63        let pin_state = parse_optional_param(parameters, "PinState")?;
64        let pu_pd = parse_optional_param(parameters, "GPIO_PuPd")?;
65
66        let speed = parse_optional_param(parameters, "GPIO_Speed")?;
67        let mode_default_output_pp = parse_optional_param(parameters, "GPIO_ModeDefaultOutputPP")?;
68
69        Ok(GpioPin {
70            port,
71            register,
72            signal,
73            label,
74            pin_state,
75            speed,
76            pu_pd,
77            mode_default_output_pp,
78        })
79    }
80
81    pub fn get_name(&self) -> String {
82        let register = &self.register;
83
84        match &self.label {
85            Some(label) => label.clone(),
86            None => match self.signal {
87                SignalType::Peripheral(ref name) => name.to_lowercase(),
88                SignalType::AdcInput => f!("adc_{register}"),
89                _ => f!("gpio_{register}"),
90            },
91        }
92    }
93}
94
95fn parse_name(name: &str) -> anyhow::Result<(String, String)> {
96    let port_char_upper = name
97        .chars()
98        .nth(1)
99        .ok_or_else(|| anyhow!("could not parse port"))?;
100    let pin: u8 = name[2..]
101        .parse()
102        .map_err(|_| anyhow!("could not parse pin number"))?;
103
104    let port_char_lower = port_char_upper.to_ascii_lowercase();
105    let port = f!("GPIO{port_char_upper}");
106    let register = f!("p{port_char_lower}{pin}");
107    Ok((port, register))
108}
109
110#[derive(Debug, PartialEq)]
111pub enum SignalType {
112    GpioInput,
113    GpioOutput,
114    AdcInput,
115    Peripheral(String),
116}
117
118impl TryFrom<&str> for SignalType {
119    type Error = anyhow::Error;
120
121    fn try_from(text: &str) -> anyhow::Result<Self, Self::Error> {
122        match text {
123            "GPIO_Input" => Ok(SignalType::GpioInput),
124            "GPIO_Output" => Ok(SignalType::GpioOutput),
125            "GPIO_Analog" => Ok(SignalType::AdcInput),
126            _ => Ok(SignalType::Peripheral(String::from(text))),
127        }
128    }
129}
130
131parameter!(PinStateType, [GPIO_PIN_SET, GPIO_PIN_RESET]);
132parameter!(
133    PullType,
134    [GPIO_PULLUP, GPIO_PULLDOWN, GPIO_NOPULL],
135    default = GPIO_NOPULL
136);
137parameter!(
138    ModeOutputType,
139    [GPIO_MODE_OUTPUT_OD, GPIO_MODE_OUTPUT_PP],
140    default = GPIO_MODE_OUTPUT_PP
141);
142parameter!(
143    SpeedType,
144    [
145        GPIO_SPEED_FREQ_LOW,
146        GPIO_SPEED_FREQ_MEDIUM,
147        GPIO_SPEED_FREQ_HIGH,
148        GPIO_SPEED_FREQ_VERY_HIGH
149    ],
150    default = GPIO_SPEED_FREQ_LOW
151);