diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-10-16 23:41:58 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-10-18 05:28:16 +0200 |
| commit | 3cbc6874247d7b814cab8ec8762bfe2f6f385828 (patch) | |
| tree | aac4c615c816f6465559874a98c9d3cf60c21817 /embassy-net-driver-channel | |
| parent | 51708c8ed1962618ac7bc244a3f5e7ceced28182 (diff) | |
net/driver: remove Medium, make HardwareAddress non_exhaustive.
Diffstat (limited to 'embassy-net-driver-channel')
| -rw-r--r-- | embassy-net-driver-channel/CHANGELOG.md | 10 | ||||
| -rw-r--r-- | embassy-net-driver-channel/README.md | 18 | ||||
| -rw-r--r-- | embassy-net-driver-channel/src/lib.rs | 20 |
3 files changed, 16 insertions, 32 deletions
diff --git a/embassy-net-driver-channel/CHANGELOG.md b/embassy-net-driver-channel/CHANGELOG.md index 589996cfd..b04d0a86b 100644 --- a/embassy-net-driver-channel/CHANGELOG.md +++ b/embassy-net-driver-channel/CHANGELOG.md | |||
| @@ -5,14 +5,12 @@ All notable changes to this project will be documented in this file. | |||
| 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), |
| 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). |
| 7 | 7 | ||
| 8 | ## 0.2.0 - 2023-10-15 | 8 | ## 0.2.0 - 2023-10-18 |
| 9 | 9 | ||
| 10 | - Update embassy-net-driver | 10 | - Update `embassy-net-driver` to v0.2 |
| 11 | - `Runner::new` now takes an `embassy_net_driver::HardwareAddress` parameter | 11 | - `Runner::new` now takes an `embassy_net_driver::HardwareAddress` parameter. |
| 12 | - Added `Runner::set_ieee802154_address`, `Runner::ieee802154_address` | 12 | - `Runner::set_ethernet_address` is now `set_hardware_address`. |
| 13 | 13 | ||
| 14 | ## 0.1.0 - 2023-06-29 | 14 | ## 0.1.0 - 2023-06-29 |
| 15 | 15 | ||
| 16 | - First release | 16 | - First release |
| 17 | |||
| 18 | |||
diff --git a/embassy-net-driver-channel/README.md b/embassy-net-driver-channel/README.md index 8f904ce95..90a216388 100644 --- a/embassy-net-driver-channel/README.md +++ b/embassy-net-driver-channel/README.md | |||
| @@ -7,7 +7,9 @@ The `embassy-net-driver` trait is polling-based. To implement it, you must write | |||
| 7 | hand, and hook up the `Waker`s provided by `embassy-net` to the right interrupt handlers so that `embassy-net` | 7 | hand, and hook up the `Waker`s provided by `embassy-net` to the right interrupt handlers so that `embassy-net` |
| 8 | knows when to poll your driver again to make more progress. | 8 | knows when to poll your driver again to make more progress. |
| 9 | 9 | ||
| 10 | With `embassy-net-driver-channel` | 10 | With `embassy-net-driver-channel` you get a "channel-like" interface instead, where you can send/receive packets |
| 11 | to/from embassy-net. The intended usage is to spawn a "driver task" in the background that does this, passing | ||
| 12 | packets between the hardware and the channel. | ||
| 11 | 13 | ||
| 12 | ## A note about deadlocks | 14 | ## A note about deadlocks |
| 13 | 15 | ||
| @@ -18,19 +20,19 @@ loop { | |||
| 18 | // Wait for either.. | 20 | // Wait for either.. |
| 19 | match select( | 21 | match select( |
| 20 | // ... the chip signaling an interrupt, indicating a packet is available to receive, or | 22 | // ... the chip signaling an interrupt, indicating a packet is available to receive, or |
| 21 | irq_pin.wait_for_low(), | 23 | irq_pin.wait_for_low(), |
| 22 | // ... a TX buffer becoming available, i.e. embassy-net wants to send a packet | 24 | // ... a TX buffer becoming available, i.e. embassy-net wants to send a packet |
| 23 | tx_chan.tx_buf(), | 25 | tx_chan.tx_buf(), |
| 24 | ).await { | 26 | ).await { |
| 25 | Either::First(_) => { | 27 | Either::First(_) => { |
| 26 | // a packet is ready to be received! | 28 | // a packet is ready to be received! |
| 27 | let buf = rx_chan.rx_buf().await; // allocate a rx buf from the packet queue | 29 | let buf = rx_chan.rx_buf().await; // allocate a rx buf from the packet queue |
| 28 | let n = receive_packet_over_spi(buf).await; | 30 | let n = receive_packet_over_spi(buf).await; |
| 29 | rx_chan.rx_done(n); | 31 | rx_chan.rx_done(n); |
| 30 | } | 32 | } |
| 31 | Either::Second(buf) => { | 33 | Either::Second(buf) => { |
| 32 | // a packet is ready to be sent! | 34 | // a packet is ready to be sent! |
| 33 | send_packet_over_spi(buf).await; | 35 | send_packet_over_spi(buf).await; |
| 34 | tx_chan.tx_done(); | 36 | tx_chan.tx_done(); |
| 35 | } | 37 | } |
| 36 | } | 38 | } |
| @@ -41,7 +43,7 @@ However, this code has a latent deadlock bug. The symptom is it can hang at `rx_ | |||
| 41 | 43 | ||
| 42 | The reason is that, under load, both the TX and RX queues can get full at the same time. When this happens, the `embassy-net` task stalls trying to send because the TX queue is full, therefore it stops processing packets in the RX queue. Your driver task also stalls because the RX queue is full, therefore it stops processing packets in the TX queue. | 44 | The reason is that, under load, both the TX and RX queues can get full at the same time. When this happens, the `embassy-net` task stalls trying to send because the TX queue is full, therefore it stops processing packets in the RX queue. Your driver task also stalls because the RX queue is full, therefore it stops processing packets in the TX queue. |
| 43 | 45 | ||
| 44 | The fix is to make sure to always service the TX queue while you're waiting for space to become available in the TX queue. For example, select on either "tx_chan.tx_buf() available" or "INT is low AND rx_chan.rx_buf() available": | 46 | The fix is to make sure to always service the TX queue while you're waiting for space to become available in the RX queue. For example, select on either "tx_chan.tx_buf() available" or "INT is low AND rx_chan.rx_buf() available": |
| 45 | 47 | ||
| 46 | ```rust,ignore | 48 | ```rust,ignore |
| 47 | loop { | 49 | loop { |
| @@ -58,12 +60,12 @@ loop { | |||
| 58 | ).await { | 60 | ).await { |
| 59 | Either::First(buf) => { | 61 | Either::First(buf) => { |
| 60 | // a packet is ready to be received! | 62 | // a packet is ready to be received! |
| 61 | let n = receive_packet_over_spi(buf).await; | 63 | let n = receive_packet_over_spi(buf).await; |
| 62 | rx_chan.rx_done(n); | 64 | rx_chan.rx_done(n); |
| 63 | } | 65 | } |
| 64 | Either::Second(buf) => { | 66 | Either::Second(buf) => { |
| 65 | // a packet is ready to be sent! | 67 | // a packet is ready to be sent! |
| 66 | send_packet_over_spi(buf).await; | 68 | send_packet_over_spi(buf).await; |
| 67 | tx_chan.tx_done(); | 69 | tx_chan.tx_done(); |
| 68 | } | 70 | } |
| 69 | } | 71 | } |
| @@ -79,12 +81,10 @@ These `embassy-net` drivers are implemented using this crate. You can look at th | |||
| 79 | - [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips. | 81 | - [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips. |
| 80 | - [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU. | 82 | - [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU. |
| 81 | 83 | ||
| 82 | |||
| 83 | ## Interoperability | 84 | ## Interoperability |
| 84 | 85 | ||
| 85 | This crate can run on any executor. | 86 | This crate can run on any executor. |
| 86 | 87 | ||
| 87 | |||
| 88 | ## License | 88 | ## License |
| 89 | 89 | ||
| 90 | This work is licensed under either of | 90 | This work is licensed under either of |
diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index bf7ae5217..bfb2c9c03 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs | |||
| @@ -8,9 +8,8 @@ use core::cell::RefCell; | |||
| 8 | use core::mem::MaybeUninit; | 8 | use core::mem::MaybeUninit; |
| 9 | use core::task::{Context, Poll}; | 9 | use core::task::{Context, Poll}; |
| 10 | 10 | ||
| 11 | use driver::HardwareAddress; | ||
| 12 | pub use embassy_net_driver as driver; | 11 | pub use embassy_net_driver as driver; |
| 13 | use embassy_net_driver::{Capabilities, LinkState, Medium}; | 12 | use embassy_net_driver::{Capabilities, LinkState}; |
| 14 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | 13 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; |
| 15 | use embassy_sync::blocking_mutex::Mutex; | 14 | use embassy_sync::blocking_mutex::Mutex; |
| 16 | use embassy_sync::waitqueue::WakerRegistration; | 15 | use embassy_sync::waitqueue::WakerRegistration; |
| @@ -161,18 +160,10 @@ impl<'d> StateRunner<'d> { | |||
| 161 | }); | 160 | }); |
| 162 | } | 161 | } |
| 163 | 162 | ||
| 164 | pub fn set_ethernet_address(&self, address: [u8; 6]) { | 163 | pub fn set_hardware_address(&self, address: driver::HardwareAddress) { |
| 165 | self.shared.lock(|s| { | 164 | self.shared.lock(|s| { |
| 166 | let s = &mut *s.borrow_mut(); | 165 | let s = &mut *s.borrow_mut(); |
| 167 | s.hardware_address = driver::HardwareAddress::Ethernet(address); | 166 | s.hardware_address = address; |
| 168 | s.waker.wake(); | ||
| 169 | }); | ||
| 170 | } | ||
| 171 | |||
| 172 | pub fn set_ieee802154_address(&self, address: [u8; 8]) { | ||
| 173 | self.shared.lock(|s| { | ||
| 174 | let s = &mut *s.borrow_mut(); | ||
| 175 | s.hardware_address = driver::HardwareAddress::Ieee802154(address); | ||
| 176 | s.waker.wake(); | 167 | s.waker.wake(); |
| 177 | }); | 168 | }); |
| 178 | } | 169 | } |
| @@ -232,11 +223,6 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( | |||
| 232 | ) -> (Runner<'d, MTU>, Device<'d, MTU>) { | 223 | ) -> (Runner<'d, MTU>, Device<'d, MTU>) { |
| 233 | let mut caps = Capabilities::default(); | 224 | let mut caps = Capabilities::default(); |
| 234 | caps.max_transmission_unit = MTU; | 225 | caps.max_transmission_unit = MTU; |
| 235 | caps.medium = match &hardware_address { | ||
| 236 | HardwareAddress::Ethernet(_) => Medium::Ethernet, | ||
| 237 | HardwareAddress::Ieee802154(_) => Medium::Ieee802154, | ||
| 238 | HardwareAddress::Ip => Medium::Ip, | ||
| 239 | }; | ||
| 240 | 226 | ||
| 241 | // safety: this is a self-referential struct, however: | 227 | // safety: this is a self-referential struct, however: |
| 242 | // - it can't move while the `'d` borrow is active. | 228 | // - it can't move while the `'d` borrow is active. |
