From 160e1c38ceab0ae8876c2bf5f12438edd4d9b018 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 21 Jun 2024 20:19:54 +0200 Subject: Add embassy-net-nrf91. --- examples/nrf9160/.cargo/config.toml | 3 +- examples/nrf9160/Cargo.toml | 5 + examples/nrf9160/memory.x | 8 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 250 +++++++++++++++++++++++++++ 4 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 examples/nrf9160/src/bin/modem_tcp_client.rs (limited to 'examples') diff --git a/examples/nrf9160/.cargo/config.toml b/examples/nrf9160/.cargo/config.toml index f64c63966..6072b8595 100644 --- a/examples/nrf9160/.cargo/config.toml +++ b/examples/nrf9160/.cargo/config.toml @@ -1,5 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-rs run --chip nRF9160_xxAA" +# runner = "probe-rs run --chip nRF9160_xxAA" +runner = [ "probe-rs", "run", "--chip=nRF9160_xxAA", "--always-print-stacktrace", "--log-format={t} {[{L}]%bold} {s} {{c} {ff}:{l:1}%dimmed}" ] [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index c30b54ebd..fc24e99d2 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -8,6 +8,8 @@ license = "MIT OR Apache-2.0" embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } defmt = "0.3" defmt-rtt = "0.4" @@ -15,6 +17,9 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } +static_cell = { version = "2" } +embedded-io = "0.6.1" +embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } [profile.release] debug = 2 diff --git a/examples/nrf9160/memory.x b/examples/nrf9160/memory.x index 4c7d4ebf0..e33498773 100644 --- a/examples/nrf9160/memory.x +++ b/examples/nrf9160/memory.x @@ -1,5 +1,9 @@ MEMORY { - FLASH : ORIGIN = 0x00000000, LENGTH = 1024K - RAM : ORIGIN = 0x20018000, LENGTH = 160K + FLASH : ORIGIN = 0x00000000, LENGTH = 1024K + RAM : ORIGIN = 0x20010000, LENGTH = 192K + IPC : ORIGIN = 0x20000000, LENGTH = 64K } + +PROVIDE(__start_ipc = ORIGIN(IPC)); +PROVIDE(__end_ipc = ORIGIN(IPC) + LENGTH(IPC)); diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs new file mode 100644 index 000000000..b1dac18a1 --- /dev/null +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -0,0 +1,250 @@ +#![no_std] +#![no_main] + +use core::mem::MaybeUninit; +use core::ptr::addr_of_mut; +use core::str::FromStr; +use core::{slice, str}; + +use defmt::{assert, *}; +use embassy_executor::Spawner; +use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net_nrf91::{Runner, State}; +use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; +use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; +use embassy_nrf::uarte::Baudrate; +use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte}; +use embassy_time::{Duration, Timer}; +use embedded_io_async::Write; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[interrupt] +fn IPC() { + embassy_net_nrf91::on_ipc_irq(); +} + +bind_interrupts!(struct Irqs { + UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler; +}); + +// embassy-net-nrf91 only supports blocking trace write for now. +// We don't want to block packet processing with slow uart writes, so +// we make an adapter that writes whatever fits in the buffer and drops +// data if it's full. +struct TraceWriter(BufferedUarteTx<'static, peripherals::SERIAL0>); + +impl embedded_io::ErrorType for TraceWriter { + type Error = core::convert::Infallible; +} + +impl embedded_io::Write for TraceWriter { + fn write(&mut self, buf: &[u8]) -> Result { + let _ = self.0.try_write(buf); + Ok(buf.len()) + } + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} + +#[embassy_executor::task] +async fn modem_task(runner: Runner<'static, TraceWriter>) -> ! { + runner.run().await +} + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack>) -> ! { + stack.run().await +} + +#[embassy_executor::task] +async fn blink_task(pin: AnyPin) { + let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); + loop { + led.set_high(); + Timer::after_millis(100).await; + led.set_low(); + Timer::after_millis(100).await; + } +} + +extern "C" { + static __start_ipc: u8; + static __end_ipc: u8; +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + + info!("Hello World!"); + + unwrap!(spawner.spawn(blink_task(p.P0_02.degrade()))); + + let ipc_mem = unsafe { + let ipc_start = &__start_ipc as *const u8 as *mut MaybeUninit; + let ipc_end = &__end_ipc as *const u8 as *mut MaybeUninit; + let ipc_len = ipc_end.offset_from(ipc_start) as usize; + slice::from_raw_parts_mut(ipc_start, ipc_len) + }; + + static mut TRACE_BUF: [u8; 4096] = [0u8; 4096]; + let mut config = uarte::Config::default(); + config.baudrate = Baudrate::BAUD1M; + let trace_writer = TraceWriter(BufferedUarteTx::new( + //let trace_uart = BufferedUarteTx::new( + unsafe { peripherals::SERIAL0::steal() }, + Irqs, + unsafe { peripherals::P0_01::steal() }, + //unsafe { peripherals::P0_14::steal() }, + config, + unsafe { &mut *addr_of_mut!(TRACE_BUF) }, + )); + + static STATE: StaticCell = StaticCell::new(); + let (device, control, runner) = embassy_net_nrf91::new(STATE.init(State::new()), ipc_mem, trace_writer).await; + unwrap!(spawner.spawn(modem_task(runner))); + + let config = embassy_net::Config::default(); + + // Generate "random" seed. nRF91 has no RNG, TODO figure out something... + let seed = 123456; + + // Init network stack + static RESOURCES: StaticCell> = StaticCell::new(); + static STACK: StaticCell>> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( + device, + config, + RESOURCES.init(StackResources::<2>::new()), + seed, + )); + + unwrap!(spawner.spawn(net_task(stack))); + + control.wait_init().await; + info!("INIT OK"); + + let mut buf = [0u8; 256]; + + let n = control.at_command(b"AT+CFUN?", &mut buf).await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + + let n = control + .at_command(b"AT+CGDCONT=0,\"IP\",\"iot.nat.es\"", &mut buf) + .await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + let n = control + .at_command(b"AT+CGAUTH=0,1,\"orange\",\"orange\"", &mut buf) + .await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + + let n = control.at_command(b"AT+CFUN=1", &mut buf).await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + + info!("waiting for attach..."); + loop { + Timer::after_millis(500).await; + let n = control.at_command(b"AT+CGATT?", &mut buf).await; + let mut res = &buf[..n]; + pop_prefix(&mut res, b"+CGATT: "); + let res = split_field(&mut res); + info!("AT resp field: '{}'", unsafe { str::from_utf8_unchecked(res) }); + if res == b"1" { + break; + } + } + + let n = control.at_command(b"AT+CGPADDR=0", &mut buf).await; + let mut res = &buf[..n]; + pop_prefix(&mut res, b"+CGPADDR: 0,"); + let ip = split_field(&mut res); + let ip = Ipv4Address::from_str(unsafe { str::from_utf8_unchecked(ip) }).unwrap(); + info!("IP: '{}'", ip); + + info!("============== OPENING SOCKET"); + control.open_raw_socket().await; + + stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { + address: Ipv4Cidr::new(ip, 32), + gateway: None, + dns_servers: Default::default(), + })); + + let mut rx_buffer = [0; 4096]; + let mut tx_buffer = [0; 4096]; + loop { + let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("Connecting..."); + let host_addr = embassy_net::Ipv4Address::from_str("83.51.182.206").unwrap(); + if let Err(e) = socket.connect((host_addr, 8000)).await { + warn!("connect error: {:?}", e); + continue; + } + info!("Connected to {:?}", socket.remote_endpoint()); + + let msg = b"Hello world!\n"; + loop { + if let Err(e) = socket.write_all(msg).await { + warn!("write error: {:?}", e); + break; + } + info!("txd: {}", core::str::from_utf8(msg).unwrap()); + Timer::after_secs(1).await; + } + } +} + +fn is_whitespace(char: u8) -> bool { + match char { + b'\r' | b'\n' | b' ' => true, + _ => false, + } +} + +fn is_separator(char: u8) -> bool { + match char { + b',' | b'\r' | b'\n' | b' ' => true, + _ => false, + } +} + +fn split_field<'a>(data: &mut &'a [u8]) -> &'a [u8] { + while !data.is_empty() && is_whitespace(data[0]) { + *data = &data[1..]; + } + + if data.is_empty() { + return &[]; + } + + if data[0] == b'"' { + let data2 = &data[1..]; + let end = data2.iter().position(|&x| x == b'"').unwrap_or(data2.len()); + let field = &data2[..end]; + let mut rest = &data2[data2.len().min(end + 1)..]; + if rest.first() == Some(&b'\"') { + rest = &rest[1..]; + } + while !rest.is_empty() && is_separator(rest[0]) { + rest = &rest[1..]; + } + *data = rest; + field + } else { + let end = data.iter().position(|&x| is_separator(x)).unwrap_or(data.len()); + let field = &data[0..end]; + let rest = &data[data.len().min(end + 1)..]; + *data = rest; + field + } +} + +fn pop_prefix(data: &mut &[u8], prefix: &[u8]) { + assert!(data.len() >= prefix.len()); + assert!(&data[..prefix.len()] == prefix); + *data = &data[prefix.len()..]; +} -- cgit From a6db8678eb5a7c9ebcf6449799b4ff525fe52d5f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 11:04:36 +0200 Subject: Add utility for setting configuration for a context --- examples/nrf9160/src/bin/modem_tcp_client.rs | 64 ++++++++++------------------ 1 file changed, 22 insertions(+), 42 deletions(-) (limited to 'examples') diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index b1dac18a1..817ad17c7 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -2,14 +2,15 @@ #![no_main] use core::mem::MaybeUninit; +use core::net::IpAddr; use core::ptr::addr_of_mut; use core::str::FromStr; use core::{slice, str}; -use defmt::{assert, *}; +use defmt::{assert, info, warn, unwrap}; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; -use embassy_net_nrf91::{Runner, State}; +use embassy_net_nrf91::{Runner, State, context}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; use embassy_nrf::uarte::Baudrate; @@ -63,9 +64,9 @@ async fn blink_task(pin: AnyPin) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); loop { led.set_high(); - Timer::after_millis(100).await; + Timer::after_millis(1000).await; led.set_low(); - Timer::after_millis(100).await; + Timer::after_millis(1000).await; } } @@ -123,51 +124,30 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); - control.wait_init().await; - info!("INIT OK"); + let control = context::Control::new(control, 0).await; - let mut buf = [0u8; 256]; - - let n = control.at_command(b"AT+CFUN?", &mut buf).await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); - - let n = control - .at_command(b"AT+CGDCONT=0,\"IP\",\"iot.nat.es\"", &mut buf) - .await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); - let n = control - .at_command(b"AT+CGAUTH=0,1,\"orange\",\"orange\"", &mut buf) - .await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); - - let n = control.at_command(b"AT+CFUN=1", &mut buf).await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + unwrap!(control.configure(context::Config { + gateway: "iot.nat.es", + auth_prot: context::AuthProt::Pap, + auth: Some(("orange", "orange")), + }).await); info!("waiting for attach..."); - loop { - Timer::after_millis(500).await; - let n = control.at_command(b"AT+CGATT?", &mut buf).await; - let mut res = &buf[..n]; - pop_prefix(&mut res, b"+CGATT: "); - let res = split_field(&mut res); - info!("AT resp field: '{}'", unsafe { str::from_utf8_unchecked(res) }); - if res == b"1" { - break; - } - } - let n = control.at_command(b"AT+CGPADDR=0", &mut buf).await; - let mut res = &buf[..n]; - pop_prefix(&mut res, b"+CGPADDR: 0,"); - let ip = split_field(&mut res); - let ip = Ipv4Address::from_str(unsafe { str::from_utf8_unchecked(ip) }).unwrap(); - info!("IP: '{}'", ip); + let mut status = unwrap!(control.status().await); + while !status.attached && status.ip.is_none() { + Timer::after_millis(1000).await; + status = unwrap!(control.status().await); + info!("STATUS: {:?}", status); + } - info!("============== OPENING SOCKET"); - control.open_raw_socket().await; + let Some(IpAddr::V4(addr)) = status.ip else { + panic!("Unexpected IP address"); + }; + let addr = Ipv4Address(addr.octets()); stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { - address: Ipv4Cidr::new(ip, 32), + address: Ipv4Cidr::new(addr, 32), gateway: None, dns_servers: Default::default(), })); -- cgit From b76b7ca9f5d64e83f7f69a6f7d97ba605ab2af7f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 12:58:33 +0200 Subject: Use at-commands crate and support DNS * Use at-commands for building and parsing AT commands which has better error handling. * Retrieve DNS servers * Retrieve gateway * Update example to configure embassy-net with retrieved parameters. --- examples/nrf9160/Cargo.toml | 1 + examples/nrf9160/src/bin/modem_tcp_client.rs | 78 ++++++++-------------------- 2 files changed, 22 insertions(+), 57 deletions(-) (limited to 'examples') diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index fc24e99d2..9aeb99317 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -14,6 +14,7 @@ embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defm defmt = "0.3" defmt-rtt = "0.4" +heapless = "0.8" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 817ad17c7..f80861693 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -5,9 +5,10 @@ use core::mem::MaybeUninit; use core::net::IpAddr; use core::ptr::addr_of_mut; use core::str::FromStr; -use core::{slice, str}; +use core::slice; use defmt::{assert, info, warn, unwrap}; +use heapless::Vec; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; use embassy_net_nrf91::{Runner, State, context}; @@ -146,10 +147,23 @@ async fn main(spawner: Spawner) { }; let addr = Ipv4Address(addr.octets()); + let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { + Some(Ipv4Address(addr.octets())) + } else { + None + }; + + let mut dns_servers = Vec::new(); + for dns in status.dns { + if let IpAddr::V4(ip) = dns { + unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); + } + } + stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { address: Ipv4Cidr::new(addr, 32), - gateway: None, - dns_servers: Default::default(), + gateway, + dns_servers, })); let mut rx_buffer = [0; 4096]; @@ -159,15 +173,16 @@ async fn main(spawner: Spawner) { socket.set_timeout(Some(Duration::from_secs(10))); info!("Connecting..."); - let host_addr = embassy_net::Ipv4Address::from_str("83.51.182.206").unwrap(); - if let Err(e) = socket.connect((host_addr, 8000)).await { + let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap(); + if let Err(e) = socket.connect((host_addr, 4242)).await { warn!("connect error: {:?}", e); + Timer::after_secs(1).await; continue; } info!("Connected to {:?}", socket.remote_endpoint()); let msg = b"Hello world!\n"; - loop { + for _ in 0..10 { if let Err(e) = socket.write_all(msg).await { warn!("write error: {:?}", e); break; @@ -177,54 +192,3 @@ async fn main(spawner: Spawner) { } } } - -fn is_whitespace(char: u8) -> bool { - match char { - b'\r' | b'\n' | b' ' => true, - _ => false, - } -} - -fn is_separator(char: u8) -> bool { - match char { - b',' | b'\r' | b'\n' | b' ' => true, - _ => false, - } -} - -fn split_field<'a>(data: &mut &'a [u8]) -> &'a [u8] { - while !data.is_empty() && is_whitespace(data[0]) { - *data = &data[1..]; - } - - if data.is_empty() { - return &[]; - } - - if data[0] == b'"' { - let data2 = &data[1..]; - let end = data2.iter().position(|&x| x == b'"').unwrap_or(data2.len()); - let field = &data2[..end]; - let mut rest = &data2[data2.len().min(end + 1)..]; - if rest.first() == Some(&b'\"') { - rest = &rest[1..]; - } - while !rest.is_empty() && is_separator(rest[0]) { - rest = &rest[1..]; - } - *data = rest; - field - } else { - let end = data.iter().position(|&x| is_separator(x)).unwrap_or(data.len()); - let field = &data[0..end]; - let rest = &data[data.len().min(end + 1)..]; - *data = rest; - field - } -} - -fn pop_prefix(data: &mut &[u8], prefix: &[u8]) { - assert!(data.len() >= prefix.len()); - assert!(&data[..prefix.len()] == prefix); - *data = &data[prefix.len()..]; -} -- cgit From 5e27a3e64f46340e50bc6f61e6ef5a89e9f077ab Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 13:09:27 +0200 Subject: Document public API and fix warnings --- examples/nrf9160/src/bin/modem_tcp_client.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index f80861693..55ab2a707 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -7,7 +7,7 @@ use core::ptr::addr_of_mut; use core::str::FromStr; use core::slice; -use defmt::{assert, info, warn, unwrap}; +use defmt::{info, warn, unwrap}; use heapless::Vec; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; @@ -93,7 +93,7 @@ async fn main(spawner: Spawner) { static mut TRACE_BUF: [u8; 4096] = [0u8; 4096]; let mut config = uarte::Config::default(); - config.baudrate = Baudrate::BAUD1M; + config.baudrate = Baudrate::BAUD115200; let trace_writer = TraceWriter(BufferedUarteTx::new( //let trace_uart = BufferedUarteTx::new( unsafe { peripherals::SERIAL0::steal() }, @@ -128,7 +128,7 @@ async fn main(spawner: Spawner) { let control = context::Control::new(control, 0).await; unwrap!(control.configure(context::Config { - gateway: "iot.nat.es", + apn: "iot.nat.es", auth_prot: context::AuthProt::Pap, auth: Some(("orange", "orange")), }).await); -- cgit From b4221d75b87664485977d37df28f7319143411fc Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 14:09:17 +0200 Subject: Make tracing optional and use dedicated task --- examples/nrf9160/src/bin/modem_tcp_client.rs | 58 +++++++++++++--------------- 1 file changed, 27 insertions(+), 31 deletions(-) (limited to 'examples') diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 55ab2a707..c65e6e153 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -4,20 +4,20 @@ use core::mem::MaybeUninit; use core::net::IpAddr; use core::ptr::addr_of_mut; -use core::str::FromStr; use core::slice; +use core::str::FromStr; -use defmt::{info, warn, unwrap}; -use heapless::Vec; +use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; -use embassy_net_nrf91::{Runner, State, context}; +use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; use embassy_nrf::uarte::Baudrate; use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; +use heapless::Vec; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -30,28 +30,17 @@ bind_interrupts!(struct Irqs { UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler; }); -// embassy-net-nrf91 only supports blocking trace write for now. -// We don't want to block packet processing with slow uart writes, so -// we make an adapter that writes whatever fits in the buffer and drops -// data if it's full. -struct TraceWriter(BufferedUarteTx<'static, peripherals::SERIAL0>); - -impl embedded_io::ErrorType for TraceWriter { - type Error = core::convert::Infallible; -} - -impl embedded_io::Write for TraceWriter { - fn write(&mut self, buf: &[u8]) -> Result { - let _ = self.0.try_write(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> Result<(), Self::Error> { - Ok(()) +#[embassy_executor::task] +async fn trace_task(mut uart: BufferedUarteTx<'static, peripherals::SERIAL0>, reader: TraceReader<'static>) -> ! { + let mut rx = [0u8; 1024]; + loop { + let n = reader.read(&mut rx[..]).await; + unwrap!(uart.write_all(&rx[..n]).await); } } #[embassy_executor::task] -async fn modem_task(runner: Runner<'static, TraceWriter>) -> ! { +async fn modem_task(runner: Runner<'static>) -> ! { runner.run().await } @@ -93,8 +82,8 @@ async fn main(spawner: Spawner) { static mut TRACE_BUF: [u8; 4096] = [0u8; 4096]; let mut config = uarte::Config::default(); - config.baudrate = Baudrate::BAUD115200; - let trace_writer = TraceWriter(BufferedUarteTx::new( + config.baudrate = Baudrate::BAUD1M; + let uart = BufferedUarteTx::new( //let trace_uart = BufferedUarteTx::new( unsafe { peripherals::SERIAL0::steal() }, Irqs, @@ -102,11 +91,14 @@ async fn main(spawner: Spawner) { //unsafe { peripherals::P0_14::steal() }, config, unsafe { &mut *addr_of_mut!(TRACE_BUF) }, - )); + ); static STATE: StaticCell = StaticCell::new(); - let (device, control, runner) = embassy_net_nrf91::new(STATE.init(State::new()), ipc_mem, trace_writer).await; + static TRACE: StaticCell = StaticCell::new(); + let (device, control, runner, tracer) = + embassy_net_nrf91::new_with_trace(STATE.init(State::new()), ipc_mem, TRACE.init(TraceBuffer::new())).await; unwrap!(spawner.spawn(modem_task(runner))); + unwrap!(spawner.spawn(trace_task(uart, tracer))); let config = embassy_net::Config::default(); @@ -127,11 +119,15 @@ async fn main(spawner: Spawner) { let control = context::Control::new(control, 0).await; - unwrap!(control.configure(context::Config { - apn: "iot.nat.es", - auth_prot: context::AuthProt::Pap, - auth: Some(("orange", "orange")), - }).await); + unwrap!( + control + .configure(context::Config { + apn: "iot.nat.es", + auth_prot: context::AuthProt::Pap, + auth: Some(("orange", "orange")), + }) + .await + ); info!("waiting for attach..."); -- cgit From 372e45dabc0cfd3eb495e902665bb752a67aa804 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 18:47:26 +0200 Subject: Add context run task --- examples/nrf9160/src/bin/modem_tcp_client.rs | 93 +++++++++++++++------------- 1 file changed, 50 insertions(+), 43 deletions(-) (limited to 'examples') diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index c65e6e153..a6f42eb3b 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -49,6 +49,43 @@ async fn net_task(stack: &'static Stack>) stack.run().await } +#[embassy_executor::task] +async fn control_task( + control: &'static context::Control<'static>, + config: context::Config<'static>, + stack: &'static Stack>, +) { + unwrap!( + control + .run(&config, |status| { + let Some(IpAddr::V4(addr)) = status.ip else { + panic!("Unexpected IP address"); + }; + let addr = Ipv4Address(addr.octets()); + + let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { + Some(Ipv4Address(addr.octets())) + } else { + None + }; + + let mut dns_servers = Vec::new(); + for dns in status.dns.iter() { + if let IpAddr::V4(ip) = dns { + unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); + } + } + + stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { + address: Ipv4Cidr::new(addr, 32), + gateway, + dns_servers, + })); + }) + .await + ); +} + #[embassy_executor::task] async fn blink_task(pin: AnyPin) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); @@ -117,50 +154,20 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); - let control = context::Control::new(control, 0).await; + static CONTROL: StaticCell> = StaticCell::new(); + let control = CONTROL.init(context::Control::new(control, 0).await); - unwrap!( - control - .configure(context::Config { - apn: "iot.nat.es", - auth_prot: context::AuthProt::Pap, - auth: Some(("orange", "orange")), - }) - .await - ); + unwrap!(spawner.spawn(control_task( + control, + context::Config { + apn: "iot.nat.es", + auth_prot: context::AuthProt::Pap, + auth: Some(("orange", "orange")), + }, + stack + ))); - info!("waiting for attach..."); - - let mut status = unwrap!(control.status().await); - while !status.attached && status.ip.is_none() { - Timer::after_millis(1000).await; - status = unwrap!(control.status().await); - info!("STATUS: {:?}", status); - } - - let Some(IpAddr::V4(addr)) = status.ip else { - panic!("Unexpected IP address"); - }; - let addr = Ipv4Address(addr.octets()); - - let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { - Some(Ipv4Address(addr.octets())) - } else { - None - }; - - let mut dns_servers = Vec::new(); - for dns in status.dns { - if let IpAddr::V4(ip) = dns { - unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); - } - } - - stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { - address: Ipv4Cidr::new(addr, 32), - gateway, - dns_servers, - })); + stack.wait_config_up().await; let mut rx_buffer = [0; 4096]; let mut tx_buffer = [0; 4096]; @@ -172,7 +179,7 @@ async fn main(spawner: Spawner) { let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap(); if let Err(e) = socket.connect((host_addr, 4242)).await { warn!("connect error: {:?}", e); - Timer::after_secs(1).await; + Timer::after_secs(10).await; continue; } info!("Connected to {:?}", socket.remote_endpoint()); -- cgit From ccfa6264b0ad258625f2dd667ba8e6eaca1cfdc3 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 19:31:55 +0200 Subject: Add closing if raw socket to handle re-attach --- examples/nrf9160/src/bin/modem_tcp_client.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'examples') diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index a6f42eb3b..fb14b746f 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -193,5 +193,7 @@ async fn main(spawner: Spawner) { info!("txd: {}", core::str::from_utf8(msg).unwrap()); Timer::after_secs(1).await; } + // Test auto-attach + unwrap!(control.detach().await); } } -- cgit From 836e8add1bcb09c476a3aa3d7a416a15b8c21e6a Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 5 Sep 2024 10:02:45 +0200 Subject: Mintor fixes after testing re-attach --- examples/nrf9160/src/bin/modem_tcp_client.rs | 54 +++++++++++++++------------- 1 file changed, 29 insertions(+), 25 deletions(-) (limited to 'examples') diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index fb14b746f..b7d56802d 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -10,6 +10,7 @@ use core::str::FromStr; use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net_nrf91::context::Status; use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; @@ -58,34 +59,38 @@ async fn control_task( unwrap!( control .run(&config, |status| { - let Some(IpAddr::V4(addr)) = status.ip else { - panic!("Unexpected IP address"); - }; - let addr = Ipv4Address(addr.octets()); - - let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { - Some(Ipv4Address(addr.octets())) - } else { - None - }; - - let mut dns_servers = Vec::new(); - for dns in status.dns.iter() { - if let IpAddr::V4(ip) = dns { - unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); - } - } - - stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { - address: Ipv4Cidr::new(addr, 32), - gateway, - dns_servers, - })); + stack.set_config_v4(status_to_config(status)); }) .await ); } +fn status_to_config(status: &Status) -> embassy_net::ConfigV4 { + let Some(IpAddr::V4(addr)) = status.ip else { + panic!("Unexpected IP address"); + }; + let addr = Ipv4Address(addr.octets()); + + let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { + Some(Ipv4Address(addr.octets())) + } else { + None + }; + + let mut dns_servers = Vec::new(); + for dns in status.dns.iter() { + if let IpAddr::V4(ip) = dns { + unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); + } + } + + embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { + address: Ipv4Cidr::new(addr, 32), + gateway, + dns_servers, + }) +} + #[embassy_executor::task] async fn blink_task(pin: AnyPin) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); @@ -193,7 +198,6 @@ async fn main(spawner: Spawner) { info!("txd: {}", core::str::from_utf8(msg).unwrap()); Timer::after_secs(1).await; } - // Test auto-attach - unwrap!(control.detach().await); + Timer::after_secs(4).await; } } -- cgit From 5d0ed246400b1e7973c1fe870dba977ab7186a21 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 5 Sep 2024 10:31:51 +0200 Subject: Move configure out of run --- examples/nrf9160/src/bin/modem_tcp_client.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index b7d56802d..7d78eba0a 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -56,9 +56,10 @@ async fn control_task( config: context::Config<'static>, stack: &'static Stack>, ) { + unwrap!(control.configure(&config).await); unwrap!( control - .run(&config, |status| { + .run(|status| { stack.set_config_v4(status_to_config(status)); }) .await -- cgit From 1b1db2401bfdfe6f813fb7738529749e4ec80882 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 6 Sep 2024 11:22:07 +0200 Subject: Use byte slice for config --- examples/nrf9160/src/bin/modem_tcp_client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 7d78eba0a..5335b6b51 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -166,9 +166,9 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(control_task( control, context::Config { - apn: "iot.nat.es", + apn: b"iot.nat.es", auth_prot: context::AuthProt::Pap, - auth: Some(("orange", "orange")), + auth: Some((b"orange", b"orange")), }, stack ))); -- cgit