diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-01-31 22:27:19 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-01-31 22:27:19 +0100 |
| commit | ca10fe7135d10084e38038f3cd433da39e505bea (patch) | |
| tree | 075aca4a76caccd1bba95869c64bbb838969c8b1 /embassy-usb/src/class/cdc_ncm/mod.rs | |
| parent | 4c1946454874597c358e7c7d5bf555b687376a5b (diff) | |
usb: docs
Diffstat (limited to 'embassy-usb/src/class/cdc_ncm/mod.rs')
| -rw-r--r-- | embassy-usb/src/class/cdc_ncm/mod.rs | 51 |
1 files changed, 35 insertions, 16 deletions
diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs index 4954a65bc..5e59b72fe 100644 --- a/embassy-usb/src/class/cdc_ncm/mod.rs +++ b/embassy-usb/src/class/cdc_ncm/mod.rs | |||
| @@ -1,18 +1,19 @@ | |||
| 1 | /// CDC-NCM, aka Ethernet over USB. | 1 | //! CDC-NCM class implementation, aka Ethernet over USB. |
| 2 | /// | 2 | //! |
| 3 | /// # Compatibility | 3 | //! # Compatibility |
| 4 | /// | 4 | //! |
| 5 | /// Windows: NOT supported in Windows 10. Supported in Windows 11. | 5 | //! Windows: NOT supported in Windows 10 (though there's apparently a driver you can install?). Supported out of the box in Windows 11. |
| 6 | /// | 6 | //! |
| 7 | /// Linux: Well-supported since forever. | 7 | //! Linux: Well-supported since forever. |
| 8 | /// | 8 | //! |
| 9 | /// Android: Support for CDC-NCM is spotty and varies across manufacturers. | 9 | //! Android: Support for CDC-NCM is spotty and varies across manufacturers. |
| 10 | /// | 10 | //! |
| 11 | /// - On Pixel 4a, it refused to work on Android 11, worked on Android 12. | 11 | //! - On Pixel 4a, it refused to work on Android 11, worked on Android 12. |
| 12 | /// - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte), | 12 | //! - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte), |
| 13 | /// it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled. | 13 | //! it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled. |
| 14 | /// 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 | 14 | //! 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 |
| 15 | /// and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757 | 15 | //! and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757 |
| 16 | |||
| 16 | use core::intrinsics::copy_nonoverlapping; | 17 | use core::intrinsics::copy_nonoverlapping; |
| 17 | use core::mem::{size_of, MaybeUninit}; | 18 | use core::mem::{size_of, MaybeUninit}; |
| 18 | 19 | ||
| @@ -114,6 +115,7 @@ fn byteify<T>(buf: &mut [u8], data: T) -> &[u8] { | |||
| 114 | &buf[..len] | 115 | &buf[..len] |
| 115 | } | 116 | } |
| 116 | 117 | ||
| 118 | /// Internal state for the CDC-NCM class. | ||
| 117 | pub struct State<'a> { | 119 | pub struct State<'a> { |
| 118 | comm_control: MaybeUninit<CommControl<'a>>, | 120 | comm_control: MaybeUninit<CommControl<'a>>, |
| 119 | data_control: MaybeUninit<DataControl>, | 121 | data_control: MaybeUninit<DataControl>, |
| @@ -121,6 +123,7 @@ pub struct State<'a> { | |||
| 121 | } | 123 | } |
| 122 | 124 | ||
| 123 | impl<'a> State<'a> { | 125 | impl<'a> State<'a> { |
| 126 | /// Create a new `State`. | ||
| 124 | pub fn new() -> Self { | 127 | pub fn new() -> Self { |
| 125 | Self { | 128 | Self { |
| 126 | comm_control: MaybeUninit::uninit(), | 129 | comm_control: MaybeUninit::uninit(), |
| @@ -223,6 +226,7 @@ impl ControlHandler for DataControl { | |||
| 223 | } | 226 | } |
| 224 | } | 227 | } |
| 225 | 228 | ||
| 229 | /// CDC-NCM class | ||
| 226 | pub struct CdcNcmClass<'d, D: Driver<'d>> { | 230 | pub struct CdcNcmClass<'d, D: Driver<'d>> { |
| 227 | _comm_if: InterfaceNumber, | 231 | _comm_if: InterfaceNumber, |
| 228 | comm_ep: D::EndpointIn, | 232 | comm_ep: D::EndpointIn, |
| @@ -235,6 +239,7 @@ pub struct CdcNcmClass<'d, D: Driver<'d>> { | |||
| 235 | } | 239 | } |
| 236 | 240 | ||
| 237 | impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { | 241 | impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { |
| 242 | /// Create a new CDC NCM class. | ||
| 238 | pub fn new( | 243 | pub fn new( |
| 239 | builder: &mut Builder<'d, D>, | 244 | builder: &mut Builder<'d, D>, |
| 240 | state: &'d mut State<'d>, | 245 | state: &'d mut State<'d>, |
| @@ -319,6 +324,9 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { | |||
| 319 | } | 324 | } |
| 320 | } | 325 | } |
| 321 | 326 | ||
| 327 | /// Split the class into a sender and receiver. | ||
| 328 | /// | ||
| 329 | /// This allows concurrently sending and receiving packets from separate tasks. | ||
| 322 | pub fn split(self) -> (Sender<'d, D>, Receiver<'d, D>) { | 330 | pub fn split(self) -> (Sender<'d, D>, Receiver<'d, D>) { |
| 323 | ( | 331 | ( |
| 324 | Sender { | 332 | Sender { |
| @@ -334,12 +342,18 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { | |||
| 334 | } | 342 | } |
| 335 | } | 343 | } |
| 336 | 344 | ||
| 345 | /// CDC NCM class packet sender. | ||
| 346 | /// | ||
| 347 | /// You can obtain a `Sender` with [`CdcNcmClass::split`] | ||
| 337 | pub struct Sender<'d, D: Driver<'d>> { | 348 | pub struct Sender<'d, D: Driver<'d>> { |
| 338 | write_ep: D::EndpointIn, | 349 | write_ep: D::EndpointIn, |
| 339 | seq: u16, | 350 | seq: u16, |
| 340 | } | 351 | } |
| 341 | 352 | ||
| 342 | impl<'d, D: Driver<'d>> Sender<'d, D> { | 353 | impl<'d, D: Driver<'d>> Sender<'d, D> { |
| 354 | /// Write a packet. | ||
| 355 | /// | ||
| 356 | /// This waits until the packet is succesfully stored in the CDC-NCM endpoint buffers. | ||
| 343 | pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> { | 357 | pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> { |
| 344 | let seq = self.seq; | 358 | let seq = self.seq; |
| 345 | self.seq = self.seq.wrapping_add(1); | 359 | self.seq = self.seq.wrapping_add(1); |
| @@ -393,6 +407,9 @@ impl<'d, D: Driver<'d>> Sender<'d, D> { | |||
| 393 | } | 407 | } |
| 394 | } | 408 | } |
| 395 | 409 | ||
| 410 | /// CDC NCM class packet receiver. | ||
| 411 | /// | ||
| 412 | /// You can obtain a `Receiver` with [`CdcNcmClass::split`] | ||
| 396 | pub struct Receiver<'d, D: Driver<'d>> { | 413 | pub struct Receiver<'d, D: Driver<'d>> { |
| 397 | data_if: InterfaceNumber, | 414 | data_if: InterfaceNumber, |
| 398 | comm_ep: D::EndpointIn, | 415 | comm_ep: D::EndpointIn, |
| @@ -400,7 +417,9 @@ pub struct Receiver<'d, D: Driver<'d>> { | |||
| 400 | } | 417 | } |
| 401 | 418 | ||
| 402 | impl<'d, D: Driver<'d>> Receiver<'d, D> { | 419 | impl<'d, D: Driver<'d>> Receiver<'d, D> { |
| 403 | /// Reads a single packet from the OUT endpoint. | 420 | /// Write a network packet. |
| 421 | /// | ||
| 422 | /// This waits until a packet is succesfully received from the endpoint buffers. | ||
| 404 | pub async fn read_packet(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { | 423 | pub async fn read_packet(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { |
| 405 | // Retry loop | 424 | // Retry loop |
| 406 | loop { | 425 | loop { |
