Skip to main content

espforge_diagnostics/
codes.rs

1//! The stable diagnostic codes this slice can reach, one per message.
2//!
3//! The ranges are reserved by stage (see the crate docs). A new message gets a
4//! new entry here; the numbers are the legacy ones, never renumbered.
5//!
6//! Codes are data: the human renderer does not print them.
7
8use crate::DiagCode;
9
10macro_rules! codes {
11    ($($(#[$doc:meta])* $name:ident = $code:literal;)*) => {
12        $(
13            $(#[$doc])*
14            pub const $name: DiagCode = DiagCode::new($code);
15        )*
16
17        /// Every code defined in this module, in declaration order.
18        pub const ALL: &[DiagCode] = &[$($name),*];
19    };
20}
21
22codes! {
23    /// A parser-junk line that is not a node.
24    SYNTAX_NODE_LINE = "E0101";
25    /// A line that should have been a `# section` header.
26    SYNTAX_SECTION_HEADER = "E0102";
27    /// Two `# section` blocks with the same name.
28    STRUCTURE_DUPLICATE_SECTION = "E0103";
29    /// A required `# section` block is absent.
30    STRUCTURE_MISSING_SECTION = "E0104";
31    /// A section outside the four-section grammar.
32    STRUCTURE_UNKNOWN_SECTION = "E0105";
33
34    /// An element the `# espforge` schema does not know.
35    CORE_UNKNOWN_ELEMENT = "E0201";
36    /// `# espforge` lacks `<project>`, `<chip>` or `<runtime>`.
37    CORE_INCOMPLETE = "E0202";
38    /// The same element is written twice in `# espforge`.
39    CORE_DUPLICATE_ELEMENT = "E0203";
40    /// `<chip>` without a `type` attribute.
41    CORE_CHIP_WITHOUT_TYPE = "E0204";
42    /// A chip name the catalog does not know.
43    CORE_UNKNOWN_CHIP = "E0205";
44    /// `<runtime>` without a `type` attribute.
45    CORE_RUNTIME_WITHOUT_TYPE = "E0206";
46    /// A runtime name the catalog does not know.
47    CORE_UNKNOWN_RUNTIME = "E0207";
48    /// `<console>` without a `type` attribute.
49    CORE_CONSOLE_WITHOUT_TYPE = "E0208";
50    /// A console name the catalog does not know.
51    CORE_UNKNOWN_CONSOLE = "E0209";
52    /// `<ota flash_size>` names a size the catalog does not know.
53    CORE_UNKNOWN_FLASH_SIZE = "E0210";
54    /// `<ota rollback>` is not `true` or `false`.
55    CORE_INVALID_ROLLBACK = "E0211";
56    /// `<logger>` names a level the catalog does not know.
57    CORE_INVALID_LOG_LEVEL = "E0212";
58    /// An attribute no element declares.
59    ///
60    /// Shared by every stage: the message names the attribute and the list
61    /// the element does accept, so a typo like `backight=` fails loudly instead
62    /// of silently taking the schema default.
63    ATTR_UNKNOWN = "E0316";
64
65    /// An option name that is not in the schema.
66    OPTION_UNKNOWN = "E0301";
67    /// An option value outside its declared choices.
68    OPTION_INVALID_VALUE = "E0302";
69    /// An option value that cannot be set in `<options>`.
70    OPTION_DERIVED = "E0306";
71    /// An option that needs another option that is off.
72    OPTION_REQUIRES = "E0307";
73    /// An option that the selected chip cannot provide.
74    OPTION_UNAVAILABLE = "E0308";
75    /// Two options in one selection group are on together.
76    OPTION_MUTUALLY_EXCLUSIVE = "E0309";
77    /// The selected console does not exist on the chip.
78    OPTION_NO_CONSOLE = "E0310";
79    /// An attribute value with the wrong type.
80    VALUE_WRONG_TYPE = "E0311";
81    /// A value that should be a boolean.
82    VALUE_NOT_BOOLEAN = "E0312";
83    /// A value that should be an unsigned number.
84    VALUE_NOT_NUMBER = "E0313";
85    /// A key used both as a plain value and as an object.
86    VALUE_KEY_KIND = "E0314";
87    /// A required attribute is absent.
88    VALUE_MISSING_ATTRIBUTE = "E0315";
89
90    /// A peripheral tag no element implements.
91    PERIPHERAL_UNSUPPORTED = "E0501";
92    /// `<gpio pin>` that is not a number.
93    GPIO_INVALID_PIN = "E0502";
94    /// `<gpio direction>` outside `input`/`output`.
95    GPIO_INVALID_DIRECTION = "E0503";
96    /// An `<i2c>` id that is not `i2c0`, `i2c1` or `i2c2`.
97    I2C_INVALID_ID = "E0504";
98    /// An `<i2c>` pin that is not a GPIO number.
99    I2C_INVALID_PIN = "E0505";
100    /// An `<i2c frequency>` that is not `100kHz`-shaped.
101    I2C_INVALID_FREQUENCY = "E0506";
102    /// An `<spi>` id other than `spi2`.
103    SPI_INVALID_ID = "E0507";
104    /// An `<spi>` pin that is not a GPIO number.
105    SPI_INVALID_PIN = "E0508";
106    /// An `<spi mode>` outside 0..=3.
107    SPI_INVALID_MODE = "E0509";
108    /// An `<spi frequency>` that is not `100kHz`-shaped.
109    SPI_INVALID_FREQUENCY = "E0510";
110    /// A `<uart>` id that is not `uart0`..`uart3`.
111    UART_INVALID_ID = "E0511";
112    /// A `<uart uart=>` value outside `UART0`..`UART3`.
113    UART_INVALID_PERIPHERAL = "E0512";
114    /// A `<uart>` pin that is not a GPIO number.
115    UART_INVALID_PIN = "E0513";
116    /// `<uart baud_rate="0">`.
117    UART_INVALID_BAUD = "E0521";
118    /// A `<wifi>` on a chip with no Wi-Fi radio.
119    WIFI_NO_RADIO = "E0514";
120    /// A `<wifi>` whose id is missing or malformed.
121    WIFI_INVALID_ID = "E0515";
122    /// A pin number larger than the chip has.
123    GPIO_NOT_ON_CHIP = "E0516";
124    /// A claim on a pin wired to the SPI flash or PSRAM bus.
125    GPIO_RESERVED_FLASH = "E0517";
126    /// An output claim on an input-only pin.
127    GPIO_NOT_OUTPUT_CAPABLE = "E0518";
128    /// A chip with no pin capability table.
129    PIN_CAPS_MISSING = "E0519";
130    /// A claim on a strapping pin: the level at boot selects a boot mode.
131    GPIO_STRAPPING = "W0520";
132
133    /// An `<led>` that cannot be built.
134    COMPONENT_INVALID_LED = "E0601";
135    /// A `<button>` that cannot be built.
136    COMPONENT_INVALID_BUTTON = "E0602";
137    /// A component tag no element implements.
138    COMPONENT_UNSUPPORTED = "E0606";
139    /// An `<led>` referencing a gpio id that does not exist.
140    COMPONENT_UNKNOWN_GPIO = "E0608";
141    /// A led on an input pin.
142    COMPONENT_WRONG_DIRECTION = "E0609";
143    /// A bus component id that cannot become a Rust identifier.
144    COMPONENT_INVALID_ID = "E0614";
145    /// A recipe component that cannot be built (the recipe's default code).
146    /// Legacy component codes stop at `E0614`; this one is free.
147    COMPONENT_INVALID = "E0615";
148    /// A `<wifi_station wifi>` reference to a radio that does not exist.
149    COMPONENT_UNKNOWN_WIFI = "E0616";
150    /// A second `<wifi_station>` on one `<wifi>` radio.
151    COMPONENT_WIFI_RADIO_USED = "E0617";
152    /// An `ssid` that is empty or longer than 32 bytes.
153    COMPONENT_INVALID_SSID = "E0618";
154    /// A password that is required but missing, or outside 8..=63 characters.
155    COMPONENT_INVALID_PASSWORD = "E0619";
156    /// `auth="open"` written together with a password.
157    COMPONENT_OPEN_WITH_PASSWORD = "E0620";
158    /// A `password="env:NAME"` whose variable name is not an identifier.
159    COMPONENT_INVALID_ENV = "E0621";
160    /// A `<wifi_station>` that cannot be built (missing or invalid attribute).
161    COMPONENT_INVALID_WIFI = "E0622";
162    /// An id the generated code already binds (`devices`, `ctx`, `__x`).
163    COMPONENT_RESERVED_ID = "E0623";
164
165    /// Two elements of different kinds on one pin.
166    CONFLICT_PIN = "E0701";
167    /// A pin claimed by two elements of the same kind.
168    CONFLICT_PIN_USED = "E0702";
169    /// One element needs an input and the other an output.
170    CONFLICT_DIRECTION = "E0703";
171    /// Two elements naming the same hardware peripheral (`UART1`).
172    CONFLICT_PERIPHERAL = "E0704";
173    /// An `<i2c>` that puts sda and scl on one pin.
174    CONFLICT_I2C_WIRING = "E0705";
175    /// An `<spi>` that puts two of its pins on one GPIO.
176    CONFLICT_SPI_WIRING = "E0706";
177    /// A `<uart>` that puts tx and rx on one pin.
178    CONFLICT_UART_WIRING = "E0707";
179    /// Two devices on one `<i2c>` bus sharing an address.
180    CONFLICT_I2C_ADDRESS = "E0708";
181    /// A peripheral the generated runtime already holds (`UART0`).
182    CONFLICT_RUNTIME_HELD = "E0709";
183
184    /// A service `network=` reference to an interface that does not exist.
185    SERVICE_UNKNOWN_NETWORK = "E0801";
186    /// A network service declared under the blocking runtime.
187    SERVICE_REQUIRES_EMBASSY = "E0802";
188    /// A service buffer below the minimum its protocol needs.
189    SERVICE_BUFFER_TOO_SMALL = "E0803";
190    /// `<https_client insecure="true">`: certificates will not be validated.
191    SERVICE_INSECURE_WARNING = "W0804";
192    /// A service that cannot be built: a bad id or a missing attribute.
193    SERVICE_INVALID = "E0805";
194    /// A service tag no element implements.
195    SERVICE_UNSUPPORTED = "E0806";
196    /// A service id the generated code already binds (`services`, `ctx`, ...).
197    SERVICE_RESERVED_ID = "E0807";
198
199    /// A device's bus reference to a component that does not exist.
200    DEVICE_UNKNOWN_COMPONENT = "E0901";
201    /// A device's auxiliary pin reference to a `<gpio>` that does not exist.
202    DEVICE_UNKNOWN_GPIO = "E0902";
203    /// A device's auxiliary pin on a GPIO declared as an input.
204    DEVICE_WRONG_DIRECTION = "E0903";
205    /// A device id that cannot become a Rust identifier.
206    DEVICE_INVALID_ID = "E0904";
207    /// A device tag no element implements.
208    DEVICE_UNSUPPORTED = "E0905";
209    /// A blocking-only display declared under the embassy runtime.
210    DEVICE_REQUIRES_BLOCKING = "E0906";
211    /// A device that cannot be built: a missing or invalid attribute.
212    DEVICE_INVALID = "E0907";
213    /// A device id the generated code already binds (`devices`, `ctx`, ...).
214    DEVICE_RESERVED_ID = "E0908";
215    /// A blocking-only and an async-only driver bound to one bus.
216    DEVICE_BUS_MODE_CONFLICT = "E0909";
217}
218
219#[cfg(test)]
220mod tests {
221    use super::*;
222
223    fn well_formed(code: &str) -> bool {
224        let bytes = code.as_bytes();
225        bytes.len() == 5
226            && matches!(bytes[0], b'E' | b'W')
227            && bytes[1..].iter().all(u8::is_ascii_digit)
228    }
229
230    #[test]
231    fn every_code_is_well_formed() {
232        for code in ALL {
233            assert!(
234                well_formed(code.as_str()),
235                "{} is not `E`/`W` + four digits",
236                code.as_str()
237            );
238        }
239    }
240
241    #[test]
242    fn no_two_codes_share_a_number() {
243        let mut seen = std::collections::BTreeSet::new();
244        for code in ALL {
245            assert!(
246                seen.insert(code.as_str()),
247                "{} is declared twice",
248                code.as_str()
249            );
250        }
251    }
252
253    #[test]
254    fn the_slice_only_defines_the_codes_it_can_reach() {
255        for code in ALL {
256            let number = &code.as_str()[1..];
257            let n: u32 = number.parse().unwrap();
258            assert!(
259                matches!(
260                    n,
261                    101..=105
262                        | 201..=212
263                        | 301
264                        | 302
265                        | 306..=316
266                        | 501..=521
267                        | 601..=623
268                        | 701..=709
269                        | 801..=807
270                        | 901..=909
271                ),
272                "{} is outside the codes this slice defines",
273                code.as_str()
274            );
275        }
276    }
277}