cntrlr_build/
lib.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright 2020 Branan Riley <me@branan.info>
3
4//! Build support for Cntrlr boards
5
6#![deny(missing_docs)]
7
8use std::{env, str::FromStr};
9
10/// Set up the rust build environment for the selected board.
11///
12/// Based on the `CNTRLR_BOARD` environment variable, this function
13/// will set the `board=` and `mcu=` rust configurations, which can be
14/// used to customize your application behavior based on the target
15/// environment. It also returns information about the selected board.
16pub fn configure_board() -> Option<Board> {
17    println!("cargo:rerun-if-changed=build.rs");
18    println!("cargo:rerun-if-env-changed=CNTRLR_BOARD");
19    env::var("CNTRLR_BOARD")
20        .ok()
21        .and_then(|board| Board::from_str(&board).ok())
22        .map(|board| {
23            println!("cargo:rustc-cfg=board=\"{}\"", board.name);
24            println!("cargo:rustc-cfg=mcu=\"{}\"", board.mcu);
25            board
26        })
27}
28
29/// The utility used to flash a board
30pub enum Flash {
31    /// This board is flashed with `avrdude`, using the specified programmer (-c)
32    AvrDude(&'static str),
33
34    /// This board is flashed with `teensy-loader-cli`, using the MCU specified in the board config
35    TeensyLoader,
36
37    /// This board is flashed with `openocd`, using the specified configuration file
38    OpenOcd(&'static str),
39}
40
41/// Information about a target board
42pub struct Board {
43    /// The name of the board, as used in Cntrlr's source code.
44    pub name: &'static str,
45
46    /// The name of the mcu used in the board, as used in Cntrlr's
47    /// source code.
48    pub mcu: &'static str,
49
50    /// The set of Rust targets for which this board is compatible.
51    pub targets: Vec<&'static str>,
52
53    /// The preferred method for flashing an image to the board
54    pub flash: Flash,
55}
56
57impl FromStr for Board {
58    type Err = ();
59    fn from_str(board: &str) -> Result<Self, ()> {
60        match normalize_board(board).as_str() {
61            "teensy30" | "teensy3" => Ok(Self {
62                name: "teensy_30",
63                mcu: "mk20dx128",
64                targets: vec![
65                    "thumbv7em-none-eabi",
66                    "thumbv7m-none-eabi",
67                    "thumbv6m-none-eabi",
68                ],
69                flash: Flash::TeensyLoader,
70            }),
71            "teensy31" | "teensy32" => Ok(Self {
72                name: "teensy_32",
73                mcu: "mk20dx256",
74                targets: vec![
75                    "thumbv7em-none-eabi",
76                    "thumbv7m-none-eabi",
77                    "thumbv6m-none-eabi",
78                ],
79                flash: Flash::TeensyLoader,
80            }),
81            "teensy35" => Ok(Self {
82                name: "teensy_35",
83                mcu: "mk64fx512",
84                targets: vec![
85                    "thumbv7em-none-eabi",
86                    "thumbv7m-none-eabi",
87                    "thumbv6m-none-eabi",
88                ],
89                flash: Flash::TeensyLoader,
90            }),
91            "teensy36" => Ok(Self {
92                name: "teensy_36",
93                mcu: "mk66fx1m0",
94                targets: vec![
95                    "thumbv7em-none-eabihf",
96                    "thumbv7em-none-eabi",
97                    "thumbv7m-none-eabi",
98                    "thumbv6m-none-eabi",
99                ],
100                flash: Flash::TeensyLoader,
101            }),
102            "teensy40" | "teensy4" => Ok(Self {
103                name: "teensy_40",
104                mcu: "imxrt1062",
105                targets: vec![
106                    "thumbv7em-none-eabihf",
107                    "thumbv7em-none-eabi",
108                    "thumbv7m-none-eabi",
109                    "thumbv6m-none-eabi",
110                ],
111                flash: Flash::TeensyLoader,
112            }),
113            "teensy41" => Ok(Self {
114                name: "teensy_41",
115                mcu: "imxrt1062",
116                targets: vec![
117                    "thumbv7em-none-eabihf",
118                    "thumbv7em-none-eabi",
119                    "thumbv7m-none-eabi",
120                    "thumbv6m-none-eabi",
121                ],
122                flash: Flash::TeensyLoader,
123            }),
124            "teensylc" => Ok(Self {
125                name: "teensy_lc",
126                mcu: "mkl26z64",
127                targets: vec!["thumbv6m-none-eabi"],
128                flash: Flash::TeensyLoader,
129            }),
130            "arduinouno" => Ok(Self {
131                name: "arduino_uno",
132                mcu: "atmega328p",
133                targets: vec!["avr-none-atmega328"],
134                flash: Flash::AvrDude("arduino"),
135            }),
136            "redv" => Ok(Self {
137                name: "red_v",
138                mcu: "fe310g002",
139                targets: vec![
140                    "riscv32imac-unknown-none-elf",
141                    "riscv32imc-unknown-none-elf",
142                    "riscv32i-unknown-none-elf",
143                ],
144                flash: Flash::OpenOcd("board/sifive-hifive1-revb.cfg"),
145            }),
146            _ => Err(()),
147        }
148    }
149}
150
151impl Board {
152    /// Check if the specified target is valid for this board.
153    pub fn validate_target(&self, target: &str) -> bool {
154        self.targets.iter().any(|item| item == &target)
155    }
156}
157
158fn normalize_board(board: &str) -> String {
159    board
160        .to_lowercase()
161        .chars()
162        .filter(|&c| c != '_' && c != '-' && c != '.')
163        .collect()
164}