From 8b674ef472bdd68ba07a1e1ebf83411331fa63b1 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 18 Feb 2020 20:54:37 +0100 Subject: [PATCH 01/25] README: Formatting and typos --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ce049f1..0229c72 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,14 @@ A program to extract AF modes on MCU pins from the database files provided with STM32CubeMX. ## Usage + ``` cargo run $PATH_TO_MCU_DB_DIR $NAME_OF_MCU_FAMILY ``` -Under a default windows install `$PATH_TO_MCU_DB_DIR` is `C:\Program Files (x86)\STMicroelectronics\STM32Cube\STM32CubeMX\db\mcu`, adjust as appropriate for your local config. The MCU family name should match one of the MCU families as defined in `families.xml`. The program will output one AF mode definition per GPIO variant, with cfg feature gates for the different MCU variants that utalise that GPIO type. \ No newline at end of file + +Under a default windows install `$PATH_TO_MCU_DB_DIR` is `C:\Program Files +(x86)\STMicroelectronics\STM32Cube\STM32CubeMX\db\mcu`, adjust as appropriate +for your local config. The MCU family name should match one of the MCU families +as defined in `families.xml`. The program will output one AF mode definition +per GPIO variant, with cfg feature gates for the different MCU variants that +utilise that GPIO type. From 5225a1d446f8511aa93330ea669970e3f9bdb9e0 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 18 Feb 2020 20:56:56 +0100 Subject: [PATCH 02/25] Run cargo update --- Cargo.lock | 139 +++++++++++++++++++++-------------------------------- Cargo.toml | 2 +- 2 files changed, 55 insertions(+), 86 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 68a2b10..d163978 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,14 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.6.9" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "alphanumeric-sort" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -18,29 +20,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.6" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cube-parse" version = "0.1.0" dependencies = [ - "alphanumeric-sort 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "alphanumeric-sort 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde-xml-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.45" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -48,66 +45,57 @@ name = "log" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memchr" -version = "2.1.2" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "proc-macro2" -version = "0.4.24" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.6.10" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex" -version = "1.1.0" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.4" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "serde" -version = "1.0.84" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -116,56 +104,41 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.84" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.15.23" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thread_local" -version = "0.3.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ucd-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "utf8-ranges" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "version_check" -version = "0.1.5" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -177,26 +150,22 @@ dependencies = [ ] [metadata] -"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" -"checksum alphanumeric-sort 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7cd2580c95c654d681db0194a310af67a293f5e1c8bafa5b35b63269c4665a39" +"checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" +"checksum alphanumeric-sort 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f37ce94154d73f6961f87571a3ab7814e1608f373bd55a933e3e771b6dd59fc4" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" -"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" -"checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9" -"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" -"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" -"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" -"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1" -"checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53445de381a1f436797497c61d851644d0e8e88e6140f22872ad33a704933978" +"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" +"checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06" +"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" "checksum serde-xml-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0c06881f4313eec67d4ecfcd8e14339f6042cfc0de4b1bd3ceae74c29d597f68" -"checksum serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d6115a3ca25c224e409185325afc16a0d5aaaabc15c42b09587d6f1ba39a5b" -"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7ec6c39eaa68382c8e31e35239402c0a9489d4141a8ceb0c716099a0b515b562" diff --git a/Cargo.toml b/Cargo.toml index 1de95d2..f45492c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,4 @@ serde-xml-rs = "0.2" serde_derive = "1.0" regex = "1.1" lazy_static = "1.2" -alphanumeric-sort = "1.0" \ No newline at end of file +alphanumeric-sort = "1.0" From 6592ccb8ccdda9f7b65a08e5358d17375bdc436f Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 18 Feb 2020 20:58:25 +0100 Subject: [PATCH 03/25] Run cargo fmt --- src/family.rs | 8 ++++---- src/internal_peripheral.rs | 2 +- src/main.rs | 5 ++++- src/mcu.rs | 1 - src/utils.rs | 14 ++++++-------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/family.rs b/src/family.rs index 4721bde..f1b2a53 100644 --- a/src/family.rs +++ b/src/family.rs @@ -8,7 +8,7 @@ use crate::utils::load_file; #[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct Families { - #[serde(rename="Family")] + #[serde(rename = "Family")] families: Vec, } @@ -16,7 +16,7 @@ pub struct Families { #[serde(rename_all = "PascalCase")] pub struct Family { pub name: String, - #[serde(rename="SubFamily")] + #[serde(rename = "SubFamily")] sub_families: Vec, } @@ -24,7 +24,7 @@ pub struct Family { #[serde(rename_all = "PascalCase")] pub struct SubFamily { pub name: String, - #[serde(rename="Mcu")] + #[serde(rename = "Mcu")] mcus: Vec, } @@ -67,4 +67,4 @@ impl<'a> IntoIterator for &'a SubFamily { fn into_iter(self) -> ::IntoIter { self.mcus.iter() } -} \ No newline at end of file +} diff --git a/src/internal_peripheral.rs b/src/internal_peripheral.rs index 12faa9a..23a54cb 100644 --- a/src/internal_peripheral.rs +++ b/src/internal_peripheral.rs @@ -47,7 +47,7 @@ pub struct GPIOPin { } #[derive(Debug, Deserialize)] -#[serde(rename="IP")] +#[serde(rename = "IP")] pub struct IpGPIO { #[serde(rename = "GPIO_Pin")] pub(crate) gpio_pin: Vec, diff --git a/src/main.rs b/src/main.rs index 98257a7..9d3c4ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -67,7 +67,10 @@ fn main() { if !mcu_gpio_map.contains_key(&gpio_version) { mcu_gpio_map.insert(gpio_version.clone(), Vec::new()); } - mcu_gpio_map.get_mut(&gpio_version).unwrap().push(mcu.name.clone()); + mcu_gpio_map + .get_mut(&gpio_version) + .unwrap() + .push(mcu.name.clone()); } } diff --git a/src/mcu.rs b/src/mcu.rs index 9d8977f..600c09f 100644 --- a/src/mcu.rs +++ b/src/mcu.rs @@ -16,7 +16,6 @@ impl Mcu { load_file(db_dir, format!("{}.xml", mcu_name)) } - pub fn get_ip(&self, name: &str) -> Option<&IP> { self.ip.iter().find(|v| v.name == name) } diff --git a/src/utils.rs b/src/utils.rs index 0d7f7b8..d51a2b1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,15 +1,13 @@ -use std::{ - error::Error, - io::BufReader, - fs::File, - path::Path, -}; +use std::{error::Error, fs::File, io::BufReader, path::Path}; use serde::Deserialize; -pub fn load_file<'a, P: AsRef, Q: AsRef, R: Deserialize<'a>>(db_dir: P, file_path: Q) -> Result> { +pub fn load_file<'a, P: AsRef, Q: AsRef, R: Deserialize<'a>>( + db_dir: P, + file_path: Q, +) -> Result> { let db_dir = db_dir.as_ref(); let mut fin = BufReader::new(File::open(&db_dir.join(file_path.as_ref()))?); Ok(serde_xml_rs::deserialize(&mut fin)?) -} \ No newline at end of file +} From b2e656daae04db99122c568836c63b76cfad6dd0 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 18 Feb 2020 21:03:47 +0100 Subject: [PATCH 04/25] Better error handling, less unwrap() in main() --- src/main.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9d3c4ff..7cdffbc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,7 +46,7 @@ fn render_pin_modes(ip: &internal_peripheral::IpGPIO) { println!("}}"); } -fn main() { +fn main() -> Result<(), String> { let args: Vec = env::args().collect(); if args.len() != 3 { eprintln!("Usage: ./cube-parse CUBEMX_MCU_DB_DIR MCU_FAMILY") @@ -54,15 +54,20 @@ fn main() { let db_dir = Path::new(&args[1]); - let familys = family::Families::load(&db_dir).unwrap(); + let families = family::Families::load(&db_dir) + .map_err(|e| format!("Could not load families XML: {}", e))?; - let family = (&familys).into_iter().find(|v| v.name == args[2]).unwrap(); + let family = (&families) + .into_iter() + .find(|v| v.name == args[2]) + .ok_or_else(|| format!("Could not find family {}", args[2]))?; let mut mcu_gpio_map = HashMap::new(); for sf in family { for mcu in sf { - let mcu_dat = mcu::Mcu::load(&db_dir, &mcu.name).unwrap(); + let mcu_dat = mcu::Mcu::load(&db_dir, &mcu.name) + .map_err(|e| format!("Could not load MCU data: {}", e))?; let gpio_version = mcu_dat.get_ip("GPIO").unwrap().get_version().to_string(); if !mcu_gpio_map.contains_key(&gpio_version) { mcu_gpio_map.insert(gpio_version.clone(), Vec::new()); @@ -75,7 +80,8 @@ fn main() { } for (gpio, mcu_list) in mcu_gpio_map { - let gpio_data = internal_peripheral::IpGPIO::load(db_dir, &gpio).unwrap(); + let gpio_data = internal_peripheral::IpGPIO::load(db_dir, &gpio) + .map_err(|e| format!("Could not load IP GPIO file: {}", e))?; println!("#[cfg(any("); for mcu in mcu_list { println!(" feature = {:?},", mcu); @@ -84,4 +90,6 @@ fn main() { render_pin_modes(&gpio_data); println!("\n"); } + + Ok(()) } From 24c83f95c93d6f0ac3393373a997d807e0c7cfc8 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 18 Feb 2020 21:04:21 +0100 Subject: [PATCH 05/25] Remove unused imports --- src/family.rs | 1 - src/internal_peripheral.rs | 1 - src/main.rs | 1 - src/mcu.rs | 1 - 4 files changed, 4 deletions(-) diff --git a/src/family.rs b/src/family.rs index f1b2a53..c555a32 100644 --- a/src/family.rs +++ b/src/family.rs @@ -1,6 +1,5 @@ use std::path::Path; -use serde; use serde_derive::Deserialize; use crate::utils::load_file; diff --git a/src/internal_peripheral.rs b/src/internal_peripheral.rs index 23a54cb..8adfea0 100644 --- a/src/internal_peripheral.rs +++ b/src/internal_peripheral.rs @@ -2,7 +2,6 @@ use std::path::Path; use lazy_static::lazy_static; use regex::Regex; -use serde; use serde_derive::Deserialize; use crate::utils::load_file; diff --git a/src/main.rs b/src/main.rs index 7cdffbc..0c25cdd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ use std::{collections::HashMap, env, path::Path}; use alphanumeric_sort::compare_str; -use serde_xml_rs; mod family; mod internal_peripheral; diff --git a/src/mcu.rs b/src/mcu.rs index 600c09f..7846680 100644 --- a/src/mcu.rs +++ b/src/mcu.rs @@ -1,6 +1,5 @@ use std::path::Path; -use serde; use serde_derive::Deserialize; use crate::utils::load_file; From 873f6c716f49db2255f5dab7b810eeb536001df5 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 18 Feb 2020 21:05:44 +0100 Subject: [PATCH 06/25] Use dyn keyword for boxed errors --- src/family.rs | 3 ++- src/internal_peripheral.rs | 3 ++- src/mcu.rs | 3 ++- src/utils.rs | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/family.rs b/src/family.rs index c555a32..77662f8 100644 --- a/src/family.rs +++ b/src/family.rs @@ -1,3 +1,4 @@ +use std::error::Error; use std::path::Path; use serde_derive::Deserialize; @@ -36,7 +37,7 @@ pub struct Mcu { } impl Families { - pub fn load>(db_dir: P) -> Result> { + pub fn load>(db_dir: P) -> Result> { load_file(db_dir, "families.xml") } } diff --git a/src/internal_peripheral.rs b/src/internal_peripheral.rs index 8adfea0..af3a590 100644 --- a/src/internal_peripheral.rs +++ b/src/internal_peripheral.rs @@ -1,3 +1,4 @@ +use std::error::Error; use std::path::Path; use lazy_static::lazy_static; @@ -53,7 +54,7 @@ pub struct IpGPIO { } impl IpGPIO { - pub fn load>(db_dir: P, version: &str) -> Result> { + pub fn load>(db_dir: P, version: &str) -> Result> { load_file(db_dir, format!("IP/GPIO-{}_Modes.xml", version)) } } diff --git a/src/mcu.rs b/src/mcu.rs index 7846680..805228d 100644 --- a/src/mcu.rs +++ b/src/mcu.rs @@ -1,3 +1,4 @@ +use std::error::Error; use std::path::Path; use serde_derive::Deserialize; @@ -11,7 +12,7 @@ pub struct Mcu { } impl Mcu { - pub fn load>(db_dir: P, mcu_name: &str) -> Result> { + pub fn load>(db_dir: P, mcu_name: &str) -> Result> { load_file(db_dir, format!("{}.xml", mcu_name)) } diff --git a/src/utils.rs b/src/utils.rs index d51a2b1..1da2d16 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -5,7 +5,7 @@ use serde::Deserialize; pub fn load_file<'a, P: AsRef, Q: AsRef, R: Deserialize<'a>>( db_dir: P, file_path: Q, -) -> Result> { +) -> Result> { let db_dir = db_dir.as_ref(); let mut fin = BufReader::new(File::open(&db_dir.join(file_path.as_ref()))?); From 482f3171af847278f5802436e361b806e0ce400f Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 18 Feb 2020 23:59:33 +0100 Subject: [PATCH 07/25] README: Document database structure and feature grouping --- README.md | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/README.md b/README.md index 0229c72..113d0af 100644 --- a/README.md +++ b/README.md @@ -14,3 +14,174 @@ for your local config. The MCU family name should match one of the MCU families as defined in `families.xml`. The program will output one AF mode definition per GPIO variant, with cfg feature gates for the different MCU variants that utilise that GPIO type. + +## The STM32CubeMX Database + +The STM32CubeMX database contains the following files that are relevant to us: + +### Families + +In the root, there is a file called `families.xml`. It contains all MCUs +grouped by family (e.g. "STM32F0") and subfamily (e.g. "STM32F0x0 Value Line"). + +```xml + + + + + Arm Cortex-M0 + 48 + 4 + ... + + + ... +``` + +### MCU + +Next to the `families.xml` file, there are a lot of MCU definitions. The +filenames match the `Name` attribute in the `Mcu` element above. + +For example, the `STM32L071KB(B-Z)Tx.xml` file starts like this: + +```xml + + Arm Cortex-M0+ + 32 + 6144 + 20 + 25 + DIE447 + 128 + 192 + + + + ... +``` + +This first part describes the MCU: How much RAM it has, what the frequency is, +how many I/Os it has, what flash variants there are, etc. Many of these things +are also encoded in the full MCU `RefName`. + +Following this general description, there are a number of `IP` elements. IP +stands for "Internal Peripheral". Here we have things like the USART peripherals: + +```xml + + +``` + +...or the RCC peripheral: + +```xml + +``` + +...and, most important to us, the GPIO peripheral. + +```xml + +``` + +Here, the value of the `Version` attribute points to the actual GPIO signal +definition. + +(There are also some other interesting entries in that file, for example the +mapping from physical pins to internal pin names. Those are not relevant for us +though.) + +### GPIO Internal Peripheral + +The GPIO IP can be found in the `IP` directory. The relevant file for us is at +`IP/GPIO-_Modes.xml`. The version can be extracted from the `IP` +element shown in the previous section. + +In the case of the `STM32L071KBTx`, the relevant GPIO IP version file is at +`IP/GPIO-STM32L071_gpio_v1_0_Modes.xml`. + +That file starts out with some `RefParameter` and `RefMode` elements. Relevant +to us are mostly the `GPIO_Pin` elements. They look like this: + +```xml + + + GPIO_PIN_6 + + + + GPIO_AF1_I2C1 + + + + + GPIO_AF2_LPTIM1 + + + + + GPIO_AF3_TSC + + + + + GPIO_AF0_USART1 + + + +``` + +As you can see, this element describes the pin `PB6`. Depending on the chosen +Alternative Function (AF), it can become an `I2C1_SCL` pin (AF1), a `USART1_TX` +pin (AF0), or some other variants. + +## Feature Groups + +When generating pin function mappings, we want to avoid generating a Cargo +feature for every possible MCU, since that would result in dozens or even +hundreds of features per family. If we don't generate a feature per MCU, we +need to group them somehow. The best way is probably to follow ST's grouping, +which is encoded in the IP versions described above. + +The feature names are mapped as follows: + +- `STM32L031_gpio_v1_0` -> `io-STM32L031` +- `STM32L051_gpio_v1_0` -> `io-STM32L051` +- `STM32L152x8_gpio_v1_0` -> `io-STM32L152x8` + +For example, the GPIO IP file named "STM32L031_gpio_v1_0" is shared among the +following MCUs: + +- STM32L010C6Tx +- STM32L031C(4-6)Tx +- STM32L031C(4-6)Tx +- STM32L031C6Ux +- STM32L031E(4-6)Yx +- STM32L031E(4-6)Yx +- STM32L031F(4-6)Px +- STM32L031F(4-6)Px +- STM32L031G(4-6)Ux +- STM32L031G(4-6)Ux +- STM32L031G6UxS +- STM32L031K(4-6)Tx +- STM32L031K(4-6)Tx +- STM32L031K(4-6)Ux +- STM32L031K(4-6)Ux +- STM32L041C(4-6)Tx +- STM32L041C(4-6)Tx +- STM32L041E6Yx +- STM32L041F6Px +- STM32L041G6Ux +- STM32L041G6UxS +- STM32L041K6Tx +- STM32L041K6Ux + +As you can see, this may be a bit confusing due to the fact that both the +`STM32L010C6Tx` and the `STM32L041E6Yx` require the `io-STM32L031` feature. +However, sticking to the (sometimes non-logical) grouping used in the CubeMX +database is probably still better than creating our own grouping, which may be +broken at any time by ST releasing a new MCU in a pre-existing group, but with +a different, incompatible GPIO IP version. From 406b21c8a1c92168dac4b4ff582372d5dcd4da75 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Wed, 19 Feb 2020 00:18:01 +0100 Subject: [PATCH 08/25] Generate only a feature per GPIO group, not per MCU --- README.md | 3 +-- src/main.rs | 43 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 113d0af..4d3fde2 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,7 @@ Under a default windows install `$PATH_TO_MCU_DB_DIR` is `C:\Program Files (x86)\STMicroelectronics\STM32Cube\STM32CubeMX\db\mcu`, adjust as appropriate for your local config. The MCU family name should match one of the MCU families as defined in `families.xml`. The program will output one AF mode definition -per GPIO variant, with cfg feature gates for the different MCU variants that -utilise that GPIO type. +per GPIO variant, with a corresponding feature gate. ## The STM32CubeMX Database diff --git a/src/main.rs b/src/main.rs index 0c25cdd..7ceac0b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ use std::{collections::HashMap, env, path::Path}; use alphanumeric_sort::compare_str; +use lazy_static::lazy_static; +use regex::Regex; mod family; mod internal_peripheral; @@ -45,6 +47,21 @@ fn render_pin_modes(ip: &internal_peripheral::IpGPIO) { println!("}}"); } +lazy_static! { + // Note: Version >1.0 is not currently supported + static ref GPIO_VERSION: Regex = Regex::new("^([^_]*)_gpio_v1_0$").unwrap(); +} + +/// Convert a GPIO IP version (e.g. "STM32L152x8_gpio_v1_0") to a feature name +/// (e.g. "io-STM32L152x8"). +fn gpio_version_to_feature(version: &str) -> Result { + if let Some(captures) = GPIO_VERSION.captures(version) { + Ok(format!("io-{}", captures.get(1).unwrap().as_str())) + } else { + Err(format!("Could not parse version {:?}", version)) + } +} + fn main() -> Result<(), String> { let args: Vec = env::args().collect(); if args.len() != 3 { @@ -81,14 +98,34 @@ fn main() -> Result<(), String> { for (gpio, mcu_list) in mcu_gpio_map { let gpio_data = internal_peripheral::IpGPIO::load(db_dir, &gpio) .map_err(|e| format!("Could not load IP GPIO file: {}", e))?; - println!("#[cfg(any("); + println!("#[cfg(feature = \"{}\")]", gpio_version_to_feature(&gpio)?); for mcu in mcu_list { - println!(" feature = {:?},", mcu); + println!("// {}", mcu); } - println!("))]"); render_pin_modes(&gpio_data); println!("\n"); } Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_gpio_version_to_feature() { + // Success + assert_eq!(gpio_version_to_feature("STM32L152x8_gpio_v1_0").unwrap(), "io-STM32L152x8"); + assert_eq!(gpio_version_to_feature("STM32F333_gpio_v1_0").unwrap(), "io-STM32F333"); + + // Error parsing, unsupported version + assert!(gpio_version_to_feature("STM32F333_gpio_v1_1").is_err()); + + // Error parsing, wrong pattern + assert!(gpio_version_to_feature("STM32F333_asdf_v1_0").is_err()); + + // Error parsing, too many underscores + assert!(gpio_version_to_feature("STM32_STM32F333_gpio_v1_0").is_err()); + } +} From 059b66d03ca37cbec4aa384126e1933390fc93c5 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Wed, 19 Feb 2020 00:19:25 +0100 Subject: [PATCH 09/25] family: Add some code documentation --- src/family.rs | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/family.rs b/src/family.rs index 77662f8..d654d94 100644 --- a/src/family.rs +++ b/src/family.rs @@ -12,6 +12,7 @@ pub struct Families { families: Vec, } +/// A MCU family (e.g. "STM32F0" or "STM32L3"). #[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct Family { @@ -20,20 +21,48 @@ pub struct Family { sub_families: Vec, } +/// A MCU subfamily (e.g. "STM32F0x0 Value Line"). #[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct SubFamily { pub name: String, #[serde(rename = "Mcu")] - mcus: Vec, + pub mcus: Vec, } +/// A MCU (e.g. STM32L071KBTx). +/// +/// Note that multiple MCUs (with unique `ref_name`) share a common name. For +/// example: +/// +/// - `` +/// - `` +/// +/// Both MCUs share the same name, but the ref name is different. +/// +/// The meaning of the name, using the `STM32L071KBTx` as an example: +/// +/// |Part |Meaning | +/// |-----|--------| +/// |STM32|Family | +/// | L |Type | +/// | 0 |Core | +/// | 71 |Line | +/// | K |Pincount| +/// | B |Flash | +/// | T |Package | +/// | x |Temp | +/// |-----|--------| +/// +/// See https://ziutek.github.io/2018/05/07/stm32_naming_scheme.html for more details. +/// +/// Note that sometimes there are exceptions from this naming rule. #[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct Mcu { pub name: String, package_name: String, - ref_name: String, + pub ref_name: String, } impl Families { From d8d816477c5681ed8c7398e33a65339c6eb71e1a Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Thu, 20 Feb 2020 21:35:28 +0100 Subject: [PATCH 10/25] Use clap for argument parsing --- Cargo.lock | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 43 ++++++++++++++++----- 3 files changed, 140 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d163978..3891c71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,21 +13,59 @@ name = "alphanumeric-sort" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cube-parse" version = "0.1.0" dependencies = [ "alphanumeric-sort 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", @@ -35,11 +73,24 @@ dependencies = [ "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hermit-abi" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "log" version = "0.3.9" @@ -118,6 +169,11 @@ dependencies = [ "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "1.0.14" @@ -128,6 +184,14 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "1.0.1" @@ -136,11 +200,40 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "xml-rs" version = "0.3.6" @@ -152,9 +245,15 @@ dependencies = [ [metadata] "checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" "checksum alphanumeric-sort 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f37ce94154d73f6961f87571a3ab7814e1608f373bd55a933e3e771b6dd59fc4" +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +"checksum hermit-abi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c55f143919fbc0bc77e427fe2d74cf23786d7c1875666f2fde3ac3c659bb67" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53445de381a1f436797497c61d851644d0e8e88e6140f22872ad33a704933978" @@ -165,7 +264,14 @@ dependencies = [ "checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" "checksum serde-xml-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0c06881f4313eec67d4ecfcd8e14339f6042cfc0de4b1bd3ceae74c29d597f68" "checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7ec6c39eaa68382c8e31e35239402c0a9489d4141a8ceb0c716099a0b515b562" diff --git a/Cargo.toml b/Cargo.toml index f45492c..7b290e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ authors = ["HarkonenBade"] edition = "2018" [dependencies] +clap = "2" serde = "1.0" serde-xml-rs = "0.2" serde_derive = "1.0" diff --git a/src/main.rs b/src/main.rs index 7ceac0b..c5a49e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use std::{collections::HashMap, env, path::Path}; use alphanumeric_sort::compare_str; +use clap::{App, Arg}; use lazy_static::lazy_static; use regex::Regex; @@ -63,20 +64,36 @@ fn gpio_version_to_feature(version: &str) -> Result { } fn main() -> Result<(), String> { - let args: Vec = env::args().collect(); - if args.len() != 3 { - eprintln!("Usage: ./cube-parse CUBEMX_MCU_DB_DIR MCU_FAMILY") - } - - let db_dir = Path::new(&args[1]); + let args = App::new("cube-parse") + .version(env!("CARGO_PKG_VERSION")) + .about("Extract AF modes on MCU pins from the database files provided with STM32CubeMX") + .author(env!("CARGO_PKG_AUTHORS")) + .arg( + Arg::with_name("db_dir") + .short("d") + .help("Path to the CubeMX MCU database directory") + .takes_value(true) + .required(true), + ) + .arg( + Arg::with_name("mcu_family") + .short("m") + .help("The MCU family to extract, e.g. \"STM32L0\"") + .takes_value(true) + .required(true), + ) + .get_matches(); + + let db_dir = Path::new(args.value_of("db_dir").unwrap()); + let mcu_family = args.value_of("mcu_family").unwrap(); let families = family::Families::load(&db_dir) .map_err(|e| format!("Could not load families XML: {}", e))?; let family = (&families) .into_iter() - .find(|v| v.name == args[2]) - .ok_or_else(|| format!("Could not find family {}", args[2]))?; + .find(|v| v.name == mcu_family) + .ok_or_else(|| format!("Could not find family {}", mcu_family))?; let mut mcu_gpio_map = HashMap::new(); @@ -116,8 +133,14 @@ mod tests { #[test] fn test_gpio_version_to_feature() { // Success - assert_eq!(gpio_version_to_feature("STM32L152x8_gpio_v1_0").unwrap(), "io-STM32L152x8"); - assert_eq!(gpio_version_to_feature("STM32F333_gpio_v1_0").unwrap(), "io-STM32F333"); + assert_eq!( + gpio_version_to_feature("STM32L152x8_gpio_v1_0").unwrap(), + "io-STM32L152x8" + ); + assert_eq!( + gpio_version_to_feature("STM32F333_gpio_v1_0").unwrap(), + "io-STM32F333" + ); // Error parsing, unsupported version assert!(gpio_version_to_feature("STM32F333_gpio_v1_1").is_err()); From a6ecda118ed4558bf2e35e5943b2132639ab2f8a Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Thu, 20 Feb 2020 21:37:08 +0100 Subject: [PATCH 11/25] Set up CI --- .github/workflows/ci.yml | 48 ++++++++++++++++++++++++++++++++++++++++ README.md | 6 +++++ 2 files changed, 54 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..085392a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + +jobs: + build_and_test: + name: Build and test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - name: Run tests + uses: actions-rs/cargo@v1 + with: + command: test + args: --all-features + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: clippy + override: true + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --all-features + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: rustfmt + override: true + - run: cargo fmt -- --check diff --git a/README.md b/README.md index 4d3fde2..2afd531 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Cube Parser +[![Build Status][github-actions-badge]][github-actions] + A program to extract AF modes on MCU pins from the database files provided with STM32CubeMX. ## Usage @@ -184,3 +186,7 @@ However, sticking to the (sometimes non-logical) grouping used in the CubeMX database is probably still better than creating our own grouping, which may be broken at any time by ST releasing a new MCU in a pre-existing group, but with a different, incompatible GPIO IP version. + + +[github-actions]: https://github.com/dbrgn/cube-parse/actions?query=branch%3Amaster +[github-actions-badge]: https://github.com/dbrgn/cube-parse/workflows/CI/badge.svg From 439efa1dde7f49da143cc4b66c4bf270773d1919 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Thu, 20 Feb 2020 21:53:17 +0100 Subject: [PATCH 12/25] Add generate target parameter --- Cargo.toml | 2 +- src/main.rs | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7b290e6..506f91c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cube-parse" version = "0.1.0" -authors = ["HarkonenBade"] +authors = ["HarkonenBade", "Danilo Bargen "] edition = "2018" [dependencies] diff --git a/src/main.rs b/src/main.rs index c5a49e2..d97f54d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,11 @@ mod internal_peripheral; mod mcu; mod utils; +enum GenerateTarget { + PinMappings, + Features, +} + fn render_pin_modes(ip: &internal_peripheral::IpGPIO) { let mut pin_map: HashMap> = HashMap::new(); @@ -67,7 +72,7 @@ fn main() -> Result<(), String> { let args = App::new("cube-parse") .version(env!("CARGO_PKG_VERSION")) .about("Extract AF modes on MCU pins from the database files provided with STM32CubeMX") - .author(env!("CARGO_PKG_AUTHORS")) + .author(&*env!("CARGO_PKG_AUTHORS").replace(":", ", ")) .arg( Arg::with_name("db_dir") .short("d") @@ -82,10 +87,24 @@ fn main() -> Result<(), String> { .takes_value(true) .required(true), ) + .arg( + Arg::with_name("generate") + .short("g") + .help("What to generate") + .takes_value(true) + .possible_values(&["pin_mappings", "features"]) + .required(true), + ) .get_matches(); + // Process args let db_dir = Path::new(args.value_of("db_dir").unwrap()); let mcu_family = args.value_of("mcu_family").unwrap(); + let generate = match args.value_of("generate").unwrap() { + "pin_mappings" => GenerateTarget::PinMappings, + "features" => GenerateTarget::Features, + _ => unreachable!(), + }; let families = family::Families::load(&db_dir) .map_err(|e| format!("Could not load families XML: {}", e))?; From cc6c4b152a6c30c74d3f2a328c0294ab3263ccf4 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Thu, 20 Feb 2020 22:41:09 +0100 Subject: [PATCH 13/25] Convert -m and -g args to positional args --- src/main.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index d97f54d..a196815 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,18 +81,16 @@ fn main() -> Result<(), String> { .required(true), ) .arg( - Arg::with_name("mcu_family") - .short("m") - .help("The MCU family to extract, e.g. \"STM32L0\"") + Arg::with_name("generate") + .help("What to generate") .takes_value(true) + .possible_values(&["pin_mappings", "features"]) .required(true), ) .arg( - Arg::with_name("generate") - .short("g") - .help("What to generate") + Arg::with_name("mcu_family") + .help("The MCU family to extract, e.g. \"STM32L0\"") .takes_value(true) - .possible_values(&["pin_mappings", "features"]) .required(true), ) .get_matches(); From 8e5d23545770ff8bd184142f1ca1065c8a199054 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Thu, 20 Feb 2020 22:51:55 +0100 Subject: [PATCH 14/25] Simplify mcu_gpio_map creation code --- src/main.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index a196815..2de4581 100644 --- a/src/main.rs +++ b/src/main.rs @@ -104,27 +104,29 @@ fn main() -> Result<(), String> { _ => unreachable!(), }; + // Load families let families = family::Families::load(&db_dir) .map_err(|e| format!("Could not load families XML: {}", e))?; + // Find target family let family = (&families) .into_iter() .find(|v| v.name == mcu_family) .ok_or_else(|| format!("Could not find family {}", mcu_family))?; - let mut mcu_gpio_map = HashMap::new(); - + // Build MCU map + // + // The keys of this map are GPIO peripheral version strings (e.g. + // "STM32L051_gpio_v1_0"), while the value is a Vec of MCU ref names. + let mut mcu_gpio_map: HashMap> = HashMap::new(); for sf in family { for mcu in sf { let mcu_dat = mcu::Mcu::load(&db_dir, &mcu.name) .map_err(|e| format!("Could not load MCU data: {}", e))?; let gpio_version = mcu_dat.get_ip("GPIO").unwrap().get_version().to_string(); - if !mcu_gpio_map.contains_key(&gpio_version) { - mcu_gpio_map.insert(gpio_version.clone(), Vec::new()); - } mcu_gpio_map - .get_mut(&gpio_version) - .unwrap() + .entry(gpio_version) + .or_insert(vec![]) .push(mcu.name.clone()); } } From 028140e5c84704a02778a685fc7cf07de755b44d Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Thu, 20 Feb 2020 23:26:59 +0100 Subject: [PATCH 15/25] Generate both pin mappings and feature list --- src/main.rs | 137 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 45 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2de4581..38c50b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,49 +10,12 @@ mod internal_peripheral; mod mcu; mod utils; +#[derive(Debug, PartialEq)] enum GenerateTarget { PinMappings, Features, } -fn render_pin_modes(ip: &internal_peripheral::IpGPIO) { - let mut pin_map: HashMap> = HashMap::new(); - - for p in &ip.gpio_pin { - let name = p.get_name(); - if let Some(n) = name { - pin_map.insert(n, p.get_af_modes()); - } - } - - let mut pin_map = pin_map - .into_iter() - .map(|(k, mut v)| { - #[allow(clippy::redundant_closure)] - v.sort_by(|a, b| compare_str(a, b)); - (k, v) - }) - .collect::>(); - - pin_map.sort_by(|a, b| compare_str(&a.0, &b.0)); - - println!("pins! {{"); - for (n, af) in pin_map { - if af.is_empty() { - continue; - } else if af.len() == 1 { - println!(" {} => {{{}}},", n, af[0]); - } else { - println!(" {} => {{", n); - for a in af { - println!(" {},", a); - } - println!(" }},"); - } - } - println!("}}"); -} - lazy_static! { // Note: Version >1.0 is not currently supported static ref GPIO_VERSION: Regex = Regex::new("^([^_]*)_gpio_v1_0$").unwrap(); @@ -127,24 +90,108 @@ fn main() -> Result<(), String> { mcu_gpio_map .entry(gpio_version) .or_insert(vec![]) - .push(mcu.name.clone()); + .push(mcu.ref_name.clone()); } } + match generate { + GenerateTarget::Features => generate_features(&mcu_gpio_map)?, + GenerateTarget::PinMappings => generate_pin_mappings(&mcu_gpio_map, &db_dir)?, + }; + + Ok(()) +} + +/// Print the IO features, followed by MCU features that act purely as aliases +/// for the IO features. +/// +/// Both lists are sorted alphanumerically. +fn generate_features(mcu_gpio_map: &HashMap>) -> Result<(), String> { + let mut main_features = mcu_gpio_map + .keys() + .map(|gpio| gpio_version_to_feature(gpio)) + .collect::, String>>()?; + main_features.sort(); + + let mut mcu_aliases = vec![]; for (gpio, mcu_list) in mcu_gpio_map { - let gpio_data = internal_peripheral::IpGPIO::load(db_dir, &gpio) - .map_err(|e| format!("Could not load IP GPIO file: {}", e))?; - println!("#[cfg(feature = \"{}\")]", gpio_version_to_feature(&gpio)?); + let gpio_version_feature = gpio_version_to_feature(gpio).unwrap(); for mcu in mcu_list { - println!("// {}", mcu); + let mcu_feature = format!("mcu-{}", mcu); + mcu_aliases.push(format!("{} = [\"{}\"]", mcu_feature, gpio_version_feature)); } + } + mcu_aliases.sort(); + + println!("// Features based on the GPIO peripheral version."); + println!("// This determines the pin function mapping of the MCU."); + for feature in main_features { + println!("{} = []", feature); + } + println!("\n// Per-MCU aliases for the GPIO peripheral version."); + for alias in mcu_aliases { + println!("{}", alias); + } + + Ok(()) +} + +/// Generate the pin mappings for the target MCU family. +fn generate_pin_mappings( + mcu_gpio_map: &HashMap>, + db_dir: &Path, +) -> Result<(), String> { + let mut gpio_versions = mcu_gpio_map.keys().collect::>(); + gpio_versions.sort(); + for gpio in gpio_versions { + let gpio_version_feature = gpio_version_to_feature(&gpio)?; + println!("#[cfg(feature = \"{}\")]", gpio_version_feature); + let gpio_data = internal_peripheral::IpGPIO::load(db_dir, &gpio) + .map_err(|e| format!("Could not load IP GPIO file: {}", e))?; render_pin_modes(&gpio_data); println!("\n"); } - Ok(()) } +fn render_pin_modes(ip: &internal_peripheral::IpGPIO) { + let mut pin_map: HashMap> = HashMap::new(); + + for p in &ip.gpio_pin { + let name = p.get_name(); + if let Some(n) = name { + pin_map.insert(n, p.get_af_modes()); + } + } + + let mut pin_map = pin_map + .into_iter() + .map(|(k, mut v)| { + #[allow(clippy::redundant_closure)] + v.sort_by(|a, b| compare_str(a, b)); + (k, v) + }) + .collect::>(); + + pin_map.sort_by(|a, b| compare_str(&a.0, &b.0)); + + println!("pins! {{"); + for (n, af) in pin_map { + if af.is_empty() { + continue; + } else if af.len() == 1 { + println!(" {} => {{{}}},", n, af[0]); + } else { + println!(" {} => {{", n); + for a in af { + println!(" {},", a); + } + println!(" }},"); + } + } + println!("}}"); +} + #[cfg(test)] mod tests { use super::*; @@ -165,7 +212,7 @@ mod tests { assert!(gpio_version_to_feature("STM32F333_gpio_v1_1").is_err()); // Error parsing, wrong pattern - assert!(gpio_version_to_feature("STM32F333_asdf_v1_0").is_err()); + assert!(gpio_version_to_feature("STM32F333_qqio_v1_0").is_err()); // Error parsing, too many underscores assert!(gpio_version_to_feature("STM32_STM32F333_gpio_v1_0").is_err()); From 4f788e08a3bbcdfe2b06aa89644342664557c81d Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Thu, 20 Feb 2020 23:55:29 +0100 Subject: [PATCH 16/25] README: Improve documentation --- README.md | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 2afd531..06718e1 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,36 @@ A program to extract AF modes on MCU pins from the database files provided with ## Usage -``` -cargo run $PATH_TO_MCU_DB_DIR $NAME_OF_MCU_FAMILY -``` + cargo run features STM32L0 -d /path/to/stm32cubemx/db/mcu/ + cargo run pin_mappings STM32L0 -d /path/to/stm32cubemx/db/mcu/ -Under a default windows install `$PATH_TO_MCU_DB_DIR` is `C:\Program Files +Under a default Windows install, the database path is `C:\Program Files (x86)\STMicroelectronics\STM32Cube\STM32CubeMX\db\mcu`, adjust as appropriate for your local config. The MCU family name should match one of the MCU families -as defined in `families.xml`. The program will output one AF mode definition -per GPIO variant, with a corresponding feature gate. +as defined in `families.xml`. At the time of writing, the following families +are available: + +* STM32F0 +* STM32F1 +* STM32F2 +* STM32F3 +* STM32F4 +* STM32F7 +* STM32G0 +* STM32G4 +* STM32H7 +* STM32L0 +* STM32L1 +* STM32L4 +* STM32L4+ +* STM32L5 +* STM32MP1 +* STM32WB + +The program will output one AF mode definition per GPIO variant, with a +corresponding feature gate. + +More on the generated feature groups can be found below. ## The STM32CubeMX Database @@ -141,10 +162,10 @@ pin (AF0), or some other variants. ## Feature Groups -When generating pin function mappings, we want to avoid generating a Cargo -feature for every possible MCU, since that would result in dozens or even -hundreds of features per family. If we don't generate a feature per MCU, we -need to group them somehow. The best way is probably to follow ST's grouping, +When generating pin function mappings, we want to avoid generating a mapping +for every possible MCU, since that would result in dozens or even hundreds of +pin definitions. However, if we don't want a mapping per MCU, we need to group +them somehow. The best way for grouping is probably to follow ST's grouping, which is encoded in the IP versions described above. The feature names are mapped as follows: @@ -187,6 +208,10 @@ database is probably still better than creating our own grouping, which may be broken at any time by ST releasing a new MCU in a pre-existing group, but with a different, incompatible GPIO IP version. +In order to simplify the GPIO IP version selection for the user, alias features +are generated. These are purely a convenience for the user and are never used +directly as feature gates in the source code. + [github-actions]: https://github.com/dbrgn/cube-parse/actions?query=branch%3Amaster [github-actions-badge]: https://github.com/dbrgn/cube-parse/workflows/CI/badge.svg From f81e0d644dd8fecd1a19fb2f5121f6f8468848e6 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sun, 23 Feb 2020 17:17:21 +0100 Subject: [PATCH 17/25] generate_features: Fix comment character --- src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 38c50b3..63271e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -123,12 +123,12 @@ fn generate_features(mcu_gpio_map: &HashMap>) -> Result<(), } mcu_aliases.sort(); - println!("// Features based on the GPIO peripheral version."); - println!("// This determines the pin function mapping of the MCU."); + println!("# Features based on the GPIO peripheral version."); + println!("# This determines the pin function mapping of the MCU."); for feature in main_features { println!("{} = []", feature); } - println!("\n// Per-MCU aliases for the GPIO peripheral version."); + println!("\n# Per-MCU aliases for the GPIO peripheral version."); for alias in mcu_aliases { println!("{}", alias); } From 272f8d26987c348b63bd2058aef5309c61b0c107 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sun, 23 Feb 2020 17:47:20 +0100 Subject: [PATCH 18/25] generate_features: Add PAC dependencies In order for PAC dependencies to work, a mapping needs to be added to the FEATURE_DEPENDENCIES map. --- src/main.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 63271e0..96179f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -95,18 +95,36 @@ fn main() -> Result<(), String> { } match generate { - GenerateTarget::Features => generate_features(&mcu_gpio_map)?, + GenerateTarget::Features => generate_features(&mcu_gpio_map, &mcu_family)?, GenerateTarget::PinMappings => generate_pin_mappings(&mcu_gpio_map, &db_dir)?, }; Ok(()) } +lazy_static! { + static ref FEATURE_DEPENDENCIES: HashMap<&'static str, HashMap<&'static str, &'static str>> = { + let mut m = HashMap::new(); + + // STM32L0 + let mut l0 = HashMap::new(); + l0.insert("^STM32L0.1", "stm32l0/stm32l0x1"); + l0.insert("^STM32L0.2", "stm32l0/stm32l0x2"); + l0.insert("^STM32L0.3", "stm32l0/stm32l0x3"); + m.insert("STM32L0", l0); + + m + }; +} + /// Print the IO features, followed by MCU features that act purely as aliases /// for the IO features. /// /// Both lists are sorted alphanumerically. -fn generate_features(mcu_gpio_map: &HashMap>) -> Result<(), String> { +fn generate_features( + mcu_gpio_map: &HashMap>, + mcu_family: &str, +) -> Result<(), String> { let mut main_features = mcu_gpio_map .keys() .map(|gpio| gpio_version_to_feature(gpio)) @@ -117,8 +135,36 @@ fn generate_features(mcu_gpio_map: &HashMap>) -> Result<(), for (gpio, mcu_list) in mcu_gpio_map { let gpio_version_feature = gpio_version_to_feature(gpio).unwrap(); for mcu in mcu_list { + let mut dependencies = vec![]; + + // PAC feature + if let Some(family) = FEATURE_DEPENDENCIES.get(mcu_family) { + for (pattern, feature) in family { + if Regex::new(pattern).unwrap().is_match(&mcu) { + dependencies.push(feature.to_string()); + break; + } + } + } + + // GPIO version feature + dependencies.push(gpio_version_feature.clone()); + let mcu_feature = format!("mcu-{}", mcu); - mcu_aliases.push(format!("{} = [\"{}\"]", mcu_feature, gpio_version_feature)); + mcu_aliases.push(format!( + "{} = [{}]", + mcu_feature, + &dependencies.iter().map(|val| format!("\"{}\"", val)).fold( + String::new(), + |mut acc, x| { + if !acc.is_empty() { + acc.push_str(", "); + } + acc.push_str(&x); + acc + } + ) + )); } } mcu_aliases.sort(); From 7c369c6bb0c9665decdf575facb751e8463977c7 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sun, 23 Feb 2020 18:28:06 +0100 Subject: [PATCH 19/25] generate_features: Add support for package features --- src/family.rs | 2 +- src/main.rs | 52 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/family.rs b/src/family.rs index d654d94..163fc49 100644 --- a/src/family.rs +++ b/src/family.rs @@ -61,7 +61,7 @@ pub struct SubFamily { #[serde(rename_all = "PascalCase")] pub struct Mcu { pub name: String, - package_name: String, + pub package_name: String, pub ref_name: String, } diff --git a/src/main.rs b/src/main.rs index 96179f0..084ecaf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -77,25 +77,38 @@ fn main() -> Result<(), String> { .find(|v| v.name == mcu_family) .ok_or_else(|| format!("Could not find family {}", mcu_family))?; - // Build MCU map + // MCU map // // The keys of this map are GPIO peripheral version strings (e.g. // "STM32L051_gpio_v1_0"), while the value is a Vec of MCU ref names. let mut mcu_gpio_map: HashMap> = HashMap::new(); + + // Package map + // + // The keys of this map are MCU ref names, the values are package names + // (e.g. ). + let mut mcu_package_map: HashMap = HashMap::new(); + for sf in family { for mcu in sf { let mcu_dat = mcu::Mcu::load(&db_dir, &mcu.name) .map_err(|e| format!("Could not load MCU data: {}", e))?; + let gpio_version = mcu_dat.get_ip("GPIO").unwrap().get_version().to_string(); mcu_gpio_map .entry(gpio_version) .or_insert(vec![]) .push(mcu.ref_name.clone()); + + if mcu_family == "STM32L0" { + // The stm32l0xx-hal has package based features + mcu_package_map.insert(mcu.ref_name.clone(), mcu.package_name.clone()); + } } } match generate { - GenerateTarget::Features => generate_features(&mcu_gpio_map, &mcu_family)?, + GenerateTarget::Features => generate_features(&mcu_gpio_map, &mcu_package_map, &mcu_family)?, GenerateTarget::PinMappings => generate_pin_mappings(&mcu_gpio_map, &db_dir)?, }; @@ -108,9 +121,9 @@ lazy_static! { // STM32L0 let mut l0 = HashMap::new(); - l0.insert("^STM32L0.1", "stm32l0/stm32l0x1"); - l0.insert("^STM32L0.2", "stm32l0/stm32l0x2"); - l0.insert("^STM32L0.3", "stm32l0/stm32l0x3"); + l0.insert("^STM32L0.1", "stm32l0x1"); + l0.insert("^STM32L0.2", "stm32l0x2"); + l0.insert("^STM32L0.3", "stm32l0x3"); m.insert("STM32L0", l0); m @@ -123,6 +136,7 @@ lazy_static! { /// Both lists are sorted alphanumerically. fn generate_features( mcu_gpio_map: &HashMap>, + mcu_package_map: &HashMap, mcu_family: &str, ) -> Result<(), String> { let mut main_features = mcu_gpio_map @@ -137,7 +151,10 @@ fn generate_features( for mcu in mcu_list { let mut dependencies = vec![]; - // PAC feature + // GPIO version feature + dependencies.push(gpio_version_feature.clone()); + + // Additional dependencies if let Some(family) = FEATURE_DEPENDENCIES.get(mcu_family) { for (pattern, feature) in family { if Regex::new(pattern).unwrap().is_match(&mcu) { @@ -147,8 +164,10 @@ fn generate_features( } } - // GPIO version feature - dependencies.push(gpio_version_feature.clone()); + // Package based feature + if let Some(package) = mcu_package_map.get(mcu) { + dependencies.push(package.to_lowercase()); + } let mcu_feature = format!("mcu-{}", mcu); mcu_aliases.push(format!( @@ -169,12 +188,23 @@ fn generate_features( } mcu_aliases.sort(); - println!("# Features based on the GPIO peripheral version."); - println!("# This determines the pin function mapping of the MCU."); + println!("# Features based on the GPIO peripheral version"); + println!("# This determines the pin function mapping of the MCU"); for feature in main_features { println!("{} = []", feature); } - println!("\n# Per-MCU aliases for the GPIO peripheral version."); + println!(); + if !mcu_package_map.is_empty() { + println!("# Physical packages"); + let mut packages = mcu_package_map.values().map(|v| v.to_lowercase()).collect::>(); + packages.sort_by(|a, b| compare_str(a, b)); + packages.dedup(); + for pkg in packages { + println!("{} = []", pkg); + } + println!(); + } + println!("# MCUs"); for alias in mcu_aliases { println!("{}", alias); } From 700893f4f45ad73d0bd735c0d6fd07e775cddd4b Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Fri, 3 Apr 2020 23:35:22 +0200 Subject: [PATCH 20/25] IP: Match LPUART as well --- src/internal_peripheral.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal_peripheral.rs b/src/internal_peripheral.rs index af3a590..e0c5944 100644 --- a/src/internal_peripheral.rs +++ b/src/internal_peripheral.rs @@ -60,8 +60,8 @@ impl IpGPIO { } lazy_static! { - static ref USART_RX: Regex = Regex::new("USART._RX").unwrap(); - static ref USART_TX: Regex = Regex::new("USART._TX").unwrap(); + static ref USART_RX: Regex = Regex::new("(LP)?US?ART._RX").unwrap(); + static ref USART_TX: Regex = Regex::new("(LP)?US?ART._TX").unwrap(); static ref SPI_MOSI: Regex = Regex::new("SPI._MOSI").unwrap(); static ref SPI_MISO: Regex = Regex::new("SPI._MISO").unwrap(); static ref SPI_SCK: Regex = Regex::new("SPI._SCK").unwrap(); From 73a46edd8fda573df9d7bbf4377db8fd150acba1 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 4 Apr 2020 01:35:25 +0200 Subject: [PATCH 21/25] Fix code formatting --- src/main.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 084ecaf..686d35b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -108,7 +108,9 @@ fn main() -> Result<(), String> { } match generate { - GenerateTarget::Features => generate_features(&mcu_gpio_map, &mcu_package_map, &mcu_family)?, + GenerateTarget::Features => { + generate_features(&mcu_gpio_map, &mcu_package_map, &mcu_family)? + } GenerateTarget::PinMappings => generate_pin_mappings(&mcu_gpio_map, &db_dir)?, }; @@ -196,7 +198,10 @@ fn generate_features( println!(); if !mcu_package_map.is_empty() { println!("# Physical packages"); - let mut packages = mcu_package_map.values().map(|v| v.to_lowercase()).collect::>(); + let mut packages = mcu_package_map + .values() + .map(|v| v.to_lowercase()) + .collect::>(); packages.sort_by(|a, b| compare_str(a, b)); packages.dedup(); for pkg in packages { From 0ed91113675a7b3111651a346049b4d33252ca45 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 8 Dec 2020 23:41:59 +0100 Subject: [PATCH 22/25] Add support for extracting EEPROM size --- README.md | 12 ++-- src/main.rs | 156 ++++++++++++++++++++++++++++++++++++++-------------- src/mcu.rs | 7 +++ 3 files changed, 128 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 06718e1..9e9e22c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ [![Build Status][github-actions-badge]][github-actions] -A program to extract AF modes on MCU pins from the database files provided with STM32CubeMX. +A program to extract hardware configuration information from the MCU database +files shipped with STM32CubeMX. + ## Usage @@ -32,10 +34,6 @@ are available: * STM32MP1 * STM32WB -The program will output one AF mode definition per GPIO variant, with a -corresponding feature gate. - -More on the generated feature groups can be found below. ## The STM32CubeMX Database @@ -160,7 +158,8 @@ As you can see, this element describes the pin `PB6`. Depending on the chosen Alternative Function (AF), it can become an `I2C1_SCL` pin (AF1), a `USART1_TX` pin (AF0), or some other variants. -## Feature Groups + +## GPIO Feature Groups When generating pin function mappings, we want to avoid generating a mapping for every possible MCU, since that would result in dozens or even hundreds of @@ -212,6 +211,7 @@ In order to simplify the GPIO IP version selection for the user, alias features are generated. These are purely a convenience for the user and are never used directly as feature gates in the source code. + [github-actions]: https://github.com/dbrgn/cube-parse/actions?query=branch%3Amaster [github-actions-badge]: https://github.com/dbrgn/cube-parse/workflows/CI/badge.svg diff --git a/src/main.rs b/src/main.rs index 686d35b..565ff02 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,8 +12,9 @@ mod utils; #[derive(Debug, PartialEq)] enum GenerateTarget { - PinMappings, Features, + PinMappings, + EepromSizes, } lazy_static! { @@ -31,6 +32,11 @@ fn gpio_version_to_feature(version: &str) -> Result { } } +/// Get the EEPROM size (in KiB) feature for a certain size. +fn eeprom_size_to_feature(size: u32) -> String { + format!("eeprom-{}", size) +} + fn main() -> Result<(), String> { let args = App::new("cube-parse") .version(env!("CARGO_PKG_VERSION")) @@ -47,7 +53,7 @@ fn main() -> Result<(), String> { Arg::with_name("generate") .help("What to generate") .takes_value(true) - .possible_values(&["pin_mappings", "features"]) + .possible_values(&["features", "pin_mappings", "eeprom_sizes"]) .required(true), ) .arg( @@ -62,8 +68,9 @@ fn main() -> Result<(), String> { let db_dir = Path::new(args.value_of("db_dir").unwrap()); let mcu_family = args.value_of("mcu_family").unwrap(); let generate = match args.value_of("generate").unwrap() { - "pin_mappings" => GenerateTarget::PinMappings, "features" => GenerateTarget::Features, + "pin_mappings" => GenerateTarget::PinMappings, + "eeprom_sizes" => GenerateTarget::EepromSizes, _ => unreachable!(), }; @@ -79,39 +86,68 @@ fn main() -> Result<(), String> { // MCU map // + // This maps a MCU ref name to the corresponding `mcu::Mcu` instance. + let mut mcu_map: HashMap = HashMap::new(); + + // GPIO map + // // The keys of this map are GPIO peripheral version strings (e.g. // "STM32L051_gpio_v1_0"), while the value is a Vec of MCU ref names. let mut mcu_gpio_map: HashMap> = HashMap::new(); // Package map // - // The keys of this map are MCU ref names, the values are package names - // (e.g. ). + // The keys of this map are MCU ref names, the values are package names. let mut mcu_package_map: HashMap = HashMap::new(); + // EEPROM size map + // + // The keys of this map are EEPROM sizes in KiB, the values are Vecs of MCU ref names. + let mut mcu_eeprom_size_map: HashMap> = HashMap::new(); + + // Iterate through subfamilies, then through MCUs. Fill the maps above with + // aggregated data. for sf in family { for mcu in sf { + // Load MCU data from the XML files let mcu_dat = mcu::Mcu::load(&db_dir, &mcu.name) .map_err(|e| format!("Could not load MCU data: {}", e))?; + // Fill GPIO map let gpio_version = mcu_dat.get_ip("GPIO").unwrap().get_version().to_string(); mcu_gpio_map .entry(gpio_version) .or_insert(vec![]) .push(mcu.ref_name.clone()); + // Fill package map if mcu_family == "STM32L0" { // The stm32l0xx-hal has package based features mcu_package_map.insert(mcu.ref_name.clone(), mcu.package_name.clone()); } + + // Fill EEPROM size map + if let Some(size) = mcu_dat.get_eeprom_size_kib() { + mcu_eeprom_size_map + .entry(size) + .or_insert(vec![]) + .push(mcu.ref_name.clone()); + } + + mcu_map.insert(mcu.ref_name.clone(), mcu_dat); } } match generate { - GenerateTarget::Features => { - generate_features(&mcu_gpio_map, &mcu_package_map, &mcu_family)? - } + GenerateTarget::Features => generate_features( + &mcu_map, + &mcu_gpio_map, + &mcu_package_map, + &mcu_eeprom_size_map, + &mcu_family, + )?, GenerateTarget::PinMappings => generate_pin_mappings(&mcu_gpio_map, &db_dir)?, + GenerateTarget::EepromSizes => generate_eeprom_sizes(&mcu_eeprom_size_map)?, }; Ok(()) @@ -132,31 +168,67 @@ lazy_static! { }; } -/// Print the IO features, followed by MCU features that act purely as aliases -/// for the IO features. +/// Generate all Cargo features /// -/// Both lists are sorted alphanumerically. +/// Feature categories: +/// +/// - IO features (`io-*`) +/// - EEPROM features (`eeprom-*`) +/// +/// Finally, the MCU features are printed, they act purely as aliases for the +/// other features. fn generate_features( + mcu_map: &HashMap, mcu_gpio_map: &HashMap>, mcu_package_map: &HashMap, + mcu_eeprom_size_map: &HashMap>, mcu_family: &str, ) -> Result<(), String> { - let mut main_features = mcu_gpio_map + // IO features + let mut io_features = mcu_gpio_map .keys() .map(|gpio| gpio_version_to_feature(gpio)) .collect::, String>>()?; - main_features.sort(); + io_features.sort(); + println!("# Features based on the GPIO peripheral version"); + println!("# This determines the pin function mapping of the MCU"); + for feature in io_features { + println!("{} = []", feature); + } + println!(); + // EEPROM sizes + let mut eeprom_sizes = mcu_eeprom_size_map.keys().collect::>(); + eeprom_sizes.sort(); + println!("# Features based on EEPROM size (in KiB)"); + for size in eeprom_sizes { + println!("{} = []", eeprom_size_to_feature(*size)); + } + println!(); + + // Physical packages + if !mcu_package_map.is_empty() { + println!("# Physical packages"); + let mut packages = mcu_package_map + .values() + .map(|v| v.to_lowercase()) + .collect::>(); + packages.sort_by(|a, b| compare_str(a, b)); + packages.dedup(); + for pkg in packages { + println!("{} = []", pkg); + } + println!(); + } + + // MCU features let mut mcu_aliases = vec![]; for (gpio, mcu_list) in mcu_gpio_map { let gpio_version_feature = gpio_version_to_feature(gpio).unwrap(); for mcu in mcu_list { let mut dependencies = vec![]; - // GPIO version feature - dependencies.push(gpio_version_feature.clone()); - - // Additional dependencies + // Static feature dependencies if let Some(family) = FEATURE_DEPENDENCIES.get(mcu_family) { for (pattern, feature) in family { if Regex::new(pattern).unwrap().is_match(&mcu) { @@ -171,10 +243,17 @@ fn generate_features( dependencies.push(package.to_lowercase()); } - let mcu_feature = format!("mcu-{}", mcu); + // GPIO version feature + dependencies.push(gpio_version_feature.clone()); + + // EEPROM size + if let Some(size) = mcu_map.get(mcu).unwrap().get_eeprom_size_kib() { + dependencies.push(eeprom_size_to_feature(size)); + } + mcu_aliases.push(format!( - "{} = [{}]", - mcu_feature, + "mcu-{} = [{}]", + mcu, &dependencies.iter().map(|val| format!("\"{}\"", val)).fold( String::new(), |mut acc, x| { @@ -189,27 +268,12 @@ fn generate_features( } } mcu_aliases.sort(); - - println!("# Features based on the GPIO peripheral version"); - println!("# This determines the pin function mapping of the MCU"); - for feature in main_features { - println!("{} = []", feature); - } - println!(); - if !mcu_package_map.is_empty() { - println!("# Physical packages"); - let mut packages = mcu_package_map - .values() - .map(|v| v.to_lowercase()) - .collect::>(); - packages.sort_by(|a, b| compare_str(a, b)); - packages.dedup(); - for pkg in packages { - println!("{} = []", pkg); - } - println!(); - } - println!("# MCUs"); + println!("# MCU aliases"); + println!("#"); + println!("# Note: These are just aliases, they should not be used to directly feature gate"); + println!( + "# functionality in the HAL! However, user code should usually depend on a MCU alias." + ); for alias in mcu_aliases { println!("{}", alias); } @@ -235,6 +299,16 @@ fn generate_pin_mappings( Ok(()) } +/// Generate code containing the EEPROM size. +fn generate_eeprom_sizes(mcu_eeprom_size_map: &HashMap>) -> Result<(), String> { + println!("// EEPROM sizes in KiB, generated with cube-parse"); + for size in mcu_eeprom_size_map.keys() { + println!("#[cfg({})]", eeprom_size_to_feature(*size)); + println!("const EEPROM_SIZE_KIB: u32 = {};", size); + } + Ok(()) +} + fn render_pin_modes(ip: &internal_peripheral::IpGPIO) { let mut pin_map: HashMap> = HashMap::new(); diff --git a/src/mcu.rs b/src/mcu.rs index 805228d..adb8416 100644 --- a/src/mcu.rs +++ b/src/mcu.rs @@ -9,6 +9,8 @@ use crate::utils::load_file; pub struct Mcu { #[serde(rename = "IP", default)] ip: Vec, + #[serde(rename = "E2prom")] + eeprom_size_kib: String, } impl Mcu { @@ -19,6 +21,11 @@ impl Mcu { pub fn get_ip(&self, name: &str) -> Option<&IP> { self.ip.iter().find(|v| v.name == name) } + + /// Return the EEPROM size in KiB + pub fn get_eeprom_size_kib(&self) -> Option { + self.eeprom_size_kib.parse().ok() + } } #[derive(Debug, Deserialize)] From 935512c30dfb6673ba1311371fb180d9889c8d39 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 8 Dec 2020 23:50:27 +0100 Subject: [PATCH 23/25] Correction: EEPROM size is in bytes --- src/main.rs | 14 +++++++------- src/mcu.rs | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index 565ff02..eb739cb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,7 +32,7 @@ fn gpio_version_to_feature(version: &str) -> Result { } } -/// Get the EEPROM size (in KiB) feature for a certain size. +/// Get the EEPROM size feature for a certain size. fn eeprom_size_to_feature(size: u32) -> String { format!("eeprom-{}", size) } @@ -102,7 +102,7 @@ fn main() -> Result<(), String> { // EEPROM size map // - // The keys of this map are EEPROM sizes in KiB, the values are Vecs of MCU ref names. + // The keys of this map are EEPROM sizes, the values are Vecs of MCU ref names. let mut mcu_eeprom_size_map: HashMap> = HashMap::new(); // Iterate through subfamilies, then through MCUs. Fill the maps above with @@ -127,7 +127,7 @@ fn main() -> Result<(), String> { } // Fill EEPROM size map - if let Some(size) = mcu_dat.get_eeprom_size_kib() { + if let Some(size) = mcu_dat.get_eeprom_size() { mcu_eeprom_size_map .entry(size) .or_insert(vec![]) @@ -200,7 +200,7 @@ fn generate_features( // EEPROM sizes let mut eeprom_sizes = mcu_eeprom_size_map.keys().collect::>(); eeprom_sizes.sort(); - println!("# Features based on EEPROM size (in KiB)"); + println!("# Features based on EEPROM size (in bytes)"); for size in eeprom_sizes { println!("{} = []", eeprom_size_to_feature(*size)); } @@ -247,7 +247,7 @@ fn generate_features( dependencies.push(gpio_version_feature.clone()); // EEPROM size - if let Some(size) = mcu_map.get(mcu).unwrap().get_eeprom_size_kib() { + if let Some(size) = mcu_map.get(mcu).unwrap().get_eeprom_size() { dependencies.push(eeprom_size_to_feature(size)); } @@ -301,10 +301,10 @@ fn generate_pin_mappings( /// Generate code containing the EEPROM size. fn generate_eeprom_sizes(mcu_eeprom_size_map: &HashMap>) -> Result<(), String> { - println!("// EEPROM sizes in KiB, generated with cube-parse"); + println!("// EEPROM sizes in bytes, generated with cube-parse"); for size in mcu_eeprom_size_map.keys() { println!("#[cfg({})]", eeprom_size_to_feature(*size)); - println!("const EEPROM_SIZE_KIB: u32 = {};", size); + println!("const EEPROM_SIZE_BYTES: u32 = {};", size); } Ok(()) } diff --git a/src/mcu.rs b/src/mcu.rs index adb8416..53533db 100644 --- a/src/mcu.rs +++ b/src/mcu.rs @@ -10,7 +10,7 @@ pub struct Mcu { #[serde(rename = "IP", default)] ip: Vec, #[serde(rename = "E2prom")] - eeprom_size_kib: String, + eeprom_size_bytes: String, } impl Mcu { @@ -22,9 +22,9 @@ impl Mcu { self.ip.iter().find(|v| v.name == name) } - /// Return the EEPROM size in KiB - pub fn get_eeprom_size_kib(&self) -> Option { - self.eeprom_size_kib.parse().ok() + /// Return the EEPROM size in bytes + pub fn get_eeprom_size(&self) -> Option { + self.eeprom_size_bytes.parse().ok() } } From 9e210cbc52ac2bbaab8497285d83cd50d94ae944 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 8 Dec 2020 23:55:44 +0100 Subject: [PATCH 24/25] Fix syntax of eeprom feature cfg attribute --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index eb739cb..105cbf8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -303,7 +303,7 @@ fn generate_pin_mappings( fn generate_eeprom_sizes(mcu_eeprom_size_map: &HashMap>) -> Result<(), String> { println!("// EEPROM sizes in bytes, generated with cube-parse"); for size in mcu_eeprom_size_map.keys() { - println!("#[cfg({})]", eeprom_size_to_feature(*size)); + println!("#[cfg(feature = \"{}\")]", eeprom_size_to_feature(*size)); println!("const EEPROM_SIZE_BYTES: u32 = {};", size); } Ok(()) From 2c71164d1726abdb9c9506fbae4b5601fce9c5a3 Mon Sep 17 00:00:00 2001 From: Mathieu David Date: Fri, 30 Jul 2021 15:35:09 +0200 Subject: [PATCH 25/25] Add support for parsing Flash and RAM sizes (#5) --- src/family.rs | 14 +++++++++ src/main.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 88 insertions(+), 5 deletions(-) diff --git a/src/family.rs b/src/family.rs index 163fc49..d8e6fcf 100644 --- a/src/family.rs +++ b/src/family.rs @@ -63,6 +63,20 @@ pub struct Mcu { pub name: String, pub package_name: String, pub ref_name: String, + #[serde(rename = "Flash")] + pub flash_size: String, + #[serde(rename = "Ram")] + pub ram_size: String, +} + +impl Mcu { + pub fn flash_size(&self) -> Option { + self.flash_size.parse().ok() + } + + pub fn ram_size(&self) -> Option { + self.ram_size.parse().ok() + } } impl Families { diff --git a/src/main.rs b/src/main.rs index 105cbf8..2b29373 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,6 +37,16 @@ fn eeprom_size_to_feature(size: u32) -> String { format!("eeprom-{}", size) } +/// Get the Flash size feature for a certain size. +fn flash_size_to_feature(size: u32) -> String { + format!("flash-{}", size) +} + +/// Get the RAM size feature for a certain size. +fn ram_size_to_feature(size: u32) -> String { + format!("ram-{}", size) +} + fn main() -> Result<(), String> { let args = App::new("cube-parse") .version(env!("CARGO_PKG_VERSION")) @@ -87,7 +97,7 @@ fn main() -> Result<(), String> { // MCU map // // This maps a MCU ref name to the corresponding `mcu::Mcu` instance. - let mut mcu_map: HashMap = HashMap::new(); + let mut mcu_map: HashMap = HashMap::new(); // GPIO map // @@ -105,13 +115,23 @@ fn main() -> Result<(), String> { // The keys of this map are EEPROM sizes, the values are Vecs of MCU ref names. let mut mcu_eeprom_size_map: HashMap> = HashMap::new(); + // Flash size map + // + // The keys of this map are flash sizes, the values are Vecs of MCU ref names. + let mut mcu_flash_size_map: HashMap> = HashMap::new(); + + // RAM size map + // + // The keys of this map are RAM sizes, the values are Vecs of MCU ref names. + let mut mcu_ram_size_map: HashMap> = HashMap::new(); + // Iterate through subfamilies, then through MCUs. Fill the maps above with // aggregated data. for sf in family { for mcu in sf { // Load MCU data from the XML files let mcu_dat = mcu::Mcu::load(&db_dir, &mcu.name) - .map_err(|e| format!("Could not load MCU data: {}", e))?; + .map_err(|e| format!("Could not load MCU data for mcu {}: {}", &mcu.name, e))?; // Fill GPIO map let gpio_version = mcu_dat.get_ip("GPIO").unwrap().get_version().to_string(); @@ -134,7 +154,23 @@ fn main() -> Result<(), String> { .push(mcu.ref_name.clone()); } - mcu_map.insert(mcu.ref_name.clone(), mcu_dat); + // Fill flash size map + if let Some(flash_size) = mcu.flash_size() { + mcu_flash_size_map + .entry(flash_size) + .or_insert(vec![]) + .push(mcu.ref_name.clone()); + } + + // Fill RAM size map + if let Some(ram_size) = mcu.ram_size() { + mcu_ram_size_map + .entry(ram_size) + .or_insert(vec![]) + .push(mcu.ref_name.clone()); + } + + mcu_map.insert(mcu.ref_name.clone(), (mcu, mcu_dat)); } } @@ -144,6 +180,8 @@ fn main() -> Result<(), String> { &mcu_gpio_map, &mcu_package_map, &mcu_eeprom_size_map, + &mcu_flash_size_map, + &mcu_ram_size_map, &mcu_family, )?, GenerateTarget::PinMappings => generate_pin_mappings(&mcu_gpio_map, &db_dir)?, @@ -178,10 +216,12 @@ lazy_static! { /// Finally, the MCU features are printed, they act purely as aliases for the /// other features. fn generate_features( - mcu_map: &HashMap, + mcu_map: &HashMap, mcu_gpio_map: &HashMap>, mcu_package_map: &HashMap, mcu_eeprom_size_map: &HashMap>, + mcu_flash_size_map: &HashMap>, + mcu_ram_size_map: &HashMap>, mcu_family: &str, ) -> Result<(), String> { // IO features @@ -206,6 +246,24 @@ fn generate_features( } println!(); + // Flash sizes + let mut flash_sizes = mcu_flash_size_map.keys().collect::>(); + flash_sizes.sort(); + println!("# Features based on Flash size (in kbytes)"); + for size in flash_sizes { + println!("{} = []", flash_size_to_feature(*size)); + } + println!(); + + // RAM sizes + let mut ram_sizes = mcu_ram_size_map.keys().collect::>(); + ram_sizes.sort(); + println!("# Features based on RAM size (in kbytes)"); + for size in ram_sizes { + println!("{} = []", ram_size_to_feature(*size)); + } + println!(); + // Physical packages if !mcu_package_map.is_empty() { println!("# Physical packages"); @@ -246,11 +304,22 @@ fn generate_features( // GPIO version feature dependencies.push(gpio_version_feature.clone()); + let (mcu_info, mcu_dat) = mcu_map.get(mcu).unwrap(); + // EEPROM size - if let Some(size) = mcu_map.get(mcu).unwrap().get_eeprom_size() { + if let Some(size) = mcu_dat.get_eeprom_size() { dependencies.push(eeprom_size_to_feature(size)); } + // Flash & RAM size + if let Some(flash_size) = mcu_info.flash_size() { + dependencies.push(flash_size_to_feature(flash_size)); + } + + if let Some(ram_size) = mcu_info.ram_size() { + dependencies.push(ram_size_to_feature(ram_size)); + } + mcu_aliases.push(format!( "mcu-{} = [{}]", mcu,