diff --git a/ci.sh b/ci.sh index 3fe1b1ce..a03efb85 100755 --- a/ci.sh +++ b/ci.sh @@ -3,7 +3,7 @@ set -euo pipefail export RUSTFLAGS=-Dwarnings -export DEFMT_LOG=trace,cyw43=info,cyw43_pio=info,smoltcp=info +export DEFMT_LOG=trace,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info # needed by wifi examples export WIFI_NETWORK=x diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index cea45c5c..4eb31b10 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -26,7 +26,7 @@ async fn wifi_task( 'static, ExclusiveDevice, Output<'static, peripherals::P0_31>>, Input<'static, AnyPin>, - Output<'static, peripherals::P1_03>, + Output<'static, peripherals::P1_05>, >, ) -> ! { runner.run().await @@ -48,11 +48,11 @@ async fn main(spawner: Spawner) { let mosi = p.P0_30; let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive); let handshake = Input::new(p.P1_01.degrade(), Pull::Up); - let ready = Input::new(p.P1_02.degrade(), Pull::None); - let reset = Output::new(p.P1_03, Level::Low, OutputDrive::Standard); + let ready = Input::new(p.P1_04.degrade(), Pull::None); + let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard); let mut config = spim::Config::default(); - config.frequency = spim::Frequency::M1; + config.frequency = spim::Frequency::M32; config.mode = spim::MODE_2; // !!! let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); let spi = ExclusiveDevice::new(spi, cs); diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 9735c87d..4f9ecc47 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -13,6 +13,10 @@ embassy-executor = { version = "0.2.0", path = "../../embassy-executor", feature embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "nightly", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io = { version = "0.4.0", features = ["async"] } +embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } +embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } +embedded-hal-async = { version = "0.2.0-alpha.1" } +static_cell = { version = "1.1", features = [ "nightly" ] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs new file mode 100644 index 00000000..277b985c --- /dev/null +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs @@ -0,0 +1,270 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../common.rs"] +mod common; + +use defmt::{error, info, unwrap}; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_net::tcp::TcpSocket; +use embassy_net::{Config, Ipv4Address, Stack, StackResources}; +use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull}; +use embassy_nrf::rng::Rng; +use embassy_nrf::spim::{self, Spim}; +use embassy_nrf::{bind_interrupts, peripherals}; +use embassy_time::{with_timeout, Duration, Timer}; +use embedded_hal_async::spi::ExclusiveDevice; +use static_cell::make_static; +use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; + +teleprobe_meta::timeout!(120); + +bind_interrupts!(struct Irqs { + SPIM3 => spim::InterruptHandler; + RNG => embassy_nrf::rng::InterruptHandler; +}); + +#[embassy_executor::task] +async fn wifi_task( + runner: hosted::Runner< + 'static, + ExclusiveDevice, Output<'static, peripherals::P0_31>>, + Input<'static, AnyPin>, + Output<'static, peripherals::P1_05>, + >, +) -> ! { + runner.run().await +} + +type MyDriver = hosted::NetDriver<'static>; + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack) -> ! { + stack.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + info!("Hello World!"); + + let p = embassy_nrf::init(Default::default()); + + let miso = p.P0_28; + let sck = p.P0_29; + let mosi = p.P0_30; + let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive); + let handshake = Input::new(p.P1_01.degrade(), Pull::Up); + let ready = Input::new(p.P1_04.degrade(), Pull::None); + let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard); + + let mut config = spim::Config::default(); + config.frequency = spim::Frequency::M32; + config.mode = spim::MODE_2; // !!! + let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); + let spi = ExclusiveDevice::new(spi, cs); + + let (device, mut control, runner) = embassy_net_esp_hosted::new( + make_static!(embassy_net_esp_hosted::State::new()), + spi, + handshake, + ready, + reset, + ) + .await; + + unwrap!(spawner.spawn(wifi_task(runner))); + + control.init().await; + control.join(WIFI_NETWORK, WIFI_PASSWORD).await; + + // Generate random seed + let mut rng = Rng::new(p.RNG, Irqs); + let mut seed = [0; 8]; + rng.blocking_fill_bytes(&mut seed); + let seed = u64::from_le_bytes(seed); + + // Init network stack + let stack = &*make_static!(Stack::new( + device, + Config::dhcpv4(Default::default()), + make_static!(StackResources::<2>::new()), + seed + )); + + unwrap!(spawner.spawn(net_task(stack))); + + info!("Waiting for DHCP up..."); + while stack.config_v4().is_none() { + Timer::after(Duration::from_millis(100)).await; + } + info!("IP addressing up!"); + + let down = test_download(stack).await; + let up = test_upload(stack).await; + let updown = test_upload_download(stack).await; + + assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS); + assert!(up > TEST_EXPECTED_UPLOAD_KBPS); + assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} + +// Test-only wifi network, no internet access! +const WIFI_NETWORK: &str = "EmbassyTest"; +const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; + +const TEST_DURATION: usize = 10; +const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 150; +const TEST_EXPECTED_UPLOAD_KBPS: usize = 150; +const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 150; +const RX_BUFFER_SIZE: usize = 4096; +const TX_BUFFER_SIZE: usize = 4096; +const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); +const DOWNLOAD_PORT: u16 = 4321; +const UPLOAD_PORT: u16 = 4322; +const UPLOAD_DOWNLOAD_PORT: u16 = 4323; + +async fn test_download(stack: &'static Stack) -> usize { + info!("Testing download..."); + + let mut rx_buffer = [0; RX_BUFFER_SIZE]; + let mut tx_buffer = [0; TX_BUFFER_SIZE]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT); + if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await { + error!("connect error: {:?}", e); + return 0; + } + info!("connected, testing..."); + + let mut rx_buf = [0; 4096]; + let mut total: usize = 0; + with_timeout(Duration::from_secs(TEST_DURATION as _), async { + loop { + match socket.read(&mut rx_buf).await { + Ok(0) => { + error!("read EOF"); + return 0; + } + Ok(n) => total += n, + Err(e) => { + error!("read error: {:?}", e); + return 0; + } + } + } + }) + .await + .ok(); + + let kbps = (total + 512) / 1024 / TEST_DURATION; + info!("download: {} kB/s", kbps); + kbps +} + +async fn test_upload(stack: &'static Stack) -> usize { + info!("Testing upload..."); + + let mut rx_buffer = [0; RX_BUFFER_SIZE]; + let mut tx_buffer = [0; TX_BUFFER_SIZE]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT); + if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await { + error!("connect error: {:?}", e); + return 0; + } + info!("connected, testing..."); + + let buf = [0; 4096]; + let mut total: usize = 0; + with_timeout(Duration::from_secs(TEST_DURATION as _), async { + loop { + match socket.write(&buf).await { + Ok(0) => { + error!("write zero?!??!?!"); + return 0; + } + Ok(n) => total += n, + Err(e) => { + error!("write error: {:?}", e); + return 0; + } + } + } + }) + .await + .ok(); + + let kbps = (total + 512) / 1024 / TEST_DURATION; + info!("upload: {} kB/s", kbps); + kbps +} + +async fn test_upload_download(stack: &'static Stack) -> usize { + info!("Testing upload+download..."); + + let mut rx_buffer = [0; RX_BUFFER_SIZE]; + let mut tx_buffer = [0; TX_BUFFER_SIZE]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT); + if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await { + error!("connect error: {:?}", e); + return 0; + } + info!("connected, testing..."); + + let (mut reader, mut writer) = socket.split(); + + let tx_buf = [0; 4096]; + let mut rx_buf = [0; 4096]; + let mut total: usize = 0; + let tx_fut = async { + loop { + match writer.write(&tx_buf).await { + Ok(0) => { + error!("write zero?!??!?!"); + return 0; + } + Ok(_) => {} + Err(e) => { + error!("write error: {:?}", e); + return 0; + } + } + } + }; + + let rx_fut = async { + loop { + match reader.read(&mut rx_buf).await { + Ok(0) => { + error!("read EOF"); + return 0; + } + Ok(n) => total += n, + Err(e) => { + error!("read error: {:?}", e); + return 0; + } + } + } + }; + + with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut)) + .await + .ok(); + + let kbps = (total + 512) / 1024 / TEST_DURATION; + info!("upload+download: {} kB/s", kbps); + kbps +} diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 7a94ea19..9fc537a4 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -63,20 +63,13 @@ async fn main(spawner: Spawner) { .set_power_management(cyw43::PowerManagementMode::PowerSave) .await; - let config = Config::dhcpv4(Default::default()); - //let config = embassy_net::Config::Static(embassy_net::Config { - // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), - // dns_servers: Vec::new(), - // gateway: Some(Ipv4Address::new(192, 168, 69, 1)), - //}); - // Generate random seed let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. // Init network stack let stack = &*make_static!(Stack::new( net_device, - config, + Config::dhcpv4(Default::default()), make_static!(StackResources::<2>::new()), seed ));