From a22b817ee53bf1e9fb4f4a6a4e2fbc18909f00b9 Mon Sep 17 00:00:00 2001 From: Sergio Gasquez Arcos Date: Thu, 11 Apr 2024 16:04:32 +0200 Subject: [PATCH] HIL updates (#1412) * docs: Document new xtask features * style: format deps * feat: enable all the aliases * feat: Update embedded-tests executors * feat: Enable running only one test * feat: Exit if a test fails * docs: Fix typo in command * build: Enable xtensa-semihosting in xtensa targets * feat: Handle probe-rs esp32 chip name * style: Clippy lints * revert: Exit if a test fails * chore: Remove aliases * feat: Remove unnecesary toogle * feat: Error if a test fails and print failed tests --- hil-test/.cargo/config.toml | 10 ----- hil-test/Cargo.toml | 77 +++++++++++++++++++++--------------- hil-test/README.md | 34 ++++++++++------ hil-test/tests/gpio.rs | 4 +- hil-test/tests/uart_async.rs | 2 +- xtask/README.md | 1 + xtask/src/cargo.rs | 8 +++- xtask/src/lib.rs | 15 ++++--- xtask/src/main.rs | 49 ++++++++++++++++------- 9 files changed, 122 insertions(+), 78 deletions(-) diff --git a/hil-test/.cargo/config.toml b/hil-test/.cargo/config.toml index 3d5a3c5c07b..82243731338 100644 --- a/hil-test/.cargo/config.toml +++ b/hil-test/.cargo/config.toml @@ -1,13 +1,3 @@ -[alias] -# esp32 = "test --release --features=esp32 --target=xtensa-esp32-none-elf -- --chip esp32-3.3v" -# esp32c2 = "test --release --features=esp32c2 --target=riscv32imc-unknown-none-elf -- --chip esp32c2" -esp32c3 = "test --release --features=esp32c3 --target=riscv32imc-unknown-none-elf -- --chip esp32c3" -esp32c6 = "test --release --features=esp32c6 --target=riscv32imac-unknown-none-elf -- --chip esp32c6" -esp32h2 = "test --release --features=esp32h2 --target=riscv32imac-unknown-none-elf -- --chip esp32h2" -# esp32p4 = "test --release --features=esp32p4 --target=riscv32imafc-unknown-none-elf -- --chip esp32p4" -# esp32s2 = "test --release --features=esp32s2 --target=xtensa-esp32s2-none-elf -- --chip esp32s2" -esp32s3 = "test --release --features=esp32s3 --target=xtensa-esp32s3-none-elf -- --chip esp32s3" - [target.'cfg(target_arch = "riscv32")'] runner = "probe-rs run" rustflags = [ diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index a485524255f..a355491ee5d 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -29,8 +29,8 @@ name = "uart" harness = false [[test]] -name = "uart_async" -harness = false +name = "uart_async" +harness = false required-features = ["async", "embassy"] [[test]] @@ -38,54 +38,69 @@ name = "ecc" harness = false [dependencies] -defmt = { version = "0.3.6" } -defmt-rtt = { version = "0.4.0" } +cfg-if = "1.0.0" +critical-section = "1.1.2" +defmt = "0.3.6" +defmt-rtt = "0.4.0" +embassy-futures = "0.1.1" embassy-time = { version = "0.3.0", features = ["generic-queue-64"] } -embassy-futures = { version = "0.1" } -embedded-hal = { version = "1.0.0" } +embedded-hal = "1.0.0" embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", features = ["unproven"] } embedded-hal-async = { version = "1.0.0", optional = true } embedded-hal-nb = { version = "1.0.0", optional = true } +esp-backtrace = { version = "0.11.1", git = "https://github.com/esp-rs/esp-backtrace", rev = "edff83c3945e8aa11081d8467af65803a82434ba", default-features = false, features = ["exception-handler", "panic-handler", "defmt", "semihosting"] } esp-hal = { path = "../esp-hal", features = ["defmt", "embedded-hal", "embedded-hal-02"], optional = true } -esp-backtrace = { version = "0.11.1", git = "https://github.com/esp-rs/esp-backtrace", rev = "edff83c3945e8aa11081d8467af65803a82434ba", default-features = false, features = ["exception-handler", "panic-handler", "defmt", "semihosting"] } -critical-section = { version = "1.1.2" } -portable-atomic = "1" -cfg-if = "1" +portable-atomic = "1.6.0" [dev-dependencies] -embassy-executor = { version = "0.5.0", default-features = false, features = ["executor-thread", "arch-riscv32"] } +crypto-bigint = { version = "0.5.5", default-features = false } +elliptic-curve = { version = "0.13.8", default-features = false, features = ["sec1"] } +embassy-executor = { version = "0.5.0", default-features = false } # Add the `embedded-test/defmt` feature for more verbose testing -embedded-test = { git = "https://github.com/probe-rs/embedded-test", rev = "b67dec33992f5bd79d414a0e70220dc4142278cf", default-features = false } -crypto-bigint = { version = "0.5.5", default-features = false } -nb = "1.1.0" -hex-literal = "0.4.1" -p192 = { version = "0.13.0", default-features = false, features = ["arithmetic"] } -p256 = { version = "0.13.2", default-features = false, features = ["arithmetic"] } -elliptic-curve = { version = "0.13.8", default-features = false, features = ["sec1"] } +embedded-test = { git = "https://github.com/probe-rs/embedded-test", rev = "1aa5a426d6b29ae2b509c5876dd33523b03e107c", default-features = false } +hex-literal = "0.4.1" +nb = "1.1.0" +p192 = { version = "0.13.0", default-features = false, features = ["arithmetic"] } +p256 = { version = "0.13.2", default-features = false, features = ["arithmetic"] } [features] -default = ["async", "embassy", "embassy-time-timg0"] +default = ["async", "embassy", "embassy-executor-thread", "embassy-time-timg0"] # Device support (required!): -esp32 = ["esp-hal/esp32", "esp-backtrace/esp32"] -esp32c2 = ["esp-hal/esp32c2", "esp-backtrace/esp32c2"] -esp32c3 = ["esp-hal/esp32c3", "esp-backtrace/esp32c3"] -esp32c6 = ["esp-hal/esp32c6", "esp-backtrace/esp32c6"] -esp32h2 = ["esp-hal/esp32h2", "esp-backtrace/esp32h2"] -esp32s2 = ["esp-hal/esp32s2", "esp-backtrace/esp32s2"] -esp32s3 = ["esp-hal/esp32s3", "esp-backtrace/esp32s3"] +esp32 = [ + "embedded-test/xtensa-semihosting", + "esp-backtrace/esp32", + "esp-hal/esp32", +] +esp32c2 = ["esp-backtrace/esp32c2", "esp-hal/esp32c2"] +esp32c3 = ["esp-backtrace/esp32c3", "esp-hal/esp32c3"] +esp32c6 = ["esp-backtrace/esp32c6", "esp-hal/esp32c6"] +esp32h2 = ["esp-backtrace/esp32h2", "esp-hal/esp32h2"] +esp32s2 = [ + "embedded-test/xtensa-semihosting", + "esp-backtrace/esp32s2", + "esp-hal/esp32s2", +] +esp32s3 = [ + "embedded-test/xtensa-semihosting", + "esp-backtrace/esp32s3", + "esp-hal/esp32s3", +] # Async & Embassy: -async = ["dep:embedded-hal-async", "esp-hal?/async"] -embassy = ["esp-hal?/embassy", "embedded-test/embassy"] +async = ["dep:embedded-hal-async", "esp-hal?/async"] +embassy = [ + "embedded-test/embassy", + "embedded-test/external-executor", + "esp-hal?/embassy", +] embassy-executor-interrupt = ["esp-hal?/embassy-executor-interrupt"] -embassy-executor-thread = ["esp-hal?/embassy-executor-thread"] +embassy-executor-thread = ["esp-hal?/embassy-executor-thread"] embassy-time-systick-16mhz = ["esp-hal?/embassy-time-systick-16mhz"] embassy-time-systick-80mhz = ["esp-hal?/embassy-time-systick-80mhz"] -embassy-time-timg0 = ["esp-hal?/embassy-time-timg0"] +embassy-time-timg0 = ["esp-hal?/embassy-time-timg0"] # https://doc.rust-lang.org/cargo/reference/profiles.html#test # Test and bench profiles inherit from dev and release respectively. - [profile.dev] codegen-units = 1 debug = 2 diff --git a/hil-test/README.md b/hil-test/README.md index 357c5f1a313..f194076d5e0 100644 --- a/hil-test/README.md +++ b/hil-test/README.md @@ -28,23 +28,27 @@ cargo install probe-rs \ Target device **MUST** connected via its USB-Serial-JTAG port, or if unavailable (eg. ESP32, ESP32-C2, ESP32-S2) then you must connect a compatible debug probe such as an [ESP-Prog]. -You can run all test for a given device using: +You can run all tests for a given device by running the following command from the `xtask` folder: ```shell -cargo +nightly esp32c6 -# or -cargo +esp esp32s3 +cargo xtask run-tests $CHIP ``` -For running a single test on a target: +For running a single test on a target, from the `xtask` folder run: +```shell +# Run GPIO tests for ESP32-C6 +cargo xtask run-tests esp32c6 --test gpio +``` + +Another alternative way of running a single test is, from the `hil-tests` folder: ```shell # Run GPIO tests for ESP32-C6 CARGO_BUILD_TARGET=riscv32imac-unknown-none-elf \ PROBE_RS_CHIP=esp32c6 \ cargo +nightly test --features=esp32c6 --test=gpio ``` -- If the `--test` argument is omitted, then all tests will be run. +- If the `--test` argument is omitted, then all tests will be run, independently if the tests are supported for that target, for this reason, we encourage using the `xtask` approach. - The build target **MUST** be specified via the `CARGO_BUILD_TARGET` environment variable or as an argument (`--target`). - The chip **MUST** be specified via the `PROBE_RS_CHIP` environment variable or as an argument of `probe-rs` (`--chip`). @@ -57,15 +61,15 @@ Our Virtual Machines have the following setup: - ESP32-C3 (`rustboard`): - Devkit: `ESP32-C3-DevKit-RUST-1` connected via USB-Serial-JTAG. - `GPIO2` and `GPIO4` are connected. - - VM: Configured with the following [setup](#vm-setup) + - VM: Ubuntu 20.04.5 configured with the following [setup](#vm-setup) - ESP32-C6 (`esp32c6-usb`): - Devkit: `ESP32-C6-DevKitC-1 V1.2` connected via USB-Serial-JTAG (`USB` port). - `GPIO2` and `GPIO4` are connected. - - VM: Configured with the following [setup](#vm-setup) + - VM: Ubuntu 20.04.5 configured with the following [setup](#vm-setup) - ESP32-H2 (`esp32h2-usb`): - Devkit: `ESP32-H2-DevKitM-1` connected via USB-Serial-JTAG (`USB` port). - `GPIO2` and `GPIO4` are connected. - - VM: Configured with the following [setup](#vm-setup) + - VM: Ubuntu 20.04.5 configured with the following [setup](#vm-setup) [`hil.yml`]: https://github.com/esp-rs/esp-hal/blob/main/.github/workflows/hil.yml @@ -83,7 +87,8 @@ cargo install probe-rs --git=https://github.com/probe-rs/probe-rs --rev=ddd59fa wget -O - https://probe.rs/files/69-probe-rs.rules | sudo tee /etc/udev/rules.d/69-probe-rs.rules > /dev/null # Add the user to plugdev group sudo usermod -a -G plugdev $USER -# Reboot the VM +# Reboot the +sudo reboot ``` ## Adding New Tests @@ -92,4 +97,11 @@ sudo usermod -a -G plugdev $USER 2. Add a corresponding `[[test]]` entry to `Cargol.toml` (**MUST** set `harness = false`) 3. Write the tests 4. Document any necessary physical connections on boards connected to self-hosted runners -5. Write some documentation at the top of the `tests/$PERIPHERAL.rs` file with the pins being used and the required connections, if applicable. +5. Add a header in the test stating which targets support the given tests. Eg: +```rust +//! AES Test + +//% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 +``` +If the test is supported by all the targets, you can omit the header. +6. Write some documentation at the top of the `tests/$PERIPHERAL.rs` file with the pins being used and the required connections, if applicable. diff --git a/hil-test/tests/gpio.rs b/hil-test/tests/gpio.rs index 2f8d251a86d..8e70dc1c5fc 100644 --- a/hil-test/tests/gpio.rs +++ b/hil-test/tests/gpio.rs @@ -69,7 +69,7 @@ pub fn interrupt_handler() { } #[cfg(test)] -#[embedded_test::tests] +#[embedded_test::tests(executor = esp_hal::embassy::executor::thread::Executor::new())] mod tests { use defmt::assert_eq; use embassy_time::{Duration, Timer}; @@ -148,8 +148,6 @@ mod tests { ctx.io4.toggle(); assert_eq!(ctx.io4.is_set_low(), false); assert_eq!(ctx.io4.is_set_high(), true); - // Leave in initial state for next test - ctx.io4.toggle(); } #[test] diff --git a/hil-test/tests/uart_async.rs b/hil-test/tests/uart_async.rs index 7820de2a11f..76ec218b729 100644 --- a/hil-test/tests/uart_async.rs +++ b/hil-test/tests/uart_async.rs @@ -56,7 +56,7 @@ impl Context { } #[cfg(test)] -#[embedded_test::tests] +#[embedded_test::tests(executor = esp_hal::embassy::executor::thread::Executor::new())] mod tests { use defmt::assert_eq; diff --git a/xtask/README.md b/xtask/README.md index 0363456690e..d86a7381911 100644 --- a/xtask/README.md +++ b/xtask/README.md @@ -14,6 +14,7 @@ Commands: bump-version Bump the version of the specified package(s) generate-efuse-fields Generate the eFuse fields source file from a CSV run-example Run the given example for the specified chip + run-tests Run all applicable tests or the specified test for a specified chip help Print this message or the help of the given subcommand(s) Options: diff --git a/xtask/src/cargo.rs b/xtask/src/cargo.rs index 3dff7f6b8ab..e4c95e447ee 100644 --- a/xtask/src/cargo.rs +++ b/xtask/src/cargo.rs @@ -35,7 +35,7 @@ pub fn run_with_input(args: &[String], cwd: &Path) -> Result<()> { bail!("The `cwd` argument MUST be a directory"); } - let _status = Command::new(get_cargo()) + let status = Command::new(get_cargo()) .args(args) .current_dir(cwd) .stdout(std::process::Stdio::inherit()) @@ -43,7 +43,11 @@ pub fn run_with_input(args: &[String], cwd: &Path) -> Result<()> { .stdin(std::process::Stdio::inherit()) .status()?; - Ok(()) + if status.success() { + Ok(()) + } else { + Err(anyhow::anyhow!("Failed to execute cargo subcommand")) + } } fn get_cargo() -> String { diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 58bb0237413..1943a498e1b 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -320,7 +320,11 @@ pub fn run_example( // probe-rs cannot currently do auto detection, so we need to tell probe-rs run // which chip we are testing if subcommand == "test" { - builder = builder.arg("--").arg("--chip").arg(format!("{}", chip)); + if chip == Chip::Esp32 { + builder = builder.arg("--").arg("--chip").arg("esp32-3.3v"); + } else { + builder = builder.arg("--").arg("--chip").arg(format!("{}", chip)); + } } // If targeting an Xtensa device, we must use the '+esp' toolchain modifier: @@ -331,8 +335,7 @@ pub fn run_example( let args = builder.build(); log::debug!("{args:#?}"); - cargo::run_with_input(&args, package_path)?; - Ok(()) + cargo::run_with_input(&args, package_path) } /// Build the specified package, using the given toolchain/target/features if @@ -427,7 +430,7 @@ const EFUSE_FIELDS_RS_HEADER: &str = r#" //! //! For information on how to regenerate these files, please refer to the //! `xtask` package's `README.md` file. -//! +//! //! Generated on: $DATE //! ESP-IDF Commit: $HASH @@ -459,8 +462,8 @@ pub fn generate_efuse_table( // Determine the commit (short) hash of the HEAD commit in the // provided ESP-IDF repository: let output = Command::new("git") - .args(&["rev-parse", "HEAD"]) - .current_dir(&idf_path) + .args(["rev-parse", "HEAD"]) + .current_dir(idf_path) .output()?; let idf_hash = String::from_utf8_lossy(&output.stdout[0..=7]).to_string(); diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 5d5d864a9d7..d9413149b62 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -25,7 +25,7 @@ enum Cli { GenerateEfuseFields(GenerateEfuseFieldsArgs), /// Run the given example for the specified chip. RunExample(RunExampleArgs), - /// Run all applicable tests for a specified chip. + /// Run all applicable tests or the specified test for a specified chip. RunTests(RunTestsArgs), } @@ -98,15 +98,18 @@ struct RunExampleArgs { /// Which chip to run the examples for. #[arg(value_enum)] chip: Chip, - /// Which example to run + /// Which example to run. example: String, } #[derive(Debug, Args)] struct RunTestsArgs { - /// Which chip to run the examples for. + /// Which chip to run the tests for. #[arg(value_enum)] chip: Chip, + /// Which example to run. + #[arg(short = 't', long)] + test: Option, } // ---------------------------------------------------------------------------- @@ -139,7 +142,7 @@ fn build_documentation(workspace: &Path, args: BuildDocumentationArgs) -> Result let resources = workspace.join("resources"); let package = args.package.to_string(); - let version = xtask::package_version(&workspace, args.package)?; + let version = xtask::package_version(workspace, args.package)?; let mut crates = Vec::new(); @@ -185,10 +188,7 @@ fn build_documentation(workspace: &Path, args: BuildDocumentationArgs) -> Result } // Copy any additional assets to the documentation's output path: - fs::copy( - &resources.join("esp-rs.svg"), - &output_path.join("esp-rs.svg"), - )?; + fs::copy(resources.join("esp-rs.svg"), output_path.join("esp-rs.svg"))?; // Render the index and write it out to the documentaiton's output path: let source = fs::read_to_string(resources.join("index.html.jinja"))?; @@ -277,7 +277,7 @@ fn generate_efuse_src(workspace: &Path, args: GenerateEfuseFieldsArgs) -> Result // Generate the Rust source file from the CSV file, and write it out to // the appropriate path: - xtask::generate_efuse_table(&args.chip, &idf_path, out_path)?; + xtask::generate_efuse_table(&args.chip, idf_path, out_path)?; // Format the generated code: xtask::cargo::run(&["fmt".into()], &esp_hal)?; @@ -334,7 +334,7 @@ fn run_example(workspace: &Path, mut args: RunExampleArgs) -> Result<()> { Ok(()) } -fn run_tests(workspace: &PathBuf, args: RunTestsArgs) -> Result<(), anyhow::Error> { +fn run_tests(workspace: &Path, args: RunTestsArgs) -> Result<(), anyhow::Error> { // Absolute path of the package's root: let package_path = xtask::windows_safe_path(&workspace.join("hil-test")); @@ -343,12 +343,33 @@ fn run_tests(workspace: &PathBuf, args: RunTestsArgs) -> Result<(), anyhow::Erro // Load all examples and parse their metadata: let tests = xtask::load_examples(&package_path.join("tests"))?; - let tests = tests.iter() + let mut supported_tests = tests + .iter() // Filter down the examples to only those for which the specified chip is supported: .filter(|example| example.supports_chip(args.chip)); - - for test in tests { - xtask::run_example(&package_path, args.chip, target, &test)?; + if let Some(test_name) = &args.test { + let test = supported_tests.find_map(|example| { + if &example.name() == test_name { + Some(example.clone()) + } else { + None + } + }); + if let Some(test) = test { + xtask::run_example(&package_path, args.chip, target, &test)?; + } else { + log::error!("Test not found or unsupported for the given chip"); + } + } else { + let mut failed_tests: Vec = Vec::new(); + for test in supported_tests { + if xtask::run_example(&package_path, args.chip, target, test).is_err() { + failed_tests.push(test.name()); + } + } + if !failed_tests.is_empty() { + bail!("Failed tests: {:?}", failed_tests); + } } Ok(())