Files
embassy/embassy-usb/src/class/cdc_ncm/embassy_net.rs

105 lines
3.4 KiB
Rust

//! [`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<const MTU: usize, const N_RX: usize, const N_TX: usize> {
ch_state: ch::State<MTU, N_RX, N_TX>,
}
impl<const MTU: usize, const N_RX: usize, const N_TX: usize> State<MTU, N_RX, N_TX> {
/// 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<const MTU: usize, const N_RX: usize, const N_TX: usize>(
self,
state: &'d mut State<MTU, N_RX, N_TX>,
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,
)
}
}