usb: docs
This commit is contained in:
		@@ -1,3 +1,4 @@
 | 
			
		||||
//! [`embassy-net`](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;
 | 
			
		||||
@@ -5,11 +6,13 @@ 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(),
 | 
			
		||||
@@ -17,6 +20,9 @@ impl<const MTU: usize, const N_RX: usize, const N_TX: usize> State<MTU, N_RX, N_
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// 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>,
 | 
			
		||||
@@ -24,6 +30,9 @@ pub struct Runner<'d, D: Driver<'d>, const MTU: usize> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
@@ -66,9 +75,11 @@ impl<'d, D: Driver<'d>, const MTU: usize> Runner<'d, D, MTU> {
 | 
			
		||||
 | 
			
		||||
// 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`](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>,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,19 @@
 | 
			
		||||
/// CDC-NCM, aka Ethernet over USB.
 | 
			
		||||
///
 | 
			
		||||
/// # Compatibility
 | 
			
		||||
///
 | 
			
		||||
/// Windows: NOT supported in Windows 10. Supported in Windows 11.
 | 
			
		||||
///
 | 
			
		||||
/// Linux: Well-supported since forever.
 | 
			
		||||
///
 | 
			
		||||
/// Android: Support for CDC-NCM is spotty and varies across manufacturers.
 | 
			
		||||
///
 | 
			
		||||
/// - 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
 | 
			
		||||
//! CDC-NCM class implementation, aka Ethernet over USB.
 | 
			
		||||
//!
 | 
			
		||||
//! # Compatibility
 | 
			
		||||
//!
 | 
			
		||||
//! Windows: NOT supported in Windows 10 (though there's apparently a driver you can install?). Supported out of the box in Windows 11.
 | 
			
		||||
//!
 | 
			
		||||
//! Linux: Well-supported since forever.
 | 
			
		||||
//!
 | 
			
		||||
//! Android: Support for CDC-NCM is spotty and varies across manufacturers.
 | 
			
		||||
//!
 | 
			
		||||
//! - 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
 | 
			
		||||
 | 
			
		||||
use core::intrinsics::copy_nonoverlapping;
 | 
			
		||||
use core::mem::{size_of, MaybeUninit};
 | 
			
		||||
 | 
			
		||||
@@ -114,6 +115,7 @@ fn byteify<T>(buf: &mut [u8], data: T) -> &[u8] {
 | 
			
		||||
    &buf[..len]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Internal state for the CDC-NCM class.
 | 
			
		||||
pub struct State<'a> {
 | 
			
		||||
    comm_control: MaybeUninit<CommControl<'a>>,
 | 
			
		||||
    data_control: MaybeUninit<DataControl>,
 | 
			
		||||
@@ -121,6 +123,7 @@ pub struct State<'a> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> State<'a> {
 | 
			
		||||
    /// Create a new `State`.
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            comm_control: MaybeUninit::uninit(),
 | 
			
		||||
@@ -223,6 +226,7 @@ impl ControlHandler for DataControl {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// CDC-NCM class
 | 
			
		||||
pub struct CdcNcmClass<'d, D: Driver<'d>> {
 | 
			
		||||
    _comm_if: InterfaceNumber,
 | 
			
		||||
    comm_ep: D::EndpointIn,
 | 
			
		||||
@@ -235,6 +239,7 @@ pub struct CdcNcmClass<'d, D: Driver<'d>> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
 | 
			
		||||
    /// Create a new CDC NCM class.
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        builder: &mut Builder<'d, D>,
 | 
			
		||||
        state: &'d mut State<'d>,
 | 
			
		||||
@@ -319,6 +324,9 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Split the class into a sender and receiver.
 | 
			
		||||
    ///
 | 
			
		||||
    /// This allows concurrently sending and receiving packets from separate tasks.
 | 
			
		||||
    pub fn split(self) -> (Sender<'d, D>, Receiver<'d, D>) {
 | 
			
		||||
        (
 | 
			
		||||
            Sender {
 | 
			
		||||
@@ -334,12 +342,18 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// CDC NCM class packet sender.
 | 
			
		||||
///
 | 
			
		||||
/// You can obtain a `Sender` with [`CdcNcmClass::split`]
 | 
			
		||||
pub struct Sender<'d, D: Driver<'d>> {
 | 
			
		||||
    write_ep: D::EndpointIn,
 | 
			
		||||
    seq: u16,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, D: Driver<'d>> Sender<'d, D> {
 | 
			
		||||
    /// Write a packet.
 | 
			
		||||
    ///
 | 
			
		||||
    /// This waits until the packet is succesfully stored in the CDC-NCM endpoint buffers.
 | 
			
		||||
    pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> {
 | 
			
		||||
        let seq = self.seq;
 | 
			
		||||
        self.seq = self.seq.wrapping_add(1);
 | 
			
		||||
@@ -393,6 +407,9 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// CDC NCM class packet receiver.
 | 
			
		||||
///
 | 
			
		||||
/// You can obtain a `Receiver` with [`CdcNcmClass::split`]
 | 
			
		||||
pub struct Receiver<'d, D: Driver<'d>> {
 | 
			
		||||
    data_if: InterfaceNumber,
 | 
			
		||||
    comm_ep: D::EndpointIn,
 | 
			
		||||
@@ -400,7 +417,9 @@ pub struct Receiver<'d, D: Driver<'d>> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, D: Driver<'d>> Receiver<'d, D> {
 | 
			
		||||
    /// Reads a single packet from the OUT endpoint.
 | 
			
		||||
    /// Write a network packet.
 | 
			
		||||
    ///
 | 
			
		||||
    /// This waits until a packet is succesfully received from the endpoint buffers.
 | 
			
		||||
    pub async fn read_packet(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
 | 
			
		||||
        // Retry loop
 | 
			
		||||
        loop {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user