From 81b57bc0986cceaab5ec70e9d7cb18f742454bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Tue, 7 Nov 2023 13:08:57 +0100 Subject: [PATCH] Add basic automated tests (#339) --- esp-wifi/Cargo.toml | 21 ++ .../automated-tests/esp_now_broadcaster.rs | 57 ++++++ esp-wifi/automated-tests/open_access_point.rs | 118 +++++++++++ esp-wifi/automated-tests/test_ble.rs | 108 ++++++++++ esp-wifi/automated-tests/test_connect.rs | 190 ++++++++++++++++++ esp-wifi/automated-tests/test_esp_now.rs | 69 +++++++ 6 files changed, 563 insertions(+) create mode 100644 esp-wifi/automated-tests/esp_now_broadcaster.rs create mode 100644 esp-wifi/automated-tests/open_access_point.rs create mode 100644 esp-wifi/automated-tests/test_ble.rs create mode 100644 esp-wifi/automated-tests/test_connect.rs create mode 100644 esp-wifi/automated-tests/test_esp_now.rs diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index e4f4e548553..d92399fd751 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -117,3 +117,24 @@ log = [ "esp32s2-hal?/log", "esp32s3-hal?/log", ] + +# These examples are used in test automation +[[example]] +name = "test_esp_now" +path = "automated-tests/test_esp_now.rs" + +[[example]] +name = "esp_now_broadcaster" +path = "automated-tests/esp_now_broadcaster.rs" + +[[example]] +name = "open_access_point" +path = "automated-tests/open_access_point.rs" + +[[example]] +name = "test_connect" +path = "automated-tests/test_connect.rs" + +[[example]] +name = "test_ble" +path = "automated-tests/test_ble.rs" diff --git a/esp-wifi/automated-tests/esp_now_broadcaster.rs b/esp-wifi/automated-tests/esp_now_broadcaster.rs new file mode 100644 index 00000000000..ddbd2627a75 --- /dev/null +++ b/esp-wifi/automated-tests/esp_now_broadcaster.rs @@ -0,0 +1,57 @@ +#![no_std] +#![no_main] + +use esp_backtrace as _; +use esp_println::println; +use esp_wifi::esp_now::BROADCAST_ADDRESS; +use esp_wifi::{current_millis, initialize, EspWifiInitFor}; +#[path = "../../examples-util/util.rs"] +mod examples_util; +use examples_util::hal; +use hal::clock::ClockControl; +use hal::Rng; +use hal::{peripherals::Peripherals, prelude::*}; + +#[entry] +fn main() -> ! { + #[cfg(feature = "log")] + esp_println::logger::init_logger(log::LevelFilter::Info); + + let peripherals = Peripherals::take(); + + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::max(system.clock_control).freeze(); + + #[cfg(target_arch = "xtensa")] + let timer = hal::timer::TimerGroup::new(peripherals.TIMG1, &clocks).timer0; + #[cfg(target_arch = "riscv32")] + let timer = hal::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let init = initialize( + EspWifiInitFor::Wifi, + timer, + Rng::new(peripherals.RNG), + system.radio_clock_control, + &clocks, + ) + .unwrap(); + + let wifi = peripherals.WIFI; + let mut esp_now = esp_wifi::esp_now::EspNow::new(&init, wifi).unwrap(); + + println!("esp-now version {}", esp_now.get_version().unwrap()); + + let next_send_time = current_millis() + 1 * 1000; + loop { + if current_millis() >= next_send_time { + println!("Send"); + let status = esp_now + .send(&BROADCAST_ADDRESS, b"0123456789") + .unwrap() + .wait(); + println!("Send broadcast status: {:?}", status); + break; + } + } + + loop {} +} diff --git a/esp-wifi/automated-tests/open_access_point.rs b/esp-wifi/automated-tests/open_access_point.rs new file mode 100644 index 00000000000..5a53d609735 --- /dev/null +++ b/esp-wifi/automated-tests/open_access_point.rs @@ -0,0 +1,118 @@ +#![no_std] +#![no_main] + +#[path = "../../examples-util/util.rs"] +mod examples_util; +use examples_util::hal; + +use embedded_io::*; +use embedded_svc::ipv4::Interface; +use embedded_svc::wifi::{AccessPointConfiguration, Configuration, Wifi}; + +use esp_backtrace as _; +use esp_println::println; +use esp_wifi::initialize; +use esp_wifi::wifi::utils::create_network_interface; +use esp_wifi::wifi::WifiApDevice; +use esp_wifi::wifi_interface::WifiStack; +use esp_wifi::{current_millis, EspWifiInitFor}; +use hal::clock::ClockControl; +use hal::Rng; +use hal::{peripherals::Peripherals, prelude::*}; + +use smoltcp::iface::SocketStorage; + +#[entry] +fn main() -> ! { + #[cfg(feature = "log")] + esp_println::logger::init_logger(log::LevelFilter::Info); + + let peripherals = Peripherals::take(); + + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::max(system.clock_control).freeze(); + + #[cfg(target_arch = "xtensa")] + let timer = hal::timer::TimerGroup::new(peripherals.TIMG1, &clocks).timer0; + #[cfg(target_arch = "riscv32")] + let timer = hal::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let init = initialize( + EspWifiInitFor::Wifi, + timer, + Rng::new(peripherals.RNG), + system.radio_clock_control, + &clocks, + ) + .unwrap(); + + let wifi = peripherals.WIFI; + let mut socket_set_entries: [SocketStorage; 3] = Default::default(); + let (iface, device, mut controller, sockets) = + create_network_interface(&init, wifi, WifiApDevice, &mut socket_set_entries).unwrap(); + let mut wifi_stack = WifiStack::new(iface, device, sockets, current_millis); + + let client_config = Configuration::AccessPoint(AccessPointConfiguration { + ssid: "esp-wifi".into(), + ..Default::default() + }); + let res = controller.set_configuration(&client_config); + println!("wifi_set_configuration returned {:?}", res); + + controller.start().unwrap(); + println!("is wifi started: {:?}", controller.is_started()); + + println!("{:?}", controller.get_capabilities()); + + wifi_stack + .set_iface_configuration(&embedded_svc::ipv4::Configuration::Client( + embedded_svc::ipv4::ClientConfiguration::Fixed(embedded_svc::ipv4::ClientSettings { + ip: embedded_svc::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), + subnet: embedded_svc::ipv4::Subnet { + gateway: embedded_svc::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), + mask: embedded_svc::ipv4::Mask(24), + }, + dns: None, + secondary_dns: None, + }), + )) + .unwrap(); + + println!("Start busy loop on main. Connect to the AP `esp-wifi` and point your browser to http://192.168.2.1:8080/"); + println!("Use a static IP in the range 192.168.2.2 .. 192.168.2.255, use gateway 192.168.2.1"); + + let mut rx_buffer = [0u8; 1536]; + let mut tx_buffer = [0u8; 1536]; + let mut socket = wifi_stack.get_socket(&mut rx_buffer, &mut tx_buffer); + + socket.listen(8080).unwrap(); + + loop { + socket.work(); + + if !socket.is_open() { + socket.listen(8080).unwrap(); + } + + if socket.is_connected() { + println!("Connected"); + socket.write_all(b"DATA!").unwrap(); + socket.flush().unwrap(); + socket.close(); + println!("Done\n"); + println!(); + } + + let wait_end = current_millis() + 5 * 1000; + while current_millis() < wait_end { + socket.work(); + } + } +} + +fn parse_ip(ip: &str) -> [u8; 4] { + let mut result = [0u8; 4]; + for (idx, octet) in ip.split(".").into_iter().enumerate() { + result[idx] = u8::from_str_radix(octet, 10).unwrap(); + } + result +} diff --git a/esp-wifi/automated-tests/test_ble.rs b/esp-wifi/automated-tests/test_ble.rs new file mode 100644 index 00000000000..f5aaf5b7051 --- /dev/null +++ b/esp-wifi/automated-tests/test_ble.rs @@ -0,0 +1,108 @@ +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use bleps::{ + ad_structure::{ + create_advertising_data, AdStructure, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE, + }, + attribute_server::{AttributeServer, WorkResult}, + gatt, Ble, HciConnector, +}; +use esp_backtrace as _; +use esp_println::println; +use esp_wifi::{ble::controller::BleConnector, initialize, EspWifiInitFor}; +use examples_util::hal; +use hal::{clock::ClockControl, peripherals::*, prelude::*, Rng, IO}; +#[path = "../../examples-util/util.rs"] +mod examples_util; + +#[entry] +fn main() -> ! { + #[cfg(feature = "log")] + esp_println::logger::init_logger(log::LevelFilter::Info); + + let peripherals = Peripherals::take(); + + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::max(system.clock_control).freeze(); + + #[cfg(target_arch = "xtensa")] + let timer = hal::timer::TimerGroup::new(peripherals.TIMG1, &clocks).timer0; + #[cfg(target_arch = "riscv32")] + let timer = hal::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let init = initialize( + EspWifiInitFor::Ble, + timer, + Rng::new(peripherals.RNG), + system.radio_clock_control, + &clocks, + ) + .unwrap(); + + let mut bluetooth = peripherals.BT; + + loop { + let connector = BleConnector::new(&init, &mut bluetooth); + let hci = HciConnector::new(connector, esp_wifi::current_millis); + let mut ble = Ble::new(&hci); + + println!("{:?}", ble.init()); + println!("{:?}", ble.cmd_set_le_advertising_parameters()); + println!( + "{:?}", + ble.cmd_set_le_advertising_data( + create_advertising_data(&[ + AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED), + AdStructure::ServiceUuids16(&[Uuid::Uuid16(0x1809)]), + AdStructure::CompleteLocalName("ESP-WIFI"), + ]) + .unwrap() + ) + ); + println!("{:?}", ble.cmd_set_le_advertise_enable(true)); + println!("started advertising"); + + println!("[HOST bletool write ESP-WIFI 937312E0-2354-11EB-9F10-FBC30A62CF38 937312E0-2354-11EB-9F10-FBC30A62CF38 Hello]"); + + let rcv_buffer = RefCell::new([0u8; 32]); + let mut rf = |_offset: usize, data: &mut [u8]| { + data[..20].copy_from_slice(&b"Hello Bare-Metal BLE"[..]); + 17 + }; + let mut wf = |offset: usize, data: &[u8]| { + println!("RECEIVED: {} {:?}", offset, data); + rcv_buffer.borrow_mut()[..data.len()].copy_from_slice(data); + }; + + gatt!([service { + uuid: "937312e0-2354-11eb-9f10-fbc30a62cf38", + characteristics: [characteristic { + uuid: "937312e0-2354-11eb-9f10-fbc30a62cf38", + read: rf, + write: wf, + },], + },]); + + let mut srv = AttributeServer::new(&mut ble, &mut gatt_attributes); + + loop { + match srv.do_work_with_notification(None) { + Ok(res) => { + if let WorkResult::GotDisconnected = res { + break; + } + } + Err(err) => { + println!("{:?}", err); + } + } + + if &rcv_buffer.borrow()[..5] == b"Hello" { + println!("[PASSED]"); + loop {} + } + } + } +} diff --git a/esp-wifi/automated-tests/test_connect.rs b/esp-wifi/automated-tests/test_connect.rs new file mode 100644 index 00000000000..6fbb65b236c --- /dev/null +++ b/esp-wifi/automated-tests/test_connect.rs @@ -0,0 +1,190 @@ +#![no_std] +#![no_main] + +#[path = "../../examples-util/util.rs"] +mod examples_util; +use examples_util::hal; + +use embedded_io::*; +use embedded_svc::ipv4::Interface; +use embedded_svc::wifi::{AccessPointInfo, AuthMethod, ClientConfiguration, Configuration, Wifi}; + +use esp_backtrace as _; +use esp_println::println; +use esp_wifi::initialize; +use esp_wifi::wifi::WifiStaDevice; +use esp_wifi::wifi::{utils::create_network_interface, WifiError}; +use esp_wifi::wifi_interface::WifiStack; +use esp_wifi::{current_millis, EspWifiInitFor}; +use hal::clock::ClockControl; +use hal::Rng; +use hal::{peripherals::Peripherals, prelude::*}; + +use smoltcp::iface::SocketStorage; +use smoltcp::wire::{IpAddress, Ipv4Address}; + +const SSID: &str = "esp-wifi"; +const STATIC_IP: &str = "192.168.2.2"; +const GATEWAY_IP: &str = "192.168.2.1"; + +#[entry] +fn main() -> ! { + #[cfg(feature = "log")] + esp_println::logger::init_logger(log::LevelFilter::Info); + + println!("Running test"); + + #[cfg(not(feature = "esp32"))] + println!("[RUN esp32 open_access_point]"); + + #[cfg(feature = "esp32")] + println!("[RUN esp32c3 open_access_point]"); + + let peripherals = Peripherals::take(); + + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::max(system.clock_control).freeze(); + + #[cfg(target_arch = "xtensa")] + let timer = hal::timer::TimerGroup::new(peripherals.TIMG1, &clocks).timer0; + #[cfg(target_arch = "riscv32")] + let timer = hal::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let init = initialize( + EspWifiInitFor::Wifi, + timer, + Rng::new(peripherals.RNG), + system.radio_clock_control, + &clocks, + ) + .unwrap(); + + let wifi = peripherals.WIFI; + let mut socket_set_entries: [SocketStorage; 3] = Default::default(); + let (iface, device, mut controller, sockets) = + create_network_interface(&init, wifi, WifiStaDevice, &mut socket_set_entries).unwrap(); + let mut wifi_stack = WifiStack::new(iface, device, sockets, current_millis); + + let client_config = Configuration::Client(ClientConfiguration { + ssid: SSID.into(), + auth_method: AuthMethod::None, + ..Default::default() + }); + let res = controller.set_configuration(&client_config); + println!("wifi_set_configuration returned {:?}", res); + + controller.start().unwrap(); + println!("is wifi started: {:?}", controller.is_started()); + + println!("{:?}", controller.get_capabilities()); + + let mut tries = 15; + + 'outer: loop { + println!("Start Wifi Scan"); + let res: Result<(heapless::Vec, usize), WifiError> = + controller.scan_n(); + if let Ok((res, _count)) = res { + for ap in res { + println!("{:?}", ap); + if ap.ssid == SSID { + break 'outer; + } + } + } + tries -= 1; + if tries == 0 { + break 'outer; + } + + let wait_end = current_millis() + 1 * 1000; + while current_millis() < wait_end { + // wait + } + } + + println!("wifi_connect {:?}", controller.connect()); + + // wait to get connected + println!("Wait to get connected"); + loop { + let res = controller.is_connected(); + match res { + Ok(connected) => { + if connected { + break; + } + } + Err(err) => { + println!("{:?}", err); + break; + } + } + } + println!("{:?}", controller.is_connected()); + + if let Ok(c) = controller.is_connected() { + if !c { + println!("[FAILED]"); + loop {} + } + } + if let Err(WifiError::Disconnected) = controller.is_connected() { + println!("[FAILED]"); + loop {} + } + + println!("Setting static IP {}", STATIC_IP); + + wifi_stack + .set_iface_configuration(&embedded_svc::ipv4::Configuration::Client( + embedded_svc::ipv4::ClientConfiguration::Fixed(embedded_svc::ipv4::ClientSettings { + ip: embedded_svc::ipv4::Ipv4Addr::from(parse_ip(STATIC_IP)), + subnet: embedded_svc::ipv4::Subnet { + gateway: embedded_svc::ipv4::Ipv4Addr::from(parse_ip(GATEWAY_IP)), + mask: embedded_svc::ipv4::Mask(24), + }, + dns: None, + secondary_dns: None, + }), + )) + .unwrap(); + + let mut rx_buffer = [0u8; 1536]; + let mut tx_buffer = [0u8; 1536]; + let mut socket = wifi_stack.get_socket(&mut rx_buffer, &mut tx_buffer); + + 'outer: loop { + socket.work(); + + socket + .open(IpAddress::Ipv4(Ipv4Address::new(192, 168, 2, 1)), 8080) + .unwrap(); + + loop { + let mut buffer = [0u8; 512]; + if let Ok(len) = socket.read(&mut buffer) { + let to_print = unsafe { core::str::from_utf8_unchecked(&buffer[..len]) }; + println!("{}", to_print); + if to_print.contains("DATA") { + println!("[PASSED]"); + break 'outer; + } + } else { + break; + } + } + println!(); + + socket.disconnect(); + } + + loop {} +} + +fn parse_ip(ip: &str) -> [u8; 4] { + let mut result = [0u8; 4]; + for (idx, octet) in ip.split(".").into_iter().enumerate() { + result[idx] = u8::from_str_radix(octet, 10).unwrap(); + } + result +} diff --git a/esp-wifi/automated-tests/test_esp_now.rs b/esp-wifi/automated-tests/test_esp_now.rs new file mode 100644 index 00000000000..dedd4fc03e8 --- /dev/null +++ b/esp-wifi/automated-tests/test_esp_now.rs @@ -0,0 +1,69 @@ +#![no_std] +#![no_main] + +use esp_backtrace as _; +use esp_println::println; +use esp_wifi::esp_now::{PeerInfo, BROADCAST_ADDRESS}; +use esp_wifi::{initialize, EspWifiInitFor}; +#[path = "../../examples-util/util.rs"] +mod examples_util; +use examples_util::hal; +use hal::clock::ClockControl; +use hal::Rng; +use hal::{peripherals::Peripherals, prelude::*}; + +#[entry] +fn main() -> ! { + #[cfg(feature = "log")] + esp_println::logger::init_logger(log::LevelFilter::Info); + + let peripherals = Peripherals::take(); + + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::max(system.clock_control).freeze(); + + #[cfg(target_arch = "xtensa")] + let timer = hal::timer::TimerGroup::new(peripherals.TIMG1, &clocks).timer0; + #[cfg(target_arch = "riscv32")] + let timer = hal::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let init = initialize( + EspWifiInitFor::Wifi, + timer, + Rng::new(peripherals.RNG), + system.radio_clock_control, + &clocks, + ) + .unwrap(); + + let wifi = peripherals.WIFI; + let esp_now = esp_wifi::esp_now::EspNow::new(&init, wifi).unwrap(); + + println!("esp-now version {}", esp_now.get_version().unwrap()); + + #[cfg(not(feature = "esp32"))] + println!("[RUN esp32 esp_now_broadcaster]"); + + #[cfg(feature = "esp32")] + println!("[RUN esp32c3 esp_now_broadcaster]"); + + loop { + let r = esp_now.receive(); + if let Some(r) = r { + println!("Received {:?}", r); + + if r.info.dst_address == BROADCAST_ADDRESS { + if !esp_now.peer_exists(&r.info.src_address) { + esp_now + .add_peer(PeerInfo { + peer_address: r.info.src_address, + lmk: None, + channel: None, + encrypt: false, + }) + .unwrap(); + } + println!("[PASSED]"); + } + } + } +}