nucleus_compiler/
model.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum Bus {
13 Ahb1,
14 Apb1,
15 Apb2,
16}
17
18impl Bus {
19 pub fn name(self) -> &'static str {
20 match self {
21 Bus::Ahb1 => "AHB1",
22 Bus::Apb1 => "APB1",
23 Bus::Apb2 => "APB2",
24 }
25 }
26}
27
28#[derive(Debug, Clone, Copy)]
31pub struct Role {
32 pub key: &'static str,
34 pub signal: &'static str,
36 pub required: bool,
38}
39
40const fn req(key: &'static str, signal: &'static str) -> Role {
41 Role {
42 key,
43 signal,
44 required: true,
45 }
46}
47
48const fn opt(key: &'static str, signal: &'static str) -> Role {
49 Role {
50 key,
51 signal,
52 required: false,
53 }
54}
55
56struct Kind {
58 roles: &'static [Role],
59}
60
61const USART: Kind = Kind {
62 roles: &[
63 req("tx", "TX"),
64 req("rx", "RX"),
65 opt("cts", "CTS"),
66 opt("rts", "RTS"),
67 opt("ck", "CK"),
68 ],
69};
70
71const SPI: Kind = Kind {
72 roles: &[
73 req("mosi", "MOSI"),
74 req("miso", "MISO"),
75 req("sck", "SCK"),
76 opt("nss", "NSS"),
77 ],
78};
79
80const I2C: Kind = Kind {
81 roles: &[req("sda", "SDA"), req("scl", "SCL"), opt("smba", "SMBA")],
82};
83
84const TIM: Kind = Kind {
85 roles: &[
86 opt("channel1", "CH1"),
87 opt("channel2", "CH2"),
88 opt("channel3", "CH3"),
89 opt("channel4", "CH4"),
90 ],
91};
92
93pub fn roles_for(instance: &str) -> Option<&'static [Role]> {
97 let kind = instance.trim_end_matches(|c: char| c.is_ascii_digit());
98 let kind = match kind {
99 "usart" | "uart" => &USART,
100 "spi" => &SPI,
101 "i2c" | "fmpi2c" => &I2C,
102 "tim" => &TIM,
103 _ => return None,
104 };
105 Some(kind.roles)
106}
107
108pub fn peripheral_name(instance: &str) -> String {
112 instance.to_ascii_uppercase()
113}
114
115pub fn peripheral_bus(peripheral: &str) -> Option<Bus> {
122 let p = peripheral;
123 let bus = match p {
124 "USART1" | "USART6" | "SPI1" | "SPI4" | "SDIO" | "ADC1" | "ADC2" | "ADC3" | "SAI1"
126 | "SAI2" | "TIM1" | "TIM8" | "TIM9" | "TIM10" | "TIM11" => Bus::Apb2,
127 "USART2" | "USART3" | "UART4" | "UART5" | "SPI2" | "SPI3" | "I2C1" | "I2C2" | "I2C3"
129 | "FMPI2C1" | "CAN1" | "CAN2" | "SPDIFRX" | "CEC" | "TIM2" | "TIM3" | "TIM4" | "TIM5"
130 | "TIM6" | "TIM7" | "TIM12" | "TIM13" | "TIM14" => Bus::Apb1,
131 "DCMI" | "QUADSPI" | "FMC" => Bus::Ahb1,
133 _ => return None,
134 };
135 Some(bus)
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn role_tables_resolve_by_prefix() {
144 assert!(roles_for("usart2").is_some());
145 assert!(roles_for("spi1").is_some());
146 assert!(roles_for("i2c3").is_some());
147 assert!(roles_for("tim2").is_some());
148 assert!(roles_for("wibble9").is_none());
149 }
150
151 #[test]
152 fn spi_required_and_optional() {
153 let roles = roles_for("spi1").unwrap();
154 let nss = roles.iter().find(|r| r.key == "nss").unwrap();
155 let sck = roles.iter().find(|r| r.key == "sck").unwrap();
156 assert!(!nss.required);
157 assert!(sck.required);
158 }
159
160 #[test]
161 fn buses_match_f446() {
162 assert_eq!(peripheral_bus("SPI1"), Some(Bus::Apb2));
163 assert_eq!(peripheral_bus("USART2"), Some(Bus::Apb1));
164 assert_eq!(peripheral_bus("I2C1"), Some(Bus::Apb1));
165 assert_eq!(peripheral_bus("MADEUP"), None);
166 }
167}