diff --git a/Cargo.lock b/Cargo.lock index 422156a..32449e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -620,6 +620,8 @@ version = "0.1.0" dependencies = [ "itertools", "rayon", + "ref_thread_local", + "regex", "serde", "serde_json", ] diff --git a/stm32-data-gen/src/chips.rs b/stm32-data-gen/src/chips.rs index e7152c9..01f38bc 100644 --- a/stm32-data-gen/src/chips.rs +++ b/stm32-data-gen/src/chips.rs @@ -68,7 +68,7 @@ pub struct ChipGroup { chip_names: Vec, xml: xml::Mcu, ips: HashMap, - pins: HashMap, + pins: HashMap, family: Option, line: Option, die: Option, @@ -503,18 +503,20 @@ fn merge_periph_pins_info( } // covert to hashmap - let af_pins: HashMap<(stm32_data_serde::chip::core::peripheral::pin::Pin, &str), Option> = - af_pins.iter().map(|v| ((v.pin, v.signal.as_str()), v.af)).collect(); + let af_pins: HashMap<(&str, &str), Option> = af_pins + .iter() + .map(|v| ((v.pin.as_str(), v.signal.as_str()), v.af)) + .collect(); for pin in core_pins { - let af = af_pins.get(&(pin.pin, &pin.signal)).copied().flatten(); + let af = af_pins.get(&(&pin.pin, &pin.signal)).copied().flatten(); // try to look for a signal with another name let af = af.or_else(|| { if pin.signal == "CTS" { // for some godforsaken reason UART4's and UART5's CTS are called CTS_NSS in the GPIO xml // so try to match with these - af_pins.get(&(pin.pin, "CTS_NSS")).copied().flatten() + af_pins.get(&(pin.pin.as_str(), "CTS_NSS")).copied().flatten() } else if periph_name == "I2C1" { // it appears that for __some__ STM32 MCUs there is no AFIO specified in GPIO file // (notably - STM32F030C6 with it's I2C1 on PF6 and PF7) @@ -910,7 +912,7 @@ fn process_core( if let Some(signal) = signal.strip_prefix(&format!("{periph}_")) { periph_pins.entry(periph.to_string()).or_default().push( stm32_data_serde::chip::core::peripheral::Pin { - pin: *pin_name, + pin: pin_name.clone(), signal: signal.to_string(), af: None, }, @@ -1002,7 +1004,7 @@ fn process_core( } p.pins.extend(i2s_pins.iter().map(|p| Pin { - pin: p.pin, + pin: p.pin.clone(), signal: "I2S_".to_owned() + &p.signal, af: p.af, })); diff --git a/stm32-data-gen/src/gpio_af.rs b/stm32-data-gen/src/gpio_af.rs index 54c0282..20353fa 100644 --- a/stm32-data-gen/src/gpio_af.rs +++ b/stm32-data-gen/src/gpio_af.rs @@ -38,16 +38,9 @@ mod xml { } } -pub fn clean_pin(pin_name: &str) -> Option { - // some H7s have analog-only pins like PC2_C, PC3_C. Ignore these for now since the - // data model can't deal with pins that are not part of a GPIO port yet. - if regex!(r"^P[A-Z]\d+_C$").is_match(pin_name) { - return None; - } - - let pin_name = regex!(r"^P[A-Z]\d+").find(pin_name)?.as_str(); - - stm32_data_serde::chip::core::peripheral::pin::Pin::parse(pin_name) +pub fn clean_pin(pin_name: &str) -> Option { + // Some H7 chips have additonal "_C" pins. + Some(regex!(r"^P[A-Z]\d+(?:_C)?").find(pin_name)?.as_str().into()) } #[derive(Debug, PartialEq, Eq)] @@ -87,7 +80,7 @@ impl Af { }; peris.entry(peri_name.to_string()).or_default().push( stm32_data_serde::chip::core::peripheral::Pin { - pin: pin_name, + pin: pin_name.clone(), signal: signal_name.to_string(), af: afn, }, diff --git a/stm32-data-serde/Cargo.toml b/stm32-data-serde/Cargo.toml index ebab5d8..4968317 100644 --- a/stm32-data-serde/Cargo.toml +++ b/stm32-data-serde/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" [dependencies] serde = { version = "1.0.157", features = ["derive"] } +regex = "1.7.1" +ref_thread_local = "0.1.1" [dev-dependencies] itertools = "0.10.5" diff --git a/stm32-data-serde/src/lib.rs b/stm32-data-serde/src/lib.rs index dd44b07..b95a3b1 100644 --- a/stm32-data-serde/src/lib.rs +++ b/stm32-data-serde/src/lib.rs @@ -1,5 +1,15 @@ use serde::{Deserialize, Serialize}; +#[macro_export] +macro_rules! regex { + ($re:literal) => {{ + ::ref_thread_local::ref_thread_local! { + static managed REGEX: ::regex::Regex = ::regex::Regex::new($re).unwrap(); + } + >::borrow(®EX) + }}; +} + #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)] pub struct Chip { pub name: String, @@ -121,76 +131,51 @@ pub mod chip { } } - #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)] + #[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct Pin { - pub pin: pin::Pin, + pub pin: String, pub signal: String, #[serde(skip_serializing_if = "Option::is_none")] pub af: Option, } - pub mod pin { - use serde::{Deserialize, Serialize}; + fn extract_port_and_pin(pin: &str) -> (char, u8) { + let captures = regex!(r"^P([A-Z])(\d+)(?:_C)?") + .captures(pin) + .expect("Could not match regex on pin"); + let port = captures + .get(1) + .expect("Could not extract port") + .as_str() + .chars() + .next() + .expect("Empty port"); + let pin_number = captures + .get(2) + .expect("Could not extract pin number") + .as_str() + .parse::() + .expect("Could not parse pin number to u8"); + (port, pin_number) + } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] - pub struct Pin { - pub port: char, - pub num: u8, - } + impl Ord for Pin { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let (port_a, pin_number_a) = extract_port_and_pin(&self.pin); + let (port_b, pin_number_b) = extract_port_and_pin(&other.pin); - impl Pin { - pub fn parse(pin: &str) -> Option { - let mut chars = pin.chars(); - let p = chars.next()?; - if p != 'P' { - return None; - } - let port = chars.next()?; - let num = chars.as_str().parse().ok()?; - - Some(Self { port, num }) + if port_a != port_b { + port_a.cmp(&port_b) + } else if pin_number_a != pin_number_b { + pin_number_a.cmp(&pin_number_b) + } else { + self.signal.cmp(&other.signal) } } - - impl std::fmt::Display for Pin { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "P{}{}", self.port, self.num) - } - } - - impl Serialize for Pin { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&format!("{self}")) - } - } - - struct PinVisitor; - - impl<'de> serde::de::Visitor<'de> for PinVisitor { - type Value = Pin; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("pin") - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - Ok(Pin::parse(v).unwrap()) - } - } - - impl<'de> Deserialize<'de> for Pin { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_str(PinVisitor) - } + } + impl PartialOrd for Pin { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) } }