diff options
55 files changed, 988 insertions, 681 deletions
| @@ -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. |
| 294 | rm -rf out/tests/stm32f103c8 | 294 | rm -rf out/tests/stm32f103c8 |
| 295 | rm -rf out/tests/nrf52840-dk | ||
| 295 | 296 | ||
| 296 | rm out/tests/stm32wb55rg/wpan_mac | 297 | rm out/tests/stm32wb55rg/wpan_mac |
| 297 | rm out/tests/stm32wb55rg/wpan_ble | 298 | rm 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 | ||
| 20 | In 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. | 20 | In 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 | ||
| 22 | STM32L0x1 devices require the `flash-erase-zero` feature to be enabled. | ||
| 23 | |||
| 22 | == Design | 24 | == Design |
| 23 | 25 | ||
| 24 | image::bootloader_flash.png[Bootloader flash layout] | 26 | image::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] |
| 48 | ed25519-dalek = ["dep:ed25519-dalek", "_verify"] | 48 | ed25519-dalek = ["dep:ed25519-dalek", "_verify"] |
| 49 | ed25519-salty = ["dep:salty", "_verify"] | 49 | ed25519-salty = ["dep:salty", "_verify"] |
| 50 | flash-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"))] | ||
| 17 | pub(crate) const STATE_ERASE_VALUE: u8 = 0xFF; | 18 | pub(crate) const STATE_ERASE_VALUE: u8 = 0xFF; |
| 19 | #[cfg(feature = "flash-erase-zero")] | ||
| 20 | pub(crate) const STATE_ERASE_VALUE: u8 = 0x00; | ||
| 21 | |||
| 18 | pub use boot_loader::{BootError, BootLoader, BootLoaderConfig}; | 22 | pub use boot_loader::{BootError, BootLoader, BootLoaderConfig}; |
| 19 | pub use firmware_updater::{ | 23 | pub 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] |
| 17 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" | 17 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" |
| 18 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" | 18 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" |
| 19 | features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] | 19 | features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"] |
| 20 | target = "thumbv7em-none-eabi" | 20 | target = "thumbv7em-none-eabi" |
| 21 | 21 | ||
| 22 | [package.metadata.docs.rs] | 22 | [package.metadata.docs.rs] |
| 23 | features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] | 23 | features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"] |
| 24 | 24 | ||
| 25 | [features] | 25 | [features] |
| 26 | default = [] | 26 | default = [] |
| @@ -60,15 +60,15 @@ medium-ethernet = ["smoltcp/medium-ethernet"] | |||
| 60 | medium-ip = ["smoltcp/medium-ip"] | 60 | medium-ip = ["smoltcp/medium-ip"] |
| 61 | ## Enable the IEEE 802.15.4 medium | 61 | ## Enable the IEEE 802.15.4 medium |
| 62 | medium-ieee802154 = ["smoltcp/medium-ieee802154"] | 62 | medium-ieee802154 = ["smoltcp/medium-ieee802154"] |
| 63 | ## Enable IGMP support | 63 | ## Enable multicast support (for both ipv4 and/or ipv6 if enabled) |
| 64 | igmp = ["smoltcp/proto-igmp"] | 64 | multicast = ["smoltcp/multicast"] |
| 65 | 65 | ||
| 66 | [dependencies] | 66 | [dependencies] |
| 67 | 67 | ||
| 68 | defmt = { version = "0.3", optional = true } | 68 | defmt = { version = "0.3", optional = true } |
| 69 | log = { version = "0.4.14", optional = true } | 69 | log = { version = "0.4.14", optional = true } |
| 70 | 70 | ||
| 71 | smoltcp = { version = "0.11.0", default-features = false, features = [ | 71 | smoltcp = { 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 | ||
| 16 | See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and | 17 | See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and |
| 17 | unimplemented features of the network protocols. | 18 | unimplemented 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}; | |||
| 9 | pub(crate) use smoltcp::socket::dns::{GetQueryResultError, StartQueryError}; | 9 | pub(crate) use smoltcp::socket::dns::{GetQueryResultError, StartQueryError}; |
| 10 | pub use smoltcp::wire::{DnsQueryType, IpAddress}; | 10 | pub use smoltcp::wire::{DnsQueryType, IpAddress}; |
| 11 | 11 | ||
| 12 | use crate::{Driver, Stack}; | 12 | use 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`. |
| 47 | pub struct DnsSocket<'a, D> | 47 | pub struct DnsSocket<'a> { |
| 48 | where | 48 | stack: Stack<'a>, |
| 49 | D: Driver + 'static, | ||
| 50 | { | ||
| 51 | stack: &'a Stack<D>, | ||
| 52 | } | 49 | } |
| 53 | 50 | ||
| 54 | impl<'a, D> DnsSocket<'a, D> | 51 | impl<'a> DnsSocket<'a> { |
| 55 | where | ||
| 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 | ||
| 75 | impl<'a, D> embedded_nal_async::Dns for DnsSocket<'a, D> | 69 | impl<'a> embedded_nal_async::Dns for DnsSocket<'a> { |
| 76 | where | ||
| 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 | |||
| 119 | fn _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. |
| 13 | pub(crate) mod fmt; | 13 | pub(crate) mod fmt; |
| 14 | 14 | ||
| 15 | mod device; | ||
| 16 | #[cfg(feature = "dns")] | 15 | #[cfg(feature = "dns")] |
| 17 | pub mod dns; | 16 | pub mod dns; |
| 17 | mod driver_util; | ||
| 18 | #[cfg(feature = "raw")] | 18 | #[cfg(feature = "raw")] |
| 19 | pub mod raw; | 19 | pub mod raw; |
| 20 | #[cfg(feature = "tcp")] | 20 | #[cfg(feature = "tcp")] |
| @@ -25,6 +25,7 @@ pub mod udp; | |||
| 25 | 25 | ||
| 26 | use core::cell::RefCell; | 26 | use core::cell::RefCell; |
| 27 | use core::future::{poll_fn, Future}; | 27 | use core::future::{poll_fn, Future}; |
| 28 | use core::mem::MaybeUninit; | ||
| 28 | use core::pin::pin; | 29 | use core::pin::pin; |
| 29 | use core::task::{Context, Poll}; | 30 | use core::task::{Context, Poll}; |
| 30 | 31 | ||
| @@ -36,7 +37,7 @@ use embassy_time::{Instant, Timer}; | |||
| 36 | use heapless::Vec; | 37 | use heapless::Vec; |
| 37 | #[cfg(feature = "dns")] | 38 | #[cfg(feature = "dns")] |
| 38 | pub use smoltcp::config::DNS_MAX_SERVER_COUNT; | 39 | pub use smoltcp::config::DNS_MAX_SERVER_COUNT; |
| 39 | #[cfg(feature = "igmp")] | 40 | #[cfg(feature = "multicast")] |
| 40 | pub use smoltcp::iface::MulticastError; | 41 | pub use smoltcp::iface::MulticastError; |
| 41 | #[allow(unused_imports)] | 42 | #[allow(unused_imports)] |
| 42 | use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage}; | 43 | use 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")] |
| 58 | pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; | 59 | pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; |
| 59 | 60 | ||
| 60 | use crate::device::DriverAdapter; | 61 | use crate::driver_util::DriverAdapter; |
| 61 | use crate::time::{instant_from_smoltcp, instant_to_smoltcp}; | 62 | use crate::time::{instant_from_smoltcp, instant_to_smoltcp}; |
| 62 | 63 | ||
| 63 | const LOCAL_PORT_MIN: u16 = 1025; | 64 | const 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. |
| 71 | pub struct StackResources<const SOCK: usize> { | 72 | pub 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")] |
| 80 | struct HostnameResources { | 82 | struct 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 | ||
| 85 | impl<const SOCK: usize> StackResources<SOCK> { | 87 | impl<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. | ||
| 246 | pub 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 |
| 245 | pub 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>>, | 256 | pub struct Stack<'d> { |
| 257 | inner: &'d RefCell<Inner>, | ||
| 248 | } | 258 | } |
| 249 | 259 | ||
| 250 | struct Inner<D: Driver> { | 260 | pub(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 | ||
| 268 | pub(crate) struct SocketStack { | 282 | fn _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. |
| 287 | pub 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 | ||
| 275 | fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddress, Medium) { | 358 | fn 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 | ||
| 295 | impl<D: Driver> Stack<D> { | 378 | impl<'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")] |
| 608 | impl<D: Driver> Stack<D> { | 612 | impl<'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 | ||
| 693 | impl SocketStack { | 629 | impl 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 | ||
| 702 | impl<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 | |||
| 864 | impl<'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 | ||
| 3 | use core::cell::RefCell; | ||
| 4 | use core::future::poll_fn; | 3 | use core::future::poll_fn; |
| 5 | use core::mem; | 4 | use core::mem; |
| 6 | use core::task::{Context, Poll}; | 5 | use core::task::{Context, Poll}; |
| @@ -11,7 +10,7 @@ use smoltcp::socket::raw; | |||
| 11 | pub use smoltcp::socket::raw::PacketMetadata; | 10 | pub use smoltcp::socket::raw::PacketMetadata; |
| 12 | use smoltcp::wire::{IpProtocol, IpVersion}; | 11 | use smoltcp::wire::{IpProtocol, IpVersion}; |
| 13 | 12 | ||
| 14 | use crate::{SocketStack, Stack}; | 13 | use 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. |
| 25 | pub struct RawSocket<'a> { | 24 | pub struct RawSocket<'a> { |
| 26 | stack: &'a RefCell<SocketStack>, | 25 | stack: Stack<'a>, |
| 27 | handle: SocketHandle, | 26 | handle: SocketHandle, |
| 28 | } | 27 | } |
| 29 | 28 | ||
| 30 | impl<'a> RawSocket<'a> { | 29 | impl<'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 | ||
| 116 | impl Drop for RawSocket<'_> { | 113 | impl 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 | |||
| 119 | fn _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 | ||
| 11 | use core::cell::RefCell; | ||
| 12 | use core::future::poll_fn; | 11 | use core::future::poll_fn; |
| 13 | use core::mem; | 12 | use core::mem; |
| 14 | use core::task::Poll; | 13 | use core::task::Poll; |
| 15 | 14 | ||
| 16 | use embassy_net_driver::Driver; | ||
| 17 | use embassy_time::Duration; | 15 | use embassy_time::Duration; |
| 18 | use smoltcp::iface::{Interface, SocketHandle}; | 16 | use smoltcp::iface::{Interface, SocketHandle}; |
| 19 | use smoltcp::socket::tcp; | 17 | use smoltcp::socket::tcp; |
| @@ -21,7 +19,7 @@ pub use smoltcp::socket::tcp::State; | |||
| 21 | use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; | 19 | use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; |
| 22 | 20 | ||
| 23 | use crate::time::duration_to_smoltcp; | 21 | use crate::time::duration_to_smoltcp; |
| 24 | use crate::{SocketStack, Stack}; | 22 | use 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 | ||
| 158 | impl<'a> TcpSocket<'a> { | 156 | impl<'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 | ||
| 402 | impl<'a> Drop for TcpSocket<'a> { | 398 | impl<'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 | ||
| 404 | fn _assert_covariant<'a, 'b: 'a>(x: TcpSocket<'b>) -> TcpSocket<'a> { | ||
| 405 | x | ||
| 406 | } | ||
| 407 | fn _assert_covariant_reader<'a, 'b: 'a>(x: TcpReader<'b>) -> TcpReader<'a> { | ||
| 408 | x | ||
| 409 | } | ||
| 410 | fn _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)] |
| 411 | struct TcpIo<'a> { | 417 | struct TcpIo<'a> { |
| 412 | stack: &'a RefCell<SocketStack>, | 418 | stack: Stack<'a>, |
| 413 | handle: SocketHandle, | 419 | handle: SocketHandle, |
| 414 | } | 420 | } |
| 415 | 421 | ||
| 416 | impl<'d> TcpIo<'d> { | 422 | impl<'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 | ||
| 3 | use core::cell::RefCell; | ||
| 4 | use core::future::poll_fn; | 3 | use core::future::poll_fn; |
| 5 | use core::mem; | 4 | use core::mem; |
| 6 | use core::task::{Context, Poll}; | 5 | use core::task::{Context, Poll}; |
| 7 | 6 | ||
| 8 | use embassy_net_driver::Driver; | ||
| 9 | use smoltcp::iface::{Interface, SocketHandle}; | 7 | use smoltcp::iface::{Interface, SocketHandle}; |
| 10 | use smoltcp::socket::udp; | 8 | use smoltcp::socket::udp; |
| 11 | pub use smoltcp::socket::udp::{PacketMetadata, UdpMetadata}; | 9 | pub use smoltcp::socket::udp::{PacketMetadata, UdpMetadata}; |
| 12 | use smoltcp::wire::IpListenEndpoint; | 10 | use smoltcp::wire::IpListenEndpoint; |
| 13 | 11 | ||
| 14 | use crate::{SocketStack, Stack}; | 12 | use 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. |
| 45 | pub struct UdpSocket<'a> { | 43 | pub struct UdpSocket<'a> { |
| 46 | stack: &'a RefCell<SocketStack>, | 44 | stack: Stack<'a>, |
| 47 | handle: SocketHandle, | 45 | handle: SocketHandle, |
| 48 | } | 46 | } |
| 49 | 47 | ||
| 50 | impl<'a> UdpSocket<'a> { | 48 | impl<'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 | ||
| 299 | impl Drop for UdpSocket<'_> { | 296 | impl 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 | |||
| 302 | fn _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 | ||
| 226 | impl<'d, T: Instance> UartTx<'d, T, Blocking> { | 226 | impl<'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; | |||
| 120 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 122 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 121 | static BUS_WAKER: AtomicWaker = NEW_AW; | 123 | static BUS_WAKER: AtomicWaker = NEW_AW; |
| 122 | static EP0_SETUP: AtomicBool = AtomicBool::new(false); | 124 | static EP0_SETUP: AtomicBool = AtomicBool::new(false); |
| 125 | |||
| 126 | const NEW_CTR_TRIGGERED: AtomicBool = AtomicBool::new(false); | ||
| 127 | static CTR_TRIGGERED: [AtomicBool; EP_COUNT] = [NEW_CTR_TRIGGERED; EP_COUNT]; | ||
| 128 | |||
| 123 | static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; | 129 | static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; |
| 124 | static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; | 130 | static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; |
| 125 | static IRQ_RESET: AtomicBool = AtomicBool::new(false); | 131 | static IRQ_RESET: AtomicBool = AtomicBool::new(false); |
| @@ -163,20 +169,37 @@ fn calc_out_len(len: u16) -> (u16, u16) { | |||
| 163 | mod btable { | 169 | mod 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 { | |||
| 184 | mod btable { | 207 | mod 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. | ||
| 720 | enum 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. |
| 660 | pub struct Endpoint<'d, T: Instance, D> { | 728 | pub 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 | ||
| 666 | impl<'d, T: Instance, D> Endpoint<'d, T, D> { | 734 | impl<'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 | ||
| 685 | impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { | 789 | impl<'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 @@ | |||
| 1 | use heapless::Vec; | 1 | use heapless::Vec; |
| 2 | 2 | ||
| 3 | use crate::config::MAX_HANDLER_COUNT; | 3 | use crate::config::MAX_HANDLER_COUNT; |
| 4 | use crate::descriptor::{BosWriter, DescriptorWriter}; | 4 | use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageType}; |
| 5 | use crate::driver::{Driver, Endpoint, EndpointType}; | 5 | use crate::driver::{Driver, Endpoint, EndpointInfo, EndpointType}; |
| 6 | use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; | 6 | use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; |
| 7 | use crate::types::{InterfaceNumber, StringIndex}; | 7 | use crate::types::{InterfaceNumber, StringIndex}; |
| 8 | use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; | 8 | use 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. |
| 2 | use embassy_usb_driver::EndpointType; | ||
| 2 | 3 | ||
| 3 | use crate::builder::Config; | 4 | use crate::builder::Config; |
| 4 | use crate::driver::EndpointInfo; | 5 | use 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))] | ||
| 48 | pub 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))] | ||
| 65 | pub 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. |
| 42 | pub(crate) struct DescriptorWriter<'a> { | 77 | pub(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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_net_enc28j60::Enc28j60; | 8 | use embassy_net_enc28j60::Enc28j60; |
| 9 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | 9 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; |
| 10 | use embassy_nrf::rng::Rng; | 10 | use embassy_nrf::rng::Rng; |
| @@ -23,11 +23,12 @@ bind_interrupts!(struct Irqs { | |||
| 23 | 23 | ||
| 24 | #[embassy_executor::task] | 24 | #[embassy_executor::task] |
| 25 | async fn net_task( | 25 | async 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; | |||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_net::tcp::TcpSocket; | 8 | use embassy_net::tcp::TcpSocket; |
| 9 | use embassy_net::{Stack, StackResources}; | 9 | use embassy_net::StackResources; |
| 10 | use embassy_nrf::rng::Rng; | 10 | use embassy_nrf::rng::Rng; |
| 11 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | 11 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; |
| 12 | use embassy_nrf::usb::Driver; | 12 | use 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] |
| 42 | async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | 42 | async 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 @@ | |||
| 4 | use defmt::{info, unwrap, warn}; | 4 | use defmt::{info, unwrap, warn}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; | 8 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; |
| 9 | use embassy_nrf::rng::Rng; | 9 | use embassy_nrf::rng::Rng; |
| 10 | use embassy_nrf::spim::{self, Spim}; | 10 | use 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] |
| 39 | async fn net_task(stack: &'static Stack<hosted::NetDriver<'static>>) -> ! { | 39 | async 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] |
| 49 | async fn net_task(stack: &'static Stack<embassy_net_nrf91::NetDriver<'static>>) -> ! { | 49 | async 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] |
| 54 | async fn control_task( | 54 | async 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] |
| 39 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 39 | async 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)] |
| 97 | async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16) { | 96 | async 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 | ||
| 134 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { | 133 | async 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] |
| 41 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 41 | async 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 | ||
| 122 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { | 121 | async 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] |
| 40 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 40 | async 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 | ||
| 131 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { | 130 | async 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] |
| 39 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 39 | async 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 | ||
| 111 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { | 110 | async 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 @@ | |||
| 8 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_net::tcp::TcpSocket; | 10 | use embassy_net::tcp::TcpSocket; |
| 11 | use embassy_net::{Stack, StackResources}; | 11 | use embassy_net::StackResources; |
| 12 | use embassy_rp::clocks::RoscRng; | 12 | use embassy_rp::clocks::RoscRng; |
| 13 | use embassy_rp::peripherals::USB; | 13 | use embassy_rp::peripherals::USB; |
| 14 | use embassy_rp::usb::{Driver, InterruptHandler}; | 14 | use 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] |
| 43 | async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | 43 | async 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; | |||
| 11 | use defmt::*; | 11 | use defmt::*; |
| 12 | use embassy_executor::Spawner; | 12 | use embassy_executor::Spawner; |
| 13 | use embassy_net::tcp::TcpSocket; | 13 | use embassy_net::tcp::TcpSocket; |
| 14 | use embassy_net::{Config, Stack, StackResources}; | 14 | use embassy_net::{Config, StackResources}; |
| 15 | use embassy_rp::bind_interrupts; | 15 | use embassy_rp::bind_interrupts; |
| 16 | use embassy_rp::clocks::RoscRng; | 16 | use embassy_rp::clocks::RoscRng; |
| 17 | use embassy_rp::gpio::{Level, Output}; | 17 | use 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] |
| 36 | async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { | 36 | async 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; | |||
| 10 | use cyw43_pio::PioSpi; | 10 | use cyw43_pio::PioSpi; |
| 11 | use defmt::*; | 11 | use defmt::*; |
| 12 | use embassy_executor::Spawner; | 12 | use embassy_executor::Spawner; |
| 13 | use embassy_net::Stack; | ||
| 14 | use embassy_rp::bind_interrupts; | 13 | use embassy_rp::bind_interrupts; |
| 15 | use embassy_rp::gpio::{Level, Output}; | 14 | use embassy_rp::gpio::{Level, Output}; |
| 16 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; | 15 | use 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] |
| 31 | async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { | 30 | async 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; | |||
| 12 | use defmt::*; | 12 | use defmt::*; |
| 13 | use embassy_executor::Spawner; | 13 | use embassy_executor::Spawner; |
| 14 | use embassy_net::tcp::TcpSocket; | 14 | use embassy_net::tcp::TcpSocket; |
| 15 | use embassy_net::{Config, Stack, StackResources}; | 15 | use embassy_net::{Config, StackResources}; |
| 16 | use embassy_rp::bind_interrupts; | 16 | use embassy_rp::bind_interrupts; |
| 17 | use embassy_rp::clocks::RoscRng; | 17 | use embassy_rp::clocks::RoscRng; |
| 18 | use embassy_rp::gpio::{Level, Output}; | 18 | use 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] |
| 40 | async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { | 40 | async 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::*; | |||
| 13 | use embassy_executor::Spawner; | 13 | use embassy_executor::Spawner; |
| 14 | use embassy_net::dns::DnsSocket; | 14 | use embassy_net::dns::DnsSocket; |
| 15 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; | 15 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; |
| 16 | use embassy_net::{Config, Stack, StackResources}; | 16 | use embassy_net::{Config, StackResources}; |
| 17 | use embassy_rp::bind_interrupts; | 17 | use embassy_rp::bind_interrupts; |
| 18 | use embassy_rp::clocks::RoscRng; | 18 | use embassy_rp::clocks::RoscRng; |
| 19 | use embassy_rp::gpio::{Level, Output}; | 19 | use 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] |
| 43 | async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { | 43 | async 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 @@ | |||
| 1 | use clap::Parser; | 1 | use clap::Parser; |
| 2 | use embassy_executor::{Executor, Spawner}; | 2 | use embassy_executor::{Executor, Spawner}; |
| 3 | use embassy_net::tcp::TcpSocket; | 3 | use embassy_net::tcp::TcpSocket; |
| 4 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; | 4 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; |
| 5 | use embassy_net_tuntap::TunTapDevice; | 5 | use embassy_net_tuntap::TunTapDevice; |
| 6 | use embassy_time::Duration; | 6 | use embassy_time::Duration; |
| 7 | use embedded_io_async::Write; | 7 | use embedded_io_async::Write; |
| @@ -22,8 +22,8 @@ struct Opts { | |||
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | #[embassy_executor::task] | 24 | #[embassy_executor::task] |
| 25 | async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { | 25 | async 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 @@ | |||
| 1 | use clap::Parser; | 1 | use clap::Parser; |
| 2 | use embassy_executor::{Executor, Spawner}; | 2 | use embassy_executor::{Executor, Spawner}; |
| 3 | use embassy_net::dns::DnsQueryType; | 3 | use embassy_net::dns::DnsQueryType; |
| 4 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; | 4 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; |
| 5 | use embassy_net_tuntap::TunTapDevice; | 5 | use embassy_net_tuntap::TunTapDevice; |
| 6 | use heapless::Vec; | 6 | use heapless::Vec; |
| 7 | use log::*; | 7 | use log::*; |
| @@ -20,8 +20,8 @@ struct Opts { | |||
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | #[embassy_executor::task] | 22 | #[embassy_executor::task] |
| 23 | async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { | 23 | async 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] |
| 40 | async fn net_task(stack: &'static Stack<embassy_net_ppp::Device<'static>>) -> ! { | 40 | async 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] |
| 45 | async fn ppp_task( | 45 | async 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 @@ | |||
| 1 | use clap::Parser; | 1 | use clap::Parser; |
| 2 | use embassy_executor::{Executor, Spawner}; | 2 | use embassy_executor::{Executor, Spawner}; |
| 3 | use embassy_net::udp::{PacketMetadata, UdpSocket}; | 3 | use embassy_net::udp::{PacketMetadata, UdpSocket}; |
| 4 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; | 4 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; |
| 5 | use embassy_net_tuntap::TunTapDevice; | 5 | use embassy_net_tuntap::TunTapDevice; |
| 6 | use heapless::Vec; | 6 | use heapless::Vec; |
| 7 | use log::*; | 7 | use log::*; |
| @@ -20,8 +20,8 @@ struct Opts { | |||
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | #[embassy_executor::task] | 22 | #[embassy_executor::task] |
| 23 | async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { | 23 | async 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 _; | |||
| 3 | use clap::Parser; | 3 | use clap::Parser; |
| 4 | use embassy_executor::{Executor, Spawner}; | 4 | use embassy_executor::{Executor, Spawner}; |
| 5 | use embassy_net::tcp::TcpSocket; | 5 | use embassy_net::tcp::TcpSocket; |
| 6 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; | 6 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; |
| 7 | use embassy_net_tuntap::TunTapDevice; | 7 | use embassy_net_tuntap::TunTapDevice; |
| 8 | use embassy_time::{Duration, Timer}; | 8 | use embassy_time::{Duration, Timer}; |
| 9 | use embedded_io_async::Write as _; | 9 | use embedded_io_async::Write as _; |
| @@ -24,8 +24,8 @@ struct Opts { | |||
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | #[embassy_executor::task] | 26 | #[embassy_executor::task] |
| 27 | async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { | 27 | async 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Ipv4Address, Stack, StackResources}; | 7 | use embassy_net::{Ipv4Address, StackResources}; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs { | |||
| 24 | type Device = Ethernet<'static, ETH, GenericSMI>; | 24 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 25 | 25 | ||
| 26 | #[embassy_executor::task] | 26 | #[embassy_executor::task] |
| 27 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 27 | async 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Ipv4Address, Stack, StackResources}; | 7 | use embassy_net::{Ipv4Address, StackResources}; |
| 8 | use embassy_net_wiznet::chip::W5500; | 8 | use embassy_net_wiznet::chip::W5500; |
| 9 | use embassy_net_wiznet::{Device, Runner, State}; | 9 | use embassy_net_wiznet::{Device, Runner, State}; |
| 10 | use embassy_stm32::exti::ExtiInput; | 10 | use 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] |
| 34 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 34 | async 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_stm32::rng::{self, Rng}; | 8 | use embassy_stm32::rng::{self, Rng}; |
| 9 | use embassy_stm32::time::Hertz; | 9 | use embassy_stm32::time::Hertz; |
| 10 | use embassy_stm32::usb::Driver; | 10 | use 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] |
| 34 | async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | 34 | async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { |
| 35 | stack.run().await | 35 | runner.run().await |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | bind_interrupts!(struct Irqs { | 38 | bind_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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Ipv4Address, Stack, StackResources}; | 7 | use embassy_net::{Ipv4Address, StackResources}; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { | |||
| 25 | type Device = Ethernet<'static, ETH, GenericSMI>; | 25 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 26 | 26 | ||
| 27 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| 28 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 28 | async 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Ipv4Address, Stack, StackResources}; | 7 | use embassy_net::{Ipv4Address, StackResources}; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -28,8 +28,8 @@ bind_interrupts!(struct Irqs { | |||
| 28 | type Device = Ethernet<'static, ETH, GenericSMI>; | 28 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 29 | 29 | ||
| 30 | #[embassy_executor::task] | 30 | #[embassy_executor::task] |
| 31 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 31 | async 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Ipv4Address, Stack, StackResources}; | 7 | use embassy_net::{Ipv4Address, StackResources}; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs { | |||
| 24 | type Device = Ethernet<'static, ETH, GenericSMI>; | 24 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 25 | 25 | ||
| 26 | #[embassy_executor::task] | 26 | #[embassy_executor::task] |
| 27 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 27 | async 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; | 6 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { | |||
| 25 | type Device = Ethernet<'static, ETH, GenericSMI>; | 25 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 26 | 26 | ||
| 27 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| 28 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 28 | async 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; | 6 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { | |||
| 25 | type Device = Ethernet<'static, ETH, GenericSMI>; | 25 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 26 | 26 | ||
| 27 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| 28 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 28 | async 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 | ||
| 277 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { | 276 | async 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] |
| 326 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 325 | async 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_stm32::rng::Rng; | 8 | use embassy_stm32::rng::Rng; |
| 9 | use embassy_stm32::usb::Driver; | 9 | use embassy_stm32::usb::Driver; |
| 10 | use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; | 10 | use 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] |
| 39 | async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | 39 | async 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 | ||
| 7 | use defmt::{info, unwrap}; | 7 | use defmt::{info, unwrap}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_net::{Stack, StackResources}; | 9 | use embassy_net::StackResources; |
| 10 | use embassy_net_enc28j60::Enc28j60; | 10 | use embassy_net_enc28j60::Enc28j60; |
| 11 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | 11 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; |
| 12 | use embassy_nrf::rng::Rng; | 12 | use embassy_nrf::rng::Rng; |
| @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { | |||
| 25 | type MyDriver = Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>; | 25 | type MyDriver = Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>; |
| 26 | 26 | ||
| 27 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| 28 | async fn net_task(stack: &'static Stack<MyDriver>) -> ! { | 28 | async 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 | ||
| 7 | use defmt::{info, unwrap}; | 7 | use defmt::{info, unwrap}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_net::{Config, Stack, StackResources}; | 9 | use embassy_net::{Config, StackResources}; |
| 10 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; | 10 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; |
| 11 | use embassy_nrf::rng::Rng; | 11 | use embassy_nrf::rng::Rng; |
| 12 | use embassy_nrf::spim::{self, Spim}; | 12 | use embassy_nrf::spim::{self, Spim}; |
| @@ -40,8 +40,8 @@ async fn wifi_task( | |||
| 40 | type MyDriver = hosted::NetDriver<'static>; | 40 | type MyDriver = hosted::NetDriver<'static>; |
| 41 | 41 | ||
| 42 | #[embassy_executor::task] | 42 | #[embassy_executor::task] |
| 43 | async fn net_task(stack: &'static Stack<MyDriver>) -> ! { | 43 | async 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 | ||
| 3 | use defmt::{assert, *}; | 3 | use defmt::{assert, *}; |
| 4 | use embassy_futures::join::join; | 4 | use embassy_futures::join::join; |
| 5 | use embassy_net::driver::Driver; | ||
| 6 | use embassy_net::tcp::TcpSocket; | 5 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Ipv4Address, Stack}; | 6 | use embassy_net::{Ipv4Address, Stack}; |
| 8 | use embassy_time::{with_timeout, Duration, Timer}; | 7 | use 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 | ||
| 16 | pub async fn run<D: Driver>(stack: &Stack<D>, expected: Expected) { | 15 | pub 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; | |||
| 38 | const UPLOAD_PORT: u16 = 4322; | 37 | const UPLOAD_PORT: u16 = 4322; |
| 39 | const UPLOAD_DOWNLOAD_PORT: u16 = 4323; | 38 | const UPLOAD_DOWNLOAD_PORT: u16 = 4323; |
| 40 | 39 | ||
| 41 | async fn test_download<D: Driver>(stack: &Stack<D>) -> usize { | 40 | async 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 | ||
| 81 | async fn test_upload<D: Driver>(stack: &Stack<D>) -> usize { | 80 | async 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 | ||
| 121 | async fn test_upload_download<D: Driver>(stack: &Stack<D>) -> usize { | 120 | async 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; | |||
| 6 | use cyw43_pio::PioSpi; | 6 | use cyw43_pio::PioSpi; |
| 7 | use defmt::{panic, *}; | 7 | use defmt::{panic, *}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_net::{Config, Stack, StackResources}; | 9 | use embassy_net::{Config, StackResources}; |
| 10 | use embassy_rp::gpio::{Level, Output}; | 10 | use embassy_rp::gpio::{Level, Output}; |
| 11 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; | 11 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; |
| 12 | use embassy_rp::pio::{InterruptHandler, Pio}; | 12 | use 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] |
| 33 | async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { | 33 | async 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 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_net::{Stack, StackResources}; | 8 | use embassy_net::StackResources; |
| 9 | use embassy_net_wiznet::chip::W5100S; | 9 | use embassy_net_wiznet::chip::W5100S; |
| 10 | use embassy_net_wiznet::*; | 10 | use embassy_net_wiznet::*; |
| 11 | use embassy_rp::clocks::RoscRng; | 11 | use embassy_rp::clocks::RoscRng; |
| @@ -32,8 +32,8 @@ async fn ethernet_task( | |||
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | #[embassy_executor::task] | 34 | #[embassy_executor::task] |
| 35 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 35 | async 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 @@ | |||
| 6 | mod common; | 6 | mod common; |
| 7 | use common::*; | 7 | use common::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_net::{Stack, StackResources}; | 9 | use embassy_net::StackResources; |
| 10 | use embassy_stm32::eth::generic_smi::GenericSMI; | 10 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 11 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 11 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 12 | use embassy_stm32::peripherals::ETH; | 12 | use embassy_stm32::peripherals::ETH; |
| @@ -32,8 +32,8 @@ bind_interrupts!(struct Irqs { | |||
| 32 | type Device = Ethernet<'static, ETH, GenericSMI>; | 32 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 33 | 33 | ||
| 34 | #[embassy_executor::task] | 34 | #[embassy_executor::task] |
| 35 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 35 | async 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, |
