Skip to content

Commit

Permalink
Feature/radio singletons (#141)
Browse files Browse the repository at this point in the history
* Use RADIO singletons

- Uses the RADIO singletons when creating wifi/ble/esp_now
- Updates all examples to use the singletons
- Simplfy esp_now::ReceiveFuture

* Fixup examples

* fmt

* fix examples
  • Loading branch information
MabezDev committed Mar 28, 2023
1 parent b65d21c commit 74e9f18
Show file tree
Hide file tree
Showing 62 changed files with 349 additions and 594 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ lto = "off"

[workspace.dependencies]
embedded-hal = "0.2.3"
esp-hal-common = { version = "0.8.0" }
esp32c3-hal = { version = "0.8.0" }
esp32c2-hal = { version = "0.6.0" }
esp32c6-hal = { version = "0.1.0" }
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ To build these ensure you are in the `examples-esp32XXX` directory matching your
- pressing the boot-button on a dev-board will send a notification if it is subscribed
- this uses a toy level BLE stack - might not work with every BLE central device (tested with Android and Windows Bluetooth LE Explorer)

`cargo run --example ble --release --features "esp32,ble"`
`cargo run --example ble --release --features "ble"`

**NOTE:** ESP32-S2 doesn't support bluetooth, for ESP32-C6 bluetooth support isn't implemented yet

Expand Down
13 changes: 7 additions & 6 deletions esp-wifi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ esp32c3 = { workspace = true, optional = true }
esp32c2 = { workspace = true, optional = true }
esp32c6 = { workspace = true, optional = true }
smoltcp = { workspace = true, optional = true }
esp-hal-common = { workspace = true, optional = true }
critical-section.workspace = true
atomic-polyfill.workspace = true
log.workspace = true
Expand All @@ -37,12 +38,12 @@ embassy-net-driver = { workspace = true, optional = true }
default = [ "utils" ]

# chip features
esp32c3 = [ "esp32c3-hal", "dep:esp32c3", "esp-wifi-sys/esp32c3" ]
esp32c2 = [ "esp32c2-hal", "dep:esp32c2", "esp-wifi-sys/esp32c2" ]
esp32c6 = [ "esp32c6-hal", "dep:esp32c6", "esp-wifi-sys/esp32c6" ]
esp32 = [ "esp32-hal", "esp-wifi-sys/esp32" ]
esp32s3 = [ "esp32s3-hal", "esp-wifi-sys/esp32s3" ]
esp32s2 = [ "esp32s2-hal", "esp-wifi-sys/esp32s2" ]
esp32c3 = [ "esp32c3-hal", "dep:esp32c3", "esp-wifi-sys/esp32c3", "esp-hal-common/esp32c3" ]
esp32c2 = [ "esp32c2-hal", "dep:esp32c2", "esp-wifi-sys/esp32c2", "esp-hal-common/esp32c2" ]
esp32c6 = [ "esp32c6-hal", "dep:esp32c6", "esp-wifi-sys/esp32c6", "esp-hal-common/esp32c6" ]
esp32 = [ "esp32-hal", "esp-wifi-sys/esp32", "esp-hal-common/esp32" ]
esp32s3 = [ "esp32s3-hal", "esp-wifi-sys/esp32s3", "esp-hal-common/esp32s3" ]
esp32s2 = [ "esp32s2-hal", "esp-wifi-sys/esp32s2", "esp-hal-common/esp32s2" ]

# async features
esp32c3-async = [ "esp32c3-hal/embassy", "esp32c3-hal/embassy-time-timg0", "async" ]
Expand Down
21 changes: 17 additions & 4 deletions esp-wifi/src/ble/controller/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@ use embedded_io::{
blocking::{Read, Write},
Error, Io,
};
use esp_hal_common::peripheral::{Peripheral, PeripheralRef};

use super::{read_hci, send_hci};

pub struct BleConnector {}
pub struct BleConnector<'d> {
_device: PeripheralRef<'d, esp_hal_common::radio::Bluetooth>,
}

