diff --git a/.github/workflows/hwtest.yml b/.github/workflows/hwtest.yml new file mode 100644 index 00000000..da665193 --- /dev/null +++ b/.github/workflows/hwtest.yml @@ -0,0 +1,51 @@ +# This workflow executes HW tests on an NXP RT600 EVK. +# NOTE: for now it simply executes a build on the self-hosted test runner PC. +# +permissions: + contents: read +on: + push: + branches: [main] + pull_request: + +env: + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} +name: hwtest-automation +jobs: + hwtest-automation: + runs-on: self-hosted + name: Run integration tests + strategy: + matrix: + target: [thumbv8m.main-none-eabihf] + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: run tests + run: | + cd examples\rt685s-evk + $sshcommand = "ssh hwrunner@172.29.127.20 ./run_tests.sh " + "${{env.BRANCH_NAME}}" + Write-Output $sshcommand + + Restore-VMCheckpoint -VMName "hwrunner" -Name "fresh" -Confirm:$false + + # Pause for 5 seconds + Start-Sleep -Seconds 5 + + $output = Invoke-Expression $sshcommand + + # Output the result + Write-Output $output + + Restore-VMCheckpoint -VMName "hwrunner" -Name "fresh" -Confirm:$false + + # Determine the success or failure based on the output + if ($output -match "Some tests failed:") { + exit 1 + } + elseif ($output -match "All tests passed!") { + exit 0 + } + + exit 1 diff --git a/examples/rt685s-evk/Cargo.toml b/examples/rt685s-evk/Cargo.toml index bc1f2bf7..c5d3d04e 100644 --- a/examples/rt685s-evk/Cargo.toml +++ b/examples/rt685s-evk/Cargo.toml @@ -40,6 +40,10 @@ futures = { version = "0.3.30", default-features = false, features = [ ] } mimxrt600-fcb = "0.1.0" rand = { version = "0.8.5", default-features = false } +test-parser-macros = { git = "https://github.com/tullom/test-parser", optional = true } [profile.release] lto = true # better optimizations + +[features] +test-parser = ["dep:test-parser-macros"] diff --git a/examples/rt685s-evk/src/bin/adc.rs b/examples/rt685s-evk/src/bin/adc.rs index 6d42c9a5..16536662 100644 --- a/examples/rt685s-evk/src/bin/adc.rs +++ b/examples/rt685s-evk/src/bin/adc.rs @@ -28,6 +28,9 @@ async fn main(_spawner: Spawner) { info!("ADC sample = {:#x}", data); + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + Timer::after_millis(1000).await; } } diff --git a/examples/rt685s-evk/src/bin/clocks-blinky.rs b/examples/rt685s-evk/src/bin/clocks-blinky.rs index d5aba94e..0c821d6d 100644 --- a/examples/rt685s-evk/src/bin/clocks-blinky.rs +++ b/examples/rt685s-evk/src/bin/clocks-blinky.rs @@ -8,7 +8,7 @@ use embassy_executor::Spawner; use embassy_imxrt::iopctl::IopctlPin; use embassy_imxrt::{clocks, gpio}; use embassy_time::Timer; -use {defmt_rtt as _, embassy_imxrt as _, panic_probe as _}; +use {defmt_rtt as _, embassy_imxrt as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -66,6 +66,10 @@ async fn main(_spawner: Spawner) { loop { info!("Toggling LED"); led.toggle(); + + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + Timer::after_millis(1000).await; } } diff --git a/examples/rt685s-evk/src/bin/crc.rs b/examples/rt685s-evk/src/bin/crc.rs index e7ee5864..48379ce3 100644 --- a/examples/rt685s-evk/src/bin/crc.rs +++ b/examples/rt685s-evk/src/bin/crc.rs @@ -6,7 +6,6 @@ extern crate embassy_imxrt_examples; use defmt::*; use embassy_executor::Spawner; use embassy_imxrt::crc::{Config, Crc, Polynomial}; -use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -21,5 +20,8 @@ async fn main(_spawner: Spawner) { defmt::assert_eq!(output, 0xebfebe9a); + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + cortex_m::asm::bkpt(); } diff --git a/examples/rt685s-evk/src/bin/dma-mem.rs b/examples/rt685s-evk/src/bin/dma-mem.rs index 4242ce2f..8aef5b49 100644 --- a/examples/rt685s-evk/src/bin/dma-mem.rs +++ b/examples/rt685s-evk/src/bin/dma-mem.rs @@ -2,12 +2,12 @@ #![no_main] use defmt::*; +use defmt_rtt as _; use embassy_executor::Spawner; use embassy_imxrt::dma::channel::Channel; use embassy_imxrt::dma::transfer::{Priority, Transfer, TransferOptions, Width}; use embassy_imxrt::dma::Dma; use embassy_imxrt::peripherals::*; -use {defmt_rtt as _, panic_probe as _}; const TEST_LEN: usize = 16; @@ -87,4 +87,7 @@ async fn main(_spawner: Spawner) { test_dma_channel!(p, DMA0_CH31, 31); info!("DMA transfer tests completed"); + + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); } diff --git a/examples/rt685s-evk/src/bin/gpio-async-input.rs b/examples/rt685s-evk/src/bin/gpio-async-input.rs index 563bafb0..aa0e49c9 100644 --- a/examples/rt685s-evk/src/bin/gpio-async-input.rs +++ b/examples/rt685s-evk/src/bin/gpio-async-input.rs @@ -4,10 +4,10 @@ extern crate embassy_imxrt_examples; use defmt::*; +use defmt_rtt as _; use embassy_executor::Spawner; use embassy_imxrt::gpio; use embassy_time::{Duration, Ticker}; -use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] async fn monitor_task(mut monitor: gpio::Input<'static>) { @@ -50,6 +50,9 @@ async fn main(spawner: Spawner) { let mut ticker = Ticker::every(Duration::from_millis(100)); + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + spawner.spawn(monitor_task(monitor)).unwrap(); loop { diff --git a/examples/rt685s-evk/src/bin/gpio-blinky.rs b/examples/rt685s-evk/src/bin/gpio-blinky.rs index 903813ce..ea7090f5 100644 --- a/examples/rt685s-evk/src/bin/gpio-blinky.rs +++ b/examples/rt685s-evk/src/bin/gpio-blinky.rs @@ -25,6 +25,10 @@ async fn main(_spawner: Spawner) { loop { info!("Toggling LED"); led.toggle(); + + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + Timer::after_millis(1000).await; } } diff --git a/examples/rt685s-evk/src/bin/gpio-flex.rs b/examples/rt685s-evk/src/bin/gpio-flex.rs index f1d5bbe2..e1981a3b 100644 --- a/examples/rt685s-evk/src/bin/gpio-flex.rs +++ b/examples/rt685s-evk/src/bin/gpio-flex.rs @@ -90,6 +90,9 @@ async fn main(_spawner: Spawner) { // check pin level is high assert!(flex.is_high()); + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + loop { Timer::after_millis(1000).await; } diff --git a/examples/rt685s-evk/src/bin/gpio-input.rs b/examples/rt685s-evk/src/bin/gpio-input.rs index d31f08f0..037e8c3e 100644 --- a/examples/rt685s-evk/src/bin/gpio-input.rs +++ b/examples/rt685s-evk/src/bin/gpio-input.rs @@ -16,6 +16,9 @@ async fn main(_spawner: Spawner) { let monitor = gpio::Input::new(p.PIO1_0, gpio::Pull::None, gpio::Inverter::Disabled); + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + loop { info!("Pin level is {}", monitor.get_level()); Timer::after_millis(1000).await; diff --git a/examples/rt685s-evk/src/bin/hello-world.rs b/examples/rt685s-evk/src/bin/hello-world.rs index b6763374..3ebd673a 100644 --- a/examples/rt685s-evk/src/bin/hello-world.rs +++ b/examples/rt685s-evk/src/bin/hello-world.rs @@ -4,9 +4,9 @@ extern crate embassy_imxrt_examples; use defmt::info; +use defmt_rtt as _; use embassy_executor::Spawner; use embassy_time::Timer; -use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -14,6 +14,9 @@ async fn main(_spawner: Spawner) { info!("Hello world"); + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + loop { Timer::after_millis(1000).await; } diff --git a/examples/rt685s-evk/src/bin/i2c-loopback-async.rs b/examples/rt685s-evk/src/bin/i2c-loopback-async.rs index 78ec0272..2820eb4d 100644 --- a/examples/rt685s-evk/src/bin/i2c-loopback-async.rs +++ b/examples/rt685s-evk/src/bin/i2c-loopback-async.rs @@ -110,6 +110,9 @@ async fn main(spawner: Spawner) { let master = I2cMaster::new_async(p.FLEXCOMM4, p.PIO0_29, p.PIO0_30, Irqs, Speed::Standard, p.DMA0_CH9).unwrap(); + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + spawner.must_spawn(master_service(master)); spawner.must_spawn(slave_service(slave)); } diff --git a/examples/rt685s-evk/src/bin/i2c-master-async.rs b/examples/rt685s-evk/src/bin/i2c-master-async.rs index be993fb0..d2654ab3 100644 --- a/examples/rt685s-evk/src/bin/i2c-master-async.rs +++ b/examples/rt685s-evk/src/bin/i2c-master-async.rs @@ -181,6 +181,10 @@ async fn main(_spawner: Spawner) { } info!("i2c example - Done! Busy Loop..."); + + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + loop { Timer::after_millis(1000).await; } diff --git a/examples/rt685s-evk/src/bin/i2c-master.rs b/examples/rt685s-evk/src/bin/i2c-master.rs index 759e5987..fae1f41d 100644 --- a/examples/rt685s-evk/src/bin/i2c-master.rs +++ b/examples/rt685s-evk/src/bin/i2c-master.rs @@ -4,11 +4,11 @@ extern crate embassy_imxrt_examples; use defmt::{error, info}; +use defmt_rtt as _; use embassy_executor::Spawner; use embassy_imxrt::i2c; use embassy_time::Timer; use embedded_hal_1::i2c::I2c; -use {defmt_rtt as _, panic_probe as _}; const ACC_ADDR: u8 = 0x1E; @@ -170,6 +170,10 @@ async fn main(_spawner: Spawner) { } info!("i2c example - Done! Busy Loop..."); + + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + loop { Timer::after_millis(1000).await; } diff --git a/examples/rt685s-evk/src/bin/i2c-slave-async.rs b/examples/rt685s-evk/src/bin/i2c-slave-async.rs index 3344ae6a..b6a11166 100644 --- a/examples/rt685s-evk/src/bin/i2c-slave-async.rs +++ b/examples/rt685s-evk/src/bin/i2c-slave-async.rs @@ -67,5 +67,8 @@ async fn main(spawner: Spawner) { info!("i2cs example - I2c::new"); let i2c = I2cSlave::new_async(p.FLEXCOMM2, p.PIO0_18, p.PIO0_17, Irqs, SLAVE_ADDR.unwrap(), p.DMA0_CH4).unwrap(); + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + spawner.must_spawn(slave_service(i2c)); } diff --git a/examples/rt685s-evk/src/bin/i2c-slave.rs b/examples/rt685s-evk/src/bin/i2c-slave.rs index 5a7a39ee..ea520fcd 100644 --- a/examples/rt685s-evk/src/bin/i2c-slave.rs +++ b/examples/rt685s-evk/src/bin/i2c-slave.rs @@ -62,5 +62,8 @@ async fn main(spawner: Spawner) { info!("i2cs example - I2c::new"); let i2c = I2cSlave::new_blocking(p.FLEXCOMM2, p.PIO0_18, p.PIO0_17, SLAVE_ADDR.unwrap()).unwrap(); + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + spawner.must_spawn(slave_service(i2c)); } diff --git a/examples/rt685s-evk/src/bin/pwm.rs b/examples/rt685s-evk/src/bin/pwm.rs index bce35f74..e81db143 100644 --- a/examples/rt685s-evk/src/bin/pwm.rs +++ b/examples/rt685s-evk/src/bin/pwm.rs @@ -98,6 +98,9 @@ async fn main(_spawner: Spawner) { Timer::after_millis(100).await; } + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + Timer::after_millis(1000).await; } } diff --git a/examples/rt685s-evk/src/bin/rng.rs b/examples/rt685s-evk/src/bin/rng.rs index 5f64cb96..d74ed48c 100644 --- a/examples/rt685s-evk/src/bin/rng.rs +++ b/examples/rt685s-evk/src/bin/rng.rs @@ -4,11 +4,11 @@ extern crate embassy_imxrt_examples; use defmt::*; +use defmt_rtt as _; use embassy_executor::Spawner; use embassy_imxrt::rng::Rng; use embassy_imxrt::{bind_interrupts, peripherals, rng}; use rand::RngCore; -use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { RNG => rng::InterruptHandler; @@ -22,6 +22,9 @@ async fn main(_spawner: Spawner) { let mut rng = Rng::new(p.RNG, Irqs); let mut buf = [0u8; 65]; + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + // Async interface unwrap!(rng.async_fill_bytes(&mut buf).await); info!("random bytes: {:02x}", buf); diff --git a/examples/rt685s-evk/src/bin/rtc-time.rs b/examples/rt685s-evk/src/bin/rtc-time.rs index ab2a0570..a7ad0891 100644 --- a/examples/rt685s-evk/src/bin/rtc-time.rs +++ b/examples/rt685s-evk/src/bin/rtc-time.rs @@ -4,16 +4,19 @@ extern crate embassy_imxrt_examples; use defmt::info; +use defmt_rtt as _; use embassy_executor::Spawner; use embassy_imxrt::time_driver::*; use embassy_time::Timer; -use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_imxrt::init(Default::default()); let r = RtcDatetime::new(p.RTC); + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + let datetime = Datetime { year: 2024, month: 10, diff --git a/examples/rt685s-evk/src/bin/sha256-async.rs b/examples/rt685s-evk/src/bin/sha256-async.rs index b7d6bed1..0c60b6da 100644 --- a/examples/rt685s-evk/src/bin/sha256-async.rs +++ b/examples/rt685s-evk/src/bin/sha256-async.rs @@ -2,9 +2,9 @@ #![no_main] use defmt::*; +use defmt_rtt as _; use embassy_executor::Spawner; use embassy_imxrt::hashcrypt::{hasher, Hashcrypt}; -use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -74,4 +74,7 @@ async fn main(_spawner: Spawner) { ] ); trace!("Hashes complete"); + + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); } diff --git a/examples/rt685s-evk/src/bin/sha256.rs b/examples/rt685s-evk/src/bin/sha256.rs index f04b53db..d6d9b65f 100644 --- a/examples/rt685s-evk/src/bin/sha256.rs +++ b/examples/rt685s-evk/src/bin/sha256.rs @@ -2,9 +2,9 @@ #![no_main] use defmt::*; +use defmt_rtt as _; use embassy_executor::Spawner; use embassy_imxrt::hashcrypt::{hasher, Hashcrypt}; -use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -68,4 +68,7 @@ async fn main(_spawner: Spawner) { ] ); trace!("Hashes complete"); + + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); } diff --git a/examples/rt685s-evk/src/bin/test.sh b/examples/rt685s-evk/src/bin/test.sh new file mode 100644 index 00000000..4dcc61fa --- /dev/null +++ b/examples/rt685s-evk/src/bin/test.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +# Get all examples in the current directory (i.e., all Rust source files) +files=(*.rs) + +testCounter=0 +failedCounter=0 +failed=false + +# Arrays to store names of the tests that failed in debug and release modes +failedArrDebug=() +failedArrRelease=() + +# We build examples first to generate build artifacts so we can quickly run tests +echo "Building examples... [debug]" +timeout 3m cargo build --features test-parser +if [ $? -eq 1 ]; then + echo "Failed to build examples [debug]" + exit 1 +fi +echo "Building examples... [release]" +timeout 3m cargo build --release --features test-parser +if [ $? -eq 1 ]; then + echo "Failed to build examples [release]" + exit 1 +fi + +# Loop through each .rs file (representing individual tests) +for file in "${files[@]}"; do + + # Strip the ".rs" extension from the filename to use it as the test name + strippedName="${file%.rs}" + ((testCounter++)) + echo "Executing test ${testCounter}: ${strippedName} [debug]" + + # Run the test in debug mode using `cargo run` and timeout after 1 minute. + # The output of the `cargo run` command is piped into `test-parser` to check for test success or failure. + timeout 1m cargo run --bin "$strippedName" --features test-parser | test-parser -s TEST-SUCCESS -f TEST-FAIL + + if [ $? -eq 1 ]; then + # If the test failed, log it, mark the failure, and increment failure counter + echo "The last command failed with exit code 1." + failedArrDebug+=("$strippedName") + failed=true + ((failedCounter++)) + fi + + ((testCounter++)) + echo "Executing test ${testCounter}: ${strippedName} [release]" + + # Run the test in release mode using `cargo run` with the --release flag + timeout 1m cargo run --bin "$strippedName" --features test-parser --release | test-parser -s TEST-SUCCESS -f TEST-FAIL + + if [ $? -eq 1 ]; then + echo "The last command failed with exit code 1." + failedArrRelease+=("$strippedName") + failed=true + ((failedCounter++)) + fi +done + +echo -e "\n========END OF TESTS SUMMARY========" +((successCounter = testCounter - failedCounter)) +echo -e "${successCounter} / ${testCounter} tests passed\n" + +# If there were failed tests, display them and exit with a non-zero code to indicate failure +if [ "$failed" = true ]; then + echo "Some tests failed: " + for failure in "${failedArrDebug[@]}"; do + echo "${failure} [debug]" + done + for failure in "${failedArrRelease[@]}"; do + echo "${failure} [release]" + done + exit 1 +else + echo "All tests passed!" + exit 0 +fi diff --git a/examples/rt685s-evk/src/bin/time-driver-blinky.rs b/examples/rt685s-evk/src/bin/time-driver-blinky.rs index 077189dc..46974397 100644 --- a/examples/rt685s-evk/src/bin/time-driver-blinky.rs +++ b/examples/rt685s-evk/src/bin/time-driver-blinky.rs @@ -7,7 +7,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_imxrt::gpio; use embassy_time::Timer; -use {defmt_rtt as _, embassy_imxrt as _, panic_probe as _}; +use {defmt_rtt as _, embassy_imxrt as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { @@ -26,6 +26,10 @@ async fn main(_spawner: Spawner) -> ! { loop { info!("Toggling GPIO0_26 (Blue LED)"); led.toggle(); + + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + Timer::after_millis(5000).await; } } diff --git a/examples/rt685s-evk/src/bin/uart-async.rs b/examples/rt685s-evk/src/bin/uart-async.rs index 2394fe4e..2e323232 100644 --- a/examples/rt685s-evk/src/bin/uart-async.rs +++ b/examples/rt685s-evk/src/bin/uart-async.rs @@ -4,11 +4,11 @@ extern crate embassy_imxrt_examples; use defmt::info; +use defmt_rtt as _; use embassy_executor::Spawner; use embassy_imxrt::uart::{Async, Uart}; use embassy_imxrt::{bind_interrupts, peripherals, uart}; use embassy_time::Timer; -use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { FLEXCOMM2 => uart::InterruptHandler; @@ -80,4 +80,7 @@ async fn main(spawner: Spawner) { ) .unwrap(); spawner.must_spawn(usart2_task(usart2)); + + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); } diff --git a/examples/rt685s-evk/src/bin/uart.rs b/examples/rt685s-evk/src/bin/uart.rs index d562c4ad..9bb16abf 100644 --- a/examples/rt685s-evk/src/bin/uart.rs +++ b/examples/rt685s-evk/src/bin/uart.rs @@ -4,10 +4,10 @@ extern crate embassy_imxrt_examples; use defmt::info; +use defmt_rtt as _; use embassy_executor::Spawner; use embassy_imxrt::uart::{Blocking, Uart, UartRx, UartTx}; use embassy_time::Timer; -use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] async fn usart4_task(mut uart: UartRx<'static, Blocking>) { @@ -52,4 +52,7 @@ async fn main(spawner: Spawner) { let usart2 = UartTx::new_blocking(p.FLEXCOMM2, p.PIO0_15, Default::default()).unwrap(); spawner.must_spawn(usart2_task(usart2)); + + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); } diff --git a/examples/rt685s-evk/src/bin/wwdt.rs b/examples/rt685s-evk/src/bin/wwdt.rs index 16dbbefd..d64876b9 100644 --- a/examples/rt685s-evk/src/bin/wwdt.rs +++ b/examples/rt685s-evk/src/bin/wwdt.rs @@ -5,11 +5,11 @@ extern crate embassy_imxrt_examples; use cortex_m::peripheral::NVIC; use defmt::{info, warn}; +use defmt_rtt as _; use embassy_executor::Spawner; use embassy_imxrt::pac::{interrupt, Interrupt}; use embassy_imxrt::wwdt::WindowedWatchdog; use embassy_time::Timer; -use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -23,6 +23,9 @@ async fn main(_spawner: Spawner) { wwdt.unleash(); info!("Watchdog enabled!"); + #[cfg(feature = "test-parser")] + test_parser_macros::pass_test(); + // Feed 5 times, afterwards watchdog will reset CPU let mut feed_count = 5; loop { diff --git a/examples/rt685s-evk/src/lib.rs b/examples/rt685s-evk/src/lib.rs index da6e1442..753b7dd1 100644 --- a/examples/rt685s-evk/src/lib.rs +++ b/examples/rt685s-evk/src/lib.rs @@ -1,8 +1,11 @@ #![no_std] +use defmt_rtt as _; use mimxrt600_fcb::FlexSPIFlashConfigurationBlock; -use {defmt_rtt as _, panic_probe as _}; - +#[cfg(not(feature = "test-parser"))] +use panic_probe as _; +#[cfg(feature = "test-parser")] +use test_parser_macros as _; // auto-generated version information from Cargo.toml include!(concat!(env!("OUT_DIR"), "/biv.rs"));