//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the CDC-NCM class. use embassy_futures::select::{select, Either}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embassy_usb_driver::Driver; use super::{CdcNcmClass, Receiver, Sender}; /// Internal state for the embassy-net integration. pub struct State { ch_state: ch::State, } impl State { /// Create a new `State`. pub const fn new() -> Self { Self { ch_state: ch::State::new(), } } } /// Background runner for the CDC-NCM class. /// /// You must call `.run()` in a background task for the class to operate. pub struct Runner<'d, D: Driver<'d>, const MTU: usize> { tx_usb: Sender<'d, D>, rx_usb: Receiver<'d, D>, ch: ch::Runner<'d, MTU>, } impl<'d, D: Driver<'d>, const MTU: usize> Runner<'d, D, MTU> { /// Run the CDC-NCM class. /// /// You must call this in a background task for the class to operate. pub async fn run(mut self) -> ! { let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); let rx_fut = async move { loop { trace!("WAITING for connection"); state_chan.set_link_state(LinkState::Down); self.rx_usb.wait_connection().await.unwrap(); trace!("Connected"); state_chan.set_link_state(LinkState::Up); loop { let p = rx_chan.rx_buf().await; match self.rx_usb.read_packet(p).await { Ok(n) => rx_chan.rx_done(n), Err(e) => { warn!("error reading packet: {:?}", e); break; } }; } } }; let tx_fut = async move { loop { let p = tx_chan.tx_buf().await; if let Err(e) = self.tx_usb.write_packet(p).await { warn!("Failed to TX packet: {:?}", e); } tx_chan.tx_done(); } }; match select(rx_fut, tx_fut).await { Either::First(x) => x, Either::Second(x) => x, } } } // would be cool to use a TAIT here, but it gives a "may not live long enough". rustc bug? //pub type Device<'d, const MTU: usize> = impl embassy_net_driver_channel::driver::Driver + 'd; /// Type alias for the embassy-net driver for CDC-NCM. pub type Device<'d, const MTU: usize> = embassy_net_driver_channel::Device<'d, MTU>; impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { /// Obtain a driver for using the CDC-NCM class with [`embassy-net`](https://crates.io/crates/embassy-net). pub fn into_embassy_net_device( self, state: &'d mut State, ethernet_address: [u8; 6], ) -> (Runner<'d, D, MTU>, Device<'d, MTU>) { let (tx_usb, rx_usb) = self.split(); let (runner, device) = ch::new( &mut state.ch_state, ch::driver::HardwareAddress::Ethernet(ethernet_address), ); ( Runner { tx_usb, rx_usb, ch: runner, }, device, ) } }