diff --git a/ci.sh b/ci.sh index 1ee4ca7..049dcfa 100755 --- a/ci.sh +++ b/ci.sh @@ -27,7 +27,7 @@ cargo batch \ --- build --release --manifest-path examples/nrf-sdc/Cargo.toml --target thumbv7em-none-eabihf --features nrf52840 \ --- build --release --manifest-path examples/nrf-sdc/Cargo.toml --target thumbv7em-none-eabihf --features nrf52833 --artifact-dir tests/nrf-sdc \ --- build --release --manifest-path examples/nrf-sdc/Cargo.toml --target thumbv7em-none-eabihf --features nrf52832 \ - --- build --release --manifest-path examples/esp32/Cargo.toml --target riscv32imc-unknown-none-elf --artifact-dir tests/esp32 \ + --- build --release --manifest-path examples/esp32/Cargo.toml --features esp32c3 --target riscv32imc-unknown-none-elf --artifact-dir tests/esp32 \ --- build --release --manifest-path examples/serial-hci/Cargo.toml \ --- build --release --manifest-path examples/rp-pico-w/Cargo.toml --target thumbv6m-none-eabi --features skip-cyw43-firmware \ --- build --release --manifest-path examples/rp-pico-2-w/Cargo.toml --target thumbv8m.main-none-eabihf --features skip-cyw43-firmware diff --git a/examples/tests/src/probe/mod.rs b/examples/tests/src/probe/mod.rs index 5c4a2bc..b81d829 100644 --- a/examples/tests/src/probe/mod.rs +++ b/examples/tests/src/probe/mod.rs @@ -53,10 +53,10 @@ impl<'d> DeviceUnderTest<'d> { let mut lines: Vec = Vec::new(); select! { r = flasher.wait() => { - log::warn!("flasher exited unexpectedly: {:?}", r); for line in lines { log::warn!("{}", line); } + return Err(anyhow::anyhow!("flasher exited unexpectedly: {:?}", r)); } _ = self.token.cancelled() => { flasher.kill().await.unwrap(); diff --git a/examples/tests/tests/ble_l2cap_central.rs b/examples/tests/tests/ble_l2cap_central.rs new file mode 100644 index 0000000..80bd544 --- /dev/null +++ b/examples/tests/tests/ble_l2cap_central.rs @@ -0,0 +1,117 @@ +use futures::future::select; +use std::time::Duration; +use tokio::select; +use trouble_example_tests::{serial, TestContext}; +use trouble_host::prelude::*; + +#[tokio::test] +async fn ble_l2cap_central_nrf52() { + let _ = pretty_env_logger::try_init(); + let firmware = "bins/nrf-sdc/ble_l2cap_central"; + let local = tokio::task::LocalSet::new(); + local + .run_until(run_l2cap_central_test( + &[("target", "nrf52"), ("board", "microbit")], + firmware, + )) + .await; +} + +#[tokio::test] +async fn ble_l2cap_central_esp32c3() { + let _ = pretty_env_logger::try_init(); + let firmware = "bins/esp32/ble_l2cap_central"; + let local = tokio::task::LocalSet::new(); + local + .run_until(run_l2cap_central_test( + &[("target", "esp32"), ("board", "esp-rust-board")], + firmware, + )) + .await; +} + +async fn run_l2cap_central_test(labels: &[(&str, &str)], firmware: &str) { + let ctx = TestContext::new(); + let peripheral = ctx.serial_adapters[0].clone(); + + let dut = ctx.find_dut(labels).unwrap(); + + // Flash the binary to the target + let token = dut.token(); + + // Spawn a runner for the target + let central = tokio::task::spawn_local(dut.run(firmware.to_string())); + + // Run the central in the test using the serial adapter to verify + let peripheral_address: Address = Address::random([0xff, 0x8f, 0x1a, 0x05, 0xe4, 0xff]); + let peripheral = tokio::task::spawn_local(async move { + let controller_peripheral = serial::create_controller(&peripheral).await; + + let mut resources: HostResources = HostResources::new(PacketQos::None); + let (stack, mut peripheral, _central, mut runner) = trouble_host::new(controller_peripheral, &mut resources) + .set_random_address(peripheral_address) + .build(); + + select! { + r = runner.run() => { + r + } + r = async { + let mut adv_data = [0; 31]; + AdStructure::encode_slice( + &[AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED)], + &mut adv_data[..], + ).unwrap(); + + let mut scan_data = [0; 31]; + AdStructure::encode_slice( + &[AdStructure::CompleteLocalName(b"trouble-l2cap-example")], + &mut scan_data[..], + ).unwrap(); + + loop { + println!("[peripheral] advertising"); + let acceptor = peripheral.advertise(&Default::default(), Advertisement::ConnectableScannableUndirected { + adv_data: &adv_data[..], + scan_data: &scan_data[..], + }).await?; + let conn = acceptor.accept().await?; + println!("[peripheral] connected"); + + let mut ch1 = L2capChannel::accept(stack, &conn, &[0x2349], &Default::default()).await?; + + println!("[peripheral] channel created"); + + const PAYLOAD_LEN: usize = 27; + // Size of payload we're expecting + let mut rx = [0; PAYLOAD_LEN]; + for i in 0..10 { + let len = ch1.receive(stack, &mut rx).await?; + assert_eq!(len, rx.len()); + assert_eq!(rx, [i; PAYLOAD_LEN]); + } + println!("[peripheral] data received"); + + for i in 0..10 { + let tx = [i; PAYLOAD_LEN]; + ch1.send::<_, PAYLOAD_LEN>(stack, &tx).await?; + } + println!("[peripheral] data sent"); + token.cancel(); + break; + } + Ok(()) + } => { + r + } + } + }); + + tokio::time::timeout(Duration::from_secs(60), select(central, peripheral)) + .await + .map_err(|_| { + println!("Test timed out"); + assert!(false); + }) + .unwrap(); +}