Create the esp-metadata package, update esp-hal build script to use it (#1256)

This commit is contained in:
Jesse Braham 2024-03-13 12:27:24 +00:00 committed by GitHub
parent c283563542
commit 1f129744fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 273 additions and 105 deletions

View File

@ -6,6 +6,7 @@ exclude = [
"esp-hal-procmacros",
"esp-hal-smartled",
"esp-lp-hal",
"esp-metadata",
"esp-riscv-rt",
"examples",
]

View File

@ -68,9 +68,10 @@ esp-riscv-rt = { version = "0.7.0", optional = true, path = "../esp-riscv-rt" }
xtensa-lx-rt = { version = "0.16.0", optional = true }
[build-dependencies]
basic-toml = "0.1.8"
cfg-if = "1.0.0"
serde = { version = "1.0.197", features = ["derive"] }
basic-toml = "0.1.8"
cfg-if = "1.0.0"
esp-metadata = { version = "0.1.0", path = "../esp-metadata" }
serde = { version = "1.0.197", features = ["derive"] }
[features]
default = ["rt", "vectored"]

View File

@ -4,9 +4,10 @@ use std::{
fs::{self, File},
io::{BufRead, Write},
path::{Path, PathBuf},
str::FromStr,
};
use serde::Deserialize;
use esp_metadata::{Arch, Chip, Config};
// Macros taken from:
// https://github.com/TheDan64/inkwell/blob/36c3b10/src/lib.rs#L81-L110
@ -45,61 +46,6 @@ macro_rules! assert_unique_used_features {
}
}
#[derive(Debug, Deserialize, PartialEq)]
enum Arch {
#[serde(rename = "riscv")]
RiscV,
#[serde(rename = "xtensa")]
Xtensa,
}
impl std::fmt::Display for Arch {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Arch::RiscV => "riscv",
Arch::Xtensa => "xtensa",
}
)
}
}
#[derive(Debug, Deserialize)]
enum CoreCount {
#[serde(rename = "single_core")]
Single,
#[serde(rename = "multi_core")]
Multi,
}
impl std::fmt::Display for CoreCount {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
match self {
CoreCount::Single => "single_core",
CoreCount::Multi => "multi_core",
}
)
}
}
#[derive(Debug, Deserialize)]
struct Device {
pub arch: Arch,
pub cores: CoreCount,
pub peripherals: Vec<String>,
pub symbols: Vec<String>,
}
#[derive(Debug, Deserialize)]
struct Config {
pub device: Device,
}
fn main() -> Result<(), Box<dyn Error>> {
// NOTE: update when adding new device support!
// Ensure that exactly one chip has been specified:
@ -157,18 +103,11 @@ fn main() -> Result<(), Box<dyn Error>> {
}
// Load the configuration file for the configured device:
let chip_toml_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("devices")
.join(device_name)
.join("device.toml")
.canonicalize()?;
let config = fs::read_to_string(chip_toml_path)?;
let config: Config = basic_toml::from_str(&config)?;
let device = &config.device;
let chip = Chip::from_str(device_name)?;
let config = Config::for_chip(&chip);
// Check PSRAM features are only given if the target supports PSRAM:
if !&device.symbols.contains(&String::from("psram"))
if !config.contains(&String::from("psram"))
&& (cfg!(feature = "psram-2m") || cfg!(feature = "psram-4m") || cfg!(feature = "psram-8m"))
{
panic!("The target does not support PSRAM");
@ -176,40 +115,17 @@ fn main() -> Result<(), Box<dyn Error>> {
// Don't support "interrupt-preemption" and "direct-vectoring" on Xtensa and
// RISC-V with CLIC:
if (device.symbols.contains(&String::from("clic")) || device.arch == Arch::Xtensa)
if (config.contains(&String::from("clic")) || config.arch() == Arch::Xtensa)
&& (cfg!(feature = "direct-vectoring") || cfg!(feature = "interrupt-preemption"))
{
panic!("The target does not support interrupt-preemption and direct-vectoring");
}
// Define all necessary configuration symbols for the configured device:
println!("cargo:rustc-cfg={}", device_name);
println!("cargo:rustc-cfg={}", device.arch);
println!("cargo:rustc-cfg={}", device.cores);
for peripheral in &device.peripherals {
println!("cargo:rustc-cfg={peripheral}");
}
for symbol in &device.symbols {
println!("cargo:rustc-cfg={symbol}");
}
let mut config_symbols = Vec::new();
let arch = device.arch.to_string();
let cores = device.cores.to_string();
config_symbols.push(device_name);
config_symbols.push(&arch);
config_symbols.push(&cores);
for peripheral in &device.peripherals {
config_symbols.push(peripheral);
}
for symbol in &device.symbols {
config_symbols.push(symbol);
}
config.define_symbols();
#[allow(unused_mut)]
let mut config_symbols = config.all();
#[cfg(feature = "flip-link")]
config_symbols.push("flip-link");
@ -260,7 +176,7 @@ fn main() -> Result<(), Box<dyn Error>> {
}
fn copy_dir_all(
config_symbols: &Vec<&str>,
config_symbols: &Vec<String>,
src: impl AsRef<Path>,
dst: impl AsRef<Path>,
) -> std::io::Result<()> {
@ -287,7 +203,7 @@ fn copy_dir_all(
/// A naive pre-processor for linker scripts
fn preprocess_file(
config: &[&str],
config: &[String],
src: impl AsRef<Path>,
dst: impl AsRef<Path>,
) -> std::io::Result<()> {
@ -302,7 +218,7 @@ fn preprocess_file(
let trimmed = line.trim();
if let Some(stripped) = trimmed.strip_prefix("#IF ") {
let condition = stripped;
let condition = stripped.to_string();
let should_take = take.iter().all(|v| *v);
let should_take = should_take && config.contains(&condition);
take.push(should_take);

14
esp-metadata/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "esp-metadata"
version = "0.1.0"
edition = "2021"
rust-version = "1.60.0"
description = "Metadata for Espressif devices"
repository = "https://github.com/esp-rs/esp-hal"
license = "MIT OR Apache-2.0"
[dependencies]
basic-toml = "0.1.8"
lazy_static = "1.4.0"
serde = { version = "1.0.197", features = ["derive"] }
strum = { version = "0.26.1", features = ["derive"] }

30
esp-metadata/README.md Normal file
View File

@ -0,0 +1,30 @@
# esp-metadata
[![Crates.io](https://img.shields.io/crates/v/esp-metadata?color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-metadata)
[![docs.rs](https://img.shields.io/docsrs/esp-metadata?color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-metadata)
![MSRV](https://img.shields.io/badge/MSRV-1.60-blue?style=flat-square)
![Crates.io](https://img.shields.io/crates/l/esp-metadata?style=flat-square)
Metadata for Espressif devices, primarily intended for use in build scripts.
## [Documentation](https://docs.rs/crate/esp-metadata)
## Minimum Supported Rust Version (MSRV)
This crate is guaranteed to compile on stable Rust 1.60 and up. It _might_
compile with older versions but that may change in any new patch release.
## License
Licensed under either of:
- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without
any additional terms or conditions.

View File

@ -1,4 +1,5 @@
[device]
name = "esp32"
arch = "xtensa"
cores = "multi_core"

View File

@ -1,5 +1,6 @@
[device]
arch = "riscv"
name = "esp32c2"
arch = "riscv"
cores = "single_core"
peripherals = [

View File

@ -1,5 +1,6 @@
[device]
arch = "riscv"
name = "esp32c3"
arch = "riscv"
cores = "single_core"
peripherals = [

View File

@ -1,5 +1,6 @@
[device]
arch = "riscv"
name = "esp32c6"
arch = "riscv"
cores = "single_core"
peripherals = [

View File

@ -1,5 +1,6 @@
[device]
arch = "riscv"
name = "esp32h2"
arch = "riscv"
cores = "single_core"
peripherals = [

View File

@ -1,5 +1,6 @@
[device]
arch = "riscv"
name = "esp32p4"
arch = "riscv"
cores = "multi_core"
peripherals = [

View File

@ -1,4 +1,5 @@
[device]
name = "esp32s2"
arch = "xtensa"
cores = "single_core"

View File

@ -1,5 +1,6 @@
[device]
arch = "xtensa"
name = "esp32s3"
arch = "xtensa"
cores = "multi_core"
peripherals = [

198
esp-metadata/src/lib.rs Normal file
View File

@ -0,0 +1,198 @@
//! Metadata for Espressif devices, primarily intended for use in build scripts.
const ESP32_TOML: &'static str = include_str!("../devices/esp32.toml");
const ESP32C2_TOML: &'static str = include_str!("../devices/esp32c2.toml");
const ESP32C3_TOML: &'static str = include_str!("../devices/esp32c3.toml");
const ESP32C6_TOML: &'static str = include_str!("../devices/esp32c6.toml");
const ESP32H2_TOML: &'static str = include_str!("../devices/esp32h2.toml");
const ESP32P4_TOML: &'static str = include_str!("../devices/esp32p4.toml");
const ESP32S2_TOML: &'static str = include_str!("../devices/esp32s2.toml");
const ESP32S3_TOML: &'static str = include_str!("../devices/esp32s3.toml");
lazy_static::lazy_static! {
static ref ESP32_CFG: Config = basic_toml::from_str(ESP32_TOML).unwrap();
static ref ESP32C2_CFG: Config = basic_toml::from_str(ESP32C2_TOML).unwrap();
static ref ESP32C3_CFG: Config = basic_toml::from_str(ESP32C3_TOML).unwrap();
static ref ESP32C6_CFG: Config = basic_toml::from_str(ESP32C6_TOML).unwrap();
static ref ESP32H2_CFG: Config = basic_toml::from_str(ESP32H2_TOML).unwrap();
static ref ESP32P4_CFG: Config = basic_toml::from_str(ESP32P4_TOML).unwrap();
static ref ESP32S2_CFG: Config = basic_toml::from_str(ESP32S2_TOML).unwrap();
static ref ESP32S3_CFG: Config = basic_toml::from_str(ESP32S3_TOML).unwrap();
}
/// Supported device architectures.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
serde::Deserialize,
serde::Serialize,
strum::Display,
strum::EnumIter,
strum::EnumString,
)]
#[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase")]
pub enum Arch {
/// RISC-V architecture
RiscV,
/// Xtensa architecture
Xtensa,
}
/// Device core count.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
serde::Deserialize,
serde::Serialize,
strum::Display,
strum::EnumIter,
strum::EnumString,
)]
pub enum Cores {
/// Single CPU core
#[serde(rename = "single_core")]
#[strum(serialize = "single_core")]
Single,
/// Two or more CPU cores
#[serde(rename = "multi_core")]
#[strum(serialize = "multi_core")]
Multi,
}
/// Supported devices.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
serde::Deserialize,
serde::Serialize,
strum::Display,
strum::EnumIter,
strum::EnumString,
)]
#[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase")]
pub enum Chip {
/// ESP32
Esp32,
/// ESP32-C2, ESP8684
Esp32c2,
/// ESP32-C3, ESP8685
Esp32c3,
/// ESP32-C6
Esp32c6,
/// ESP32-H2
Esp32h2,
/// ESP32-P4
Esp32p4,
/// ESP32-S2
Esp32s2,
/// ESP32-S3
Esp32s3,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
struct Device {
pub name: String,
pub arch: Arch,
pub cores: Cores,
pub peripherals: Vec<String>,
pub symbols: Vec<String>,
}
/// Device configuration file format.
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct Config {
device: Device,
}
impl Config {
/// The configuration for the specified chip.
pub fn for_chip(chip: &Chip) -> Self {
match chip {
Chip::Esp32 => ESP32_CFG.clone(),
Chip::Esp32c2 => ESP32C2_CFG.clone(),
Chip::Esp32c3 => ESP32C3_CFG.clone(),
Chip::Esp32c6 => ESP32C6_CFG.clone(),
Chip::Esp32h2 => ESP32H2_CFG.clone(),
Chip::Esp32p4 => ESP32P4_CFG.clone(),
Chip::Esp32s2 => ESP32S2_CFG.clone(),
Chip::Esp32s3 => ESP32S3_CFG.clone(),
}
}
/// The name of the device.
pub fn name(&self) -> String {
self.device.name.clone()
}
/// The CPU architecture of the device.
pub fn arch(&self) -> Arch {
self.device.arch
}
/// The core count of the device.
pub fn cores(&self) -> Cores {
self.device.cores
}
/// The peripherals of the device.
pub fn peripherals(&self) -> &[String] {
&self.device.peripherals
}
/// User-defined symbols for the device.
pub fn symbols(&self) -> &[String] {
&self.device.symbols
}
/// All configuration values for the device.
pub fn all(&self) -> Vec<String> {
[
vec![
self.device.name.clone(),
self.device.arch.to_string(),
self.device.cores.to_string(),
],
self.device.peripherals.clone(),
self.device.symbols.clone(),
]
.concat()
}
/// Does the configuration contain `item`?
pub fn contains(&self, item: &String) -> bool {
self.all().contains(item)
}
/// Define all symbols for a given configuration.
pub fn define_symbols(&self) {
// Define all necessary configuration symbols for the configured device:
println!("cargo:rustc-cfg={}", self.name());
println!("cargo:rustc-cfg={}", self.arch());
println!("cargo:rustc-cfg={}", self.cores());
for peripheral in self.peripherals() {
println!("cargo:rustc-cfg={peripheral}");
}
for symbol in self.symbols() {
println!("cargo:rustc-cfg={symbol}");
}
}
}