aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xci.sh5
-rw-r--r--docs/pages/bootloader.adoc2
-rw-r--r--embassy-boot/Cargo.toml1
-rw-r--r--embassy-boot/src/firmware_updater/asynch.rs12
-rw-r--r--embassy-boot/src/firmware_updater/blocking.rs12
-rw-r--r--embassy-boot/src/lib.rs4
-rw-r--r--embassy-net/Cargo.toml10
-rw-r--r--embassy-net/README.md3
-rw-r--r--embassy-net/src/dns.rs25
-rw-r--r--embassy-net/src/driver_util.rs (renamed from embassy-net/src/device.rs)2
-rw-r--r--embassy-net/src/lib.rs445
-rw-r--r--embassy-net/src/raw.rs53
-rw-r--r--embassy-net/src/tcp.rs76
-rw-r--r--embassy-net/src/udp.rs63
-rw-r--r--embassy-rp/src/gpio.rs24
-rw-r--r--embassy-rp/src/uart/mod.rs11
-rw-r--r--embassy-stm32/src/usb/usb.rs211
-rw-r--r--embassy-usb-synopsys-otg/src/lib.rs30
-rw-r--r--embassy-usb-synopsys-otg/src/otg_v1.rs16
-rw-r--r--embassy-usb/src/builder.rs140
-rw-r--r--embassy-usb/src/descriptor.rs91
-rw-r--r--examples/nrf52840/src/bin/ethernet_enc28j60.rs14
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs11
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs11
-rw-r--r--examples/nrf9160/src/bin/modem_tcp_client.rs16
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs19
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs13
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs13
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs13
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs11
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs18
-rw-r--r--examples/rp/src/bin/wifi_scan.rs5
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs18
-rw-r--r--examples/rp/src/bin/wifi_webrequest.rs18
-rw-r--r--examples/std/src/bin/net.rs11
-rw-r--r--examples/std/src/bin/net_dns.rs11
-rw-r--r--examples/std/src/bin/net_ppp.rs17
-rw-r--r--examples/std/src/bin/net_udp.rs11
-rw-r--r--examples/std/src/bin/tcp_accept.rs11
-rw-r--r--examples/stm32f4/src/bin/eth.rs13
-rw-r--r--examples/stm32f4/src/bin/eth_w5500.rs11
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs11
-rw-r--r--examples/stm32f7/src/bin/eth.rs13
-rw-r--r--examples/stm32h5/src/bin/eth.rs13
-rw-r--r--examples/stm32h7/src/bin/eth.rs13
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs13
-rw-r--r--examples/stm32h7/src/bin/eth_client_mii.rs13
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs11
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs11
-rw-r--r--tests/nrf/src/bin/ethernet_enc28j60_perf.rs11
-rw-r--r--tests/nrf/src/bin/wifi_esp_hosted_perf.rs13
-rw-r--r--tests/perf-client/src/lib.rs9
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs13
-rw-r--r--tests/rp/src/bin/ethernet_w5100s_perf.rs13
-rw-r--r--tests/stm32/src/bin/eth.rs11
55 files changed, 988 insertions, 681 deletions
diff --git a/ci.sh b/ci.sh
index 8fef731a4..50331bdba 100755
--- a/ci.sh
+++ b/ci.sh
@@ -47,7 +47,7 @@ cargo batch \
47 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ 47 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \
48 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,generic-queue-8,mock-driver \ 48 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,generic-queue-8,mock-driver \
49 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ 49 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \
50 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,igmp,medium-ethernet \ 50 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \
51 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ 51 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
52 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,dhcpv4-hostname \ 52 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,dhcpv4-hostname \
53 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \ 53 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
@@ -290,8 +290,9 @@ cargo batch \
290 $BUILD_EXTRA 290 $BUILD_EXTRA
291 291
292 292
293# temporarily disabled, bluepill board got bricked 293# temporarily disabled, these boards are dead.
294rm -rf out/tests/stm32f103c8 294rm -rf out/tests/stm32f103c8
295rm -rf out/tests/nrf52840-dk
295 296
296rm out/tests/stm32wb55rg/wpan_mac 297rm out/tests/stm32wb55rg/wpan_mac
297rm out/tests/stm32wb55rg/wpan_ble 298rm out/tests/stm32wb55rg/wpan_ble
diff --git a/docs/pages/bootloader.adoc b/docs/pages/bootloader.adoc
index 3b0cdb182..d8d50040b 100644
--- a/docs/pages/bootloader.adoc
+++ b/docs/pages/bootloader.adoc
@@ -19,6 +19,8 @@ The bootloader supports
19 19
20In general, the bootloader works on any platform that implements the `embedded-storage` traits for its internal flash, but may require custom initialization code to work. 20In general, the bootloader works on any platform that implements the `embedded-storage` traits for its internal flash, but may require custom initialization code to work.
21 21
22STM32L0x1 devices require the `flash-erase-zero` feature to be enabled.
23
22== Design 24== Design
23 25
24image::bootloader_flash.png[Bootloader flash layout] 26image::bootloader_flash.png[Bootloader flash layout]
diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml
index d27fe763e..79ba6456a 100644
--- a/embassy-boot/Cargo.toml
+++ b/embassy-boot/Cargo.toml
@@ -47,6 +47,7 @@ ed25519-dalek = { version = "2", default-features = false, features = ["std", "r
47[features] 47[features]
48ed25519-dalek = ["dep:ed25519-dalek", "_verify"] 48ed25519-dalek = ["dep:ed25519-dalek", "_verify"]
49ed25519-salty = ["dep:salty", "_verify"] 49ed25519-salty = ["dep:salty", "_verify"]
50flash-erase-zero = []
50 51
51#Internal features 52#Internal features
52_verify = [] 53_verify = []
diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs
index 26f65f295..86b441592 100644
--- a/embassy-boot/src/firmware_updater/asynch.rs
+++ b/embassy-boot/src/firmware_updater/asynch.rs
@@ -107,7 +107,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
107 let mut message = [0; 64]; 107 let mut message = [0; 64];
108 self.hash::<Sha512>(_update_len, &mut chunk_buf, &mut message).await?; 108 self.hash::<Sha512>(_update_len, &mut chunk_buf, &mut message).await?;
109 109
110 public_key.verify(&message, &signature).map_err(into_signature_error)? 110 public_key.verify(&message, &signature).map_err(into_signature_error)?;
111 return self.state.mark_updated().await;
111 } 112 }
112 #[cfg(feature = "ed25519-salty")] 113 #[cfg(feature = "ed25519-salty")]
113 { 114 {
@@ -134,10 +135,13 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
134 message, 135 message,
135 r.is_ok() 136 r.is_ok()
136 ); 137 );
137 r.map_err(into_signature_error)? 138 r.map_err(into_signature_error)?;
139 return self.state.mark_updated().await;
140 }
141 #[cfg(not(any(feature = "ed25519-dalek", feature = "ed25519-salty")))]
142 {
143 Err(FirmwareUpdaterError::Signature(signature::Error::new()))
138 } 144 }
139
140 self.state.mark_updated().await
141 } 145 }
142 146
143 /// Verify the update in DFU with any digest. 147 /// Verify the update in DFU with any digest.
diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs
index 35772a856..d3c723456 100644
--- a/embassy-boot/src/firmware_updater/blocking.rs
+++ b/embassy-boot/src/firmware_updater/blocking.rs
@@ -142,7 +142,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
142 let mut chunk_buf = [0; 2]; 142 let mut chunk_buf = [0; 2];
143 self.hash::<Sha512>(_update_len, &mut chunk_buf, &mut message)?; 143 self.hash::<Sha512>(_update_len, &mut chunk_buf, &mut message)?;
144 144
145 public_key.verify(&message, &signature).map_err(into_signature_error)? 145 public_key.verify(&message, &signature).map_err(into_signature_error)?;
146 return self.state.mark_updated();
146 } 147 }
147 #[cfg(feature = "ed25519-salty")] 148 #[cfg(feature = "ed25519-salty")]
148 { 149 {
@@ -169,10 +170,13 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
169 message, 170 message,
170 r.is_ok() 171 r.is_ok()
171 ); 172 );
172 r.map_err(into_signature_error)? 173 r.map_err(into_signature_error)?;
174 return self.state.mark_updated();
175 }
176 #[cfg(not(any(feature = "ed25519-dalek", feature = "ed25519-salty")))]
177 {
178 Err(FirmwareUpdaterError::Signature(signature::Error::new()))
173 } 179 }
174
175 self.state.mark_updated()
176 } 180 }
177 181
178 /// Verify the update in DFU with any digest. 182 /// Verify the update in DFU with any digest.
diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs
index b4f03e01e..8849055e8 100644
--- a/embassy-boot/src/lib.rs
+++ b/embassy-boot/src/lib.rs
@@ -14,7 +14,11 @@ mod test_flash;
14 14
15// The expected value of the flash after an erase 15// The expected value of the flash after an erase
16// TODO: Use the value provided by NorFlash when available 16// TODO: Use the value provided by NorFlash when available
17#[cfg(not(feature = "flash-erase-zero"))]
17pub(crate) const STATE_ERASE_VALUE: u8 = 0xFF; 18pub(crate) const STATE_ERASE_VALUE: u8 = 0xFF;
19#[cfg(feature = "flash-erase-zero")]
20pub(crate) const STATE_ERASE_VALUE: u8 = 0x00;
21
18pub use boot_loader::{BootError, BootLoader, BootLoaderConfig}; 22pub use boot_loader::{BootError, BootLoader, BootLoaderConfig};
19pub use firmware_updater::{ 23pub use firmware_updater::{
20 BlockingFirmwareState, BlockingFirmwareUpdater, FirmwareState, FirmwareUpdater, FirmwareUpdaterConfig, 24 BlockingFirmwareState, BlockingFirmwareUpdater, FirmwareState, FirmwareUpdater, FirmwareUpdaterConfig,
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 28bac485b..2e21b4231 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -16,11 +16,11 @@ categories = [
16[package.metadata.embassy_docs] 16[package.metadata.embassy_docs]
17src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" 17src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/"
18src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" 18src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/"
19features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] 19features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"]
20target = "thumbv7em-none-eabi" 20target = "thumbv7em-none-eabi"
21 21
22[package.metadata.docs.rs] 22[package.metadata.docs.rs]
23features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] 23features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"]
24 24
25[features] 25[features]
26default = [] 26default = []
@@ -60,15 +60,15 @@ medium-ethernet = ["smoltcp/medium-ethernet"]
60medium-ip = ["smoltcp/medium-ip"] 60medium-ip = ["smoltcp/medium-ip"]
61## Enable the IEEE 802.15.4 medium 61## Enable the IEEE 802.15.4 medium
62medium-ieee802154 = ["smoltcp/medium-ieee802154"] 62medium-ieee802154 = ["smoltcp/medium-ieee802154"]
63## Enable IGMP support 63## Enable multicast support (for both ipv4 and/or ipv6 if enabled)
64igmp = ["smoltcp/proto-igmp"] 64multicast = ["smoltcp/multicast"]
65 65
66[dependencies] 66[dependencies]
67 67
68defmt = { version = "0.3", optional = true } 68defmt = { version = "0.3", optional = true }
69log = { version = "0.4.14", optional = true } 69log = { version = "0.4.14", optional = true }
70 70
71smoltcp = { version = "0.11.0", default-features = false, features = [ 71smoltcp = { git="https://github.com/smoltcp-rs/smoltcp", rev="dd43c8f189178b0ab3bda798ed8578b5b0a6f094", default-features = false, features = [
72 "socket", 72 "socket",
73 "async", 73 "async",
74] } 74] }
diff --git a/embassy-net/README.md b/embassy-net/README.md
index 6b7d46934..1722ffc7b 100644
--- a/embassy-net/README.md
+++ b/embassy-net/README.md
@@ -10,8 +10,9 @@ memory management designed to work well for embedded systems, aiming for a more
10 10
11- IPv4, IPv6 11- IPv4, IPv6
12- Ethernet and bare-IP mediums. 12- Ethernet and bare-IP mediums.
13- TCP, UDP, DNS, DHCPv4, IGMPv4 13- TCP, UDP, DNS, DHCPv4
14- TCP sockets implement the `embedded-io` async traits. 14- TCP sockets implement the `embedded-io` async traits.
15- Multicast
15 16
16See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and 17See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and
17unimplemented features of the network protocols. 18unimplemented features of the network protocols.
diff --git a/embassy-net/src/dns.rs b/embassy-net/src/dns.rs
index 8ccfa4e4f..1fbaea4f0 100644
--- a/embassy-net/src/dns.rs
+++ b/embassy-net/src/dns.rs
@@ -9,7 +9,7 @@ pub use smoltcp::socket::dns::{DnsQuery, Socket};
9pub(crate) use smoltcp::socket::dns::{GetQueryResultError, StartQueryError}; 9pub(crate) use smoltcp::socket::dns::{GetQueryResultError, StartQueryError};
10pub use smoltcp::wire::{DnsQueryType, IpAddress}; 10pub use smoltcp::wire::{DnsQueryType, IpAddress};
11 11
12use crate::{Driver, Stack}; 12use crate::Stack;
13 13
14/// Errors returned by DnsSocket. 14/// Errors returned by DnsSocket.
15#[derive(Debug, PartialEq, Eq, Clone, Copy)] 15#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -44,21 +44,15 @@ impl From<StartQueryError> for Error {
44/// This exists only for compatibility with crates that use `embedded-nal-async`. 44/// This exists only for compatibility with crates that use `embedded-nal-async`.
45/// Prefer using [`Stack::dns_query`](crate::Stack::dns_query) directly if you're 45/// Prefer using [`Stack::dns_query`](crate::Stack::dns_query) directly if you're
46/// not using `embedded-nal-async`. 46/// not using `embedded-nal-async`.
47pub struct DnsSocket<'a, D> 47pub struct DnsSocket<'a> {
48where 48 stack: Stack<'a>,
49 D: Driver + 'static,
50{
51 stack: &'a Stack<D>,
52} 49}
53 50
54impl<'a, D> DnsSocket<'a, D> 51impl<'a> DnsSocket<'a> {
55where
56 D: Driver + 'static,
57{
58 /// Create a new DNS socket using the provided stack. 52 /// Create a new DNS socket using the provided stack.
59 /// 53 ///
60 /// NOTE: If using DHCP, make sure it has reconfigured the stack to ensure the DNS servers are updated. 54 /// NOTE: If using DHCP, make sure it has reconfigured the stack to ensure the DNS servers are updated.
61 pub fn new(stack: &'a Stack<D>) -> Self { 55 pub fn new(stack: Stack<'a>) -> Self {
62 Self { stack } 56 Self { stack }
63 } 57 }
64 58
@@ -72,10 +66,7 @@ where
72 } 66 }
73} 67}
74 68
75impl<'a, D> embedded_nal_async::Dns for DnsSocket<'a, D> 69impl<'a> embedded_nal_async::Dns for DnsSocket<'a> {
76where
77 D: Driver + 'static,
78{
79 type Error = Error; 70 type Error = Error;
80 71
81 async fn get_host_by_name( 72 async fn get_host_by_name(
@@ -124,3 +115,7 @@ where
124 todo!() 115 todo!()
125 } 116 }
126} 117}
118
119fn _assert_covariant<'a, 'b: 'a>(x: DnsSocket<'b>) -> DnsSocket<'a> {
120 x
121}
diff --git a/embassy-net/src/device.rs b/embassy-net/src/driver_util.rs
index 3b1d3c47c..b2af1d499 100644
--- a/embassy-net/src/device.rs
+++ b/embassy-net/src/driver_util.rs
@@ -74,7 +74,7 @@ where
74{ 74{
75 fn consume<R, F>(self, f: F) -> R 75 fn consume<R, F>(self, f: F) -> R
76 where 76 where
77 F: FnOnce(&mut [u8]) -> R, 77 F: FnOnce(&[u8]) -> R,
78 { 78 {
79 self.0.consume(|buf| { 79 self.0.consume(|buf| {
80 #[cfg(feature = "packet-trace")] 80 #[cfg(feature = "packet-trace")]
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 56321cec9..ef53fb905 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -12,9 +12,9 @@ compile_error!("You must enable at least one of the following features: proto-ip
12// This mod MUST go first, so that the others see its macros. 12// This mod MUST go first, so that the others see its macros.
13pub(crate) mod fmt; 13pub(crate) mod fmt;
14 14
15mod device;
16#[cfg(feature = "dns")] 15#[cfg(feature = "dns")]
17pub mod dns; 16pub mod dns;
17mod driver_util;
18#[cfg(feature = "raw")] 18#[cfg(feature = "raw")]
19pub mod raw; 19pub mod raw;
20#[cfg(feature = "tcp")] 20#[cfg(feature = "tcp")]
@@ -25,6 +25,7 @@ pub mod udp;
25 25
26use core::cell::RefCell; 26use core::cell::RefCell;
27use core::future::{poll_fn, Future}; 27use core::future::{poll_fn, Future};
28use core::mem::MaybeUninit;
28use core::pin::pin; 29use core::pin::pin;
29use core::task::{Context, Poll}; 30use core::task::{Context, Poll};
30 31
@@ -36,7 +37,7 @@ use embassy_time::{Instant, Timer};
36use heapless::Vec; 37use heapless::Vec;
37#[cfg(feature = "dns")] 38#[cfg(feature = "dns")]
38pub use smoltcp::config::DNS_MAX_SERVER_COUNT; 39pub use smoltcp::config::DNS_MAX_SERVER_COUNT;
39#[cfg(feature = "igmp")] 40#[cfg(feature = "multicast")]
40pub use smoltcp::iface::MulticastError; 41pub use smoltcp::iface::MulticastError;
41#[allow(unused_imports)] 42#[allow(unused_imports)]
42use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage}; 43use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage};
@@ -57,7 +58,7 @@ pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr};
57#[cfg(feature = "proto-ipv6")] 58#[cfg(feature = "proto-ipv6")]
58pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; 59pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr};
59 60
60use crate::device::DriverAdapter; 61use crate::driver_util::DriverAdapter;
61use crate::time::{instant_from_smoltcp, instant_to_smoltcp}; 62use crate::time::{instant_from_smoltcp, instant_to_smoltcp};
62 63
63const LOCAL_PORT_MIN: u16 = 1025; 64const LOCAL_PORT_MIN: u16 = 1025;
@@ -69,33 +70,33 @@ const MAX_HOSTNAME_LEN: usize = 32;
69 70
70/// Memory resources needed for a network stack. 71/// Memory resources needed for a network stack.
71pub struct StackResources<const SOCK: usize> { 72pub struct StackResources<const SOCK: usize> {
72 sockets: [SocketStorage<'static>; SOCK], 73 sockets: MaybeUninit<[SocketStorage<'static>; SOCK]>,
74 inner: MaybeUninit<RefCell<Inner>>,
73 #[cfg(feature = "dns")] 75 #[cfg(feature = "dns")]
74 queries: [Option<dns::DnsQuery>; MAX_QUERIES], 76 queries: MaybeUninit<[Option<dns::DnsQuery>; MAX_QUERIES]>,
75 #[cfg(feature = "dhcpv4-hostname")] 77 #[cfg(feature = "dhcpv4-hostname")]
76 hostname: core::cell::UnsafeCell<HostnameResources>, 78 hostname: HostnameResources,
77} 79}
78 80
79#[cfg(feature = "dhcpv4-hostname")] 81#[cfg(feature = "dhcpv4-hostname")]
80struct HostnameResources { 82struct HostnameResources {
81 option: smoltcp::wire::DhcpOption<'static>, 83 option: MaybeUninit<smoltcp::wire::DhcpOption<'static>>,
82 data: [u8; MAX_HOSTNAME_LEN], 84 data: MaybeUninit<[u8; MAX_HOSTNAME_LEN]>,
83} 85}
84 86
85impl<const SOCK: usize> StackResources<SOCK> { 87impl<const SOCK: usize> StackResources<SOCK> {
86 /// Create a new set of stack resources. 88 /// Create a new set of stack resources.
87 pub const fn new() -> Self { 89 pub const fn new() -> Self {
88 #[cfg(feature = "dns")]
89 const INIT: Option<dns::DnsQuery> = None;
90 Self { 90 Self {
91 sockets: [SocketStorage::EMPTY; SOCK], 91 sockets: MaybeUninit::uninit(),
92 inner: MaybeUninit::uninit(),
92 #[cfg(feature = "dns")] 93 #[cfg(feature = "dns")]
93 queries: [INIT; MAX_QUERIES], 94 queries: MaybeUninit::uninit(),
94 #[cfg(feature = "dhcpv4-hostname")] 95 #[cfg(feature = "dhcpv4-hostname")]
95 hostname: core::cell::UnsafeCell::new(HostnameResources { 96 hostname: HostnameResources {
96 option: smoltcp::wire::DhcpOption { kind: 0, data: &[] }, 97 option: MaybeUninit::uninit(),
97 data: [0; MAX_HOSTNAME_LEN], 98 data: MaybeUninit::uninit(),
98 }), 99 },
99 } 100 }
100 } 101 }
101} 102}
@@ -239,16 +240,29 @@ pub enum ConfigV6 {
239 Static(StaticConfigV6), 240 Static(StaticConfigV6),
240} 241}
241 242
242/// A network stack. 243/// Network stack runner.
244///
245/// You must call [`Runner::run()`] in a background task for the network stack to work.
246pub struct Runner<'d, D: Driver> {
247 driver: D,
248 stack: Stack<'d>,
249}
250
251/// Network stack handle
243/// 252///
244/// This is the main entry point for the network stack. 253/// Use this to create sockets. It's `Copy`, so you can pass
245pub struct Stack<D: Driver> { 254/// it by value instead of by reference.
246 pub(crate) socket: RefCell<SocketStack>, 255#[derive(Copy, Clone)]
247 inner: RefCell<Inner<D>>, 256pub struct Stack<'d> {
257 inner: &'d RefCell<Inner>,
248} 258}
249 259
250struct Inner<D: Driver> { 260pub(crate) struct Inner {
251 device: D, 261 pub(crate) sockets: SocketSet<'static>, // Lifetime type-erased.
262 pub(crate) iface: Interface,
263 pub(crate) waker: WakerRegistration,
264 hardware_address: HardwareAddress,
265 next_local_port: u16,
252 link_up: bool, 266 link_up: bool,
253 #[cfg(feature = "proto-ipv4")] 267 #[cfg(feature = "proto-ipv4")]
254 static_v4: Option<StaticConfigV4>, 268 static_v4: Option<StaticConfigV4>,
@@ -262,14 +276,83 @@ struct Inner<D: Driver> {
262 #[cfg(feature = "dns")] 276 #[cfg(feature = "dns")]
263 dns_waker: WakerRegistration, 277 dns_waker: WakerRegistration,
264 #[cfg(feature = "dhcpv4-hostname")] 278 #[cfg(feature = "dhcpv4-hostname")]
265 hostname: &'static mut core::cell::UnsafeCell<HostnameResources>, 279 hostname: *mut HostnameResources,
266} 280}
267 281
268pub(crate) struct SocketStack { 282fn _assert_covariant<'a, 'b: 'a>(x: Stack<'b>) -> Stack<'a> {
269 pub(crate) sockets: SocketSet<'static>, 283 x
270 pub(crate) iface: Interface, 284}
271 pub(crate) waker: WakerRegistration, 285
272 next_local_port: u16, 286/// Create a new network stack.
287pub fn new<'d, D: Driver, const SOCK: usize>(
288 mut driver: D,
289 config: Config,
290 resources: &'d mut StackResources<SOCK>,
291 random_seed: u64,
292) -> (Stack<'d>, Runner<'d, D>) {
293 let (hardware_address, medium) = to_smoltcp_hardware_address(driver.hardware_address());
294 let mut iface_cfg = smoltcp::iface::Config::new(hardware_address);
295 iface_cfg.random_seed = random_seed;
296
297 let iface = Interface::new(
298 iface_cfg,
299 &mut DriverAdapter {
300 inner: &mut driver,
301 cx: None,
302 medium,
303 },
304 instant_to_smoltcp(Instant::now()),
305 );
306
307 unsafe fn transmute_slice<T>(x: &mut [T]) -> &'static mut [T] {
308 core::mem::transmute(x)
309 }
310
311 let sockets = resources.sockets.write([SocketStorage::EMPTY; SOCK]);
312 #[allow(unused_mut)]
313 let mut sockets: SocketSet<'static> = SocketSet::new(unsafe { transmute_slice(sockets) });
314
315 let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN;
316
317 #[cfg(feature = "dns")]
318 let dns_socket = sockets.add(dns::Socket::new(
319 &[],
320 managed::ManagedSlice::Borrowed(unsafe {
321 transmute_slice(resources.queries.write([const { None }; MAX_QUERIES]))
322 }),
323 ));
324
325 let mut inner = Inner {
326 sockets,
327 iface,
328 waker: WakerRegistration::new(),
329 next_local_port,
330 hardware_address,
331 link_up: false,
332 #[cfg(feature = "proto-ipv4")]
333 static_v4: None,
334 #[cfg(feature = "proto-ipv6")]
335 static_v6: None,
336 #[cfg(feature = "dhcpv4")]
337 dhcp_socket: None,
338 config_waker: WakerRegistration::new(),
339 #[cfg(feature = "dns")]
340 dns_socket,
341 #[cfg(feature = "dns")]
342 dns_waker: WakerRegistration::new(),
343 #[cfg(feature = "dhcpv4-hostname")]
344 hostname: &mut resources.hostname,
345 };
346
347 #[cfg(feature = "proto-ipv4")]
348 inner.set_config_v4(config.ipv4);
349 #[cfg(feature = "proto-ipv6")]
350 inner.set_config_v6(config.ipv6);
351 inner.apply_static_config();
352
353 let inner = &*resources.inner.write(RefCell::new(inner));
354 let stack = Stack { inner };
355 (stack, Runner { driver, stack })
273} 356}
274 357
275fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddress, Medium) { 358fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddress, Medium) {
@@ -292,89 +375,23 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddres
292 } 375 }
293} 376}
294 377
295impl<D: Driver> Stack<D> { 378impl<'d> Stack<'d> {
296 /// Create a new network stack. 379 fn with<R>(&self, f: impl FnOnce(&Inner) -> R) -> R {
297 pub fn new<const SOCK: usize>( 380 f(&*self.inner.borrow())
298 mut device: D,
299 config: Config,
300 resources: &'static mut StackResources<SOCK>,
301 random_seed: u64,
302 ) -> Self {
303 let (hardware_addr, medium) = to_smoltcp_hardware_address(device.hardware_address());
304 let mut iface_cfg = smoltcp::iface::Config::new(hardware_addr);
305 iface_cfg.random_seed = random_seed;
306
307 let iface = Interface::new(
308 iface_cfg,
309 &mut DriverAdapter {
310 inner: &mut device,
311 cx: None,
312 medium,
313 },
314 instant_to_smoltcp(Instant::now()),
315 );
316
317 let sockets = SocketSet::new(&mut resources.sockets[..]);
318
319 let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN;
320
321 #[cfg_attr(feature = "medium-ieee802154", allow(unused_mut))]
322 let mut socket = SocketStack {
323 sockets,
324 iface,
325 waker: WakerRegistration::new(),
326 next_local_port,
327 };
328
329 let mut inner = Inner {
330 device,
331 link_up: false,
332 #[cfg(feature = "proto-ipv4")]
333 static_v4: None,
334 #[cfg(feature = "proto-ipv6")]
335 static_v6: None,
336 #[cfg(feature = "dhcpv4")]
337 dhcp_socket: None,
338 config_waker: WakerRegistration::new(),
339 #[cfg(feature = "dns")]
340 dns_socket: socket.sockets.add(dns::Socket::new(
341 &[],
342 managed::ManagedSlice::Borrowed(&mut resources.queries),
343 )),
344 #[cfg(feature = "dns")]
345 dns_waker: WakerRegistration::new(),
346 #[cfg(feature = "dhcpv4-hostname")]
347 hostname: &mut resources.hostname,
348 };
349
350 #[cfg(feature = "proto-ipv4")]
351 inner.set_config_v4(&mut socket, config.ipv4);
352 #[cfg(feature = "proto-ipv6")]
353 inner.set_config_v6(&mut socket, config.ipv6);
354 inner.apply_static_config(&mut socket);
355
356 Self {
357 socket: RefCell::new(socket),
358 inner: RefCell::new(inner),
359 }
360 }
361
362 fn with<R>(&self, f: impl FnOnce(&SocketStack, &Inner<D>) -> R) -> R {
363 f(&*self.socket.borrow(), &*self.inner.borrow())
364 } 381 }
365 382
366 fn with_mut<R>(&self, f: impl FnOnce(&mut SocketStack, &mut Inner<D>) -> R) -> R { 383 fn with_mut<R>(&self, f: impl FnOnce(&mut Inner) -> R) -> R {
367 f(&mut *self.socket.borrow_mut(), &mut *self.inner.borrow_mut()) 384 f(&mut *self.inner.borrow_mut())
368 } 385 }
369 386
370 /// Get the hardware address of the network interface. 387 /// Get the hardware address of the network interface.
371 pub fn hardware_address(&self) -> HardwareAddress { 388 pub fn hardware_address(&self) -> HardwareAddress {
372 self.with(|_s, i| to_smoltcp_hardware_address(i.device.hardware_address()).0) 389 self.with(|i| i.hardware_address)
373 } 390 }
374 391
375 /// Get whether the link is up. 392 /// Get whether the link is up.
376 pub fn is_link_up(&self) -> bool { 393 pub fn is_link_up(&self) -> bool {
377 self.with(|_s, i| i.link_up) 394 self.with(|i| i.link_up)
378 } 395 }
379 396
380 /// Get whether the network stack has a valid IP configuration. 397 /// Get whether the network stack has a valid IP configuration.
@@ -420,15 +437,14 @@ impl<D: Driver> Stack<D> {
420 /// // provisioning space for 3 sockets here: one for DHCP, one for DNS, and one for your code (e.g. TCP). 437 /// // provisioning space for 3 sockets here: one for DHCP, one for DNS, and one for your code (e.g. TCP).
421 /// // If you use more sockets you must increase this. If you don't enable DHCP or DNS you can decrease it. 438 /// // If you use more sockets you must increase this. If you don't enable DHCP or DNS you can decrease it.
422 /// static RESOURCES: StaticCell<embassy_net::StackResources<3>> = StaticCell::new(); 439 /// static RESOURCES: StaticCell<embassy_net::StackResources<3>> = StaticCell::new();
423 /// static STACK: StaticCell<embassy_net::Stack> = StaticCell::new(); 440 /// let (stack, runner) = embassy_net::new(
424 /// let stack = &*STACK.init(embassy_net::Stack::new( 441 /// driver,
425 /// device,
426 /// config, 442 /// config,
427 /// RESOURCES.init(embassy_net::StackResources::new()), 443 /// RESOURCES.init(embassy_net::StackResources::new()),
428 /// seed 444 /// seed
429 /// )); 445 /// );
430 /// // Launch network task that runs `stack.run().await` 446 /// // Launch network task that runs `runner.run().await`
431 /// spawner.spawn(net_task(stack)).unwrap(); 447 /// spawner.spawn(net_task(runner)).unwrap();
432 /// // Wait for DHCP config 448 /// // Wait for DHCP config
433 /// stack.wait_config_up().await; 449 /// stack.wait_config_up().await;
434 /// // use the network stack 450 /// // use the network stack
@@ -448,7 +464,7 @@ impl<D: Driver> Stack<D> {
448 // when a config is applied (static or DHCP). 464 // when a config is applied (static or DHCP).
449 trace!("Waiting for config up"); 465 trace!("Waiting for config up");
450 466
451 self.with_mut(|_, i| { 467 self.with_mut(|i| {
452 i.config_waker.register(cx.waker()); 468 i.config_waker.register(cx.waker());
453 }); 469 });
454 470
@@ -464,45 +480,33 @@ impl<D: Driver> Stack<D> {
464 /// acquire an IP address, or Some if it has. 480 /// acquire an IP address, or Some if it has.
465 #[cfg(feature = "proto-ipv4")] 481 #[cfg(feature = "proto-ipv4")]
466 pub fn config_v4(&self) -> Option<StaticConfigV4> { 482 pub fn config_v4(&self) -> Option<StaticConfigV4> {
467 self.with(|_, i| i.static_v4.clone()) 483 self.with(|i| i.static_v4.clone())
468 } 484 }
469 485
470 /// Get the current IPv6 configuration. 486 /// Get the current IPv6 configuration.
471 #[cfg(feature = "proto-ipv6")] 487 #[cfg(feature = "proto-ipv6")]
472 pub fn config_v6(&self) -> Option<StaticConfigV6> { 488 pub fn config_v6(&self) -> Option<StaticConfigV6> {
473 self.with(|_, i| i.static_v6.clone()) 489 self.with(|i| i.static_v6.clone())
474 } 490 }
475 491
476 /// Set the IPv4 configuration. 492 /// Set the IPv4 configuration.
477 #[cfg(feature = "proto-ipv4")] 493 #[cfg(feature = "proto-ipv4")]
478 pub fn set_config_v4(&self, config: ConfigV4) { 494 pub fn set_config_v4(&self, config: ConfigV4) {
479 self.with_mut(|s, i| { 495 self.with_mut(|i| {
480 i.set_config_v4(s, config); 496 i.set_config_v4(config);
481 i.apply_static_config(s); 497 i.apply_static_config();
482 }) 498 })
483 } 499 }
484 500
485 /// Set the IPv6 configuration. 501 /// Set the IPv6 configuration.
486 #[cfg(feature = "proto-ipv6")] 502 #[cfg(feature = "proto-ipv6")]
487 pub fn set_config_v6(&self, config: ConfigV6) { 503 pub fn set_config_v6(&self, config: ConfigV6) {
488 self.with_mut(|s, i| { 504 self.with_mut(|i| {
489 i.set_config_v6(s, config); 505 i.set_config_v6(config);
490 i.apply_static_config(s); 506 i.apply_static_config();
491 }) 507 })
492 } 508 }
493 509
494 /// Run the network stack.
495 ///
496 /// You must call this in a background task, to process network events.
497 pub async fn run(&self) -> ! {
498 poll_fn(|cx| {
499 self.with_mut(|s, i| i.poll(cx, s));
500 Poll::<()>::Pending
501 })
502 .await;
503 unreachable!()
504 }
505
506 /// Make a query for a given name and return the corresponding IP addresses. 510 /// Make a query for a given name and return the corresponding IP addresses.
507 #[cfg(feature = "dns")] 511 #[cfg(feature = "dns")]
508 pub async fn dns_query( 512 pub async fn dns_query(
@@ -528,11 +532,11 @@ impl<D: Driver> Stack<D> {
528 } 532 }
529 533
530 let query = poll_fn(|cx| { 534 let query = poll_fn(|cx| {
531 self.with_mut(|s, i| { 535 self.with_mut(|i| {
532 let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket); 536 let socket = i.sockets.get_mut::<dns::Socket>(i.dns_socket);
533 match socket.start_query(s.iface.context(), name, qtype) { 537 match socket.start_query(i.iface.context(), name, qtype) {
534 Ok(handle) => { 538 Ok(handle) => {
535 s.waker.wake(); 539 i.waker.wake();
536 Poll::Ready(Ok(handle)) 540 Poll::Ready(Ok(handle))
537 } 541 }
538 Err(dns::StartQueryError::NoFreeSlot) => { 542 Err(dns::StartQueryError::NoFreeSlot) => {
@@ -569,17 +573,17 @@ impl<D: Driver> Stack<D> {
569 } 573 }
570 574
571 let drop = OnDrop::new(|| { 575 let drop = OnDrop::new(|| {
572 self.with_mut(|s, i| { 576 self.with_mut(|i| {
573 let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket); 577 let socket = i.sockets.get_mut::<dns::Socket>(i.dns_socket);
574 socket.cancel_query(query); 578 socket.cancel_query(query);
575 s.waker.wake(); 579 i.waker.wake();
576 i.dns_waker.wake(); 580 i.dns_waker.wake();
577 }) 581 })
578 }); 582 });
579 583
580 let res = poll_fn(|cx| { 584 let res = poll_fn(|cx| {
581 self.with_mut(|s, i| { 585 self.with_mut(|i| {
582 let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket); 586 let socket = i.sockets.get_mut::<dns::Socket>(i.dns_socket);
583 match socket.get_query_result(query) { 587 match socket.get_query_result(query) {
584 Ok(addrs) => { 588 Ok(addrs) => {
585 i.dns_waker.wake(); 589 i.dns_waker.wake();
@@ -604,104 +608,34 @@ impl<D: Driver> Stack<D> {
604 } 608 }
605} 609}
606 610
607#[cfg(feature = "igmp")] 611#[cfg(feature = "multicast")]
608impl<D: Driver> Stack<D> { 612impl<'d> Stack<'d> {
609 /// Join a multicast group. 613 /// Join a multicast group.
610 pub async fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError> 614 pub fn join_multicast_group(&self, addr: impl Into<IpAddress>) -> Result<(), MulticastError> {
611 where 615 self.with_mut(|i| i.iface.join_multicast_group(addr))
612 T: Into<IpAddress>,
613 {
614 let addr = addr.into();
615
616 poll_fn(move |cx| self.poll_join_multicast_group(addr, cx)).await
617 }
618
619 /// Join a multicast group.
620 ///
621 /// When the send queue is full, this method will return `Poll::Pending`
622 /// and register the current task to be notified when the queue has space available.
623 pub fn poll_join_multicast_group<T>(&self, addr: T, cx: &mut Context<'_>) -> Poll<Result<bool, MulticastError>>
624 where
625 T: Into<IpAddress>,
626 {
627 let addr = addr.into();
628
629 self.with_mut(|s, i| {
630 let (_hardware_addr, medium) = to_smoltcp_hardware_address(i.device.hardware_address());
631 let mut smoldev = DriverAdapter {
632 cx: Some(cx),
633 inner: &mut i.device,
634 medium,
635 };
636
637 match s
638 .iface
639 .join_multicast_group(&mut smoldev, addr, instant_to_smoltcp(Instant::now()))
640 {
641 Ok(announce_sent) => Poll::Ready(Ok(announce_sent)),
642 Err(MulticastError::Exhausted) => Poll::Pending,
643 Err(other) => Poll::Ready(Err(other)),
644 }
645 })
646 } 616 }
647 617
648 /// Leave a multicast group. 618 /// Leave a multicast group.
649 pub async fn leave_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError> 619 pub fn leave_multicast_group(&self, addr: impl Into<IpAddress>) -> Result<(), MulticastError> {
650 where 620 self.with_mut(|i| i.iface.leave_multicast_group(addr))
651 T: Into<IpAddress>,
652 {
653 let addr = addr.into();
654
655 poll_fn(move |cx| self.poll_leave_multicast_group(addr, cx)).await
656 }
657
658 /// Leave a multicast group.
659 ///
660 /// When the send queue is full, this method will return `Poll::Pending`
661 /// and register the current task to be notified when the queue has space available.
662 pub fn poll_leave_multicast_group<T>(&self, addr: T, cx: &mut Context<'_>) -> Poll<Result<bool, MulticastError>>
663 where
664 T: Into<IpAddress>,
665 {
666 let addr = addr.into();
667
668 self.with_mut(|s, i| {
669 let (_hardware_addr, medium) = to_smoltcp_hardware_address(i.device.hardware_address());
670 let mut smoldev = DriverAdapter {
671 cx: Some(cx),
672 inner: &mut i.device,
673 medium,
674 };
675
676 match s
677 .iface
678 .leave_multicast_group(&mut smoldev, addr, instant_to_smoltcp(Instant::now()))
679 {
680 Ok(leave_sent) => Poll::Ready(Ok(leave_sent)),
681 Err(MulticastError::Exhausted) => Poll::Pending,
682 Err(other) => Poll::Ready(Err(other)),
683 }
684 })
685 } 621 }
686 622
687 /// Get whether the network stack has joined the given multicast group. 623 /// Get whether the network stack has joined the given multicast group.
688 pub fn has_multicast_group<T: Into<IpAddress>>(&self, addr: T) -> bool { 624 pub fn has_multicast_group(&self, addr: impl Into<IpAddress>) -> bool {
689 self.socket.borrow().iface.has_multicast_group(addr) 625 self.with(|i| i.iface.has_multicast_group(addr))
690 } 626 }
691} 627}
692 628
693impl SocketStack { 629impl Inner {
694 #[allow(clippy::absurd_extreme_comparisons, dead_code)] 630 #[allow(clippy::absurd_extreme_comparisons, dead_code)]
695 pub fn get_local_port(&mut self) -> u16 { 631 pub fn get_local_port(&mut self) -> u16 {
696 let res = self.next_local_port; 632 let res = self.next_local_port;
697 self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 }; 633 self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 };
698 res 634 res
699 } 635 }
700}
701 636
702impl<D: Driver> Inner<D> {
703 #[cfg(feature = "proto-ipv4")] 637 #[cfg(feature = "proto-ipv4")]
704 pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) { 638 pub fn set_config_v4(&mut self, config: ConfigV4) {
705 // Handle static config. 639 // Handle static config.
706 self.static_v4 = match config.clone() { 640 self.static_v4 = match config.clone() {
707 ConfigV4::None => None, 641 ConfigV4::None => None,
@@ -717,12 +651,12 @@ impl<D: Driver> Inner<D> {
717 // Create the socket if it doesn't exist. 651 // Create the socket if it doesn't exist.
718 if self.dhcp_socket.is_none() { 652 if self.dhcp_socket.is_none() {
719 let socket = smoltcp::socket::dhcpv4::Socket::new(); 653 let socket = smoltcp::socket::dhcpv4::Socket::new();
720 let handle = _s.sockets.add(socket); 654 let handle = self.sockets.add(socket);
721 self.dhcp_socket = Some(handle); 655 self.dhcp_socket = Some(handle);
722 } 656 }
723 657
724 // Configure it 658 // Configure it
725 let socket = _s.sockets.get_mut::<dhcpv4::Socket>(unwrap!(self.dhcp_socket)); 659 let socket = self.sockets.get_mut::<dhcpv4::Socket>(unwrap!(self.dhcp_socket));
726 socket.set_ignore_naks(c.ignore_naks); 660 socket.set_ignore_naks(c.ignore_naks);
727 socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp)); 661 socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp));
728 socket.set_ports(c.server_port, c.client_port); 662 socket.set_ports(c.server_port, c.client_port);
@@ -731,19 +665,20 @@ impl<D: Driver> Inner<D> {
731 socket.set_outgoing_options(&[]); 665 socket.set_outgoing_options(&[]);
732 #[cfg(feature = "dhcpv4-hostname")] 666 #[cfg(feature = "dhcpv4-hostname")]
733 if let Some(h) = c.hostname { 667 if let Some(h) = c.hostname {
734 // safety: we just did set_outgoing_options([]) so we know the socket is no longer holding a reference. 668 // safety:
735 let hostname = unsafe { &mut *self.hostname.get() }; 669 // - we just did set_outgoing_options([]) so we know the socket is no longer holding a reference.
670 // - we know this pointer lives for as long as the stack exists, because `new()` borrows
671 // the resources for `'d`. Therefore it's OK to pass a reference to this to smoltcp.
672 let hostname = unsafe { &mut *self.hostname };
736 673
737 // create data 674 // create data
738 // safety: we know the buffer lives forever, new borrows the StackResources for 'static. 675 let data = hostname.data.write([0; MAX_HOSTNAME_LEN]);
739 // also we won't modify it until next call to this function. 676 data[..h.len()].copy_from_slice(h.as_bytes());
740 hostname.data[..h.len()].copy_from_slice(h.as_bytes()); 677 let data: &[u8] = &data[..h.len()];
741 let data: &[u8] = &hostname.data[..h.len()];
742 let data: &'static [u8] = unsafe { core::mem::transmute(data) };
743 678
744 // set the option. 679 // set the option.
745 hostname.option = smoltcp::wire::DhcpOption { data, kind: 12 }; 680 let option = hostname.option.write(smoltcp::wire::DhcpOption { data, kind: 12 });
746 socket.set_outgoing_options(core::slice::from_ref(&hostname.option)); 681 socket.set_outgoing_options(core::slice::from_ref(option));
747 } 682 }
748 683
749 socket.reset(); 684 socket.reset();
@@ -751,7 +686,7 @@ impl<D: Driver> Inner<D> {
751 _ => { 686 _ => {
752 // Remove DHCP socket if any. 687 // Remove DHCP socket if any.
753 if let Some(socket) = self.dhcp_socket { 688 if let Some(socket) = self.dhcp_socket {
754 _s.sockets.remove(socket); 689 self.sockets.remove(socket);
755 self.dhcp_socket = None; 690 self.dhcp_socket = None;
756 } 691 }
757 } 692 }
@@ -759,14 +694,14 @@ impl<D: Driver> Inner<D> {
759 } 694 }
760 695
761 #[cfg(feature = "proto-ipv6")] 696 #[cfg(feature = "proto-ipv6")]
762 pub fn set_config_v6(&mut self, _s: &mut SocketStack, config: ConfigV6) { 697 pub fn set_config_v6(&mut self, config: ConfigV6) {
763 self.static_v6 = match config { 698 self.static_v6 = match config {
764 ConfigV6::None => None, 699 ConfigV6::None => None,
765 ConfigV6::Static(c) => Some(c), 700 ConfigV6::Static(c) => Some(c),
766 }; 701 };
767 } 702 }
768 703
769 fn apply_static_config(&mut self, s: &mut SocketStack) { 704 fn apply_static_config(&mut self) {
770 let mut addrs = Vec::new(); 705 let mut addrs = Vec::new();
771 #[cfg(feature = "dns")] 706 #[cfg(feature = "dns")]
772 let mut dns_servers: Vec<_, 6> = Vec::new(); 707 let mut dns_servers: Vec<_, 6> = Vec::new();
@@ -810,20 +745,20 @@ impl<D: Driver> Inner<D> {
810 } 745 }
811 746
812 // Apply addresses 747 // Apply addresses
813 s.iface.update_ip_addrs(|a| *a = addrs); 748 self.iface.update_ip_addrs(|a| *a = addrs);
814 749
815 // Apply gateways 750 // Apply gateways
816 #[cfg(feature = "proto-ipv4")] 751 #[cfg(feature = "proto-ipv4")]
817 if let Some(gateway) = gateway_v4 { 752 if let Some(gateway) = gateway_v4 {
818 unwrap!(s.iface.routes_mut().add_default_ipv4_route(gateway)); 753 unwrap!(self.iface.routes_mut().add_default_ipv4_route(gateway));
819 } else { 754 } else {
820 s.iface.routes_mut().remove_default_ipv4_route(); 755 self.iface.routes_mut().remove_default_ipv4_route();
821 } 756 }
822 #[cfg(feature = "proto-ipv6")] 757 #[cfg(feature = "proto-ipv6")]
823 if let Some(gateway) = gateway_v6 { 758 if let Some(gateway) = gateway_v6 {
824 unwrap!(s.iface.routes_mut().add_default_ipv6_route(gateway)); 759 unwrap!(self.iface.routes_mut().add_default_ipv6_route(gateway));
825 } else { 760 } else {
826 s.iface.routes_mut().remove_default_ipv6_route(); 761 self.iface.routes_mut().remove_default_ipv6_route();
827 } 762 }
828 763
829 // Apply DNS servers 764 // Apply DNS servers
@@ -835,7 +770,7 @@ impl<D: Driver> Inner<D> {
835 } else { 770 } else {
836 dns_servers.len() 771 dns_servers.len()
837 }; 772 };
838 s.sockets 773 self.sockets
839 .get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket) 774 .get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket)
840 .update_servers(&dns_servers[..count]); 775 .update_servers(&dns_servers[..count]);
841 } 776 }
@@ -843,10 +778,10 @@ impl<D: Driver> Inner<D> {
843 self.config_waker.wake(); 778 self.config_waker.wake();
844 } 779 }
845 780
846 fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { 781 fn poll<D: Driver>(&mut self, cx: &mut Context<'_>, driver: &mut D) {
847 s.waker.register(cx.waker()); 782 self.waker.register(cx.waker());
848 783
849 let (_hardware_addr, medium) = to_smoltcp_hardware_address(self.device.hardware_address()); 784 let (_hardware_addr, medium) = to_smoltcp_hardware_address(driver.hardware_address());
850 785
851 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))] 786 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
852 { 787 {
@@ -859,21 +794,21 @@ impl<D: Driver> Inner<D> {
859 _ => false, 794 _ => false,
860 }; 795 };
861 if do_set { 796 if do_set {
862 s.iface.set_hardware_addr(_hardware_addr); 797 self.iface.set_hardware_addr(_hardware_addr);
863 } 798 }
864 } 799 }
865 800
866 let timestamp = instant_to_smoltcp(Instant::now()); 801 let timestamp = instant_to_smoltcp(Instant::now());
867 let mut smoldev = DriverAdapter { 802 let mut smoldev = DriverAdapter {
868 cx: Some(cx), 803 cx: Some(cx),
869 inner: &mut self.device, 804 inner: driver,
870 medium, 805 medium,
871 }; 806 };
872 s.iface.poll(timestamp, &mut smoldev, &mut s.sockets); 807 self.iface.poll(timestamp, &mut smoldev, &mut self.sockets);
873 808
874 // Update link up 809 // Update link up
875 let old_link_up = self.link_up; 810 let old_link_up = self.link_up;
876 self.link_up = self.device.link_state(cx) == LinkState::Up; 811 self.link_up = driver.link_state(cx) == LinkState::Up;
877 812
878 // Print when changed 813 // Print when changed
879 if old_link_up != self.link_up { 814 if old_link_up != self.link_up {
@@ -885,7 +820,7 @@ impl<D: Driver> Inner<D> {
885 820
886 #[cfg(feature = "dhcpv4")] 821 #[cfg(feature = "dhcpv4")]
887 if let Some(dhcp_handle) = self.dhcp_socket { 822 if let Some(dhcp_handle) = self.dhcp_socket {
888 let socket = s.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle); 823 let socket = self.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle);
889 824
890 if self.link_up { 825 if self.link_up {
891 if old_link_up != self.link_up { 826 if old_link_up != self.link_up {
@@ -914,10 +849,10 @@ impl<D: Driver> Inner<D> {
914 } 849 }
915 850
916 if apply_config { 851 if apply_config {
917 self.apply_static_config(s); 852 self.apply_static_config();
918 } 853 }
919 854
920 if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) { 855 if let Some(poll_at) = self.iface.poll_at(timestamp, &mut self.sockets) {
921 let t = pin!(Timer::at(instant_from_smoltcp(poll_at))); 856 let t = pin!(Timer::at(instant_from_smoltcp(poll_at)));
922 if t.poll(cx).is_ready() { 857 if t.poll(cx).is_ready() {
923 cx.waker().wake_by_ref(); 858 cx.waker().wake_by_ref();
@@ -925,3 +860,17 @@ impl<D: Driver> Inner<D> {
925 } 860 }
926 } 861 }
927} 862}
863
864impl<'d, D: Driver> Runner<'d, D> {
865 /// Run the network stack.
866 ///
867 /// You must call this in a background task, to process network events.
868 pub async fn run(&mut self) -> ! {
869 poll_fn(|cx| {
870 self.stack.with_mut(|i| i.poll(cx, &mut self.driver));
871 Poll::<()>::Pending
872 })
873 .await;
874 unreachable!()
875 }
876}
diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs
index 7ecd913e7..1098dc208 100644
--- a/embassy-net/src/raw.rs
+++ b/embassy-net/src/raw.rs
@@ -1,6 +1,5 @@
1//! Raw sockets. 1//! Raw sockets.
2 2
3use core::cell::RefCell;
4use core::future::poll_fn; 3use core::future::poll_fn;
5use core::mem; 4use core::mem;
6use core::task::{Context, Poll}; 5use core::task::{Context, Poll};
@@ -11,7 +10,7 @@ use smoltcp::socket::raw;
11pub use smoltcp::socket::raw::PacketMetadata; 10pub use smoltcp::socket::raw::PacketMetadata;
12use smoltcp::wire::{IpProtocol, IpVersion}; 11use smoltcp::wire::{IpProtocol, IpVersion};
13 12
14use crate::{SocketStack, Stack}; 13use crate::Stack;
15 14
16/// Error returned by [`RawSocket::recv`] and [`RawSocket::send`]. 15/// Error returned by [`RawSocket::recv`] and [`RawSocket::send`].
17#[derive(PartialEq, Eq, Clone, Copy, Debug)] 16#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@@ -23,14 +22,14 @@ pub enum RecvError {
23 22
24/// An Raw socket. 23/// An Raw socket.
25pub struct RawSocket<'a> { 24pub struct RawSocket<'a> {
26 stack: &'a RefCell<SocketStack>, 25 stack: Stack<'a>,
27 handle: SocketHandle, 26 handle: SocketHandle,
28} 27}
29 28
30impl<'a> RawSocket<'a> { 29impl<'a> RawSocket<'a> {
31 /// Create a new Raw socket using the provided stack and buffers. 30 /// Create a new Raw socket using the provided stack and buffers.
32 pub fn new<D: Driver>( 31 pub fn new<D: Driver>(
33 stack: &'a Stack<D>, 32 stack: Stack<'a>,
34 ip_version: IpVersion, 33 ip_version: IpVersion,
35 ip_protocol: IpProtocol, 34 ip_protocol: IpProtocol,
36 rx_meta: &'a mut [PacketMetadata], 35 rx_meta: &'a mut [PacketMetadata],
@@ -38,31 +37,29 @@ impl<'a> RawSocket<'a> {
38 tx_meta: &'a mut [PacketMetadata], 37 tx_meta: &'a mut [PacketMetadata],
39 tx_buffer: &'a mut [u8], 38 tx_buffer: &'a mut [u8],
40 ) -> Self { 39 ) -> Self {
41 let s = &mut *stack.socket.borrow_mut(); 40 let handle = stack.with_mut(|i| {
41 let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) };
42 let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
43 let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) };
44 let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
45 i.sockets.add(raw::Socket::new(
46 ip_version,
47 ip_protocol,
48 raw::PacketBuffer::new(rx_meta, rx_buffer),
49 raw::PacketBuffer::new(tx_meta, tx_buffer),
50 ))
51 });
42 52
43 let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; 53 Self { stack, handle }
44 let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
45 let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) };
46 let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
47 let handle = s.sockets.add(raw::Socket::new(
48 ip_version,
49 ip_protocol,
50 raw::PacketBuffer::new(rx_meta, rx_buffer),
51 raw::PacketBuffer::new(tx_meta, tx_buffer),
52 ));
53
54 Self {
55 stack: &stack.socket,
56 handle,
57 }
58 } 54 }
59 55
60 fn with_mut<R>(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R { 56 fn with_mut<R>(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R {
61 let s = &mut *self.stack.borrow_mut(); 57 self.stack.with_mut(|i| {
62 let socket = s.sockets.get_mut::<raw::Socket>(self.handle); 58 let socket = i.sockets.get_mut::<raw::Socket>(self.handle);
63 let res = f(socket, &mut s.iface); 59 let res = f(socket, &mut i.iface);
64 s.waker.wake(); 60 i.waker.wake();
65 res 61 res
62 })
66 } 63 }
67 64
68 /// Receive a datagram. 65 /// Receive a datagram.
@@ -115,6 +112,10 @@ impl<'a> RawSocket<'a> {
115 112
116impl Drop for RawSocket<'_> { 113impl Drop for RawSocket<'_> {
117 fn drop(&mut self) { 114 fn drop(&mut self) {
118 self.stack.borrow_mut().sockets.remove(self.handle); 115 self.stack.with_mut(|i| i.sockets.remove(self.handle));
119 } 116 }
120} 117}
118
119fn _assert_covariant<'a, 'b: 'a>(x: RawSocket<'b>) -> RawSocket<'a> {
120 x
121}
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index b2e3279cc..bcddbc95b 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -8,12 +8,10 @@
8//! Incoming connections when no socket is listening are rejected. To accept many incoming 8//! Incoming connections when no socket is listening are rejected. To accept many incoming
9//! connections, create many sockets and put them all into listening mode. 9//! connections, create many sockets and put them all into listening mode.
10 10
11use core::cell::RefCell;
12use core::future::poll_fn; 11use core::future::poll_fn;
13use core::mem; 12use core::mem;
14use core::task::Poll; 13use core::task::Poll;
15 14
16use embassy_net_driver::Driver;
17use embassy_time::Duration; 15use embassy_time::Duration;
18use smoltcp::iface::{Interface, SocketHandle}; 16use smoltcp::iface::{Interface, SocketHandle};
19use smoltcp::socket::tcp; 17use smoltcp::socket::tcp;
@@ -21,7 +19,7 @@ pub use smoltcp::socket::tcp::State;
21use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; 19use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
22 20
23use crate::time::duration_to_smoltcp; 21use crate::time::duration_to_smoltcp;
24use crate::{SocketStack, Stack}; 22use crate::Stack;
25 23
26/// Error returned by TcpSocket read/write functions. 24/// Error returned by TcpSocket read/write functions.
27#[derive(PartialEq, Eq, Clone, Copy, Debug)] 25#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@@ -157,20 +155,18 @@ impl<'a> TcpWriter<'a> {
157 155
158impl<'a> TcpSocket<'a> { 156impl<'a> TcpSocket<'a> {
159 /// Create a new TCP socket on the given stack, with the given buffers. 157 /// Create a new TCP socket on the given stack, with the given buffers.
160 pub fn new<D: Driver>(stack: &'a Stack<D>, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self { 158 pub fn new(stack: Stack<'a>, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self {
161 let s = &mut *stack.socket.borrow_mut(); 159 let handle = stack.with_mut(|i| {
162 let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; 160 let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
163 let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; 161 let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
164 let handle = s.sockets.add(tcp::Socket::new( 162 i.sockets.add(tcp::Socket::new(
165 tcp::SocketBuffer::new(rx_buffer), 163 tcp::SocketBuffer::new(rx_buffer),
166 tcp::SocketBuffer::new(tx_buffer), 164 tcp::SocketBuffer::new(tx_buffer),
167 )); 165 ))
166 });
168 167
169 Self { 168 Self {
170 io: TcpIo { 169 io: TcpIo { stack: stack, handle },
171 stack: &stack.socket,
172 handle,
173 },
174 } 170 }
175 } 171 }
176 172
@@ -228,7 +224,7 @@ impl<'a> TcpSocket<'a> {
228 where 224 where
229 T: Into<IpEndpoint>, 225 T: Into<IpEndpoint>,
230 { 226 {
231 let local_port = self.io.stack.borrow_mut().get_local_port(); 227 let local_port = self.io.stack.with_mut(|i| i.get_local_port());
232 228
233 match { 229 match {
234 self.io 230 self.io
@@ -401,31 +397,43 @@ impl<'a> TcpSocket<'a> {
401 397
402impl<'a> Drop for TcpSocket<'a> { 398impl<'a> Drop for TcpSocket<'a> {
403 fn drop(&mut self) { 399 fn drop(&mut self) {
404 self.io.stack.borrow_mut().sockets.remove(self.io.handle); 400 self.io.stack.with_mut(|i| i.sockets.remove(self.io.handle));
405 } 401 }
406} 402}
407 403
404fn _assert_covariant<'a, 'b: 'a>(x: TcpSocket<'b>) -> TcpSocket<'a> {
405 x
406}
407fn _assert_covariant_reader<'a, 'b: 'a>(x: TcpReader<'b>) -> TcpReader<'a> {
408 x
409}
410fn _assert_covariant_writer<'a, 'b: 'a>(x: TcpWriter<'b>) -> TcpWriter<'a> {
411 x
412}
413
408// ======================= 414// =======================
409 415
410#[derive(Copy, Clone)] 416#[derive(Copy, Clone)]
411struct TcpIo<'a> { 417struct TcpIo<'a> {
412 stack: &'a RefCell<SocketStack>, 418 stack: Stack<'a>,
413 handle: SocketHandle, 419 handle: SocketHandle,
414} 420}
415 421
416impl<'d> TcpIo<'d> { 422impl<'d> TcpIo<'d> {
417 fn with<R>(&self, f: impl FnOnce(&tcp::Socket, &Interface) -> R) -> R { 423 fn with<R>(&self, f: impl FnOnce(&tcp::Socket, &Interface) -> R) -> R {
418 let s = &*self.stack.borrow(); 424 self.stack.with(|i| {
419 let socket = s.sockets.get::<tcp::Socket>(self.handle); 425 let socket = i.sockets.get::<tcp::Socket>(self.handle);
420 f(socket, &s.iface) 426 f(socket, &i.iface)
427 })
421 } 428 }
422 429
423 fn with_mut<R>(&mut self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R { 430 fn with_mut<R>(&mut self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R {
424 let s = &mut *self.stack.borrow_mut(); 431 self.stack.with_mut(|i| {
425 let socket = s.sockets.get_mut::<tcp::Socket>(self.handle); 432 let socket = i.sockets.get_mut::<tcp::Socket>(self.handle);
426 let res = f(socket, &mut s.iface); 433 let res = f(socket, &mut i.iface);
427 s.waker.wake(); 434 i.waker.wake();
428 res 435 res
436 })
429 } 437 }
430 438
431 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 439 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
@@ -676,15 +684,15 @@ pub mod client {
676 /// TCP client connection pool compatible with `embedded-nal-async` traits. 684 /// TCP client connection pool compatible with `embedded-nal-async` traits.
677 /// 685 ///
678 /// The pool is capable of managing up to N concurrent connections with tx and rx buffers according to TX_SZ and RX_SZ. 686 /// The pool is capable of managing up to N concurrent connections with tx and rx buffers according to TX_SZ and RX_SZ.
679 pub struct TcpClient<'d, D: Driver, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> { 687 pub struct TcpClient<'d, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> {
680 stack: &'d Stack<D>, 688 stack: Stack<'d>,
681 state: &'d TcpClientState<N, TX_SZ, RX_SZ>, 689 state: &'d TcpClientState<N, TX_SZ, RX_SZ>,
682 socket_timeout: Option<Duration>, 690 socket_timeout: Option<Duration>,
683 } 691 }
684 692
685 impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> { 693 impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, N, TX_SZ, RX_SZ> {
686 /// Create a new `TcpClient`. 694 /// Create a new `TcpClient`.
687 pub fn new(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Self { 695 pub fn new(stack: Stack<'d>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Self {
688 Self { 696 Self {
689 stack, 697 stack,
690 state, 698 state,
@@ -701,8 +709,8 @@ pub mod client {
701 } 709 }
702 } 710 }
703 711
704 impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect 712 impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect
705 for TcpClient<'d, D, N, TX_SZ, RX_SZ> 713 for TcpClient<'d, N, TX_SZ, RX_SZ>
706 { 714 {
707 type Error = Error; 715 type Error = Error;
708 type Connection<'m> = TcpConnection<'m, N, TX_SZ, RX_SZ> where Self: 'm; 716 type Connection<'m> = TcpConnection<'m, N, TX_SZ, RX_SZ> where Self: 'm;
@@ -722,7 +730,7 @@ pub mod client {
722 IpAddr::V6(_) => panic!("ipv6 support not enabled"), 730 IpAddr::V6(_) => panic!("ipv6 support not enabled"),
723 }; 731 };
724 let remote_endpoint = (addr, remote.port()); 732 let remote_endpoint = (addr, remote.port());
725 let mut socket = TcpConnection::new(&self.stack, self.state)?; 733 let mut socket = TcpConnection::new(self.stack, self.state)?;
726 socket.socket.set_timeout(self.socket_timeout.clone()); 734 socket.socket.set_timeout(self.socket_timeout.clone());
727 socket 735 socket
728 .socket 736 .socket
@@ -741,7 +749,7 @@ pub mod client {
741 } 749 }
742 750
743 impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpConnection<'d, N, TX_SZ, RX_SZ> { 751 impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpConnection<'d, N, TX_SZ, RX_SZ> {
744 fn new<D: Driver>(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Result<Self, Error> { 752 fn new(stack: Stack<'d>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Result<Self, Error> {
745 let mut bufs = state.pool.alloc().ok_or(Error::ConnectionReset)?; 753 let mut bufs = state.pool.alloc().ok_or(Error::ConnectionReset)?;
746 Ok(Self { 754 Ok(Self {
747 socket: unsafe { TcpSocket::new(stack, &mut bufs.as_mut().1, &mut bufs.as_mut().0) }, 755 socket: unsafe { TcpSocket::new(stack, &mut bufs.as_mut().1, &mut bufs.as_mut().0) },
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index 1d5360187..3eb6e2f83 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -1,17 +1,15 @@
1//! UDP sockets. 1//! UDP sockets.
2 2
3use core::cell::RefCell;
4use core::future::poll_fn; 3use core::future::poll_fn;
5use core::mem; 4use core::mem;
6use core::task::{Context, Poll}; 5use core::task::{Context, Poll};
7 6
8use embassy_net_driver::Driver;
9use smoltcp::iface::{Interface, SocketHandle}; 7use smoltcp::iface::{Interface, SocketHandle};
10use smoltcp::socket::udp; 8use smoltcp::socket::udp;
11pub use smoltcp::socket::udp::{PacketMetadata, UdpMetadata}; 9pub use smoltcp::socket::udp::{PacketMetadata, UdpMetadata};
12use smoltcp::wire::IpListenEndpoint; 10use smoltcp::wire::IpListenEndpoint;
13 11
14use crate::{SocketStack, Stack}; 12use crate::Stack;
15 13
16/// Error returned by [`UdpSocket::bind`]. 14/// Error returned by [`UdpSocket::bind`].
17#[derive(PartialEq, Eq, Clone, Copy, Debug)] 15#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@@ -43,34 +41,31 @@ pub enum RecvError {
43 41
44/// An UDP socket. 42/// An UDP socket.
45pub struct UdpSocket<'a> { 43pub struct UdpSocket<'a> {
46 stack: &'a RefCell<SocketStack>, 44 stack: Stack<'a>,
47 handle: SocketHandle, 45 handle: SocketHandle,
48} 46}
49 47
50impl<'a> UdpSocket<'a> { 48impl<'a> UdpSocket<'a> {
51 /// Create a new UDP socket using the provided stack and buffers. 49 /// Create a new UDP socket using the provided stack and buffers.
52 pub fn new<D: Driver>( 50 pub fn new(
53 stack: &'a Stack<D>, 51 stack: Stack<'a>,
54 rx_meta: &'a mut [PacketMetadata], 52 rx_meta: &'a mut [PacketMetadata],
55 rx_buffer: &'a mut [u8], 53 rx_buffer: &'a mut [u8],
56 tx_meta: &'a mut [PacketMetadata], 54 tx_meta: &'a mut [PacketMetadata],
57 tx_buffer: &'a mut [u8], 55 tx_buffer: &'a mut [u8],
58 ) -> Self { 56 ) -> Self {
59 let s = &mut *stack.socket.borrow_mut(); 57 let handle = stack.with_mut(|i| {
60 58 let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) };
61 let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; 59 let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
62 let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; 60 let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) };
63 let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; 61 let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
64 let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; 62 i.sockets.add(udp::Socket::new(
65 let handle = s.sockets.add(udp::Socket::new( 63 udp::PacketBuffer::new(rx_meta, rx_buffer),
66 udp::PacketBuffer::new(rx_meta, rx_buffer), 64 udp::PacketBuffer::new(tx_meta, tx_buffer),
67 udp::PacketBuffer::new(tx_meta, tx_buffer), 65 ))
68 )); 66 });
69 67
70 Self { 68 Self { stack, handle }
71 stack: &stack.socket,
72 handle,
73 }
74 } 69 }
75 70
76 /// Bind the socket to a local endpoint. 71 /// Bind the socket to a local endpoint.
@@ -82,7 +77,7 @@ impl<'a> UdpSocket<'a> {
82 77
83 if endpoint.port == 0 { 78 if endpoint.port == 0 {
84 // If user didn't specify port allocate a dynamic port. 79 // If user didn't specify port allocate a dynamic port.
85 endpoint.port = self.stack.borrow_mut().get_local_port(); 80 endpoint.port = self.stack.with_mut(|i| i.get_local_port());
86 } 81 }
87 82
88 match self.with_mut(|s, _| s.bind(endpoint)) { 83 match self.with_mut(|s, _| s.bind(endpoint)) {
@@ -93,17 +88,19 @@ impl<'a> UdpSocket<'a> {
93 } 88 }
94 89
95 fn with<R>(&self, f: impl FnOnce(&udp::Socket, &Interface) -> R) -> R { 90 fn with<R>(&self, f: impl FnOnce(&udp::Socket, &Interface) -> R) -> R {
96 let s = &*self.stack.borrow(); 91 self.stack.with(|i| {
97 let socket = s.sockets.get::<udp::Socket>(self.handle); 92 let socket = i.sockets.get::<udp::Socket>(self.handle);
98 f(socket, &s.iface) 93 f(socket, &i.iface)
94 })
99 } 95 }
100 96
101 fn with_mut<R>(&self, f: impl FnOnce(&mut udp::Socket, &mut Interface) -> R) -> R { 97 fn with_mut<R>(&self, f: impl FnOnce(&mut udp::Socket, &mut Interface) -> R) -> R {
102 let s = &mut *self.stack.borrow_mut(); 98 self.stack.with_mut(|i| {
103 let socket = s.sockets.get_mut::<udp::Socket>(self.handle); 99 let socket = i.sockets.get_mut::<udp::Socket>(self.handle);
104 let res = f(socket, &mut s.iface); 100 let res = f(socket, &mut i.iface);
105 s.waker.wake(); 101 i.waker.wake();
106 res 102 res
103 })
107 } 104 }
108 105
109 /// Receive a datagram. 106 /// Receive a datagram.
@@ -298,6 +295,10 @@ impl<'a> UdpSocket<'a> {
298 295
299impl Drop for UdpSocket<'_> { 296impl Drop for UdpSocket<'_> {
300 fn drop(&mut self) { 297 fn drop(&mut self) {
301 self.stack.borrow_mut().sockets.remove(self.handle); 298 self.stack.with_mut(|i| i.sockets.remove(self.handle));
302 } 299 }
303} 300}
301
302fn _assert_covariant<'a, 'b: 'a>(x: UdpSocket<'b>) -> UdpSocket<'a> {
303 x
304}
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index d0bb7e574..31397172c 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -846,12 +846,12 @@ pub(crate) trait SealedPin: Sized {
846 846
847 #[inline] 847 #[inline]
848 fn _pin(&self) -> u8 { 848 fn _pin(&self) -> u8 {
849 self.pin_bank() & 0x1f 849 self.pin_bank() & 0x7f
850 } 850 }
851 851
852 #[inline] 852 #[inline]
853 fn _bank(&self) -> Bank { 853 fn _bank(&self) -> Bank {
854 match self.pin_bank() >> 5 { 854 match self.pin_bank() >> 7 {
855 #[cfg(feature = "qspi-as-gpio")] 855 #[cfg(feature = "qspi-as-gpio")]
856 1 => Bank::Qspi, 856 1 => Bank::Qspi,
857 _ => Bank::Bank0, 857 _ => Bank::Bank0,
@@ -880,15 +880,27 @@ pub(crate) trait SealedPin: Sized {
880 } 880 }
881 881
882 fn sio_out(&self) -> pac::sio::Gpio { 882 fn sio_out(&self) -> pac::sio::Gpio {
883 SIO.gpio_out(self._bank() as _) 883 if cfg!(feature = "rp2040") {
884 SIO.gpio_out(self._bank() as _)
885 } else {
886 SIO.gpio_out((self._pin() / 32) as _)
887 }
884 } 888 }
885 889
886 fn sio_oe(&self) -> pac::sio::Gpio { 890 fn sio_oe(&self) -> pac::sio::Gpio {
887 SIO.gpio_oe(self._bank() as _) 891 if cfg!(feature = "rp2040") {
892 SIO.gpio_oe(self._bank() as _)
893 } else {
894 SIO.gpio_oe((self._pin() / 32) as _)
895 }
888 } 896 }
889 897
890 fn sio_in(&self) -> Reg<u32, RW> { 898 fn sio_in(&self) -> Reg<u32, RW> {
891 SIO.gpio_in(self._bank() as _) 899 if cfg!(feature = "rp2040") {
900 SIO.gpio_in(self._bank() as _)
901 } else {
902 SIO.gpio_in((self._pin() / 32) as _)
903 }
892 } 904 }
893 905
894 fn int_proc(&self) -> pac::io::Int { 906 fn int_proc(&self) -> pac::io::Int {
@@ -953,7 +965,7 @@ macro_rules! impl_pin {
953 impl SealedPin for peripherals::$name { 965 impl SealedPin for peripherals::$name {
954 #[inline] 966 #[inline]
955 fn pin_bank(&self) -> u8 { 967 fn pin_bank(&self) -> u8 {
956 ($bank as u8) * 32 + $pin_num 968 ($bank as u8) * 128 + $pin_num
957 } 969 }
958 } 970 }
959 971
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index aba4b792a..c94e5e185 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -224,6 +224,17 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
224} 224}
225 225
226impl<'d, T: Instance> UartTx<'d, T, Blocking> { 226impl<'d, T: Instance> UartTx<'d, T, Blocking> {
227 /// Create a new UART TX instance for blocking mode operations.
228 pub fn new_blocking(
229 _uart: impl Peripheral<P = T> + 'd,
230 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
231 config: Config,
232 ) -> Self {
233 into_ref!(tx);
234 Uart::<T, Blocking>::init(Some(tx.map_into()), None, None, None, config);
235 Self::new_inner(None)
236 }
237
227 /// Convert this uart TX instance into a buffered uart using the provided 238 /// Convert this uart TX instance into a buffered uart using the provided
228 /// irq and transmit buffer. 239 /// irq and transmit buffer.
229 pub fn into_buffered( 240 pub fn into_buffered(
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 9384c8688..0ab2306c8 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -80,6 +80,8 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
80 80
81 if istr.ctr() { 81 if istr.ctr() {
82 let index = istr.ep_id() as usize; 82 let index = istr.ep_id() as usize;
83 CTR_TRIGGERED[index].store(true, Ordering::Relaxed);
84
83 let mut epr = regs.epr(index).read(); 85 let mut epr = regs.epr(index).read();
84 if epr.ctr_rx() { 86 if epr.ctr_rx() {
85 if index == 0 && epr.setup() { 87 if index == 0 && epr.setup() {
@@ -120,6 +122,10 @@ const USBRAM_ALIGN: usize = 4;
120const NEW_AW: AtomicWaker = AtomicWaker::new(); 122const NEW_AW: AtomicWaker = AtomicWaker::new();
121static BUS_WAKER: AtomicWaker = NEW_AW; 123static BUS_WAKER: AtomicWaker = NEW_AW;
122static EP0_SETUP: AtomicBool = AtomicBool::new(false); 124static EP0_SETUP: AtomicBool = AtomicBool::new(false);
125
126const NEW_CTR_TRIGGERED: AtomicBool = AtomicBool::new(false);
127static CTR_TRIGGERED: [AtomicBool; EP_COUNT] = [NEW_CTR_TRIGGERED; EP_COUNT];
128
123static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; 129static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
124static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; 130static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
125static IRQ_RESET: AtomicBool = AtomicBool::new(false); 131static IRQ_RESET: AtomicBool = AtomicBool::new(false);
@@ -163,20 +169,37 @@ fn calc_out_len(len: u16) -> (u16, u16) {
163mod btable { 169mod btable {
164 use super::*; 170 use super::*;
165 171
166 pub(super) fn write_in<T: Instance>(index: usize, addr: u16) { 172 pub(super) fn write_in_tx<T: Instance>(index: usize, addr: u16) {
167 USBRAM.mem(index * 4 + 0).write_value(addr); 173 USBRAM.mem(index * 4 + 0).write_value(addr);
168 } 174 }
169 175
170 pub(super) fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) { 176 pub(super) fn write_in_rx<T: Instance>(index: usize, addr: u16) {
177 USBRAM.mem(index * 4 + 2).write_value(addr);
178 }
179
180 pub(super) fn write_in_len_rx<T: Instance>(index: usize, _addr: u16, len: u16) {
181 USBRAM.mem(index * 4 + 3).write_value(len);
182 }
183
184 pub(super) fn write_in_len_tx<T: Instance>(index: usize, _addr: u16, len: u16) {
171 USBRAM.mem(index * 4 + 1).write_value(len); 185 USBRAM.mem(index * 4 + 1).write_value(len);
172 } 186 }
173 187
174 pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { 188 pub(super) fn write_out_rx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
175 USBRAM.mem(index * 4 + 2).write_value(addr); 189 USBRAM.mem(index * 4 + 2).write_value(addr);
176 USBRAM.mem(index * 4 + 3).write_value(max_len_bits); 190 USBRAM.mem(index * 4 + 3).write_value(max_len_bits);
177 } 191 }
178 192
179 pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 { 193 pub(super) fn write_out_tx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
194 USBRAM.mem(index * 4 + 0).write_value(addr);
195 USBRAM.mem(index * 4 + 1).write_value(max_len_bits);
196 }
197
198 pub(super) fn read_out_len_tx<T: Instance>(index: usize) -> u16 {
199 USBRAM.mem(index * 4 + 1).read()
200 }
201
202 pub(super) fn read_out_len_rx<T: Instance>(index: usize) -> u16 {
180 USBRAM.mem(index * 4 + 3).read() 203 USBRAM.mem(index * 4 + 3).read()
181 } 204 }
182} 205}
@@ -184,19 +207,37 @@ mod btable {
184mod btable { 207mod btable {
185 use super::*; 208 use super::*;
186 209
187 pub(super) fn write_in<T: Instance>(_index: usize, _addr: u16) {} 210 pub(super) fn write_in_tx<T: Instance>(_index: usize, _addr: u16) {}
188 211
189 pub(super) fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) { 212 pub(super) fn write_in_rx<T: Instance>(_index: usize, _addr: u16) {}
213
214 pub(super) fn write_in_len_tx<T: Instance>(index: usize, addr: u16, len: u16) {
190 USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); 215 USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
191 } 216 }
192 217
193 pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { 218 pub(super) fn write_in_len_rx<T: Instance>(index: usize, addr: u16, len: u16) {
219 USBRAM
220 .mem(index * 2 + 1)
221 .write_value((addr as u32) | ((len as u32) << 16));
222 }
223
224 pub(super) fn write_out_tx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
225 USBRAM
226 .mem(index * 2)
227 .write_value((addr as u32) | ((max_len_bits as u32) << 16));
228 }
229
230 pub(super) fn write_out_rx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
194 USBRAM 231 USBRAM
195 .mem(index * 2 + 1) 232 .mem(index * 2 + 1)
196 .write_value((addr as u32) | ((max_len_bits as u32) << 16)); 233 .write_value((addr as u32) | ((max_len_bits as u32) << 16));
197 } 234 }
198 235
199 pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 { 236 pub(super) fn read_out_len_tx<T: Instance>(index: usize) -> u16 {
237 (USBRAM.mem(index * 2).read() >> 16) as u16
238 }
239
240 pub(super) fn read_out_len_rx<T: Instance>(index: usize) -> u16 {
200 (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 241 (USBRAM.mem(index * 2 + 1).read() >> 16) as u16
201 } 242 }
202} 243}
@@ -327,6 +368,13 @@ impl<'d, T: Instance> Driver<'d, T> {
327 return false; // reserved for control pipe 368 return false; // reserved for control pipe
328 } 369 }
329 let used = ep.used_out || ep.used_in; 370 let used = ep.used_out || ep.used_in;
371 if used && (ep.ep_type == EndpointType::Isochronous || ep.ep_type == EndpointType::Bulk) {
372 // Isochronous and bulk endpoints are double-buffered.
373 // Their corresponding endpoint/channel registers are forced to be unidirectional.
374 // Do not reuse this index.
375 return false;
376 }
377
330 let used_dir = match D::dir() { 378 let used_dir = match D::dir() {
331 Direction::Out => ep.used_out, 379 Direction::Out => ep.used_out,
332 Direction::In => ep.used_in, 380 Direction::In => ep.used_in,
@@ -350,7 +398,11 @@ impl<'d, T: Instance> Driver<'d, T> {
350 let addr = self.alloc_ep_mem(len); 398 let addr = self.alloc_ep_mem(len);
351 399
352 trace!(" len_bits = {:04x}", len_bits); 400 trace!(" len_bits = {:04x}", len_bits);
353 btable::write_out::<T>(index, addr, len_bits); 401 btable::write_out_rx::<T>(index, addr, len_bits);
402
403 if ep_type == EndpointType::Isochronous {
404 btable::write_out_tx::<T>(index, addr, len_bits);
405 }
354 406
355 EndpointBuffer { 407 EndpointBuffer {
356 addr, 408 addr,
@@ -366,7 +418,11 @@ impl<'d, T: Instance> Driver<'d, T> {
366 let addr = self.alloc_ep_mem(len); 418 let addr = self.alloc_ep_mem(len);
367 419
368 // ep_in_len is written when actually TXing packets. 420 // ep_in_len is written when actually TXing packets.
369 btable::write_in::<T>(index, addr); 421 btable::write_in_tx::<T>(index, addr);
422
423 if ep_type == EndpointType::Isochronous {
424 btable::write_in_rx::<T>(index, addr);
425 }
370 426
371 EndpointBuffer { 427 EndpointBuffer {
372 addr, 428 addr,
@@ -656,6 +712,18 @@ impl Dir for Out {
656 } 712 }
657} 713}
658 714
715/// Selects the packet buffer.
716///
717/// For double-buffered endpoints, both the `Rx` and `Tx` buffer from a channel are used for the same
718/// direction of transfer. This is opposed to single-buffered endpoints, where one channel can serve
719/// two directions at the same time.
720enum PacketBuffer {
721 /// The RX buffer - must be used for single-buffered OUT endpoints
722 Rx,
723 /// The TX buffer - must be used for single-buffered IN endpoints
724 Tx,
725}
726
659/// USB endpoint. 727/// USB endpoint.
660pub struct Endpoint<'d, T: Instance, D> { 728pub struct Endpoint<'d, T: Instance, D> {
661 _phantom: PhantomData<(&'d mut T, D)>, 729 _phantom: PhantomData<(&'d mut T, D)>,
@@ -664,15 +732,46 @@ pub struct Endpoint<'d, T: Instance, D> {
664} 732}
665 733
666impl<'d, T: Instance, D> Endpoint<'d, T, D> { 734impl<'d, T: Instance, D> Endpoint<'d, T, D> {
667 fn write_data(&mut self, buf: &[u8]) { 735 /// Write to a double-buffered endpoint.
736 ///
737 /// For double-buffered endpoints, the data buffers overlap, but we still need to write to the right counter field.
738 /// The DTOG_TX bit indicates the buffer that is currently in use by the USB peripheral, that is, the buffer in
739 /// which the next transmit packet will be stored, so we need to write the counter of the OTHER buffer, which is
740 /// where the last transmitted packet was stored.
741 fn write_data_double_buffered(&mut self, buf: &[u8], packet_buffer: PacketBuffer) {
668 let index = self.info.addr.index(); 742 let index = self.info.addr.index();
669 self.buf.write(buf); 743 self.buf.write(buf);
670 btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _); 744
745 match packet_buffer {
746 PacketBuffer::Rx => btable::write_in_len_rx::<T>(index, self.buf.addr, buf.len() as _),
747 PacketBuffer::Tx => btable::write_in_len_tx::<T>(index, self.buf.addr, buf.len() as _),
748 }
671 } 749 }
672 750
673 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { 751 /// Write to a single-buffered endpoint.
752 fn write_data(&mut self, buf: &[u8]) {
753 self.write_data_double_buffered(buf, PacketBuffer::Tx);
754 }
755
756 /// Read from a double-buffered endpoint.
757 ///
758 /// For double-buffered endpoints, the data buffers overlap, but we still need to read from the right counter field.
759 /// The DTOG_RX bit indicates the buffer that is currently in use by the USB peripheral, that is, the buffer in
760 /// which the next received packet will be stored, so we need to read the counter of the OTHER buffer, which is
761 /// where the last received packet was stored.
762 fn read_data_double_buffered(
763 &mut self,
764 buf: &mut [u8],
765 packet_buffer: PacketBuffer,
766 ) -> Result<usize, EndpointError> {
674 let index = self.info.addr.index(); 767 let index = self.info.addr.index();
675 let rx_len = btable::read_out_len::<T>(index) as usize & 0x3FF; 768
769 let rx_len = match packet_buffer {
770 PacketBuffer::Rx => btable::read_out_len_rx::<T>(index),
771 PacketBuffer::Tx => btable::read_out_len_tx::<T>(index),
772 } as usize
773 & 0x3FF;
774
676 trace!("READ DONE, rx_len = {}", rx_len); 775 trace!("READ DONE, rx_len = {}", rx_len);
677 if rx_len > buf.len() { 776 if rx_len > buf.len() {
678 return Err(EndpointError::BufferOverflow); 777 return Err(EndpointError::BufferOverflow);
@@ -680,6 +779,11 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> {
680 self.buf.read(&mut buf[..rx_len]); 779 self.buf.read(&mut buf[..rx_len]);
681 Ok(rx_len) 780 Ok(rx_len)
682 } 781 }
782
783 /// Read from a single-buffered endpoint.
784 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
785 self.read_data_double_buffered(buf, PacketBuffer::Rx)
786 }
683} 787}
684 788
685impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { 789impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
@@ -734,25 +838,53 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
734 EP_OUT_WAKERS[index].register(cx.waker()); 838 EP_OUT_WAKERS[index].register(cx.waker());
735 let regs = T::regs(); 839 let regs = T::regs();
736 let stat = regs.epr(index).read().stat_rx(); 840 let stat = regs.epr(index).read().stat_rx();
737 if matches!(stat, Stat::NAK | Stat::DISABLED) { 841 if self.info.ep_type == EndpointType::Isochronous {
738 Poll::Ready(stat) 842 // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet.
843 // Therefore, this instead waits until the `CTR` interrupt was triggered.
844 if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) {
845 Poll::Ready(stat)
846 } else {
847 Poll::Pending
848 }
739 } else { 849 } else {
740 Poll::Pending 850 if matches!(stat, Stat::NAK | Stat::DISABLED) {
851 Poll::Ready(stat)
852 } else {
853 Poll::Pending
854 }
741 } 855 }
742 }) 856 })
743 .await; 857 .await;
744 858
859 CTR_TRIGGERED[index].store(false, Ordering::Relaxed);
860
745 if stat == Stat::DISABLED { 861 if stat == Stat::DISABLED {
746 return Err(EndpointError::Disabled); 862 return Err(EndpointError::Disabled);
747 } 863 }
748 864
749 let rx_len = self.read_data(buf)?;
750
751 let regs = T::regs(); 865 let regs = T::regs();
866
867 let packet_buffer = if self.info.ep_type == EndpointType::Isochronous {
868 // Find the buffer, which is currently in use. Read from the OTHER buffer.
869 if regs.epr(index).read().dtog_rx() {
870 PacketBuffer::Rx
871 } else {
872 PacketBuffer::Tx
873 }
874 } else {
875 PacketBuffer::Rx
876 };
877
878 let rx_len = self.read_data_double_buffered(buf, packet_buffer)?;
879
752 regs.epr(index).write(|w| { 880 regs.epr(index).write(|w| {
753 w.set_ep_type(convert_type(self.info.ep_type)); 881 w.set_ep_type(convert_type(self.info.ep_type));
754 w.set_ea(self.info.addr.index() as _); 882 w.set_ea(self.info.addr.index() as _);
755 w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); 883 if self.info.ep_type == EndpointType::Isochronous {
884 w.set_stat_rx(Stat::from_bits(0)); // STAT_RX remains `VALID`.
885 } else {
886 w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
887 }
756 w.set_stat_tx(Stat::from_bits(0)); 888 w.set_stat_tx(Stat::from_bits(0));
757 w.set_ctr_rx(true); // don't clear 889 w.set_ctr_rx(true); // don't clear
758 w.set_ctr_tx(true); // don't clear 890 w.set_ctr_tx(true); // don't clear
@@ -776,25 +908,54 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
776 EP_IN_WAKERS[index].register(cx.waker()); 908 EP_IN_WAKERS[index].register(cx.waker());
777 let regs = T::regs(); 909 let regs = T::regs();
778 let stat = regs.epr(index).read().stat_tx(); 910 let stat = regs.epr(index).read().stat_tx();
779 if matches!(stat, Stat::NAK | Stat::DISABLED) { 911 if self.info.ep_type == EndpointType::Isochronous {
780 Poll::Ready(stat) 912 // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet.
913 // Therefore, this instead waits until the `CTR` interrupt was triggered.
914 if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) {
915 Poll::Ready(stat)
916 } else {
917 Poll::Pending
918 }
781 } else { 919 } else {
782 Poll::Pending 920 if matches!(stat, Stat::NAK | Stat::DISABLED) {
921 Poll::Ready(stat)
922 } else {
923 Poll::Pending
924 }
783 } 925 }
784 }) 926 })
785 .await; 927 .await;
786 928
929 CTR_TRIGGERED[index].store(false, Ordering::Relaxed);
930
787 if stat == Stat::DISABLED { 931 if stat == Stat::DISABLED {
788 return Err(EndpointError::Disabled); 932 return Err(EndpointError::Disabled);
789 } 933 }
790 934
791 self.write_data(buf); 935 let regs = T::regs();
936
937 let packet_buffer = if self.info.ep_type == EndpointType::Isochronous {
938 // Find the buffer, which is currently in use. Write to the OTHER buffer.
939 if regs.epr(index).read().dtog_tx() {
940 PacketBuffer::Tx
941 } else {
942 PacketBuffer::Rx
943 }
944 } else {
945 PacketBuffer::Tx
946 };
947
948 self.write_data_double_buffered(buf, packet_buffer);
792 949
793 let regs = T::regs(); 950 let regs = T::regs();
794 regs.epr(index).write(|w| { 951 regs.epr(index).write(|w| {
795 w.set_ep_type(convert_type(self.info.ep_type)); 952 w.set_ep_type(convert_type(self.info.ep_type));
796 w.set_ea(self.info.addr.index() as _); 953 w.set_ea(self.info.addr.index() as _);
797 w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); 954 if self.info.ep_type == EndpointType::Isochronous {
955 w.set_stat_tx(Stat::from_bits(0)); // STAT_TX remains `VALID`.
956 } else {
957 w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
958 }
798 w.set_stat_rx(Stat::from_bits(0)); 959 w.set_stat_rx(Stat::from_bits(0));
799 w.set_ctr_rx(true); // don't clear 960 w.set_ctr_rx(true); // don't clear
800 w.set_ctr_tx(true); // don't clear 961 w.set_ctr_tx(true); // don't clear
diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs
index 5fb82db42..b145f4aa8 100644
--- a/embassy-usb-synopsys-otg/src/lib.rs
+++ b/embassy-usb-synopsys-otg/src/lib.rs
@@ -1071,6 +1071,21 @@ impl<'d> embassy_usb_driver::EndpointOut for Endpoint<'d, Out> {
1071 w.set_pktcnt(1); 1071 w.set_pktcnt(1);
1072 }); 1072 });
1073 1073
1074 if self.info.ep_type == EndpointType::Isochronous {
1075 // Isochronous endpoints must set the correct even/odd frame bit to
1076 // correspond with the next frame's number.
1077 let frame_number = self.regs.dsts().read().fnsof();
1078 let frame_is_odd = frame_number & 0x01 == 1;
1079
1080 self.regs.doepctl(index).modify(|r| {
1081 if frame_is_odd {
1082 r.set_sd0pid_sevnfrm(true);
1083 } else {
1084 r.set_sd1pid_soddfrm(true);
1085 }
1086 });
1087 }
1088
1074 // Clear NAK to indicate we are ready to receive more data 1089 // Clear NAK to indicate we are ready to receive more data
1075 self.regs.doepctl(index).modify(|w| { 1090 self.regs.doepctl(index).modify(|w| {
1076 w.set_cnak(true); 1091 w.set_cnak(true);
@@ -1158,6 +1173,21 @@ impl<'d> embassy_usb_driver::EndpointIn for Endpoint<'d, In> {
1158 w.set_xfrsiz(buf.len() as _); 1173 w.set_xfrsiz(buf.len() as _);
1159 }); 1174 });
1160 1175
1176 if self.info.ep_type == EndpointType::Isochronous {
1177 // Isochronous endpoints must set the correct even/odd frame bit to
1178 // correspond with the next frame's number.
1179 let frame_number = self.regs.dsts().read().fnsof();
1180 let frame_is_odd = frame_number & 0x01 == 1;
1181
1182 self.regs.diepctl(index).modify(|r| {
1183 if frame_is_odd {
1184 r.set_sd0pid_sevnfrm(true);
1185 } else {
1186 r.set_sd1pid_soddfrm(true);
1187 }
1188 });
1189 }
1190
1161 // Enable endpoint 1191 // Enable endpoint
1162 self.regs.diepctl(index).modify(|w| { 1192 self.regs.diepctl(index).modify(|w| {
1163 w.set_cnak(true); 1193 w.set_cnak(true);
diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs
index a8530980c..d3abc328d 100644
--- a/embassy-usb-synopsys-otg/src/otg_v1.rs
+++ b/embassy-usb-synopsys-otg/src/otg_v1.rs
@@ -795,15 +795,15 @@ pub mod regs {
795 pub fn set_sd0pid_sevnfrm(&mut self, val: bool) { 795 pub fn set_sd0pid_sevnfrm(&mut self, val: bool) {
796 self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); 796 self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize);
797 } 797 }
798 #[doc = "SODDFRM/SD1PID"] 798 #[doc = "SD1PID/SODDFRM"]
799 #[inline(always)] 799 #[inline(always)]
800 pub const fn soddfrm_sd1pid(&self) -> bool { 800 pub const fn sd1pid_soddfrm(&self) -> bool {
801 let val = (self.0 >> 29usize) & 0x01; 801 let val = (self.0 >> 29usize) & 0x01;
802 val != 0 802 val != 0
803 } 803 }
804 #[doc = "SODDFRM/SD1PID"] 804 #[doc = "SD1PID/SODDFRM"]
805 #[inline(always)] 805 #[inline(always)]
806 pub fn set_soddfrm_sd1pid(&mut self, val: bool) { 806 pub fn set_sd1pid_soddfrm(&mut self, val: bool) {
807 self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); 807 self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize);
808 } 808 }
809 #[doc = "EPDIS"] 809 #[doc = "EPDIS"]
@@ -1174,15 +1174,15 @@ pub mod regs {
1174 pub fn set_sd0pid_sevnfrm(&mut self, val: bool) { 1174 pub fn set_sd0pid_sevnfrm(&mut self, val: bool) {
1175 self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); 1175 self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize);
1176 } 1176 }
1177 #[doc = "SODDFRM"] 1177 #[doc = "SD1PID/SODDFRM"]
1178 #[inline(always)] 1178 #[inline(always)]
1179 pub const fn soddfrm(&self) -> bool { 1179 pub const fn sd1pid_soddfrm(&self) -> bool {
1180 let val = (self.0 >> 29usize) & 0x01; 1180 let val = (self.0 >> 29usize) & 0x01;
1181 val != 0 1181 val != 0
1182 } 1182 }
1183 #[doc = "SODDFRM"] 1183 #[doc = "SD1PID/SODDFRM"]
1184 #[inline(always)] 1184 #[inline(always)]
1185 pub fn set_soddfrm(&mut self, val: bool) { 1185 pub fn set_sd1pid_soddfrm(&mut self, val: bool) {
1186 self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); 1186 self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize);
1187 } 1187 }
1188 #[doc = "EPDIS"] 1188 #[doc = "EPDIS"]
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 7168e077c..e1bf8041f 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -1,8 +1,8 @@
1use heapless::Vec; 1use heapless::Vec;
2 2
3use crate::config::MAX_HANDLER_COUNT; 3use crate::config::MAX_HANDLER_COUNT;
4use crate::descriptor::{BosWriter, DescriptorWriter}; 4use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageType};
5use crate::driver::{Driver, Endpoint, EndpointType}; 5use crate::driver::{Driver, Endpoint, EndpointInfo, EndpointType};
6use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; 6use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter};
7use crate::types::{InterfaceNumber, StringIndex}; 7use crate::types::{InterfaceNumber, StringIndex};
8use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; 8use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
@@ -414,7 +414,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
414 /// Descriptors are written in the order builder functions are called. Note that some 414 /// Descriptors are written in the order builder functions are called. Note that some
415 /// classes care about the order. 415 /// classes care about the order.
416 pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) { 416 pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) {
417 self.builder.config_descriptor.write(descriptor_type, descriptor); 417 self.builder.config_descriptor.write(descriptor_type, descriptor, &[]);
418 } 418 }
419 419
420 /// Add a custom Binary Object Store (BOS) descriptor to this alternate setting. 420 /// Add a custom Binary Object Store (BOS) descriptor to this alternate setting.
@@ -422,26 +422,80 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
422 self.builder.bos_descriptor.capability(capability_type, capability); 422 self.builder.bos_descriptor.capability(capability_type, capability);
423 } 423 }
424 424
425 fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { 425 /// Write a custom endpoint descriptor for a certain endpoint.
426 ///
427 /// This can be necessary, if the endpoint descriptors can only be written
428 /// after the endpoint was created. As an example, an endpoint descriptor
429 /// may contain the address of an endpoint that was allocated earlier.
430 pub fn endpoint_descriptor(
431 &mut self,
432 endpoint: &EndpointInfo,
433 synchronization_type: SynchronizationType,
434 usage_type: UsageType,
435 extra_fields: &[u8],
436 ) {
437 self.builder
438 .config_descriptor
439 .endpoint(endpoint, synchronization_type, usage_type, extra_fields);
440 }
441
442 /// Allocate an IN endpoint, without writing its descriptor.
443 ///
444 /// Used for granular control over the order of endpoint and descriptor creation.
445 pub fn alloc_endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {
426 let ep = self 446 let ep = self
427 .builder 447 .builder
428 .driver 448 .driver
429 .alloc_endpoint_in(ep_type, max_packet_size, interval_ms) 449 .alloc_endpoint_in(ep_type, max_packet_size, interval_ms)
430 .expect("alloc_endpoint_in failed"); 450 .expect("alloc_endpoint_in failed");
431 451
432 self.builder.config_descriptor.endpoint(ep.info()); 452 ep
453 }
454
455 fn endpoint_in(
456 &mut self,
457 ep_type: EndpointType,
458 max_packet_size: u16,
459 interval_ms: u8,
460 synchronization_type: SynchronizationType,
461 usage_type: UsageType,
462 extra_fields: &[u8],
463 ) -> D::EndpointIn {
464 let ep = self.alloc_endpoint_in(ep_type, max_packet_size, interval_ms);
465 self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
433 466
434 ep 467 ep
435 } 468 }
436 469
437 fn endpoint_out(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { 470 /// Allocate an OUT endpoint, without writing its descriptor.
471 ///
472 /// Use for granular control over the order of endpoint and descriptor creation.
473 pub fn alloc_endpoint_out(
474 &mut self,
475 ep_type: EndpointType,
476 max_packet_size: u16,
477 interval_ms: u8,
478 ) -> D::EndpointOut {
438 let ep = self 479 let ep = self
439 .builder 480 .builder
440 .driver 481 .driver
441 .alloc_endpoint_out(ep_type, max_packet_size, interval_ms) 482 .alloc_endpoint_out(ep_type, max_packet_size, interval_ms)
442 .expect("alloc_endpoint_out failed"); 483 .expect("alloc_endpoint_out failed");
443 484
444 self.builder.config_descriptor.endpoint(ep.info()); 485 ep
486 }
487
488 fn endpoint_out(
489 &mut self,
490 ep_type: EndpointType,
491 max_packet_size: u16,
492 interval_ms: u8,
493 synchronization_type: SynchronizationType,
494 usage_type: UsageType,
495 extra_fields: &[u8],
496 ) -> D::EndpointOut {
497 let ep = self.alloc_endpoint_out(ep_type, max_packet_size, interval_ms);
498 self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
445 499
446 ep 500 ep
447 } 501 }
@@ -451,7 +505,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
451 /// Descriptors are written in the order builder functions are called. Note that some 505 /// Descriptors are written in the order builder functions are called. Note that some
452 /// classes care about the order. 506 /// classes care about the order.
453 pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn { 507 pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn {
454 self.endpoint_in(EndpointType::Bulk, max_packet_size, 0) 508 self.endpoint_in(
509 EndpointType::Bulk,
510 max_packet_size,
511 0,
512 SynchronizationType::NoSynchronization,
513 UsageType::DataEndpoint,
514 &[],
515 )
455 } 516 }
456 517
457 /// Allocate a BULK OUT endpoint and write its descriptor. 518 /// Allocate a BULK OUT endpoint and write its descriptor.
@@ -459,7 +520,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
459 /// Descriptors are written in the order builder functions are called. Note that some 520 /// Descriptors are written in the order builder functions are called. Note that some
460 /// classes care about the order. 521 /// classes care about the order.
461 pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut { 522 pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut {
462 self.endpoint_out(EndpointType::Bulk, max_packet_size, 0) 523 self.endpoint_out(
524 EndpointType::Bulk,
525 max_packet_size,
526 0,
527 SynchronizationType::NoSynchronization,
528 UsageType::DataEndpoint,
529 &[],
530 )
463 } 531 }
464 532
465 /// Allocate a INTERRUPT IN endpoint and write its descriptor. 533 /// Allocate a INTERRUPT IN endpoint and write its descriptor.
@@ -467,24 +535,66 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
467 /// Descriptors are written in the order builder functions are called. Note that some 535 /// Descriptors are written in the order builder functions are called. Note that some
468 /// classes care about the order. 536 /// classes care about the order.
469 pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { 537 pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {
470 self.endpoint_in(EndpointType::Interrupt, max_packet_size, interval_ms) 538 self.endpoint_in(
539 EndpointType::Interrupt,
540 max_packet_size,
541 interval_ms,
542 SynchronizationType::NoSynchronization,
543 UsageType::DataEndpoint,
544 &[],
545 )
471 } 546 }
472 547
473 /// Allocate a INTERRUPT OUT endpoint and write its descriptor. 548 /// Allocate a INTERRUPT OUT endpoint and write its descriptor.
474 pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { 549 pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut {
475 self.endpoint_out(EndpointType::Interrupt, max_packet_size, interval_ms) 550 self.endpoint_out(
551 EndpointType::Interrupt,
552 max_packet_size,
553 interval_ms,
554 SynchronizationType::NoSynchronization,
555 UsageType::DataEndpoint,
556 &[],
557 )
476 } 558 }
477 559
478 /// Allocate a ISOCHRONOUS IN endpoint and write its descriptor. 560 /// Allocate a ISOCHRONOUS IN endpoint and write its descriptor.
479 /// 561 ///
480 /// Descriptors are written in the order builder functions are called. Note that some 562 /// Descriptors are written in the order builder functions are called. Note that some
481 /// classes care about the order. 563 /// classes care about the order.
482 pub fn endpoint_isochronous_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { 564 pub fn endpoint_isochronous_in(
483 self.endpoint_in(EndpointType::Isochronous, max_packet_size, interval_ms) 565 &mut self,
566 max_packet_size: u16,
567 interval_ms: u8,
568 synchronization_type: SynchronizationType,
569 usage_type: UsageType,
570 extra_fields: &[u8],
571 ) -> D::EndpointIn {
572 self.endpoint_in(
573 EndpointType::Isochronous,
574 max_packet_size,
575 interval_ms,
576 synchronization_type,
577 usage_type,
578 extra_fields,
579 )
484 } 580 }
485 581
486 /// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor. 582 /// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor.
487 pub fn endpoint_isochronous_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { 583 pub fn endpoint_isochronous_out(
488 self.endpoint_out(EndpointType::Isochronous, max_packet_size, interval_ms) 584 &mut self,
585 max_packet_size: u16,
586 interval_ms: u8,
587 synchronization_type: SynchronizationType,
588 usage_type: UsageType,
589 extra_fields: &[u8],
590 ) -> D::EndpointOut {
591 self.endpoint_out(
592 EndpointType::Isochronous,
593 max_packet_size,
594 interval_ms,
595 synchronization_type,
596 usage_type,
597 extra_fields,
598 )
489 } 599 }
490} 600}
diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs
index c4d79e39f..06ebe0481 100644
--- a/embassy-usb/src/descriptor.rs
+++ b/embassy-usb/src/descriptor.rs
@@ -1,4 +1,5 @@
1//! Utilities for writing USB descriptors. 1//! Utilities for writing USB descriptors.
2use embassy_usb_driver::EndpointType;
2 3
3use crate::builder::Config; 4use crate::builder::Config;
4use crate::driver::EndpointInfo; 5use crate::driver::EndpointInfo;
@@ -38,6 +39,40 @@ pub mod capability_type {
38 pub const PLATFORM: u8 = 5; 39 pub const PLATFORM: u8 = 5;
39} 40}
40 41
42/// USB endpoint synchronization type. The values of this enum can be directly
43/// cast into `u8` to get the bmAttributes synchronization type bits.
44/// Values other than `NoSynchronization` are only allowed on isochronous endpoints.
45#[repr(u8)]
46#[derive(Copy, Clone, Eq, PartialEq, Debug)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48pub enum SynchronizationType {
49 /// No synchronization is used.
50 NoSynchronization = 0b00,
51 /// Unsynchronized, although sinks provide data rate feedback.
52 Asynchronous = 0b01,
53 /// Synchronized using feedback or feedforward data rate information.
54 Adaptive = 0b10,
55 /// Synchronized to the USB’s SOF.
56 Synchronous = 0b11,
57}
58
59/// USB endpoint usage type. The values of this enum can be directly cast into
60/// `u8` to get the bmAttributes usage type bits.
61/// Values other than `DataEndpoint` are only allowed on isochronous endpoints.
62#[repr(u8)]
63#[derive(Copy, Clone, Eq, PartialEq, Debug)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65pub enum UsageType {
66 /// Use the endpoint for regular data transfer.
67 DataEndpoint = 0b00,
68 /// Endpoint conveys explicit feedback information for one or more data endpoints.
69 FeedbackEndpoint = 0b01,
70 /// A data endpoint that also serves as an implicit feedback endpoint for one or more data endpoints.
71 ImplicitFeedbackDataEndpoint = 0b10,
72 /// Reserved usage type.
73 Reserved = 0b11,
74}
75
41/// A writer for USB descriptors. 76/// A writer for USB descriptors.
42pub(crate) struct DescriptorWriter<'a> { 77pub(crate) struct DescriptorWriter<'a> {
43 pub buf: &'a mut [u8], 78 pub buf: &'a mut [u8],
@@ -65,23 +100,26 @@ impl<'a> DescriptorWriter<'a> {
65 self.position 100 self.position
66 } 101 }
67 102
68 /// Writes an arbitrary (usually class-specific) descriptor. 103 /// Writes an arbitrary (usually class-specific) descriptor with optional extra fields.
69 pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) { 104 pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8], extra_fields: &[u8]) {
70 let length = descriptor.len(); 105 let descriptor_length = descriptor.len();
106 let extra_fields_length = extra_fields.len();
107 let total_length = descriptor_length + extra_fields_length;
71 108
72 assert!( 109 assert!(
73 (self.position + 2 + length) <= self.buf.len() && (length + 2) <= 255, 110 (self.position + 2 + total_length) <= self.buf.len() && (total_length + 2) <= 255,
74 "Descriptor buffer full" 111 "Descriptor buffer full"
75 ); 112 );
76 113
77 self.buf[self.position] = (length + 2) as u8; 114 self.buf[self.position] = (total_length + 2) as u8;
78 self.buf[self.position + 1] = descriptor_type; 115 self.buf[self.position + 1] = descriptor_type;
79 116
80 let start = self.position + 2; 117 let start = self.position + 2;
81 118
82 self.buf[start..start + length].copy_from_slice(descriptor); 119 self.buf[start..start + descriptor_length].copy_from_slice(descriptor);
120 self.buf[start + descriptor_length..start + total_length].copy_from_slice(extra_fields);
83 121
84 self.position = start + length; 122 self.position = start + total_length;
85 } 123 }
86 124
87 pub(crate) fn configuration(&mut self, config: &Config) { 125 pub(crate) fn configuration(&mut self, config: &Config) {
@@ -99,6 +137,7 @@ impl<'a> DescriptorWriter<'a> {
99 | if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes 137 | if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes
100 (config.max_power / 2) as u8, // bMaxPower 138 (config.max_power / 2) as u8, // bMaxPower
101 ], 139 ],
140 &[],
102 ); 141 );
103 } 142 }
104 143
@@ -145,6 +184,7 @@ impl<'a> DescriptorWriter<'a> {
145 function_protocol, 184 function_protocol,
146 0, 185 0,
147 ], 186 ],
187 &[],
148 ); 188 );
149 } 189 }
150 190
@@ -195,6 +235,7 @@ impl<'a> DescriptorWriter<'a> {
195 interface_protocol, // bInterfaceProtocol 235 interface_protocol, // bInterfaceProtocol
196 str_index, // iInterface 236 str_index, // iInterface
197 ], 237 ],
238 &[],
198 ); 239 );
199 } 240 }
200 241
@@ -204,21 +245,50 @@ impl<'a> DescriptorWriter<'a> {
204 /// 245 ///
205 /// * `endpoint` - Endpoint previously allocated with 246 /// * `endpoint` - Endpoint previously allocated with
206 /// [`UsbDeviceBuilder`](crate::bus::UsbDeviceBuilder). 247 /// [`UsbDeviceBuilder`](crate::bus::UsbDeviceBuilder).
207 pub fn endpoint(&mut self, endpoint: &EndpointInfo) { 248 /// * `synchronization_type` - The synchronization type of the endpoint.
249 /// * `usage_type` - The usage type of the endpoint.
250 /// * `extra_fields` - Additional, class-specific entries at the end of the endpoint descriptor.
251 pub fn endpoint(
252 &mut self,
253 endpoint: &EndpointInfo,
254 synchronization_type: SynchronizationType,
255 usage_type: UsageType,
256 extra_fields: &[u8],
257 ) {
208 match self.num_endpoints_mark { 258 match self.num_endpoints_mark {
209 Some(mark) => self.buf[mark] += 1, 259 Some(mark) => self.buf[mark] += 1,
210 None => panic!("you can only call `endpoint` after `interface/interface_alt`."), 260 None => panic!("you can only call `endpoint` after `interface/interface_alt`."),
211 }; 261 };
212 262
263 let mut bm_attributes = endpoint.ep_type as u8;
264
265 // Synchronization types other than `NoSynchronization`,
266 // and usage types other than `DataEndpoint`
267 // are only allowed for isochronous endpoints.
268 if endpoint.ep_type != EndpointType::Isochronous {
269 assert_eq!(synchronization_type, SynchronizationType::NoSynchronization);
270 assert_eq!(usage_type, UsageType::DataEndpoint);
271 } else {
272 if usage_type == UsageType::FeedbackEndpoint {
273 assert_eq!(synchronization_type, SynchronizationType::NoSynchronization)
274 }
275
276 let synchronization_bm_attibutes: u8 = (synchronization_type as u8) << 2;
277 let usage_bm_attibutes: u8 = (usage_type as u8) << 4;
278
279 bm_attributes |= usage_bm_attibutes | synchronization_bm_attibutes;
280 }
281
213 self.write( 282 self.write(
214 descriptor_type::ENDPOINT, 283 descriptor_type::ENDPOINT,
215 &[ 284 &[
216 endpoint.addr.into(), // bEndpointAddress 285 endpoint.addr.into(), // bEndpointAddress
217 endpoint.ep_type as u8, // bmAttributes 286 bm_attributes, // bmAttributes
218 endpoint.max_packet_size as u8, 287 endpoint.max_packet_size as u8,
219 (endpoint.max_packet_size >> 8) as u8, // wMaxPacketSize 288 (endpoint.max_packet_size >> 8) as u8, // wMaxPacketSize
220 endpoint.interval_ms, // bInterval 289 endpoint.interval_ms, // bInterval
221 ], 290 ],
291 extra_fields,
222 ); 292 );
223 } 293 }
224 294
@@ -318,6 +388,7 @@ impl<'a> BosWriter<'a> {
318 0x00, 0x00, // wTotalLength 388 0x00, 0x00, // wTotalLength
319 0x00, // bNumDeviceCaps 389 0x00, // bNumDeviceCaps
320 ], 390 ],
391 &[],
321 ); 392 );
322 393
323 self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4]); 394 self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4]);
diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
index 94cf09c88..0946492fe 100644
--- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs
+++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_net_enc28j60::Enc28j60; 8use embassy_net_enc28j60::Enc28j60;
9use embassy_nrf::gpio::{Level, Output, OutputDrive}; 9use embassy_nrf::gpio::{Level, Output, OutputDrive};
10use embassy_nrf::rng::Rng; 10use embassy_nrf::rng::Rng;
@@ -23,11 +23,12 @@ bind_interrupts!(struct Irqs {
23 23
24#[embassy_executor::task] 24#[embassy_executor::task]
25async fn net_task( 25async fn net_task(
26 stack: &'static Stack< 26 mut runner: embassy_net::Runner<
27 'static,
27 Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>, 28 Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>,
28 >, 29 >,
29) -> ! { 30) -> ! {
30 stack.run().await 31 runner.run().await
31} 32}
32 33
33#[embassy_executor::main] 34#[embassy_executor::main]
@@ -67,12 +68,9 @@ async fn main(spawner: Spawner) {
67 68
68 // Init network stack 69 // Init network stack
69 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 70 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
70 static STACK: StaticCell< 71 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
71 Stack<Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>>,
72 > = StaticCell::new();
73 let stack = STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
74 72
75 unwrap!(spawner.spawn(net_task(stack))); 73 unwrap!(spawner.spawn(net_task(runner)));
76 74
77 // And now we can use it! 75 // And now we can use it!
78 76
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index e56b215e3..b07adac1f 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -6,7 +6,7 @@ use core::mem;
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_net::tcp::TcpSocket; 8use embassy_net::tcp::TcpSocket;
9use embassy_net::{Stack, StackResources}; 9use embassy_net::StackResources;
10use embassy_nrf::rng::Rng; 10use embassy_nrf::rng::Rng;
11use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; 11use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
12use embassy_nrf::usb::Driver; 12use embassy_nrf::usb::Driver;
@@ -39,8 +39,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
39} 39}
40 40
41#[embassy_executor::task] 41#[embassy_executor::task]
42async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 42async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
43 stack.run().await 43 runner.run().await
44} 44}
45 45
46#[embassy_executor::main] 46#[embassy_executor::main]
@@ -116,10 +116,9 @@ async fn main(spawner: Spawner) {
116 116
117 // Init network stack 117 // Init network stack
118 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 118 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
119 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); 119 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
120 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
121 120
122 unwrap!(spawner.spawn(net_task(stack))); 121 unwrap!(spawner.spawn(net_task(runner)));
123 122
124 // And now we can use it! 123 // And now we can use it!
125 124
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index a3b69a99b..26eaf485e 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -4,7 +4,7 @@
4use defmt::{info, unwrap, warn}; 4use defmt::{info, unwrap, warn};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; 8use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
9use embassy_nrf::rng::Rng; 9use embassy_nrf::rng::Rng;
10use embassy_nrf::spim::{self, Spim}; 10use embassy_nrf::spim::{self, Spim};
@@ -36,8 +36,8 @@ async fn wifi_task(
36} 36}
37 37
38#[embassy_executor::task] 38#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<hosted::NetDriver<'static>>) -> ! { 39async fn net_task(mut runner: embassy_net::Runner<'static, hosted::NetDriver<'static>>) -> ! {
40 stack.run().await 40 runner.run().await
41} 41}
42 42
43#[embassy_executor::main] 43#[embassy_executor::main]
@@ -90,10 +90,9 @@ async fn main(spawner: Spawner) {
90 90
91 // Init network stack 91 // Init network stack
92 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 92 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
93 static STACK: StaticCell<Stack<hosted::NetDriver<'static>>> = StaticCell::new(); 93 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
94 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
95 94
96 unwrap!(spawner.spawn(net_task(stack))); 95 unwrap!(spawner.spawn(net_task(runner)));
97 96
98 // And now we can use it! 97 // And now we can use it!
99 98
diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs
index 5335b6b51..929883884 100644
--- a/examples/nrf9160/src/bin/modem_tcp_client.rs
+++ b/examples/nrf9160/src/bin/modem_tcp_client.rs
@@ -46,15 +46,15 @@ async fn modem_task(runner: Runner<'static>) -> ! {
46} 46}
47 47
48#[embassy_executor::task] 48#[embassy_executor::task]
49async fn net_task(stack: &'static Stack<embassy_net_nrf91::NetDriver<'static>>) -> ! { 49async fn net_task(mut runner: embassy_net::Runner<'static, embassy_net_nrf91::NetDriver<'static>>) -> ! {
50 stack.run().await 50 runner.run().await
51} 51}
52 52
53#[embassy_executor::task] 53#[embassy_executor::task]
54async fn control_task( 54async fn control_task(
55 control: &'static context::Control<'static>, 55 control: &'static context::Control<'static>,
56 config: context::Config<'static>, 56 config: context::Config<'static>,
57 stack: &'static Stack<embassy_net_nrf91::NetDriver<'static>>, 57 stack: Stack<'static>,
58) { 58) {
59 unwrap!(control.configure(&config).await); 59 unwrap!(control.configure(&config).await);
60 unwrap!( 60 unwrap!(
@@ -150,15 +150,9 @@ async fn main(spawner: Spawner) {
150 150
151 // Init network stack 151 // Init network stack
152 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 152 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
153 static STACK: StaticCell<Stack<embassy_net_nrf91::NetDriver<'static>>> = StaticCell::new(); 153 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::<2>::new()), seed);
154 let stack = &*STACK.init(Stack::new(
155 device,
156 config,
157 RESOURCES.init(StackResources::<2>::new()),
158 seed,
159 ));
160 154
161 unwrap!(spawner.spawn(net_task(stack))); 155 unwrap!(spawner.spawn(net_task(runner)));
162 156
163 static CONTROL: StaticCell<context::Control<'static>> = StaticCell::new(); 157 static CONTROL: StaticCell<context::Control<'static>> = StaticCell::new();
164 let control = CONTROL.init(context::Control::new(control, 0).await); 158 let control = CONTROL.init(context::Control::new(control, 0).await);
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
index aaa035a72..12003adbe 100644
--- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -36,8 +36,8 @@ async fn ethernet_task(
36} 36}
37 37
38#[embassy_executor::task] 38#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 39async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
40 stack.run().await 40 runner.run().await
41} 41}
42 42
43#[embassy_executor::main] 43#[embassy_executor::main]
@@ -71,17 +71,16 @@ async fn main(spawner: Spawner) {
71 let seed = rng.next_u64(); 71 let seed = rng.next_u64();
72 72
73 // Init network stack 73 // Init network stack
74 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
75 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 74 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
76 let stack = &*STACK.init(Stack::new( 75 let (stack, runner) = embassy_net::new(
77 device, 76 device,
78 embassy_net::Config::dhcpv4(Default::default()), 77 embassy_net::Config::dhcpv4(Default::default()),
79 RESOURCES.init(StackResources::new()), 78 RESOURCES.init(StackResources::new()),
80 seed, 79 seed,
81 )); 80 );
82 81
83 // Launch network task 82 // Launch network task
84 unwrap!(spawner.spawn(net_task(&stack))); 83 unwrap!(spawner.spawn(net_task(runner)));
85 84
86 info!("Waiting for DHCP..."); 85 info!("Waiting for DHCP...");
87 let cfg = wait_for_config(stack).await; 86 let cfg = wait_for_config(stack).await;
@@ -89,12 +88,12 @@ async fn main(spawner: Spawner) {
89 info!("IP address: {:?}", local_addr); 88 info!("IP address: {:?}", local_addr);
90 89
91 // Create two sockets listening to the same port, to handle simultaneous connections 90 // Create two sockets listening to the same port, to handle simultaneous connections
92 unwrap!(spawner.spawn(listen_task(&stack, 0, 1234))); 91 unwrap!(spawner.spawn(listen_task(stack, 0, 1234)));
93 unwrap!(spawner.spawn(listen_task(&stack, 1, 1234))); 92 unwrap!(spawner.spawn(listen_task(stack, 1, 1234)));
94} 93}
95 94
96#[embassy_executor::task(pool_size = 2)] 95#[embassy_executor::task(pool_size = 2)]
97async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16) { 96async fn listen_task(stack: Stack<'static>, id: u8, port: u16) {
98 let mut rx_buffer = [0; 4096]; 97 let mut rx_buffer = [0; 4096];
99 let mut tx_buffer = [0; 4096]; 98 let mut tx_buffer = [0; 4096];
100 let mut buf = [0; 4096]; 99 let mut buf = [0; 4096];
@@ -131,7 +130,7 @@ async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16)
131 } 130 }
132} 131}
133 132
134async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 133async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
135 loop { 134 loop {
136 if let Some(config) = stack.config_v4() { 135 if let Some(config) = stack.config_v4() {
137 return config.clone(); 136 return config.clone();
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
index 8e96a114c..d66a43a88 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -38,8 +38,8 @@ async fn ethernet_task(
38} 38}
39 39
40#[embassy_executor::task] 40#[embassy_executor::task]
41async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 41async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
42 stack.run().await 42 runner.run().await
43} 43}
44 44
45#[embassy_executor::main] 45#[embassy_executor::main]
@@ -74,17 +74,16 @@ async fn main(spawner: Spawner) {
74 let seed = rng.next_u64(); 74 let seed = rng.next_u64();
75 75
76 // Init network stack 76 // Init network stack
77 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
78 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 77 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
79 let stack = &*STACK.init(Stack::new( 78 let (stack, runner) = embassy_net::new(
80 device, 79 device,
81 embassy_net::Config::dhcpv4(Default::default()), 80 embassy_net::Config::dhcpv4(Default::default()),
82 RESOURCES.init(StackResources::new()), 81 RESOURCES.init(StackResources::new()),
83 seed, 82 seed,
84 )); 83 );
85 84
86 // Launch network task 85 // Launch network task
87 unwrap!(spawner.spawn(net_task(&stack))); 86 unwrap!(spawner.spawn(net_task(runner)));
88 87
89 info!("Waiting for DHCP..."); 88 info!("Waiting for DHCP...");
90 let cfg = wait_for_config(stack).await; 89 let cfg = wait_for_config(stack).await;
@@ -119,7 +118,7 @@ async fn main(spawner: Spawner) {
119 } 118 }
120} 119}
121 120
122async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 121async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
123 loop { 122 loop {
124 if let Some(config) = stack.config_v4() { 123 if let Some(config) = stack.config_v4() {
125 return config.clone(); 124 return config.clone();
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
index 40736bf3c..97d9bd4c9 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -37,8 +37,8 @@ async fn ethernet_task(
37} 37}
38 38
39#[embassy_executor::task] 39#[embassy_executor::task]
40async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 40async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
41 stack.run().await 41 runner.run().await
42} 42}
43 43
44#[embassy_executor::main] 44#[embassy_executor::main]
@@ -73,17 +73,16 @@ async fn main(spawner: Spawner) {
73 let seed = rng.next_u64(); 73 let seed = rng.next_u64();
74 74
75 // Init network stack 75 // Init network stack
76 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
77 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 76 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
78 let stack = &*STACK.init(Stack::new( 77 let (stack, runner) = embassy_net::new(
79 device, 78 device,
80 embassy_net::Config::dhcpv4(Default::default()), 79 embassy_net::Config::dhcpv4(Default::default()),
81 RESOURCES.init(StackResources::new()), 80 RESOURCES.init(StackResources::new()),
82 seed, 81 seed,
83 )); 82 );
84 83
85 // Launch network task 84 // Launch network task
86 unwrap!(spawner.spawn(net_task(&stack))); 85 unwrap!(spawner.spawn(net_task(runner)));
87 86
88 info!("Waiting for DHCP..."); 87 info!("Waiting for DHCP...");
89 let cfg = wait_for_config(stack).await; 88 let cfg = wait_for_config(stack).await;
@@ -128,7 +127,7 @@ async fn main(spawner: Spawner) {
128 } 127 }
129} 128}
130 129
131async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 130async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
132 loop { 131 loop {
133 if let Some(config) = stack.config_v4() { 132 if let Some(config) = stack.config_v4() {
134 return config.clone(); 133 return config.clone();
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
index c79f01538..b1b5f9758 100644
--- a/examples/rp/src/bin/ethernet_w5500_udp.rs
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -36,8 +36,8 @@ async fn ethernet_task(
36} 36}
37 37
38#[embassy_executor::task] 38#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 39async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
40 stack.run().await 40 runner.run().await
41} 41}
42 42
43#[embassy_executor::main] 43#[embassy_executor::main]
@@ -71,17 +71,16 @@ async fn main(spawner: Spawner) {
71 let seed = rng.next_u64(); 71 let seed = rng.next_u64();
72 72
73 // Init network stack 73 // Init network stack
74 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
75 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 74 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
76 let stack = &*STACK.init(Stack::new( 75 let (stack, runner) = embassy_net::new(
77 device, 76 device,
78 embassy_net::Config::dhcpv4(Default::default()), 77 embassy_net::Config::dhcpv4(Default::default()),
79 RESOURCES.init(StackResources::new()), 78 RESOURCES.init(StackResources::new()),
80 seed, 79 seed,
81 )); 80 );
82 81
83 // Launch network task 82 // Launch network task
84 unwrap!(spawner.spawn(net_task(&stack))); 83 unwrap!(spawner.spawn(net_task(runner)));
85 84
86 info!("Waiting for DHCP..."); 85 info!("Waiting for DHCP...");
87 let cfg = wait_for_config(stack).await; 86 let cfg = wait_for_config(stack).await;
@@ -108,7 +107,7 @@ async fn main(spawner: Spawner) {
108 } 107 }
109} 108}
110 109
111async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 110async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
112 loop { 111 loop {
113 if let Some(config) = stack.config_v4() { 112 if let Some(config) = stack.config_v4() {
114 return config.clone(); 113 return config.clone();
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 03c510f37..9a15125d4 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -8,7 +8,7 @@
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_net::tcp::TcpSocket; 10use embassy_net::tcp::TcpSocket;
11use embassy_net::{Stack, StackResources}; 11use embassy_net::StackResources;
12use embassy_rp::clocks::RoscRng; 12use embassy_rp::clocks::RoscRng;
13use embassy_rp::peripherals::USB; 13use embassy_rp::peripherals::USB;
14use embassy_rp::usb::{Driver, InterruptHandler}; 14use embassy_rp::usb::{Driver, InterruptHandler};
@@ -40,8 +40,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
40} 40}
41 41
42#[embassy_executor::task] 42#[embassy_executor::task]
43async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 43async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
44 stack.run().await 44 runner.run().await
45} 45}
46 46
47#[embassy_executor::main] 47#[embassy_executor::main]
@@ -108,11 +108,10 @@ async fn main(spawner: Spawner) {
108 let seed = rng.next_u64(); 108 let seed = rng.next_u64();
109 109
110 // Init network stack 110 // Init network stack
111 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
112 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 111 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
113 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 112 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
114 113
115 unwrap!(spawner.spawn(net_task(stack))); 114 unwrap!(spawner.spawn(net_task(runner)));
116 115
117 // And now we can use it! 116 // And now we can use it!
118 117
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
index 00f404a9b..4c9651433 100644
--- a/examples/rp/src/bin/wifi_ap_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -11,7 +11,7 @@ use cyw43_pio::PioSpi;
11use defmt::*; 11use defmt::*;
12use embassy_executor::Spawner; 12use embassy_executor::Spawner;
13use embassy_net::tcp::TcpSocket; 13use embassy_net::tcp::TcpSocket;
14use embassy_net::{Config, Stack, StackResources}; 14use embassy_net::{Config, StackResources};
15use embassy_rp::bind_interrupts; 15use embassy_rp::bind_interrupts;
16use embassy_rp::clocks::RoscRng; 16use embassy_rp::clocks::RoscRng;
17use embassy_rp::gpio::{Level, Output}; 17use embassy_rp::gpio::{Level, Output};
@@ -33,8 +33,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat
33} 33}
34 34
35#[embassy_executor::task] 35#[embassy_executor::task]
36async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 36async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
37 stack.run().await 37 runner.run().await
38} 38}
39 39
40#[embassy_executor::main] 40#[embassy_executor::main]
@@ -80,16 +80,10 @@ async fn main(spawner: Spawner) {
80 let seed = rng.next_u64(); 80 let seed = rng.next_u64();
81 81
82 // Init network stack 82 // Init network stack
83 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
84 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 83 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
85 let stack = &*STACK.init(Stack::new( 84 let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed);
86 net_device, 85
87 config, 86 unwrap!(spawner.spawn(net_task(runner)));
88 RESOURCES.init(StackResources::new()),
89 seed,
90 ));
91
92 unwrap!(spawner.spawn(net_task(stack)));
93 87
94 //control.start_ap_open("cyw43", 5).await; 88 //control.start_ap_open("cyw43", 5).await;
95 control.start_ap_wpa2("cyw43", "password", 5).await; 89 control.start_ap_wpa2("cyw43", "password", 5).await;
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
index ab3529112..434f0074c 100644
--- a/examples/rp/src/bin/wifi_scan.rs
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -10,7 +10,6 @@ use core::str;
10use cyw43_pio::PioSpi; 10use cyw43_pio::PioSpi;
11use defmt::*; 11use defmt::*;
12use embassy_executor::Spawner; 12use embassy_executor::Spawner;
13use embassy_net::Stack;
14use embassy_rp::bind_interrupts; 13use embassy_rp::bind_interrupts;
15use embassy_rp::gpio::{Level, Output}; 14use embassy_rp::gpio::{Level, Output};
16use embassy_rp::peripherals::{DMA_CH0, PIO0}; 15use embassy_rp::peripherals::{DMA_CH0, PIO0};
@@ -28,8 +27,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat
28} 27}
29 28
30#[embassy_executor::task] 29#[embassy_executor::task]
31async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 30async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
32 stack.run().await 31 runner.run().await
33} 32}
34 33
35#[embassy_executor::main] 34#[embassy_executor::main]
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index b2950d98a..7bf546e01 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -12,7 +12,7 @@ use cyw43_pio::PioSpi;
12use defmt::*; 12use defmt::*;
13use embassy_executor::Spawner; 13use embassy_executor::Spawner;
14use embassy_net::tcp::TcpSocket; 14use embassy_net::tcp::TcpSocket;
15use embassy_net::{Config, Stack, StackResources}; 15use embassy_net::{Config, StackResources};
16use embassy_rp::bind_interrupts; 16use embassy_rp::bind_interrupts;
17use embassy_rp::clocks::RoscRng; 17use embassy_rp::clocks::RoscRng;
18use embassy_rp::gpio::{Level, Output}; 18use embassy_rp::gpio::{Level, Output};
@@ -37,8 +37,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat
37} 37}
38 38
39#[embassy_executor::task] 39#[embassy_executor::task]
40async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 40async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
41 stack.run().await 41 runner.run().await
42} 42}
43 43
44#[embassy_executor::main] 44#[embassy_executor::main]
@@ -84,16 +84,10 @@ async fn main(spawner: Spawner) {
84 let seed = rng.next_u64(); 84 let seed = rng.next_u64();
85 85
86 // Init network stack 86 // Init network stack
87 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
88 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 87 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
89 let stack = &*STACK.init(Stack::new( 88 let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed);
90 net_device, 89
91 config, 90 unwrap!(spawner.spawn(net_task(runner)));
92 RESOURCES.init(StackResources::new()),
93 seed,
94 ));
95
96 unwrap!(spawner.spawn(net_task(stack)));
97 91
98 loop { 92 loop {
99 match control 93 match control
diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs
index b43be8905..1ae909917 100644
--- a/examples/rp/src/bin/wifi_webrequest.rs
+++ b/examples/rp/src/bin/wifi_webrequest.rs
@@ -13,7 +13,7 @@ use defmt::*;
13use embassy_executor::Spawner; 13use embassy_executor::Spawner;
14use embassy_net::dns::DnsSocket; 14use embassy_net::dns::DnsSocket;
15use embassy_net::tcp::client::{TcpClient, TcpClientState}; 15use embassy_net::tcp::client::{TcpClient, TcpClientState};
16use embassy_net::{Config, Stack, StackResources}; 16use embassy_net::{Config, StackResources};
17use embassy_rp::bind_interrupts; 17use embassy_rp::bind_interrupts;
18use embassy_rp::clocks::RoscRng; 18use embassy_rp::clocks::RoscRng;
19use embassy_rp::gpio::{Level, Output}; 19use embassy_rp::gpio::{Level, Output};
@@ -40,8 +40,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat
40} 40}
41 41
42#[embassy_executor::task] 42#[embassy_executor::task]
43async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 43async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
44 stack.run().await 44 runner.run().await
45} 45}
46 46
47#[embassy_executor::main] 47#[embassy_executor::main]
@@ -87,16 +87,10 @@ async fn main(spawner: Spawner) {
87 let seed = rng.next_u64(); 87 let seed = rng.next_u64();
88 88
89 // Init network stack 89 // Init network stack
90 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
91 static RESOURCES: StaticCell<StackResources<5>> = StaticCell::new(); 90 static RESOURCES: StaticCell<StackResources<5>> = StaticCell::new();
92 let stack = &*STACK.init(Stack::new( 91 let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed);
93 net_device, 92
94 config, 93 unwrap!(spawner.spawn(net_task(runner)));
95 RESOURCES.init(StackResources::new()),
96 seed,
97 ));
98
99 unwrap!(spawner.spawn(net_task(stack)));
100 94
101 loop { 95 loop {
102 match control 96 match control
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index 310e7264d..cefa5448c 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -1,7 +1,7 @@
1use clap::Parser; 1use clap::Parser;
2use embassy_executor::{Executor, Spawner}; 2use embassy_executor::{Executor, Spawner};
3use embassy_net::tcp::TcpSocket; 3use embassy_net::tcp::TcpSocket;
4use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 4use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources};
5use embassy_net_tuntap::TunTapDevice; 5use embassy_net_tuntap::TunTapDevice;
6use embassy_time::Duration; 6use embassy_time::Duration;
7use embedded_io_async::Write; 7use embedded_io_async::Write;
@@ -22,8 +22,8 @@ struct Opts {
22} 22}
23 23
24#[embassy_executor::task] 24#[embassy_executor::task]
25async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { 25async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! {
26 stack.run().await 26 runner.run().await
27} 27}
28 28
29#[embassy_executor::task] 29#[embassy_executor::task]
@@ -50,12 +50,11 @@ async fn main_task(spawner: Spawner) {
50 let seed = u64::from_le_bytes(seed); 50 let seed = u64::from_le_bytes(seed);
51 51
52 // Init network stack 52 // Init network stack
53 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
54 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 53 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
55 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 54 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
56 55
57 // Launch network task 56 // Launch network task
58 spawner.spawn(net_task(stack)).unwrap(); 57 spawner.spawn(net_task(runner)).unwrap();
59 58
60 // Then we can use it! 59 // Then we can use it!
61 let mut rx_buffer = [0; 4096]; 60 let mut rx_buffer = [0; 4096];
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs
index c9615ef35..a42c5dbb7 100644
--- a/examples/std/src/bin/net_dns.rs
+++ b/examples/std/src/bin/net_dns.rs
@@ -1,7 +1,7 @@
1use clap::Parser; 1use clap::Parser;
2use embassy_executor::{Executor, Spawner}; 2use embassy_executor::{Executor, Spawner};
3use embassy_net::dns::DnsQueryType; 3use embassy_net::dns::DnsQueryType;
4use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 4use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources};
5use embassy_net_tuntap::TunTapDevice; 5use embassy_net_tuntap::TunTapDevice;
6use heapless::Vec; 6use heapless::Vec;
7use log::*; 7use log::*;
@@ -20,8 +20,8 @@ struct Opts {
20} 20}
21 21
22#[embassy_executor::task] 22#[embassy_executor::task]
23async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { 23async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! {
24 stack.run().await 24 runner.run().await
25} 25}
26 26
27#[embassy_executor::task] 27#[embassy_executor::task]
@@ -49,12 +49,11 @@ async fn main_task(spawner: Spawner) {
49 let seed = u64::from_le_bytes(seed); 49 let seed = u64::from_le_bytes(seed);
50 50
51 // Init network stack 51 // Init network stack
52 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
53 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 52 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
54 let stack: &Stack<_> = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 53 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
55 54
56 // Launch network task 55 // Launch network task
57 spawner.spawn(net_task(stack)).unwrap(); 56 spawner.spawn(net_task(runner)).unwrap();
58 57
59 let host = "example.com"; 58 let host = "example.com";
60 info!("querying host {:?}...", host); 59 info!("querying host {:?}...", host);
diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs
index c5c27c4a3..7d0f1327f 100644
--- a/examples/std/src/bin/net_ppp.rs
+++ b/examples/std/src/bin/net_ppp.rs
@@ -37,16 +37,12 @@ struct Opts {
37} 37}
38 38
39#[embassy_executor::task] 39#[embassy_executor::task]
40async fn net_task(stack: &'static Stack<embassy_net_ppp::Device<'static>>) -> ! { 40async fn net_task(mut runner: embassy_net::Runner<'static, embassy_net_ppp::Device<'static>>) -> ! {
41 stack.run().await 41 runner.run().await
42} 42}
43 43
44#[embassy_executor::task] 44#[embassy_executor::task]
45async fn ppp_task( 45async fn ppp_task(stack: Stack<'static>, mut runner: Runner<'static>, port: SerialPort) -> ! {
46 stack: &'static Stack<embassy_net_ppp::Device<'static>>,
47 mut runner: Runner<'static>,
48 port: SerialPort,
49) -> ! {
50 let port = Async::new(port).unwrap(); 46 let port = Async::new(port).unwrap();
51 let port = BufReader::new(port); 47 let port = BufReader::new(port);
52 let port = adapter::FromFutures::new(port); 48 let port = adapter::FromFutures::new(port);
@@ -97,17 +93,16 @@ async fn main_task(spawner: Spawner) {
97 let seed = u64::from_le_bytes(seed); 93 let seed = u64::from_le_bytes(seed);
98 94
99 // Init network stack 95 // Init network stack
100 static STACK: StaticCell<Stack<embassy_net_ppp::Device<'static>>> = StaticCell::new();
101 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 96 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
102 let stack = &*STACK.init(Stack::new( 97 let (stack, net_runner) = embassy_net::new(
103 device, 98 device,
104 Config::default(), // don't configure IP yet 99 Config::default(), // don't configure IP yet
105 RESOURCES.init(StackResources::new()), 100 RESOURCES.init(StackResources::new()),
106 seed, 101 seed,
107 )); 102 );
108 103
109 // Launch network task 104 // Launch network task
110 spawner.spawn(net_task(stack)).unwrap(); 105 spawner.spawn(net_task(net_runner)).unwrap();
111 spawner.spawn(ppp_task(stack, runner, port)).unwrap(); 106 spawner.spawn(ppp_task(stack, runner, port)).unwrap();
112 107
113 // Then we can use it! 108 // Then we can use it!
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index b2ba4915a..02d4d3efb 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -1,7 +1,7 @@
1use clap::Parser; 1use clap::Parser;
2use embassy_executor::{Executor, Spawner}; 2use embassy_executor::{Executor, Spawner};
3use embassy_net::udp::{PacketMetadata, UdpSocket}; 3use embassy_net::udp::{PacketMetadata, UdpSocket};
4use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 4use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources};
5use embassy_net_tuntap::TunTapDevice; 5use embassy_net_tuntap::TunTapDevice;
6use heapless::Vec; 6use heapless::Vec;
7use log::*; 7use log::*;
@@ -20,8 +20,8 @@ struct Opts {
20} 20}
21 21
22#[embassy_executor::task] 22#[embassy_executor::task]
23async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { 23async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! {
24 stack.run().await 24 runner.run().await
25} 25}
26 26
27#[embassy_executor::task] 27#[embassy_executor::task]
@@ -48,12 +48,11 @@ async fn main_task(spawner: Spawner) {
48 let seed = u64::from_le_bytes(seed); 48 let seed = u64::from_le_bytes(seed);
49 49
50 // Init network stack 50 // Init network stack
51 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
52 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 51 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
53 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 52 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
54 53
55 // Launch network task 54 // Launch network task
56 spawner.spawn(net_task(stack)).unwrap(); 55 spawner.spawn(net_task(runner)).unwrap();
57 56
58 // Then we can use it! 57 // Then we can use it!
59 let mut rx_meta = [PacketMetadata::EMPTY; 16]; 58 let mut rx_meta = [PacketMetadata::EMPTY; 16];
diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs
index 39b29a449..5d36b739d 100644
--- a/examples/std/src/bin/tcp_accept.rs
+++ b/examples/std/src/bin/tcp_accept.rs
@@ -3,7 +3,7 @@ use core::fmt::Write as _;
3use clap::Parser; 3use clap::Parser;
4use embassy_executor::{Executor, Spawner}; 4use embassy_executor::{Executor, Spawner};
5use embassy_net::tcp::TcpSocket; 5use embassy_net::tcp::TcpSocket;
6use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 6use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources};
7use embassy_net_tuntap::TunTapDevice; 7use embassy_net_tuntap::TunTapDevice;
8use embassy_time::{Duration, Timer}; 8use embassy_time::{Duration, Timer};
9use embedded_io_async::Write as _; 9use embedded_io_async::Write as _;
@@ -24,8 +24,8 @@ struct Opts {
24} 24}
25 25
26#[embassy_executor::task] 26#[embassy_executor::task]
27async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { 27async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! {
28 stack.run().await 28 runner.run().await
29} 29}
30 30
31#[derive(Default)] 31#[derive(Default)]
@@ -62,12 +62,11 @@ async fn main_task(spawner: Spawner) {
62 let seed = u64::from_le_bytes(seed); 62 let seed = u64::from_le_bytes(seed);
63 63
64 // Init network stack 64 // Init network stack
65 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
66 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 65 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
67 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 66 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
68 67
69 // Launch network task 68 // Launch network task
70 spawner.spawn(net_task(stack)).unwrap(); 69 spawner.spawn(net_task(runner)).unwrap();
71 70
72 // Then we can use it! 71 // Then we can use it!
73 let mut rx_buffer = [0; 4096]; 72 let mut rx_buffer = [0; 4096];
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
index 9388c64bf..baed96449 100644
--- a/examples/stm32f4/src/bin/eth.rs
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, Stack, StackResources}; 7use embassy_net::{Ipv4Address, StackResources};
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs {
24type Device = Ethernet<'static, ETH, GenericSMI>; 24type Device = Ethernet<'static, ETH, GenericSMI>;
25 25
26#[embassy_executor::task] 26#[embassy_executor::task]
27async fn net_task(stack: &'static Stack<Device>) -> ! { 27async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
28 stack.run().await 28 runner.run().await
29} 29}
30 30
31#[embassy_executor::main] 31#[embassy_executor::main]
@@ -88,12 +88,11 @@ async fn main(spawner: Spawner) -> ! {
88 //}); 88 //});
89 89
90 // Init network stack 90 // Init network stack
91 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
92 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 91 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
93 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 92 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
94 93
95 // Launch network task 94 // Launch network task
96 unwrap!(spawner.spawn(net_task(stack))); 95 unwrap!(spawner.spawn(net_task(runner)));
97 96
98 // Ensure DHCP configuration is up before trying connect 97 // Ensure DHCP configuration is up before trying connect
99 stack.wait_config_up().await; 98 stack.wait_config_up().await;
@@ -105,7 +104,7 @@ async fn main(spawner: Spawner) -> ! {
105 let mut tx_buffer = [0; 4096]; 104 let mut tx_buffer = [0; 4096];
106 105
107 loop { 106 loop {
108 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 107 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
109 108
110 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 109 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
111 110
diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs
index 5c3c6c3ba..6e6bef08c 100644
--- a/examples/stm32f4/src/bin/eth_w5500.rs
+++ b/examples/stm32f4/src/bin/eth_w5500.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, Stack, StackResources}; 7use embassy_net::{Ipv4Address, StackResources};
8use embassy_net_wiznet::chip::W5500; 8use embassy_net_wiznet::chip::W5500;
9use embassy_net_wiznet::{Device, Runner, State}; 9use embassy_net_wiznet::{Device, Runner, State};
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
@@ -31,8 +31,8 @@ async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'st
31} 31}
32 32
33#[embassy_executor::task] 33#[embassy_executor::task]
34async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 34async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
35 stack.run().await 35 runner.run().await
36} 36}
37 37
38#[embassy_executor::main] 38#[embassy_executor::main]
@@ -92,12 +92,11 @@ async fn main(spawner: Spawner) -> ! {
92 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 92 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
93 //}); 93 //});
94 94
95 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
96 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
97 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 96 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
98 97
99 // Launch network task 98 // Launch network task
100 unwrap!(spawner.spawn(net_task(stack))); 99 unwrap!(spawner.spawn(net_task(runner)));
101 100
102 // Ensure DHCP configuration is up before trying connect 101 // Ensure DHCP configuration is up before trying connect
103 stack.wait_config_up().await; 102 stack.wait_config_up().await;
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index 94e51c338..a9504ec04 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_stm32::rng::{self, Rng}; 8use embassy_stm32::rng::{self, Rng};
9use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
10use embassy_stm32::usb::Driver; 10use embassy_stm32::usb::Driver;
@@ -31,8 +31,8 @@ async fn usb_ncm_task(class: Runner<'static, UsbDriver, MTU>) -> ! {
31} 31}
32 32
33#[embassy_executor::task] 33#[embassy_executor::task]
34async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 34async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
35 stack.run().await 35 runner.run().await
36} 36}
37 37
38bind_interrupts!(struct Irqs { 38bind_interrupts!(struct Irqs {
@@ -144,11 +144,10 @@ async fn main(spawner: Spawner) {
144 let seed = u64::from_le_bytes(seed); 144 let seed = u64::from_le_bytes(seed);
145 145
146 // Init network stack 146 // Init network stack
147 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
148 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 147 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
149 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 148 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
150 149
151 unwrap!(spawner.spawn(net_task(stack))); 150 unwrap!(spawner.spawn(net_task(runner)));
152 151
153 // And now we can use it! 152 // And now we can use it!
154 153
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index 2fd10c8fb..1f1eadf37 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, Stack, StackResources}; 7use embassy_net::{Ipv4Address, StackResources};
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs {
25type Device = Ethernet<'static, ETH, GenericSMI>; 25type Device = Ethernet<'static, ETH, GenericSMI>;
26 26
27#[embassy_executor::task] 27#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<Device>) -> ! { 28async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
29 stack.run().await 29 runner.run().await
30} 30}
31 31
32#[embassy_executor::main] 32#[embassy_executor::main]
@@ -89,12 +89,11 @@ async fn main(spawner: Spawner) -> ! {
89 //}); 89 //});
90 90
91 // Init network stack 91 // Init network stack
92 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
93 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 92 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
94 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 93 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
95 94
96 // Launch network task 95 // Launch network task
97 unwrap!(spawner.spawn(net_task(stack))); 96 unwrap!(spawner.spawn(net_task(runner)));
98 97
99 // Ensure DHCP configuration is up before trying connect 98 // Ensure DHCP configuration is up before trying connect
100 stack.wait_config_up().await; 99 stack.wait_config_up().await;
@@ -106,7 +105,7 @@ async fn main(spawner: Spawner) -> ! {
106 let mut tx_buffer = [0; 4096]; 105 let mut tx_buffer = [0; 4096];
107 106
108 loop { 107 loop {
109 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 108 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
110 109
111 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 110 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
112 111
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index 65cfad8c9..eee1632f5 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, Stack, StackResources}; 7use embassy_net::{Ipv4Address, StackResources};
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -28,8 +28,8 @@ bind_interrupts!(struct Irqs {
28type Device = Ethernet<'static, ETH, GenericSMI>; 28type Device = Ethernet<'static, ETH, GenericSMI>;
29 29
30#[embassy_executor::task] 30#[embassy_executor::task]
31async fn net_task(stack: &'static Stack<Device>) -> ! { 31async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
32 stack.run().await 32 runner.run().await
33} 33}
34 34
35#[embassy_executor::main] 35#[embassy_executor::main]
@@ -92,12 +92,11 @@ async fn main(spawner: Spawner) -> ! {
92 //}); 92 //});
93 93
94 // Init network stack 94 // Init network stack
95 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
96 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
97 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 96 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
98 97
99 // Launch network task 98 // Launch network task
100 unwrap!(spawner.spawn(net_task(&stack))); 99 unwrap!(spawner.spawn(net_task(runner)));
101 100
102 // Ensure DHCP configuration is up before trying connect 101 // Ensure DHCP configuration is up before trying connect
103 stack.wait_config_up().await; 102 stack.wait_config_up().await;
@@ -109,7 +108,7 @@ async fn main(spawner: Spawner) -> ! {
109 let mut tx_buffer = [0; 1024]; 108 let mut tx_buffer = [0; 1024];
110 109
111 loop { 110 loop {
112 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 111 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
113 112
114 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 113 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
115 114
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index b2f8ed91e..ec3f2c000 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, Stack, StackResources}; 7use embassy_net::{Ipv4Address, StackResources};
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs {
24type Device = Ethernet<'static, ETH, GenericSMI>; 24type Device = Ethernet<'static, ETH, GenericSMI>;
25 25
26#[embassy_executor::task] 26#[embassy_executor::task]
27async fn net_task(stack: &'static Stack<Device>) -> ! { 27async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
28 stack.run().await 28 runner.run().await
29} 29}
30 30
31#[embassy_executor::main] 31#[embassy_executor::main]
@@ -91,12 +91,11 @@ async fn main(spawner: Spawner) -> ! {
91 //}); 91 //});
92 92
93 // Init network stack 93 // Init network stack
94 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 94 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
96 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 95 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
97 96
98 // Launch network task 97 // Launch network task
99 unwrap!(spawner.spawn(net_task(&stack))); 98 unwrap!(spawner.spawn(net_task(runner)));
100 99
101 // Ensure DHCP configuration is up before trying connect 100 // Ensure DHCP configuration is up before trying connect
102 stack.wait_config_up().await; 101 stack.wait_config_up().await;
@@ -108,7 +107,7 @@ async fn main(spawner: Spawner) -> ! {
108 let mut tx_buffer = [0; 1024]; 107 let mut tx_buffer = [0; 1024];
109 108
110 loop { 109 loop {
111 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 110 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
112 111
113 socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); 112 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
114 113
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 274c24ab1..24983ca85 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::client::{TcpClient, TcpClientState}; 6use embassy_net::tcp::client::{TcpClient, TcpClientState};
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs {
25type Device = Ethernet<'static, ETH, GenericSMI>; 25type Device = Ethernet<'static, ETH, GenericSMI>;
26 26
27#[embassy_executor::task] 27#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<Device>) -> ! { 28async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
29 stack.run().await 29 runner.run().await
30} 30}
31 31
32#[embassy_executor::main] 32#[embassy_executor::main]
@@ -91,12 +91,11 @@ async fn main(spawner: Spawner) -> ! {
91 //}); 91 //});
92 92
93 // Init network stack 93 // Init network stack
94 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 94 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
96 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 95 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
97 96
98 // Launch network task 97 // Launch network task
99 unwrap!(spawner.spawn(net_task(stack))); 98 unwrap!(spawner.spawn(net_task(runner)));
100 99
101 // Ensure DHCP configuration is up before trying connect 100 // Ensure DHCP configuration is up before trying connect
102 stack.wait_config_up().await; 101 stack.wait_config_up().await;
@@ -104,7 +103,7 @@ async fn main(spawner: Spawner) -> ! {
104 info!("Network task initialized"); 103 info!("Network task initialized");
105 104
106 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); 105 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new();
107 let client = TcpClient::new(&stack, &state); 106 let client = TcpClient::new(stack, &state);
108 107
109 loop { 108 loop {
110 // You need to start a server on the host machine, for example: `nc -l 8000` 109 // You need to start a server on the host machine, for example: `nc -l 8000`
diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs
index aa6544f41..768d85993 100644
--- a/examples/stm32h7/src/bin/eth_client_mii.rs
+++ b/examples/stm32h7/src/bin/eth_client_mii.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::client::{TcpClient, TcpClientState}; 6use embassy_net::tcp::client::{TcpClient, TcpClientState};
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_stm32::eth::generic_smi::GenericSMI; 8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue}; 9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH; 10use embassy_stm32::peripherals::ETH;
@@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs {
25type Device = Ethernet<'static, ETH, GenericSMI>; 25type Device = Ethernet<'static, ETH, GenericSMI>;
26 26
27#[embassy_executor::task] 27#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<Device>) -> ! { 28async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
29 stack.run().await 29 runner.run().await
30} 30}
31 31
32#[embassy_executor::main] 32#[embassy_executor::main]
@@ -97,12 +97,11 @@ async fn main(spawner: Spawner) -> ! {
97 //}); 97 //});
98 98
99 // Init network stack 99 // Init network stack
100 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
101 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 100 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
102 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 101 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
103 102
104 // Launch network task 103 // Launch network task
105 unwrap!(spawner.spawn(net_task(stack))); 104 unwrap!(spawner.spawn(net_task(runner)));
106 105
107 // Ensure DHCP configuration is up before trying connect 106 // Ensure DHCP configuration is up before trying connect
108 stack.wait_config_up().await; 107 stack.wait_config_up().await;
@@ -110,7 +109,7 @@ async fn main(spawner: Spawner) -> ! {
110 info!("Network task initialized"); 109 info!("Network task initialized");
111 110
112 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); 111 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new();
113 let client = TcpClient::new(&stack, &state); 112 let client = TcpClient::new(stack, &state);
114 113
115 loop { 114 loop {
116 // You need to start a server on the host machine, for example: `nc -l 8000` 115 // You need to start a server on the host machine, for example: `nc -l 8000`
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index bd633cecb..be4270ada 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -206,12 +206,11 @@ async fn main(spawner: Spawner) {
206 }; 206 };
207 207
208 // Init network stack 208 // Init network stack
209 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
210 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 209 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
211 let stack = &*STACK.init(Stack::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed)); 210 let (stack, runner) = embassy_net::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed);
212 211
213 // Launch network task 212 // Launch network task
214 unwrap!(spawner.spawn(net_task(stack))); 213 unwrap!(spawner.spawn(net_task(runner)));
215 214
216 let cfg = wait_for_config(stack).await; 215 let cfg = wait_for_config(stack).await;
217 let local_addr = cfg.address.address(); 216 let local_addr = cfg.address.address();
@@ -274,7 +273,7 @@ async fn main(spawner: Spawner) {
274 } 273 }
275} 274}
276 275
277async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { 276async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
278 loop { 277 loop {
279 if let Some(config) = stack.config_v4() { 278 if let Some(config) = stack.config_v4() {
280 return config; 279 return config;
@@ -323,8 +322,8 @@ async fn ethernet_task(runner: Runner<'static, SpeSpiCs, SpeInt, SpeRst>) -> ! {
323} 322}
324 323
325#[embassy_executor::task] 324#[embassy_executor::task]
326async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 325async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
327 stack.run().await 326 runner.run().await
328} 327}
329 328
330// same panicking *behavior* as `panic-probe` but doesn't print a panic message 329// same panicking *behavior* as `panic-probe` but doesn't print a panic message
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index d02bac91d..095d50c73 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources}; 7use embassy_net::StackResources;
8use embassy_stm32::rng::Rng; 8use embassy_stm32::rng::Rng;
9use embassy_stm32::usb::Driver; 9use embassy_stm32::usb::Driver;
10use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; 10use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config};
@@ -36,8 +36,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
36} 36}
37 37
38#[embassy_executor::task] 38#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 39async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
40 stack.run().await 40 runner.run().await
41} 41}
42 42
43#[embassy_executor::main] 43#[embassy_executor::main]
@@ -121,11 +121,10 @@ async fn main(spawner: Spawner) {
121 let seed = rng.next_u64(); 121 let seed = rng.next_u64();
122 122
123 // Init network stack 123 // Init network stack
124 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
125 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 124 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
126 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 125 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
127 126
128 unwrap!(spawner.spawn(net_task(stack))); 127 unwrap!(spawner.spawn(net_task(runner)));
129 128
130 // And now we can use it! 129 // And now we can use it!
131 130
diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
index 304754c0e..ed58627f1 100644
--- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
+++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
@@ -6,7 +6,7 @@ teleprobe_meta::timeout!(120);
6 6
7use defmt::{info, unwrap}; 7use defmt::{info, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_net::{Stack, StackResources}; 9use embassy_net::StackResources;
10use embassy_net_enc28j60::Enc28j60; 10use embassy_net_enc28j60::Enc28j60;
11use embassy_nrf::gpio::{Level, Output, OutputDrive}; 11use embassy_nrf::gpio::{Level, Output, OutputDrive};
12use embassy_nrf::rng::Rng; 12use embassy_nrf::rng::Rng;
@@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs {
25type MyDriver = Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>; 25type MyDriver = Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>;
26 26
27#[embassy_executor::task] 27#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<MyDriver>) -> ! { 28async fn net_task(mut runner: embassy_net::Runner<'static, MyDriver>) -> ! {
29 stack.run().await 29 runner.run().await
30} 30}
31 31
32#[embassy_executor::main] 32#[embassy_executor::main]
@@ -65,11 +65,10 @@ async fn main(spawner: Spawner) {
65 let seed = u64::from_le_bytes(seed); 65 let seed = u64::from_le_bytes(seed);
66 66
67 // Init network stack 67 // Init network stack
68 static STACK: StaticCell<Stack<MyDriver>> = StaticCell::new();
69 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 68 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
70 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 69 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
71 70
72 unwrap!(spawner.spawn(net_task(stack))); 71 unwrap!(spawner.spawn(net_task(runner)));
73 72
74 perf_client::run( 73 perf_client::run(
75 stack, 74 stack,
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
index 6632442f1..34fb8103b 100644
--- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
+++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
@@ -6,7 +6,7 @@ teleprobe_meta::timeout!(120);
6 6
7use defmt::{info, unwrap}; 7use defmt::{info, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_net::{Config, Stack, StackResources}; 9use embassy_net::{Config, StackResources};
10use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; 10use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
11use embassy_nrf::rng::Rng; 11use embassy_nrf::rng::Rng;
12use embassy_nrf::spim::{self, Spim}; 12use embassy_nrf::spim::{self, Spim};
@@ -40,8 +40,8 @@ async fn wifi_task(
40type MyDriver = hosted::NetDriver<'static>; 40type MyDriver = hosted::NetDriver<'static>;
41 41
42#[embassy_executor::task] 42#[embassy_executor::task]
43async fn net_task(stack: &'static Stack<MyDriver>) -> ! { 43async fn net_task(mut runner: embassy_net::Runner<'static, MyDriver>) -> ! {
44 stack.run().await 44 runner.run().await
45} 45}
46 46
47#[embassy_executor::main] 47#[embassy_executor::main]
@@ -86,16 +86,15 @@ async fn main(spawner: Spawner) {
86 let seed = u64::from_le_bytes(seed); 86 let seed = u64::from_le_bytes(seed);
87 87
88 // Init network stack 88 // Init network stack
89 static STACK: StaticCell<Stack<MyDriver>> = StaticCell::new();
90 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 89 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
91 let stack = &*STACK.init(Stack::new( 90 let (stack, runner) = embassy_net::new(
92 device, 91 device,
93 Config::dhcpv4(Default::default()), 92 Config::dhcpv4(Default::default()),
94 RESOURCES.init(StackResources::new()), 93 RESOURCES.init(StackResources::new()),
95 seed, 94 seed,
96 )); 95 );
97 96
98 unwrap!(spawner.spawn(net_task(stack))); 97 unwrap!(spawner.spawn(net_task(runner)));
99 98
100 perf_client::run( 99 perf_client::run(
101 stack, 100 stack,
diff --git a/tests/perf-client/src/lib.rs b/tests/perf-client/src/lib.rs
index 54762379a..4bd9e5674 100644
--- a/tests/perf-client/src/lib.rs
+++ b/tests/perf-client/src/lib.rs
@@ -2,7 +2,6 @@
2 2
3use defmt::{assert, *}; 3use defmt::{assert, *};
4use embassy_futures::join::join; 4use embassy_futures::join::join;
5use embassy_net::driver::Driver;
6use embassy_net::tcp::TcpSocket; 5use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, Stack}; 6use embassy_net::{Ipv4Address, Stack};
8use embassy_time::{with_timeout, Duration, Timer}; 7use embassy_time::{with_timeout, Duration, Timer};
@@ -13,7 +12,7 @@ pub struct Expected {
13 pub updown_kbps: usize, 12 pub updown_kbps: usize,
14} 13}
15 14
16pub async fn run<D: Driver>(stack: &Stack<D>, expected: Expected) { 15pub async fn run(stack: Stack<'_>, expected: Expected) {
17 info!("Waiting for DHCP up..."); 16 info!("Waiting for DHCP up...");
18 while stack.config_v4().is_none() { 17 while stack.config_v4().is_none() {
19 Timer::after_millis(100).await; 18 Timer::after_millis(100).await;
@@ -38,7 +37,7 @@ const DOWNLOAD_PORT: u16 = 4321;
38const UPLOAD_PORT: u16 = 4322; 37const UPLOAD_PORT: u16 = 4322;
39const UPLOAD_DOWNLOAD_PORT: u16 = 4323; 38const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
40 39
41async fn test_download<D: Driver>(stack: &Stack<D>) -> usize { 40async fn test_download(stack: Stack<'_>) -> usize {
42 info!("Testing download..."); 41 info!("Testing download...");
43 42
44 let mut rx_buffer = [0; RX_BUFFER_SIZE]; 43 let mut rx_buffer = [0; RX_BUFFER_SIZE];
@@ -78,7 +77,7 @@ async fn test_download<D: Driver>(stack: &Stack<D>) -> usize {
78 kbps 77 kbps
79} 78}
80 79
81async fn test_upload<D: Driver>(stack: &Stack<D>) -> usize { 80async fn test_upload(stack: Stack<'_>) -> usize {
82 info!("Testing upload..."); 81 info!("Testing upload...");
83 82
84 let mut rx_buffer = [0; RX_BUFFER_SIZE]; 83 let mut rx_buffer = [0; RX_BUFFER_SIZE];
@@ -118,7 +117,7 @@ async fn test_upload<D: Driver>(stack: &Stack<D>) -> usize {
118 kbps 117 kbps
119} 118}
120 119
121async fn test_upload_download<D: Driver>(stack: &Stack<D>) -> usize { 120async fn test_upload_download(stack: Stack<'_>) -> usize {
122 info!("Testing upload+download..."); 121 info!("Testing upload+download...");
123 122
124 let mut rx_buffer = [0; RX_BUFFER_SIZE]; 123 let mut rx_buffer = [0; RX_BUFFER_SIZE];
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
index 11c8aa58c..30e4afb07 100644
--- a/tests/rp/src/bin/cyw43-perf.rs
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -6,7 +6,7 @@ use cyw43::JoinOptions;
6use cyw43_pio::PioSpi; 6use cyw43_pio::PioSpi;
7use defmt::{panic, *}; 7use defmt::{panic, *};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_net::{Config, Stack, StackResources}; 9use embassy_net::{Config, StackResources};
10use embassy_rp::gpio::{Level, Output}; 10use embassy_rp::gpio::{Level, Output};
11use embassy_rp::peripherals::{DMA_CH0, PIO0}; 11use embassy_rp::peripherals::{DMA_CH0, PIO0};
12use embassy_rp::pio::{InterruptHandler, Pio}; 12use embassy_rp::pio::{InterruptHandler, Pio};
@@ -30,8 +30,8 @@ async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stati
30} 30}
31 31
32#[embassy_executor::task] 32#[embassy_executor::task]
33async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 33async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
34 stack.run().await 34 runner.run().await
35} 35}
36 36
37#[embassy_executor::main] 37#[embassy_executor::main]
@@ -70,16 +70,15 @@ async fn main(spawner: Spawner) {
70 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. 70 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
71 71
72 // Init network stack 72 // Init network stack
73 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
74 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 73 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
75 let stack = &*STACK.init(Stack::new( 74 let (stack, runner) = embassy_net::new(
76 net_device, 75 net_device,
77 Config::dhcpv4(Default::default()), 76 Config::dhcpv4(Default::default()),
78 RESOURCES.init(StackResources::new()), 77 RESOURCES.init(StackResources::new()),
79 seed, 78 seed,
80 )); 79 );
81 80
82 unwrap!(spawner.spawn(net_task(stack))); 81 unwrap!(spawner.spawn(net_task(runner)));
83 82
84 loop { 83 loop {
85 match control 84 match control
diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs
index f15f33743..ae2adfa55 100644
--- a/tests/rp/src/bin/ethernet_w5100s_perf.rs
+++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs
@@ -5,7 +5,7 @@ teleprobe_meta::timeout!(120);
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_net::{Stack, StackResources}; 8use embassy_net::StackResources;
9use embassy_net_wiznet::chip::W5100S; 9use embassy_net_wiznet::chip::W5100S;
10use embassy_net_wiznet::*; 10use embassy_net_wiznet::*;
11use embassy_rp::clocks::RoscRng; 11use embassy_rp::clocks::RoscRng;
@@ -32,8 +32,8 @@ async fn ethernet_task(
32} 32}
33 33
34#[embassy_executor::task] 34#[embassy_executor::task]
35async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { 35async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
36 stack.run().await 36 runner.run().await
37} 37}
38 38
39#[embassy_executor::main] 39#[embassy_executor::main]
@@ -67,17 +67,16 @@ async fn main(spawner: Spawner) {
67 let seed = rng.next_u64(); 67 let seed = rng.next_u64();
68 68
69 // Init network stack 69 // Init network stack
70 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
71 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 70 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
72 let stack = &*STACK.init(Stack::new( 71 let (stack, runner) = embassy_net::new(
73 device, 72 device,
74 embassy_net::Config::dhcpv4(Default::default()), 73 embassy_net::Config::dhcpv4(Default::default()),
75 RESOURCES.init(StackResources::new()), 74 RESOURCES.init(StackResources::new()),
76 seed, 75 seed,
77 )); 76 );
78 77
79 // Launch network task 78 // Launch network task
80 unwrap!(spawner.spawn(net_task(&stack))); 79 unwrap!(spawner.spawn(net_task(runner)));
81 80
82 perf_client::run( 81 perf_client::run(
83 stack, 82 stack,
diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs
index 9da514881..bf1922dde 100644
--- a/tests/stm32/src/bin/eth.rs
+++ b/tests/stm32/src/bin/eth.rs
@@ -6,7 +6,7 @@
6mod common; 6mod common;
7use common::*; 7use common::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_net::{Stack, StackResources}; 9use embassy_net::StackResources;
10use embassy_stm32::eth::generic_smi::GenericSMI; 10use embassy_stm32::eth::generic_smi::GenericSMI;
11use embassy_stm32::eth::{Ethernet, PacketQueue}; 11use embassy_stm32::eth::{Ethernet, PacketQueue};
12use embassy_stm32::peripherals::ETH; 12use embassy_stm32::peripherals::ETH;
@@ -32,8 +32,8 @@ bind_interrupts!(struct Irqs {
32type Device = Ethernet<'static, ETH, GenericSMI>; 32type Device = Ethernet<'static, ETH, GenericSMI>;
33 33
34#[embassy_executor::task] 34#[embassy_executor::task]
35async fn net_task(stack: &'static Stack<Device>) -> ! { 35async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
36 stack.run().await 36 runner.run().await
37} 37}
38 38
39#[embassy_executor::main] 39#[embassy_executor::main]
@@ -99,12 +99,11 @@ async fn main(spawner: Spawner) {
99 //}); 99 //});
100 100
101 // Init network stack 101 // Init network stack
102 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
103 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 102 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
104 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 103 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
105 104
106 // Launch network task 105 // Launch network task
107 unwrap!(spawner.spawn(net_task(&stack))); 106 unwrap!(spawner.spawn(net_task(runner)));
108 107
109 perf_client::run( 108 perf_client::run(
110 stack, 109 stack,