diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index eb460e73..8a341b8f 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -69,6 +69,7 @@ jobs: builder ./embassy-futures crates/embassy-futures/git.zup builder ./embassy-lora crates/embassy-lora/git.zup builder ./embassy-net crates/embassy-net/git.zup + builder ./embassy-net-driver crates/embassy-net-driver/git.zup builder ./embassy-nrf crates/embassy-nrf/git.zup builder ./embassy-rp crates/embassy-rp/git.zup builder ./embassy-sync crates/embassy-sync/git.zup diff --git a/.vscode/settings.json b/.vscode/settings.json index 6b8183f8..086f435d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,27 +4,21 @@ "rust-analyzer.checkOnSave.noDefaultFeatures": true, "rust-analyzer.cargo.noDefaultFeatures": true, "rust-analyzer.procMacro.enable": true, - //"rust-analyzer.cargo.target": "thumbv7em-none-eabi", - "rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", + "rust-analyzer.cargo.target": "thumbv7em-none-eabi", + //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", "rust-analyzer.cargo.features": [ - // These are needed to prevent embassy-net from failing to build - //"embassy-net/medium-ethernet", - //"embassy-net/tcp", - //"time-tick-16mhz", - //"defmt-timestamp-uptime", - //"nightly", - //"unstable-traits", + "nightly", ], "rust-analyzer.linkedProjects": [ // Declare for the target you wish to develop - //"embassy-executor/Cargo.toml", - //"embassy-sync/Cargo.toml", - //"examples/nrf/Cargo.toml", + // "embassy-executor/Cargo.toml", + // "embassy-sync/Cargo.toml", + "examples/nrf/Cargo.toml", // "examples/nrf-rtos-trace/Cargo.toml", // "examples/rp/Cargo.toml", // "examples/std/Cargo.toml", // "examples/stm32f0/Cargo.toml", - //"examples/stm32f1/Cargo.toml", + // "examples/stm32f1/Cargo.toml", // "examples/stm32f2/Cargo.toml", // "examples/stm32f3/Cargo.toml", // "examples/stm32f4/Cargo.toml", @@ -35,7 +29,7 @@ // "examples/stm32l0/Cargo.toml", // "examples/stm32l1/Cargo.toml", // "examples/stm32l4/Cargo.toml", - "examples/stm32l5/Cargo.toml", + // "examples/stm32l5/Cargo.toml", // "examples/stm32u5/Cargo.toml", // "examples/stm32wb/Cargo.toml", // "examples/stm32wb55/Cargo.toml", diff --git a/embassy-net-driver/Cargo.toml b/embassy-net-driver/Cargo.toml new file mode 100644 index 00000000..7ab9d119 --- /dev/null +++ b/embassy-net-driver/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "embassy-net-driver" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + + +[package.metadata.embassy_docs] +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-v$VERSION/embassy-net/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-driver/src/" +features = ["defmt"] +target = "thumbv7em-none-eabi" + +[dependencies] +defmt = { version = "0.3", optional = true } \ No newline at end of file diff --git a/embassy-net-driver/src/lib.rs b/embassy-net-driver/src/lib.rs new file mode 100644 index 00000000..a39cfecc --- /dev/null +++ b/embassy-net-driver/src/lib.rs @@ -0,0 +1,175 @@ +#![no_std] + +use core::task::Context; + +pub trait Driver { + type RxToken<'a>: RxToken + where + Self: 'a; + type TxToken<'a>: TxToken + where + Self: 'a; + + fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>; + fn transmit(&mut self, cx: &mut Context) -> Option>; + fn link_state(&mut self, cx: &mut Context) -> LinkState; + + fn capabilities(&self) -> Capabilities; + fn ethernet_address(&self) -> [u8; 6]; +} + +impl Driver for &mut T { + type RxToken<'a> = T::RxToken<'a> + where + Self: 'a; + type TxToken<'a> = T::TxToken<'a> + where + Self: 'a; + + fn transmit(&mut self, cx: &mut Context) -> Option> { + T::transmit(self, cx) + } + fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { + T::receive(self, cx) + } + fn capabilities(&self) -> Capabilities { + T::capabilities(self) + } + fn link_state(&mut self, cx: &mut Context) -> LinkState { + T::link_state(self, cx) + } + fn ethernet_address(&self) -> [u8; 6] { + T::ethernet_address(self) + } +} + +/// A token to receive a single network packet. +pub trait RxToken { + /// Consumes the token to receive a single network packet. + /// + /// This method receives a packet and then calls the given closure `f` with the raw + /// packet bytes as argument. + fn consume(self, f: F) -> R + where + F: FnOnce(&mut [u8]) -> R; +} + +/// A token to transmit a single network packet. +pub trait TxToken { + /// Consumes the token to send a single network packet. + /// + /// This method constructs a transmit buffer of size `len` and calls the passed + /// closure `f` with a mutable reference to that buffer. The closure should construct + /// a valid network packet (e.g. an ethernet packet) in the buffer. When the closure + /// returns, the transmit buffer is sent out. + fn consume(self, len: usize, f: F) -> R + where + F: FnOnce(&mut [u8]) -> R; +} + +/// A description of device capabilities. +/// +/// Higher-level protocols may achieve higher throughput or lower latency if they consider +/// the bandwidth or packet size limitations. +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct Capabilities { + /// Medium of the device. + /// + /// This indicates what kind of packet the sent/received bytes are, and determines + /// some behaviors of Interface. For example, ARP/NDISC address resolution is only done + /// for Ethernet mediums. + pub medium: Medium, + + /// Maximum transmission unit. + /// + /// The network device is unable to send or receive frames larger than the value returned + /// by this function. + /// + /// For Ethernet devices, this is the maximum Ethernet frame size, including the Ethernet header (14 octets), but + /// *not* including the Ethernet FCS (4 octets). Therefore, Ethernet MTU = IP MTU + 14. + /// + /// Note that in Linux and other OSes, "MTU" is the IP MTU, not the Ethernet MTU, even for Ethernet + /// devices. This is a common source of confusion. + /// + /// Most common IP MTU is 1500. Minimum is 576 (for IPv4) or 1280 (for IPv6). Maximum is 9216 octets. + pub max_transmission_unit: usize, + + /// Maximum burst size, in terms of MTU. + /// + /// The network device is unable to send or receive bursts large than the value returned + /// by this function. + /// + /// If `None`, there is no fixed limit on burst size, e.g. if network buffers are + /// dynamically allocated. + pub max_burst_size: Option, + + /// Checksum behavior. + /// + /// If the network device is capable of verifying or computing checksums for some protocols, + /// it can request that the stack not do so in software to improve performance. + pub checksum: ChecksumCapabilities, +} + +/// Type of medium of a device. +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Medium { + /// Ethernet medium. Devices of this type send and receive Ethernet frames, + /// and interfaces using it must do neighbor discovery via ARP or NDISC. + /// + /// Examples of devices of this type are Ethernet, WiFi (802.11), Linux `tap`, and VPNs in tap (layer 2) mode. + Ethernet, + + /// IP medium. Devices of this type send and receive IP frames, without an + /// Ethernet header. MAC addresses are not used, and no neighbor discovery (ARP, NDISC) is done. + /// + /// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode. + Ip, +} + +impl Default for Medium { + fn default() -> Medium { + Medium::Ethernet + } +} + +/// A description of checksum behavior for every supported protocol. +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct ChecksumCapabilities { + pub ipv4: Checksum, + pub udp: Checksum, + pub tcp: Checksum, + pub icmpv4: Checksum, + pub icmpv6: Checksum, +} + +/// A description of checksum behavior for a particular protocol. +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Checksum { + /// Verify checksum when receiving and compute checksum when sending. + Both, + /// Verify checksum when receiving. + Rx, + /// Compute checksum before sending. + Tx, + /// Ignore checksum completely. + None, +} + +impl Default for Checksum { + fn default() -> Checksum { + Checksum::Both + } +} + +#[derive(PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum LinkState { + Down, + Up, +} diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 357f8792..9214fd17 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -15,7 +15,7 @@ target = "thumbv7em-none-eabi" default = [] std = [] -defmt = ["dep:defmt", "smoltcp/defmt"] +defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt"] nightly = ["dep:embedded-io", "embedded-io?/async", "dep:embedded-nal-async"] unstable-traits = [] @@ -33,6 +33,7 @@ medium-ip = ["smoltcp/medium-ip"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } +embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } embassy-time = { version = "0.1.0", path = "../embassy-time" } embassy-sync = { version = "0.1.0", path = "../embassy-sync" } embedded-io = { version = "0.4.0", optional = true } diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index 5d86ca91..44f7dc7b 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs @@ -1,93 +1,20 @@ use core::task::Context; +use embassy_net_driver::{Capabilities, Checksum, Driver, Medium, RxToken, TxToken}; use smoltcp::phy; -pub use smoltcp::phy::{Checksum, ChecksumCapabilities, DeviceCapabilities, Medium}; -#[derive(PartialEq, Eq, Clone, Copy)] -pub enum LinkState { - Down, - Up, -} - -pub trait Device { - type RxToken<'a>: RxToken - where - Self: 'a; - type TxToken<'a>: TxToken - where - Self: 'a; - - fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>; - fn transmit(&mut self, cx: &mut Context) -> Option>; - fn link_state(&mut self, cx: &mut Context) -> LinkState; - - fn capabilities(&self) -> phy::DeviceCapabilities; - fn ethernet_address(&self) -> [u8; 6]; -} - -impl Device for &mut T { - type RxToken<'a> = T::RxToken<'a> - where - Self: 'a; - type TxToken<'a> = T::TxToken<'a> - where - Self: 'a; - - fn transmit(&mut self, cx: &mut Context) -> Option> { - T::transmit(self, cx) - } - fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { - T::receive(self, cx) - } - fn capabilities(&self) -> phy::DeviceCapabilities { - T::capabilities(self) - } - fn link_state(&mut self, cx: &mut Context) -> LinkState { - T::link_state(self, cx) - } - fn ethernet_address(&self) -> [u8; 6] { - T::ethernet_address(self) - } -} - -/// A token to receive a single network packet. -pub trait RxToken { - /// Consumes the token to receive a single network packet. - /// - /// This method receives a packet and then calls the given closure `f` with the raw - /// packet bytes as argument. - fn consume(self, f: F) -> R - where - F: FnOnce(&mut [u8]) -> R; -} - -/// A token to transmit a single network packet. -pub trait TxToken { - /// Consumes the token to send a single network packet. - /// - /// This method constructs a transmit buffer of size `len` and calls the passed - /// closure `f` with a mutable reference to that buffer. The closure should construct - /// a valid network packet (e.g. an ethernet packet) in the buffer. When the closure - /// returns, the transmit buffer is sent out. - fn consume(self, len: usize, f: F) -> R - where - F: FnOnce(&mut [u8]) -> R; -} - -/////////////////////////// - -pub(crate) struct DeviceAdapter<'d, 'c, T> +pub(crate) struct DriverAdapter<'d, 'c, T> where - T: Device, + T: Driver, { // must be Some when actually using this to rx/tx pub cx: Option<&'d mut Context<'c>>, pub inner: &'d mut T, } -impl<'d, 'c, T> phy::Device for DeviceAdapter<'d, 'c, T> +impl<'d, 'c, T> phy::Device for DriverAdapter<'d, 'c, T> where - T: Device, + T: Driver, { type RxToken<'a> = RxTokenAdapter> where Self: 'a; type TxToken<'a> = TxTokenAdapter> where Self: 'a; @@ -105,7 +32,39 @@ where /// Get a description of device capabilities. fn capabilities(&self) -> phy::DeviceCapabilities { - self.inner.capabilities() + fn convert(c: Checksum) -> phy::Checksum { + match c { + Checksum::Both => phy::Checksum::Both, + Checksum::Tx => phy::Checksum::Tx, + Checksum::Rx => phy::Checksum::Rx, + Checksum::None => phy::Checksum::None, + } + } + let caps: Capabilities = self.inner.capabilities(); + let mut smolcaps = phy::DeviceCapabilities::default(); + + smolcaps.max_transmission_unit = caps.max_transmission_unit; + smolcaps.max_burst_size = caps.max_burst_size; + smolcaps.medium = match caps.medium { + #[cfg(feature = "medium-ethernet")] + Medium::Ethernet => phy::Medium::Ethernet, + #[cfg(feature = "medium-ip")] + Medium::Ip => phy::Medium::Ip, + _ => panic!( + "Unsupported medium {:?}. MAke sure to enable it in embassy-net's Cargo features.", + caps.medium + ), + }; + smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4); + #[cfg(feature = "proto-ipv6")] + { + smolcaps.checksum.ipv6 = convert(caps.checksum.ipv6); + } + smolcaps.checksum.tcp = convert(caps.checksum.tcp); + smolcaps.checksum.udp = convert(caps.checksum.udp); + smolcaps.checksum.icmpv4 = convert(caps.checksum.icmpv4); + + smolcaps } } diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index afe0d6da..b58c9cf3 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -18,6 +18,7 @@ use core::cell::RefCell; use core::future::{poll_fn, Future}; use core::task::{Context, Poll}; +use embassy_net_driver::{Driver, LinkState, Medium}; use embassy_sync::waitqueue::WakerRegistration; use embassy_time::{Instant, Timer}; use futures::pin_mut; @@ -27,8 +28,6 @@ use smoltcp::iface::SocketHandle; use smoltcp::iface::{Interface, InterfaceBuilder, SocketSet, SocketStorage}; #[cfg(feature = "medium-ethernet")] use smoltcp::iface::{Neighbor, NeighborCache, Route, Routes}; -#[cfg(feature = "medium-ethernet")] -use smoltcp::phy::Medium; #[cfg(feature = "dhcpv4")] use smoltcp::socket::dhcpv4; // smoltcp reexports @@ -41,7 +40,7 @@ pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; #[cfg(feature = "udp")] pub use smoltcp::{socket::udp::PacketMetadata, wire::IpListenEndpoint}; -use crate::device::{Device, DeviceAdapter, LinkState}; +use crate::device::DriverAdapter; const LOCAL_PORT_MIN: u16 = 1025; const LOCAL_PORT_MAX: u16 = 65535; @@ -82,12 +81,12 @@ pub enum ConfigStrategy { Dhcp, } -pub struct Stack { +pub struct Stack { pub(crate) socket: RefCell, inner: RefCell>, } -struct Inner { +struct Inner { device: D, link_up: bool, config: Option, @@ -102,7 +101,7 @@ pub(crate) struct SocketStack { next_local_port: u16, } -impl Stack { +impl Stack { pub fn new( mut device: D, config: ConfigStrategy, @@ -130,7 +129,7 @@ impl Stack { b = b.routes(Routes::new(&mut resources.routes[..])); } - let iface = b.finalize(&mut DeviceAdapter { + let iface = b.finalize(&mut DriverAdapter { inner: &mut device, cx: None, }); @@ -211,7 +210,7 @@ impl SocketStack { } } -impl Inner { +impl Inner { fn apply_config(&mut self, s: &mut SocketStack, config: Config) { #[cfg(feature = "medium-ethernet")] let medium = self.device.capabilities().medium; @@ -263,7 +262,7 @@ impl Inner { s.waker.register(cx.waker()); let timestamp = instant_to_smoltcp(Instant::now()); - let mut smoldev = DeviceAdapter { + let mut smoldev = DriverAdapter { cx: Some(cx), inner: &mut self.device, }; diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 0dc8da73..0fbf0c91 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -3,12 +3,12 @@ use core::future::poll_fn; use core::mem; use core::task::Poll; +use embassy_net_driver::Driver; use smoltcp::iface::{Interface, SocketHandle}; use smoltcp::socket::tcp; use smoltcp::time::Duration; use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; -use crate::device::Device; use crate::{SocketStack, Stack}; #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -66,7 +66,7 @@ impl<'a> TcpWriter<'a> { } impl<'a> TcpSocket<'a> { - pub fn new(stack: &'a Stack, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self { + pub fn new(stack: &'a Stack, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self { let s = &mut *stack.socket.borrow_mut(); let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; @@ -336,19 +336,19 @@ pub mod client { use super::*; /// TCP client capable of creating up to N multiple connections with tx and rx buffers according to TX_SZ and RX_SZ. - pub struct TcpClient<'d, D: Device, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> { + pub struct TcpClient<'d, D: Driver, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> { stack: &'d Stack, state: &'d TcpClientState, } - impl<'d, D: Device, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> { + impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> { /// Create a new TcpClient pub fn new(stack: &'d Stack, state: &'d TcpClientState) -> Self { Self { stack, state } } } - impl<'d, D: Device, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect + impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect for TcpClient<'d, D, N, TX_SZ, RX_SZ> { type Error = Error; @@ -386,7 +386,7 @@ pub mod client { } impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpConnection<'d, N, TX_SZ, RX_SZ> { - fn new(stack: &'d Stack, state: &'d TcpClientState) -> Result { + fn new(stack: &'d Stack, state: &'d TcpClientState) -> Result { let mut bufs = state.pool.alloc().ok_or(Error::ConnectionReset)?; Ok(Self { socket: unsafe { TcpSocket::new(stack, &mut bufs.as_mut().0, &mut bufs.as_mut().1) }, diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 2f5334df..0ee8c6e1 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -3,11 +3,12 @@ use core::future::poll_fn; use core::mem; use core::task::Poll; +use embassy_net_driver::Driver; use smoltcp::iface::{Interface, SocketHandle}; use smoltcp::socket::udp::{self, PacketMetadata}; use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; -use crate::{Device, SocketStack, Stack}; +use crate::{SocketStack, Stack}; #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -31,7 +32,7 @@ pub struct UdpSocket<'a> { } impl<'a> UdpSocket<'a> { - pub fn new( + pub fn new( stack: &'a Stack, rx_meta: &'a mut [PacketMetadata], rx_buffer: &'a mut [u8], diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 0c491ee4..67996cca 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -39,7 +39,7 @@ embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]} embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } -embassy-net = { version = "0.1.0", path = "../embassy-net", optional = true } +embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } @@ -75,7 +75,7 @@ quote = "1.0.15" stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]} [features] -defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt"] +defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"] sdmmc-rs = ["embedded-sdmmc"] memory-x = ["stm32-metapac/memory-x"] subghz = [] diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index fd1b4853..9f62b61e 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -1,14 +1,17 @@ #![macro_use] -#![cfg_attr(not(feature = "embassy-net"), allow(unused))] #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] #[cfg_attr(eth_v2, path = "v2/mod.rs")] mod _version; pub mod generic_smi; -pub use _version::*; +use core::task::Context; + +use embassy_net_driver::{Capabilities, LinkState}; use embassy_sync::waitqueue::AtomicWaker; +pub use self::_version::*; + #[allow(unused)] const MTU: usize = 1514; const TX_BUFFER_SIZE: usize = 1514; @@ -40,92 +43,84 @@ impl PacketQueue { static WAKER: AtomicWaker = AtomicWaker::new(); -#[cfg(feature = "embassy-net")] -mod embassy_net_impl { - use core::task::Context; +impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P> { + type RxToken<'a> = RxToken<'a, 'd> where Self: 'a; + type TxToken<'a> = TxToken<'a, 'd> where Self: 'a; - use embassy_net::device::{Device, DeviceCapabilities, LinkState}; - - use super::*; - - impl<'d, T: Instance, P: PHY> Device for Ethernet<'d, T, P> { - type RxToken<'a> = RxToken<'a, 'd> where Self: 'a; - type TxToken<'a> = TxToken<'a, 'd> where Self: 'a; - - fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { - WAKER.register(cx.waker()); - if self.rx.available().is_some() && self.tx.available().is_some() { - Some((RxToken { rx: &mut self.rx }, TxToken { tx: &mut self.tx })) - } else { - None - } - } - - fn transmit(&mut self, cx: &mut Context) -> Option> { - WAKER.register(cx.waker()); - if self.tx.available().is_some() { - Some(TxToken { tx: &mut self.tx }) - } else { - None - } - } - - fn capabilities(&self) -> DeviceCapabilities { - let mut caps = DeviceCapabilities::default(); - caps.max_transmission_unit = MTU; - caps.max_burst_size = Some(self.tx.len()); - caps - } - - fn link_state(&mut self, cx: &mut Context) -> LinkState { - // TODO: wake cx.waker on link state change - cx.waker().wake_by_ref(); - if P::poll_link(self) { - LinkState::Up - } else { - LinkState::Down - } - } - - fn ethernet_address(&self) -> [u8; 6] { - self.mac_addr + fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { + WAKER.register(cx.waker()); + if self.rx.available().is_some() && self.tx.available().is_some() { + Some((RxToken { rx: &mut self.rx }, TxToken { tx: &mut self.tx })) + } else { + None } } - pub struct RxToken<'a, 'd> { - rx: &'a mut RDesRing<'d>, - } - - impl<'a, 'd> embassy_net::device::RxToken for RxToken<'a, 'd> { - fn consume(self, f: F) -> R - where - F: FnOnce(&mut [u8]) -> R, - { - // NOTE(unwrap): we checked the queue wasn't full when creating the token. - let pkt = unwrap!(self.rx.available()); - let r = f(pkt); - self.rx.pop_packet(); - r + fn transmit(&mut self, cx: &mut Context) -> Option> { + WAKER.register(cx.waker()); + if self.tx.available().is_some() { + Some(TxToken { tx: &mut self.tx }) + } else { + None } } - pub struct TxToken<'a, 'd> { - tx: &'a mut TDesRing<'d>, + fn capabilities(&self) -> Capabilities { + let mut caps = Capabilities::default(); + caps.max_transmission_unit = MTU; + caps.max_burst_size = Some(self.tx.len()); + caps } - impl<'a, 'd> embassy_net::device::TxToken for TxToken<'a, 'd> { - fn consume(self, len: usize, f: F) -> R - where - F: FnOnce(&mut [u8]) -> R, - { - // NOTE(unwrap): we checked the queue wasn't full when creating the token. - let pkt = unwrap!(self.tx.available()); - let r = f(&mut pkt[..len]); - self.tx.transmit(len); - r + fn link_state(&mut self, cx: &mut Context) -> LinkState { + // TODO: wake cx.waker on link state change + cx.waker().wake_by_ref(); + if P::poll_link(self) { + LinkState::Up + } else { + LinkState::Down } } + + fn ethernet_address(&self) -> [u8; 6] { + self.mac_addr + } } + +pub struct RxToken<'a, 'd> { + rx: &'a mut RDesRing<'d>, +} + +impl<'a, 'd> embassy_net_driver::RxToken for RxToken<'a, 'd> { + fn consume(self, f: F) -> R + where + F: FnOnce(&mut [u8]) -> R, + { + // NOTE(unwrap): we checked the queue wasn't full when creating the token. + let pkt = unwrap!(self.rx.available()); + let r = f(pkt); + self.rx.pop_packet(); + r + } +} + +pub struct TxToken<'a, 'd> { + tx: &'a mut TDesRing<'d>, +} + +impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> { + fn consume(self, len: usize, f: F) -> R + where + F: FnOnce(&mut [u8]) -> R, + { + // NOTE(unwrap): we checked the queue wasn't full when creating the token. + let pkt = unwrap!(self.tx.available()); + let r = f(&mut pkt[..len]); + self.tx.transmit(len); + r + } +} + /// Station Management Interface (SMI) on an ethernet PHY /// /// # Safety diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index de36d3da..9c0f4d66 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -13,7 +13,7 @@ pub(crate) use self::rx_desc::{RDes, RDesRing}; pub(crate) use self::tx_desc::{TDes, TDesRing}; use super::*; use crate::gpio::sealed::{AFType, Pin as __GpioPin}; -use crate::gpio::{AnyPin, Speed}; +use crate::gpio::AnyPin; #[cfg(eth_v1a)] use crate::pac::AFIO; #[cfg(any(eth_v1b, eth_v1c))] @@ -66,7 +66,7 @@ macro_rules! config_pins { critical_section::with(|_| { $( $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); - $pin.set_speed(Speed::VeryHigh); + $pin.set_speed(crate::gpio::Speed::VeryHigh); )* }) }; diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index 1e72ce68..d0742ceb 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -19,7 +19,7 @@ default = ["usbd-hid"] embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } embassy-sync = { version = "0.1.0", path = "../embassy-sync" } -embassy-net = { version = "0.1.0", path = "../embassy-net", optional = true } +embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } diff --git a/embassy-usb/src/class/cdc_ncm/embassy_net.rs b/embassy-usb/src/class/cdc_ncm/embassy_net.rs index 60bbfd8d..093afeff 100644 --- a/embassy-usb/src/class/cdc_ncm/embassy_net.rs +++ b/embassy-usb/src/class/cdc_ncm/embassy_net.rs @@ -3,7 +3,7 @@ use core::mem::MaybeUninit; use core::task::Context; use embassy_futures::select::{select, Either}; -use embassy_net::device::{Device as DeviceTrait, DeviceCapabilities, LinkState, Medium}; +use embassy_net_driver::{Capabilities, LinkState, Medium}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_sync::waitqueue::WakerRegistration; @@ -108,7 +108,7 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { ) -> (Runner<'d, D, MTU>, Device<'d, MTU>) { let (tx_usb, rx_usb) = self.split(); - let mut caps = DeviceCapabilities::default(); + let mut caps = Capabilities::default(); caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header caps.medium = Medium::Ethernet; @@ -158,11 +158,11 @@ pub struct Device<'d, const MTU: usize> { rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf>, link_state: &'d Mutex>, - caps: DeviceCapabilities, + caps: Capabilities, ethernet_address: [u8; 6], } -impl<'d, const MTU: usize> DeviceTrait for Device<'d, MTU> { +impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> { type RxToken<'a> = RxToken<'a, MTU> where Self: 'a ; type TxToken<'a> = TxToken<'a, MTU> where Self: 'a ; @@ -184,7 +184,7 @@ impl<'d, const MTU: usize> DeviceTrait for Device<'d, MTU> { } /// Get a description of device capabilities. - fn capabilities(&self) -> DeviceCapabilities { + fn capabilities(&self) -> Capabilities { self.caps.clone() } @@ -205,7 +205,7 @@ pub struct RxToken<'a, const MTU: usize> { rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf>, } -impl<'a, const MTU: usize> embassy_net::device::RxToken for RxToken<'a, MTU> { +impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> { fn consume(mut self, f: F) -> R where F: FnOnce(&mut [u8]) -> R, @@ -222,7 +222,7 @@ pub struct TxToken<'a, const MTU: usize> { tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf>, } -impl<'a, const MTU: usize> embassy_net::device::TxToken for TxToken<'a, MTU> { +impl<'a, const MTU: usize> embassy_net_driver::TxToken for TxToken<'a, MTU> { fn consume(mut self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R, diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs index 2ee47f68..4954a65b 100644 --- a/embassy-usb/src/class/cdc_ncm/mod.rs +++ b/embassy-usb/src/class/cdc_ncm/mod.rs @@ -21,7 +21,6 @@ use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::types::*; use crate::Builder; -#[cfg(feature = "embassy-net")] pub mod embassy_net; /// This should be used as `device_class` when building the `UsbDevice`. diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index 54a477b4..994823a9 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml @@ -16,7 +16,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "embassy-net"], optional = true } +embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } embedded-io = "0.4.0" embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 57cddd43..afd1042a 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "pio", "critical-section-impl"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "embassy-net"] } +embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 649e3974..45b2a4a4 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -9,6 +9,7 @@ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["lo embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dhcpv4"] } +embassy-net-driver = { version = "0.1.0", path = "../../embassy-net-driver" } embedded-io = { version = "0.4.0", features = ["async", "std", "futures"] } critical-section = { version = "1.1", features = ["std"] } diff --git a/examples/std/src/tuntap.rs b/examples/std/src/tuntap.rs index bb3e194c..d918a2e6 100644 --- a/examples/std/src/tuntap.rs +++ b/examples/std/src/tuntap.rs @@ -4,7 +4,7 @@ use std::os::unix::io::{AsRawFd, RawFd}; use std::task::Context; use async_io::Async; -use embassy_net::device::{self, Device, DeviceCapabilities, LinkState}; +use embassy_net_driver::{self, Capabilities, Driver, LinkState}; use log::*; pub const SIOCGIFMTU: libc::c_ulong = 0x8921; @@ -137,7 +137,7 @@ impl TunTapDevice { } } -impl Device for TunTapDevice { +impl Driver for TunTapDevice { type RxToken<'a> = RxToken where Self: 'a; type TxToken<'a> = TxToken<'a> where Self: 'a; @@ -170,8 +170,8 @@ impl Device for TunTapDevice { }) } - fn capabilities(&self) -> DeviceCapabilities { - let mut caps = DeviceCapabilities::default(); + fn capabilities(&self) -> Capabilities { + let mut caps = Capabilities::default(); caps.max_transmission_unit = self.device.get_ref().mtu; caps } @@ -190,7 +190,7 @@ pub struct RxToken { buffer: Vec, } -impl device::RxToken for RxToken { +impl embassy_net_driver::RxToken for RxToken { fn consume(mut self, f: F) -> R where F: FnOnce(&mut [u8]) -> R, @@ -204,7 +204,7 @@ pub struct TxToken<'a> { device: &'a mut Async, } -impl<'a> device::TxToken for TxToken<'a> { +impl<'a> embassy_net_driver::TxToken for TxToken<'a> { fn consume(self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R, diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index a8b2baf2..b80dbbf9 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "embassy-net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io = { version = "0.4.0", features = ["async"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 63e6caa7..d30c42b1 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "embassy-net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits"] } embedded-io = { version = "0.4.0", features = ["async"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index ce999f67..c0accb0d 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "embassy-net"] } +embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.6.0"