From e9219405ca04e23b6543fb841fd97df54cf72f94 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 7 Dec 2022 16:03:03 +0100 Subject: usb/cdc-ncm: add embassy-net Device implementation. --- examples/nrf/Cargo.toml | 2 +- examples/nrf/src/bin/usb_ethernet.rs | 139 ++++-------------------------- examples/rp/Cargo.toml | 2 +- examples/rp/src/bin/usb_ethernet.rs | 140 ++++--------------------------- examples/stm32l5/Cargo.toml | 2 +- examples/stm32l5/src/bin/usb_ethernet.rs | 140 ++++--------------------------- 6 files changed, 54 insertions(+), 371 deletions(-) (limited to 'examples') diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index 8b95ac3a6..a980a505c 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", "pool-16"], optional = true } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } +embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "embassy-net"], 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/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs index de93a2b45..e5f704524 100644 --- a/examples/nrf/src/bin/usb_ethernet.rs +++ b/examples/nrf/src/bin/usb_ethernet.rs @@ -3,19 +3,16 @@ #![feature(type_alias_impl_trait)] use core::mem; -use core::sync::atomic::{AtomicBool, Ordering}; -use core::task::Waker; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources}; +use embassy_net::{Stack, StackResources}; use embassy_nrf::rng::Rng; use embassy_nrf::usb::{Driver, PowerUsb}; use embassy_nrf::{interrupt, pac, peripherals}; -use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; -use embassy_sync::channel::Channel; -use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State}; +use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; +use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, Config, UsbDevice}; use embedded_io::asynch::Write; use static_cell::StaticCell; @@ -27,56 +24,25 @@ macro_rules! singleton { ($val:expr) => {{ type T = impl Sized; static STATIC_CELL: StaticCell = StaticCell::new(); - STATIC_CELL.init_with(move || $val) + let (x,) = STATIC_CELL.init(($val,)); + x }}; } +const MTU: usize = 1514; + #[embassy_executor::task] async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! { device.run().await } #[embassy_executor::task] -async fn usb_ncm_rx_task(mut class: Receiver<'static, MyDriver>) { - loop { - warn!("WAITING for connection"); - LINK_UP.store(false, Ordering::Relaxed); - - class.wait_connection().await.unwrap(); - - warn!("Connected"); - LINK_UP.store(true, Ordering::Relaxed); - - loop { - let mut p = unwrap!(PacketBox::new(embassy_net::Packet::new())); - let n = match class.read_packet(&mut p[..]).await { - Ok(n) => n, - Err(e) => { - warn!("error reading packet: {:?}", e); - break; - } - }; - - let buf = p.slice(0..n); - if RX_CHANNEL.try_send(buf).is_err() { - warn!("Failed pushing rx'd packet to channel."); - } - } - } -} - -#[embassy_executor::task] -async fn usb_ncm_tx_task(mut class: Sender<'static, MyDriver>) { - loop { - let pkt = TX_CHANNEL.recv().await; - if let Err(e) = class.write_packet(&pkt[..]).await { - warn!("Failed to TX packet: {:?}", e); - } - } +async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { + class.run().await } #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { +async fn net_task(stack: &'static Stack>) -> ! { stack.run().await } @@ -108,55 +74,32 @@ async fn main(spawner: Spawner) { config.device_sub_class = 0x02; config.device_protocol = 0x01; - struct Resources { - device_descriptor: [u8; 256], - config_descriptor: [u8; 256], - bos_descriptor: [u8; 256], - control_buf: [u8; 128], - serial_state: State<'static>, - } - let res: &mut Resources = singleton!(Resources { - device_descriptor: [0; 256], - config_descriptor: [0; 256], - bos_descriptor: [0; 256], - control_buf: [0; 128], - serial_state: State::new(), - }); - // Create embassy-usb DeviceBuilder using the driver and config. let mut builder = Builder::new( driver, config, - &mut res.device_descriptor, - &mut res.config_descriptor, - &mut res.bos_descriptor, - &mut res.control_buf, + &mut singleton!([0; 256])[..], + &mut singleton!([0; 256])[..], + &mut singleton!([0; 256])[..], + &mut singleton!([0; 128])[..], None, ); - // WARNINGS for Android ethernet tethering: - // - On Pixel 4a, it refused to work on Android 11, worked on Android 12. - // - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte), - // it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled. - // This is due to regex spaghetti: https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r84/core/res/res/values/config.xml#417 - // and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757 - // Our MAC addr. let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC]; // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has. let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; // Create classes on the builder. - let class = CdcNcmClass::new(&mut builder, &mut res.serial_state, host_mac_addr, 64); + let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); // Build the builder. let usb = builder.build(); unwrap!(spawner.spawn(usb_task(usb))); - let (tx, rx) = class.split(); - unwrap!(spawner.spawn(usb_ncm_rx_task(rx))); - unwrap!(spawner.spawn(usb_ncm_tx_task(tx))); + let (runner, device) = class.into_embassy_net_device::(singleton!(NetState::new()), our_mac_addr); + unwrap!(spawner.spawn(usb_ncm_task(runner))); let config = embassy_net::ConfigStrategy::Dhcp; //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { @@ -172,7 +115,6 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - let device = Device { mac_addr: our_mac_addr }; let stack = &*singleton!(Stack::new( device, config, @@ -225,50 +167,3 @@ async fn main(spawner: Spawner) { } } } - -static TX_CHANNEL: Channel = Channel::new(); -static RX_CHANNEL: Channel = Channel::new(); -static LINK_UP: AtomicBool = AtomicBool::new(false); - -struct Device { - mac_addr: [u8; 6], -} - -impl embassy_net::Device for Device { - fn register_waker(&mut self, waker: &Waker) { - // loopy loopy wakey wakey - waker.wake_by_ref() - } - - fn link_state(&mut self) -> embassy_net::LinkState { - match LINK_UP.load(Ordering::Relaxed) { - true => embassy_net::LinkState::Up, - false => embassy_net::LinkState::Down, - } - } - - fn capabilities(&self) -> embassy_net::DeviceCapabilities { - let mut caps = embassy_net::DeviceCapabilities::default(); - caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header - caps.medium = embassy_net::Medium::Ethernet; - caps - } - - fn is_transmit_ready(&mut self) -> bool { - true - } - - fn transmit(&mut self, pkt: PacketBuf) { - if TX_CHANNEL.try_send(pkt).is_err() { - warn!("TX failed") - } - } - - fn receive<'a>(&mut self) -> Option { - RX_CHANNEL.try_recv().ok() - } - - fn ethernet_address(&self) -> [u8; 6] { - self.mac_addr - } -} diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index dfbc26426..31a08cfb6 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-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "embassy-net"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 1057fe7fd..d0aec874a 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -2,18 +2,14 @@ #![no_main] #![feature(type_alias_impl_trait)] -use core::sync::atomic::{AtomicBool, Ordering}; -use core::task::Waker; - use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources}; +use embassy_net::{Stack, StackResources}; use embassy_rp::usb::Driver; use embassy_rp::{interrupt, peripherals}; -use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; -use embassy_sync::channel::Channel; -use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State}; +use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; +use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, Config, UsbDevice}; use embedded_io::asynch::Write; use static_cell::StaticCell; @@ -25,56 +21,25 @@ macro_rules! singleton { ($val:expr) => {{ type T = impl Sized; static STATIC_CELL: StaticCell = StaticCell::new(); - STATIC_CELL.init_with(move || $val) + let (x,) = STATIC_CELL.init(($val,)); + x }}; } +const MTU: usize = 1514; + #[embassy_executor::task] async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! { device.run().await } #[embassy_executor::task] -async fn usb_ncm_rx_task(mut class: Receiver<'static, MyDriver>) { - loop { - warn!("WAITING for connection"); - LINK_UP.store(false, Ordering::Relaxed); - - class.wait_connection().await.unwrap(); - - warn!("Connected"); - LINK_UP.store(true, Ordering::Relaxed); - - loop { - let mut p = unwrap!(PacketBox::new(embassy_net::Packet::new())); - let n = match class.read_packet(&mut p[..]).await { - Ok(n) => n, - Err(e) => { - warn!("error reading packet: {:?}", e); - break; - } - }; - - let buf = p.slice(0..n); - if RX_CHANNEL.try_send(buf).is_err() { - warn!("Failed pushing rx'd packet to channel."); - } - } - } -} - -#[embassy_executor::task] -async fn usb_ncm_tx_task(mut class: Sender<'static, MyDriver>) { - loop { - let pkt = TX_CHANNEL.recv().await; - if let Err(e) = class.write_packet(&pkt[..]).await { - warn!("Failed to TX packet: {:?}", e); - } - } +async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { + class.run().await } #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { +async fn net_task(stack: &'static Stack>) -> ! { stack.run().await } @@ -100,55 +65,32 @@ async fn main(spawner: Spawner) { config.device_sub_class = 0x02; config.device_protocol = 0x01; - struct Resources { - device_descriptor: [u8; 256], - config_descriptor: [u8; 256], - bos_descriptor: [u8; 256], - control_buf: [u8; 128], - serial_state: State<'static>, - } - let res: &mut Resources = singleton!(Resources { - device_descriptor: [0; 256], - config_descriptor: [0; 256], - bos_descriptor: [0; 256], - control_buf: [0; 128], - serial_state: State::new(), - }); - // Create embassy-usb DeviceBuilder using the driver and config. let mut builder = Builder::new( driver, config, - &mut res.device_descriptor, - &mut res.config_descriptor, - &mut res.bos_descriptor, - &mut res.control_buf, + &mut singleton!([0; 256])[..], + &mut singleton!([0; 256])[..], + &mut singleton!([0; 256])[..], + &mut singleton!([0; 128])[..], None, ); - // WARNINGS for Android ethernet tethering: - // - On Pixel 4a, it refused to work on Android 11, worked on Android 12. - // - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte), - // it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled. - // This is due to regex spaghetti: https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r84/core/res/res/values/config.xml#417 - // and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757 - // Our MAC addr. let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC]; // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has. let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; // Create classes on the builder. - let class = CdcNcmClass::new(&mut builder, &mut res.serial_state, host_mac_addr, 64); + let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); // Build the builder. let usb = builder.build(); unwrap!(spawner.spawn(usb_task(usb))); - let (tx, rx) = class.split(); - unwrap!(spawner.spawn(usb_ncm_rx_task(rx))); - unwrap!(spawner.spawn(usb_ncm_tx_task(tx))); + let (runner, device) = class.into_embassy_net_device::(singleton!(NetState::new()), our_mac_addr); + unwrap!(spawner.spawn(usb_ncm_task(runner))); let config = embassy_net::ConfigStrategy::Dhcp; //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { @@ -161,7 +103,6 @@ async fn main(spawner: Spawner) { let seed = 1234; // guaranteed random, chosen by a fair dice roll // Init network stack - let device = Device { mac_addr: our_mac_addr }; let stack = &*singleton!(Stack::new( device, config, @@ -214,50 +155,3 @@ async fn main(spawner: Spawner) { } } } - -static TX_CHANNEL: Channel = Channel::new(); -static RX_CHANNEL: Channel = Channel::new(); -static LINK_UP: AtomicBool = AtomicBool::new(false); - -struct Device { - mac_addr: [u8; 6], -} - -impl embassy_net::Device for Device { - fn register_waker(&mut self, waker: &Waker) { - // loopy loopy wakey wakey - waker.wake_by_ref() - } - - fn link_state(&mut self) -> embassy_net::LinkState { - match LINK_UP.load(Ordering::Relaxed) { - true => embassy_net::LinkState::Up, - false => embassy_net::LinkState::Down, - } - } - - fn capabilities(&self) -> embassy_net::DeviceCapabilities { - let mut caps = embassy_net::DeviceCapabilities::default(); - caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header - caps.medium = embassy_net::Medium::Ethernet; - caps - } - - fn is_transmit_ready(&mut self) -> bool { - true - } - - fn transmit(&mut self, pkt: PacketBuf) { - if TX_CHANNEL.try_send(pkt).is_err() { - warn!("TX failed") - } - } - - fn receive<'a>(&mut self) -> Option { - RX_CHANNEL.try_recv().ok() - } - - fn ethernet_address(&self) -> [u8; 6] { - self.mac_addr - } -} diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 73ad50787..bb8515312 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-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "embassy-net"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.6.0" diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 4f36d3f5a..b49329ea4 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -2,20 +2,16 @@ #![no_main] #![feature(type_alias_impl_trait)] -use core::sync::atomic::{AtomicBool, Ordering}; -use core::task::Waker; - use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources}; +use embassy_net::{Stack, StackResources}; use embassy_stm32::rcc::*; use embassy_stm32::rng::Rng; use embassy_stm32::usb::Driver; use embassy_stm32::{interrupt, Config}; -use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; -use embassy_sync::channel::Channel; -use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State}; +use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; +use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, UsbDevice}; use embedded_io::asynch::Write; use rand_core::RngCore; @@ -28,56 +24,25 @@ macro_rules! singleton { ($val:expr) => {{ type T = impl Sized; static STATIC_CELL: StaticCell = StaticCell::new(); - STATIC_CELL.init_with(move || $val) + let (x,) = STATIC_CELL.init(($val,)); + x }}; } +const MTU: usize = 1514; + #[embassy_executor::task] async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! { device.run().await } #[embassy_executor::task] -async fn usb_ncm_rx_task(mut class: Receiver<'static, MyDriver>) { - loop { - warn!("WAITING for connection"); - LINK_UP.store(false, Ordering::Relaxed); - - class.wait_connection().await.unwrap(); - - warn!("Connected"); - LINK_UP.store(true, Ordering::Relaxed); - - loop { - let mut p = unwrap!(PacketBox::new(embassy_net::Packet::new())); - let n = match class.read_packet(&mut p[..]).await { - Ok(n) => n, - Err(e) => { - warn!("error reading packet: {:?}", e); - break; - } - }; - - let buf = p.slice(0..n); - if RX_CHANNEL.try_send(buf).is_err() { - warn!("Failed pushing rx'd packet to channel."); - } - } - } -} - -#[embassy_executor::task] -async fn usb_ncm_tx_task(mut class: Sender<'static, MyDriver>) { - loop { - let pkt = TX_CHANNEL.recv().await; - if let Err(e) = class.write_packet(&pkt[..]).await { - warn!("Failed to TX packet: {:?}", e); - } - } +async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { + class.run().await } #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { +async fn net_task(stack: &'static Stack>) -> ! { stack.run().await } @@ -106,55 +71,32 @@ async fn main(spawner: Spawner) { config.device_sub_class = 0x02; config.device_protocol = 0x01; - struct Resources { - device_descriptor: [u8; 256], - config_descriptor: [u8; 256], - bos_descriptor: [u8; 256], - control_buf: [u8; 128], - serial_state: State<'static>, - } - let res: &mut Resources = singleton!(Resources { - device_descriptor: [0; 256], - config_descriptor: [0; 256], - bos_descriptor: [0; 256], - control_buf: [0; 128], - serial_state: State::new(), - }); - // Create embassy-usb DeviceBuilder using the driver and config. let mut builder = Builder::new( driver, config, - &mut res.device_descriptor, - &mut res.config_descriptor, - &mut res.bos_descriptor, - &mut res.control_buf, + &mut singleton!([0; 256])[..], + &mut singleton!([0; 256])[..], + &mut singleton!([0; 256])[..], + &mut singleton!([0; 128])[..], None, ); - // WARNINGS for Android ethernet tethering: - // - On Pixel 4a, it refused to work on Android 11, worked on Android 12. - // - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte), - // it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled. - // This is due to regex spaghetti: https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r84/core/res/res/values/config.xml#417 - // and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757 - // Our MAC addr. let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC]; // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has. let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; // Create classes on the builder. - let class = CdcNcmClass::new(&mut builder, &mut res.serial_state, host_mac_addr, 64); + let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); // Build the builder. let usb = builder.build(); unwrap!(spawner.spawn(usb_task(usb))); - let (tx, rx) = class.split(); - unwrap!(spawner.spawn(usb_ncm_rx_task(rx))); - unwrap!(spawner.spawn(usb_ncm_tx_task(tx))); + let (runner, device) = class.into_embassy_net_device::(singleton!(NetState::new()), our_mac_addr); + unwrap!(spawner.spawn(usb_ncm_task(runner))); let config = embassy_net::ConfigStrategy::Dhcp; //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { @@ -168,7 +110,6 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - let device = Device { mac_addr: our_mac_addr }; let stack = &*singleton!(Stack::new( device, config, @@ -221,50 +162,3 @@ async fn main(spawner: Spawner) { } } } - -static TX_CHANNEL: Channel = Channel::new(); -static RX_CHANNEL: Channel = Channel::new(); -static LINK_UP: AtomicBool = AtomicBool::new(false); - -struct Device { - mac_addr: [u8; 6], -} - -impl embassy_net::Device for Device { - fn register_waker(&mut self, waker: &Waker) { - // loopy loopy wakey wakey - waker.wake_by_ref() - } - - fn link_state(&mut self) -> embassy_net::LinkState { - match LINK_UP.load(Ordering::Relaxed) { - true => embassy_net::LinkState::Up, - false => embassy_net::LinkState::Down, - } - } - - fn capabilities(&self) -> embassy_net::DeviceCapabilities { - let mut caps = embassy_net::DeviceCapabilities::default(); - caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header - caps.medium = embassy_net::Medium::Ethernet; - caps - } - - fn is_transmit_ready(&mut self) -> bool { - true - } - - fn transmit(&mut self, pkt: PacketBuf) { - if TX_CHANNEL.try_send(pkt).is_err() { - warn!("TX failed") - } - } - - fn receive<'a>(&mut self) -> Option { - RX_CHANNEL.try_recv().ok() - } - - fn ethernet_address(&self) -> [u8; 6] { - self.mac_addr - } -} -- cgit From 8f3065210927b6e92f6d727741189155b2eab91e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 9 Dec 2022 03:18:45 +0100 Subject: stm32/eth_v1: update to new embassy-net trait, remove PeripheralMutex. --- examples/stm32f7/src/bin/eth.rs | 50 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'examples') diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 5202edf62..224cc202b 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -7,7 +7,7 @@ use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, Stack, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; -use embassy_stm32::eth::{Ethernet, State}; +use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::mhz; @@ -22,11 +22,12 @@ macro_rules! singleton { ($val:expr) => {{ type T = impl Sized; static STATIC_CELL: StaticCell = StaticCell::new(); - STATIC_CELL.init_with(move || $val) + let (x,) = STATIC_CELL.init(($val,)); + x }}; } -type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>; +type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] async fn net_task(stack: &'static Stack) -> ! { @@ -50,25 +51,23 @@ async fn main(spawner: Spawner) -> ! { let eth_int = interrupt::take!(ETH); let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; - let device = unsafe { - Ethernet::new( - singleton!(State::new()), - p.ETH, - eth_int, - p.PA1, - p.PA2, - p.PC1, - p.PA7, - p.PC4, - p.PC5, - p.PG13, - p.PB13, - p.PG11, - GenericSMI, - mac_addr, - 0, - ) - }; + let device = Ethernet::new( + singleton!(PacketQueue::<16, 16>::new()), + p.ETH, + eth_int, + p.PA1, + p.PA2, + p.PC1, + p.PA7, + p.PC4, + p.PC5, + p.PG13, + p.PB13, + p.PG11, + GenericSMI, + mac_addr, + 0, + ); let config = embassy_net::ConfigStrategy::Dhcp; //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { @@ -91,8 +90,8 @@ async fn main(spawner: Spawner) -> ! { info!("Network task initialized"); // Then we can use it! - let mut rx_buffer = [0; 1024]; - let mut tx_buffer = [0; 1024]; + let mut rx_buffer = [0; 4096]; + let mut tx_buffer = [0; 4096]; loop { let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); @@ -107,8 +106,9 @@ async fn main(spawner: Spawner) -> ! { continue; } info!("connected!"); + let buf = [0; 1024]; loop { - let r = socket.write_all(b"Hello\n").await; + let r = socket.write_all(&buf).await; if let Err(e) = r { info!("write error: {:?}", e); return; -- cgit From 3005ee0178af46ef8a2b7f8b02f4aea69ed9202b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Dec 2022 02:04:33 +0100 Subject: stm32/eth_v2: update to new embassy-net trait, remove PeripheralMutex. --- examples/stm32h7/src/bin/eth.rs | 43 +++++++++++++++++----------------- examples/stm32h7/src/bin/eth_client.rs | 43 +++++++++++++++++----------------- 2 files changed, 42 insertions(+), 44 deletions(-) (limited to 'examples') diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 4ccc0b5ef..551325ca4 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -7,7 +7,7 @@ use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, Stack, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; -use embassy_stm32::eth::{Ethernet, State}; +use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::mhz; @@ -22,11 +22,12 @@ macro_rules! singleton { ($val:expr) => {{ type T = impl Sized; static STATIC_CELL: StaticCell = StaticCell::new(); - STATIC_CELL.init_with(move || $val) + let (x,) = STATIC_CELL.init(($val,)); + x }}; } -type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>; +type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] async fn net_task(stack: &'static Stack) -> ! { @@ -51,25 +52,23 @@ async fn main(spawner: Spawner) -> ! { let eth_int = interrupt::take!(ETH); let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; - let device = unsafe { - Ethernet::new( - singleton!(State::new()), - p.ETH, - eth_int, - p.PA1, - p.PA2, - p.PC1, - p.PA7, - p.PC4, - p.PC5, - p.PG13, - p.PB13, - p.PG11, - GenericSMI, - mac_addr, - 0, - ) - }; + let device = Ethernet::new( + singleton!(PacketQueue::<16, 16>::new()), + p.ETH, + eth_int, + p.PA1, + p.PA2, + p.PC1, + p.PA7, + p.PC4, + p.PC5, + p.PG13, + p.PB13, + p.PG11, + GenericSMI, + mac_addr, + 0, + ); let config = embassy_net::ConfigStrategy::Dhcp; //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 64fd84141..61a08ae10 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -7,7 +7,7 @@ use embassy_executor::Spawner; use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_net::{Stack, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; -use embassy_stm32::eth::{Ethernet, State}; +use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::mhz; @@ -23,11 +23,12 @@ macro_rules! singleton { ($val:expr) => {{ type T = impl Sized; static STATIC_CELL: StaticCell = StaticCell::new(); - STATIC_CELL.init_with(move || $val) + let (x,) = STATIC_CELL.init(($val,)); + x }}; } -type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>; +type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] async fn net_task(stack: &'static Stack) -> ! { @@ -52,25 +53,23 @@ async fn main(spawner: Spawner) -> ! { let eth_int = interrupt::take!(ETH); let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; - let device = unsafe { - Ethernet::new( - singleton!(State::new()), - p.ETH, - eth_int, - p.PA1, - p.PA2, - p.PC1, - p.PA7, - p.PC4, - p.PC5, - p.PG13, - p.PB13, - p.PG11, - GenericSMI, - mac_addr, - 0, - ) - }; + let device = Ethernet::new( + singleton!(PacketQueue::<16, 16>::new()), + p.ETH, + eth_int, + p.PA1, + p.PA2, + p.PC1, + p.PA7, + p.PC4, + p.PC5, + p.PG13, + p.PB13, + p.PG11, + GenericSMI, + mac_addr, + 0, + ); let config = embassy_net::ConfigStrategy::Dhcp; //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { -- cgit From 5eae295c8ad8da529490b89f914f2cca07ae6972 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 13 Dec 2022 16:14:50 +0100 Subject: stm32: rename feature `net` to `embassy-net`. The eth code is always built and available, but has no own API (other than the embassy-net Device impl) to rx/tx packets. We could add this API in the future, so the feature only means "embassy-net support". --- examples/stm32f7/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index f4d674cdc..afdf87000 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", "net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "embassy-net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } embedded-io = { version = "0.4.0", features = ["async"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 11ce35053..5acf0035d 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", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "embassy-net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16", "unstable-traits"] } embedded-io = { version = "0.4.0", features = ["async"] } -- cgit From 790e4e1594d455d06c7303a628172244e78af0da Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 13 Dec 2022 16:18:16 +0100 Subject: examples/std: update to new embassy-net trait. --- examples/std/src/tuntap.rs | 113 +++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 55 deletions(-) (limited to 'examples') diff --git a/examples/std/src/tuntap.rs b/examples/std/src/tuntap.rs index a0cace7f7..bb3e194cc 100644 --- a/examples/std/src/tuntap.rs +++ b/examples/std/src/tuntap.rs @@ -1,8 +1,10 @@ use std::io; use std::io::{Read, Write}; use std::os::unix::io::{AsRawFd, RawFd}; +use std::task::Context; use async_io::Async; +use embassy_net::device::{self, Device, DeviceCapabilities, LinkState}; use log::*; pub const SIOCGIFMTU: libc::c_ulong = 0x8921; @@ -125,54 +127,35 @@ impl io::Write for TunTap { pub struct TunTapDevice { device: Async, - waker: Option, } impl TunTapDevice { pub fn new(name: &str) -> io::Result { Ok(Self { device: Async::new(TunTap::new(name)?)?, - waker: None, }) } } -use core::task::Waker; -use std::task::Context; - -use embassy_net::{Device, DeviceCapabilities, LinkState, Packet, PacketBox, PacketBoxExt, PacketBuf}; - impl Device for TunTapDevice { - fn is_transmit_ready(&mut self) -> bool { - true - } + type RxToken<'a> = RxToken where Self: 'a; + type TxToken<'a> = TxToken<'a> where Self: 'a; - fn transmit(&mut self, pkt: PacketBuf) { - // todo handle WouldBlock - match self.device.get_mut().write(&pkt) { - Ok(_) => {} - Err(e) if e.kind() == io::ErrorKind::WouldBlock => { - info!("transmit WouldBlock"); - } - Err(e) => panic!("transmit error: {:?}", e), - } - } - - fn receive(&mut self) -> Option { - let mut pkt = PacketBox::new(Packet::new()).unwrap(); + fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { + let mut buf = vec![0; self.device.get_ref().mtu]; loop { - match self.device.get_mut().read(&mut pkt[..]) { + match self.device.get_mut().read(&mut buf) { Ok(n) => { - return Some(pkt.slice(0..n)); + buf.truncate(n); + return Some(( + RxToken { buffer: buf }, + TxToken { + device: &mut self.device, + }, + )); } Err(e) if e.kind() == io::ErrorKind::WouldBlock => { - let ready = if let Some(w) = self.waker.as_ref() { - let mut cx = Context::from_waker(w); - self.device.poll_readable(&mut cx).is_ready() - } else { - false - }; - if !ready { + if !self.device.poll_readable(cx).is_ready() { return None; } } @@ -181,28 +164,10 @@ impl Device for TunTapDevice { } } - fn register_waker(&mut self, w: &Waker) { - match self.waker { - // Optimization: If both the old and new Wakers wake the same task, we can simply - // keep the old waker, skipping the clone. (In most executor implementations, - // cloning a waker is somewhat expensive, comparable to cloning an Arc). - Some(ref w2) if (w2.will_wake(w)) => {} - _ => { - // clone the new waker and store it - if let Some(old_waker) = core::mem::replace(&mut self.waker, Some(w.clone())) { - // We had a waker registered for another task. Wake it, so the other task can - // reregister itself if it's still interested. - // - // If two tasks are waiting on the same thing concurrently, this will cause them - // to wake each other in a loop fighting over this WakerRegistration. This wastes - // CPU but things will still work. - // - // If the user wants to have two tasks waiting on the same thing they should use - // a more appropriate primitive that can store multiple wakers. - old_waker.wake() - } - } - } + fn transmit(&mut self, _cx: &mut Context) -> Option> { + Some(TxToken { + device: &mut self.device, + }) } fn capabilities(&self) -> DeviceCapabilities { @@ -211,7 +176,7 @@ impl Device for TunTapDevice { caps } - fn link_state(&mut self) -> LinkState { + fn link_state(&mut self, _cx: &mut Context) -> LinkState { LinkState::Up } @@ -219,3 +184,41 @@ impl Device for TunTapDevice { [0x02, 0x03, 0x04, 0x05, 0x06, 0x07] } } + +#[doc(hidden)] +pub struct RxToken { + buffer: Vec, +} + +impl device::RxToken for RxToken { + fn consume(mut self, f: F) -> R + where + F: FnOnce(&mut [u8]) -> R, + { + f(&mut self.buffer) + } +} + +#[doc(hidden)] +pub struct TxToken<'a> { + device: &'a mut Async, +} + +impl<'a> device::TxToken for TxToken<'a> { + fn consume(self, len: usize, f: F) -> R + where + F: FnOnce(&mut [u8]) -> R, + { + let mut buffer = vec![0; len]; + let result = f(&mut buffer); + + // todo handle WouldBlock with async + match self.device.get_mut().write(&buffer) { + Ok(_) => {} + Err(e) if e.kind() == io::ErrorKind::WouldBlock => info!("transmit WouldBlock"), + Err(e) => panic!("transmit error: {:?}", e), + } + + result + } +} -- cgit