Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/radio singletons #141

Merged
merged 4 commits into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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