impl<'d> BleConnector<'d> {
pub fn new(
device: impl Peripheral<P = esp_hal_common::radio::Bluetooth> + 'd,
) -> BleConnector<'d> {
Self {
_device: device.into_ref(),
}
}
}

#[derive(Debug)]
pub enum BleConnectorError {
Expand All @@ -18,11 +31,11 @@ impl Error for BleConnectorError {
}
}

impl Io for BleConnector {
impl Io for BleConnector<'_> {
type Error = BleConnectorError;
}

impl Read for BleConnector {
impl Read for BleConnector<'_> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
let mut total = 0;
for b in buf {
Expand All @@ -41,7 +54,7 @@ impl Read for BleConnector {
}
}

impl Write for BleConnector {
impl Write for BleConnector<'_> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
for b in buf {
send_hci(&[*b]);
Expand Down
84 changes: 28 additions & 56 deletions esp-wifi/src/esp_now/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use core::{cell::RefCell, fmt::Debug};

use critical_section::Mutex;
use esp_hal_common::peripheral::{Peripheral, PeripheralRef};

use crate::compat::queue::SimpleQueue;

Expand All @@ -20,10 +21,6 @@ pub const ESP_NOW_MAX_DATA_LEN: usize = 250;
/// Broadcast address
pub const BROADCAST_ADDRESS: [u8; 6] = [0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8];

static ESP_NOW: Mutex<RefCell<EspNowHolder>> = Mutex::new(RefCell::new(EspNowHolder {
esp_now: Some(EspNowCreator { _private: () }),
}));

static RECEIVE_QUEUE: Mutex<RefCell<SimpleQueue<ReceivedData, 10>>> =
Mutex::new(RefCell::new(SimpleQueue::new()));

Expand Down Expand Up @@ -236,17 +233,17 @@ impl Debug for ReceivedData {
}
}

pub struct EspNowCreator {
_private: (),
pub struct EspNow<'d> {
_device: PeripheralRef<'d, esp_hal_common::radio::Wifi>,
}

impl EspNowCreator {
/// Initialize esp-now
///
/// Must be called after initializing esp-wifi.
/// After this the broadcast address is already added as a peer.
pub fn initialize(self) -> Result<EspNow, EspNowError> {
let mut esp_now = EspNow { _private: () };
impl<'d> EspNow<'d> {
pub fn new(
device: impl Peripheral<P = esp_hal_common::radio::Wifi> + 'd,
) -> Result<EspNow<'d>, EspNowError> {
let mut esp_now = EspNow {
_device: device.into_ref(),
};
check_error!({ esp_wifi_set_mode(wifi_mode_t_WIFI_MODE_STA) });
check_error!({ esp_wifi_start() });
check_error!({ esp_now_init() });
Expand All @@ -261,34 +258,6 @@ impl EspNowCreator {

Ok(esp_now)
}
}

struct EspNowHolder {
esp_now: Option<EspNowCreator>,
}

pub fn esp_now() -> EspNowCreator {
critical_section::with(|cs| ESP_NOW.borrow_ref_mut(cs).esp_now.take().unwrap())
}

pub struct EspNow {
_private: (),
}

impl EspNow {
/// Deinit
pub fn free(self) {
unsafe {
esp_now_unregister_recv_cb();
esp_now_deinit();
critical_section::with(|cs| {
ESP_NOW
.borrow_ref_mut(cs)
.esp_now
.replace(EspNowCreator { _private: () });
})
}
}

/// Get the version of ESPNOW
pub fn get_version(&self) -> Result<u32, EspNowError> {
Expand Down Expand Up @@ -454,6 +423,15 @@ impl EspNow {
}
}

impl Drop for EspNow<'_> {
fn drop(&mut self) {
unsafe {
esp_now_unregister_recv_cb();
esp_now_deinit();
}
}
}

unsafe extern "C" fn rcv_cb(
esp_now_info: *const esp_now_recv_info_t,
data: *const u8,
Expand Down Expand Up @@ -555,36 +533,30 @@ unsafe extern "C" fn rcv_cb(

#[cfg(feature = "async")]
mod asynch {
use super::*;
use core::task::{Context, Poll};
use embassy_sync::waitqueue::AtomicWaker;

use super::{EspNow, ReceivedData};

pub(super) static ESP_NOW_WAKER: AtomicWaker = AtomicWaker::new();

impl EspNow {
impl<'d> EspNow<'d> {
pub async fn receive_async(&mut self) -> ReceivedData {
ReceiveFuture::new(self).await
ReceiveFuture.await
}
}

struct ReceiveFuture<'a> {
esp_now: &'a mut EspNow,
}

impl<'a> ReceiveFuture<'a> {
fn new(esp_now: &'a mut EspNow) -> Self {
Self { esp_now }
}
}
struct ReceiveFuture;

impl<'a> core::future::Future for ReceiveFuture<'a> {
impl core::future::Future for ReceiveFuture {
type Output = ReceivedData;

fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
ESP_NOW_WAKER.register(cx.waker());

if let Some(data) = self.esp_now.receive() {
if let Some(data) = critical_section::with(|cs| {
let mut queue = RECEIVE_QUEUE.borrow_ref_mut(cs);
queue.dequeue()
}) {
Poll::Ready(data)
} else {
Poll::Pending
Expand Down
74 changes: 48 additions & 26 deletions esp-wifi/src/wifi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use critical_section::Mutex;
use embedded_svc::wifi::{AccessPointInfo, AuthMethod, SecondaryChannel};
use enumset::EnumSet;
use enumset::EnumSetType;
use esp_hal_common::peripheral::Peripheral;
use esp_hal_common::peripheral::PeripheralRef;
use esp_wifi_sys::include::esp_interface_t_ESP_IF_WIFI_AP;
use esp_wifi_sys::include::esp_wifi_disconnect;
use esp_wifi_sys::include::esp_wifi_get_mode;
Expand Down Expand Up @@ -682,52 +684,72 @@ pub fn wifi_start_scan(block: bool) -> i32 {
unsafe { esp_wifi_scan_start(&scan_config, block) }
}

pub fn new_with_config(config: embedded_svc::wifi::Configuration) -> (WifiDevice, WifiController) {
pub fn new_with_config<'d>(
device: impl Peripheral<P = esp_hal_common::radio::Wifi> + 'd,
config: embedded_svc::wifi::Configuration,
) -> (WifiDevice<'d>, WifiController<'d>) {
esp_hal_common::into_ref!(device);
let mode = match config {
embedded_svc::wifi::Configuration::None => panic!(),
embedded_svc::wifi::Configuration::Client(_) => WifiMode::Sta,
embedded_svc::wifi::Configuration::AccessPoint(_) => WifiMode::Ap,
embedded_svc::wifi::Configuration::Mixed(_, _) => panic!(),
};
(
WifiDevice::new(mode),
WifiController::new_with_config(config),
WifiDevice::new(unsafe { device.clone_unchecked() }, mode),
WifiController::new_with_config(device, config),
)
}

pub fn new_with_mode<'d>(
device: impl Peripheral<P = esp_hal_common::radio::Wifi> + 'd,
mode: WifiMode,
) -> (WifiDevice<'d>, WifiController<'d>) {
new_with_config(
device,
match mode {
WifiMode::Sta => embedded_svc::wifi::Configuration::Client(Default::default()),
WifiMode::Ap => embedded_svc::wifi::Configuration::AccessPoint(Default::default()),
},
)
}

pub fn new(mode: WifiMode) -> (WifiDevice, WifiController) {
(WifiDevice::new(mode), WifiController::new())
pub fn new<'d>(
device: impl Peripheral<P = esp_hal_common::radio::Wifi> + 'd,
) -> (WifiDevice<'d>, WifiController<'d>) {
new_with_config(device, Default::default())
}

/// A wifi device implementing smoltcp's Device trait.
pub struct WifiDevice {
_private: (),
pub struct WifiDevice<'d> {
_device: PeripheralRef<'d, esp_hal_common::radio::Wifi>,

// only used by embassy-net
#[allow(unused)]
mode: WifiMode,
}

impl WifiDevice {
pub(crate) fn new(mode: WifiMode) -> WifiDevice {
Self { _private: (), mode }
impl<'d> WifiDevice<'d> {
pub(crate) fn new(
_device: PeripheralRef<'d, esp_hal_common::radio::Wifi>,
mode: WifiMode,
) -> WifiDevice {
Self { _device, mode }
}
}

/// A wifi controller implementing embedded_svc::Wifi traits
pub struct WifiController {
pub struct WifiController<'d> {
_device: PeripheralRef<'d, esp_hal_common::radio::Wifi>,
config: embedded_svc::wifi::Configuration,
}

impl WifiController {
pub(crate) fn new_with_config(config: embedded_svc::wifi::Configuration) -> Self {
Self { config }
}

pub(crate) fn new() -> Self {
Self {
config: Default::default(),
}
impl<'d> WifiController<'d> {
pub(crate) fn new_with_config(
_device: PeripheralRef<'d, esp_hal_common::radio::Wifi>,
config: embedded_svc::wifi::Configuration,
) -> Self {
Self { _device, config }
}

fn is_sta_enabled(&self) -> Result<bool, WifiError> {
Expand Down Expand Up @@ -864,9 +886,9 @@ impl WifiController {
}

// see https://docs.rs/smoltcp/0.7.1/smoltcp/phy/index.html
impl Device for WifiDevice {
type RxToken<'a> = WifiRxToken;
type TxToken<'a> = WifiTxToken;
impl<'d> Device for WifiDevice<'d> {
type RxToken<'a> = WifiRxToken where Self: 'a;
type TxToken<'a> = WifiTxToken where Self: 'a;

fn receive(
&mut self,
Expand Down Expand Up @@ -989,7 +1011,7 @@ pub fn send_data_if_needed() {
});
}

impl embedded_svc::wifi::Wifi for WifiController {
impl embedded_svc::wifi::Wifi for WifiController<'_> {
type Error = WifiError;

/// This currently only supports the `Client` and `AccessPoint` capability.
Expand Down Expand Up @@ -1290,7 +1312,7 @@ pub(crate) mod embassy {
}
}

impl Driver for WifiDevice {
impl Driver for WifiDevice<'_> {
type RxToken<'a> = WifiRxToken
where
Self: 'a;
Expand Down Expand Up @@ -1381,7 +1403,7 @@ mod asynch {
use super::*;

// TODO assumes STA mode only
impl WifiController {
impl<'d> WifiController<'d> {
/// Async version of [`embedded_svc::wifi::Wifi`]'s `scan_n` method
pub async fn scan_n<const N: usize>(
&mut self,
Expand Down
7 changes: 4 additions & 3 deletions esp-wifi/src/wifi/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ use super::{WifiController, WifiDevice, WifiMode};

/// Convenient way to create an `smoltcp` ethernet interface
/// You can use the provided macros to create and pass a suitable backing storage.
pub fn create_network_interface<'a>(
pub fn create_network_interface<'a, 'd>(
device: impl esp_hal_common::peripheral::Peripheral<P = esp_hal_common::radio::Wifi> + 'd,
mode: WifiMode,
storage: &'a mut [SocketStorage<'a>],
) -> (Interface, WifiDevice, WifiController, SocketSet<'a>) {
) -> (Interface, WifiDevice<'d>, WifiController<'d>, SocketSet<'a>) {
let socket_set_entries = storage;

let mut mac = [0u8; 6];
Expand All @@ -25,7 +26,7 @@ pub fn create_network_interface<'a>(
}
let hw_address = EthernetAddress::from_bytes(&mac);

let (mut device, controller) = crate::wifi::new(mode);
let (mut device, controller) = crate::wifi::new_with_mode(device, mode);

let mut config = Config::new();

Expand Down
Loading

0 comments on commit 74e9f18

Please sign in to comment.