Skip to content

Commit

Permalink
Async ble (esp-rs#161)
Browse files Browse the repository at this point in the history
* Async BLE HCI

* Add async-ble example

* Use nightly-2023-03-09 for CI (for now)
  • Loading branch information
bjoernQ committed May 23, 2024
1 parent 0a958fd commit 117ae63
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 15 deletions.
19 changes: 14 additions & 5 deletions esp-wifi/src/ble/btdm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ extern "C" fn notify_host_recv(data: *mut u8, len: u16) -> i32 {
let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs);
queue.enqueue(packet).unwrap();
});

#[cfg(feature = "async")]
crate::ble::controller::asynch::hci_read_data_available();
}

0
Expand Down Expand Up @@ -522,18 +525,24 @@ static mut BLE_HCI_READ_DATA: [u8; 256] = [0u8; 256];
static mut BLE_HCI_READ_DATA_INDEX: usize = 0;
static mut BLE_HCI_READ_DATA_LEN: usize = 0;

#[cfg(feature = "async")]
pub fn have_hci_read_data() -> bool {
critical_section::with(|cs| {
let queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs);
!queue.is_empty() || unsafe { BLE_HCI_READ_DATA_LEN > 0 && (BLE_HCI_READ_DATA_LEN >= BLE_HCI_READ_DATA_INDEX) }
})
}

pub fn read_hci(data: &mut [u8]) -> usize {
unsafe {
if BLE_HCI_READ_DATA_LEN == 0 {
critical_section::with(|cs| {
let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs);

if let Some(packet) = queue.dequeue() {
for i in 0..(packet.len as usize + 0/*1*/) {
BLE_HCI_READ_DATA[i] = packet.data[i];
}

BLE_HCI_READ_DATA_LEN = packet.len as usize + 0 /*1*/;
BLE_HCI_READ_DATA[..packet.len as usize]
.copy_from_slice(&packet.data[..packet.len as usize]);
BLE_HCI_READ_DATA_LEN = packet.len as usize;
BLE_HCI_READ_DATA_INDEX = 0;
}
});
Expand Down
92 changes: 92 additions & 0 deletions esp-wifi/src/ble/controller/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,95 @@ impl Write for BleConnector<'_> {
Ok(())
}
}

#[cfg(feature = "async")]
pub mod asynch {
use core::task::Poll;

use crate::ble::ble::have_hci_read_data;

use super::BleConnectorError;
use super::{read_hci, send_hci};
use embassy_sync::waitqueue::AtomicWaker;
use embedded_io::asynch;
use embedded_io::Io;
use esp_hal_common::peripheral::{Peripheral, PeripheralRef};

static HCI_WAKER: AtomicWaker = AtomicWaker::new();

pub(crate) fn hci_read_data_available() {
HCI_WAKER.wake();
}

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(),
}
}
}

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

impl asynch::Read for BleConnector<'_> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, BleConnectorError> {
if !have_hci_read_data() {
HciReadyEventFuture.await;
}

let mut total = 0;
for b in buf {
let mut buffer = [0u8];
let len = read_hci(&mut buffer);

if len == 1 {
*b = buffer[0];
total += 1;
} else {
return Ok(total);
}
}

Ok(total)
}
}

impl asynch::Write for BleConnector<'_> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, BleConnectorError> {
send_hci(buf);
Ok(buf.len())
}

async fn flush(&mut self) -> Result<(), BleConnectorError> {
// nothing to do
Ok(())
}
}

pub(crate) struct HciReadyEventFuture;

impl core::future::Future for HciReadyEventFuture {
type Output = ();

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

if have_hci_read_data() {
Poll::Ready(())
} else {
Poll::Pending
}
}
}
}
15 changes: 14 additions & 1 deletion esp-wifi/src/ble/npl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,9 @@ unsafe extern "C" fn ble_hs_hci_rx_evt(cmd: *const u8, arg: *const c_void) {
})
.unwrap();
});

#[cfg(feature = "async")]
crate::ble::controller::asynch::hci_read_data_available();
}

unsafe extern "C" fn ble_hs_rx_data(om: *const OsMbuf, arg: *const c_void) {
Expand All @@ -1255,12 +1258,23 @@ unsafe extern "C" fn ble_hs_rx_data(om: *const OsMbuf, arg: *const c_void) {
})
.unwrap();
});

#[cfg(feature = "async")]
crate::ble::controller::asynch::hci_read_data_available();
}

static mut BLE_HCI_READ_DATA: [u8; 256] = [0u8; 256];
static mut BLE_HCI_READ_DATA_INDEX: usize = 0;
static mut BLE_HCI_READ_DATA_LEN: usize = 0;

#[cfg(feature = "async")]
pub fn have_hci_read_data() -> bool {
critical_section::with(|cs| {
let queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs);
!queue.is_empty() || unsafe { BLE_HCI_READ_DATA_LEN > 0 && (BLE_HCI_READ_DATA_LEN >= BLE_HCI_READ_DATA_INDEX) }
})
}

pub fn read_hci(data: &mut [u8]) -> usize {
unsafe {
if BLE_HCI_READ_DATA_LEN == 0 {
Expand All @@ -1274,7 +1288,6 @@ pub fn read_hci(data: &mut [u8]) -> usize {
BLE_HCI_READ_DATA_INDEX = 0;
}
});
return 0;
}

if BLE_HCI_READ_DATA_LEN > 0 {
Expand Down
13 changes: 4 additions & 9 deletions esp-wifi/src/ble/os_adapter_esp32c3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ pub(crate) fn create_ble_config() -> esp_bt_controller_config_t {
hci_tl_funcs: core::ptr::null_mut(),
txant_dft: 0,
rxant_dft: 0,
txpwr_dft: 7,
txpwr_dft: 9,
cfg_mask: 1,
scan_duplicate_mode: 0,
scan_duplicate_type: 0,
Expand All @@ -179,9 +179,7 @@ pub(crate) fn create_ble_config() -> esp_bt_controller_config_t {
pub(crate) unsafe extern "C" fn interrupt_on(intr_num: i32) {
trace!("interrupt_on {}", intr_num);

(*esp32c3::INTERRUPT_CORE0::PTR)
.cpu_int_enable
.modify(|r, w| w.bits(r.bits() | 1 << intr_num));
// NO-OP
}

pub(crate) unsafe extern "C" fn interrupt_off(_intr_num: i32) {
Expand Down Expand Up @@ -218,13 +216,10 @@ pub(crate) unsafe extern "C" fn interrupt_set(
interrupt_prio
);

((0x600c2000 + 0x114 + interrupt_no * 4) as *mut u32).write_volatile(interrupt_prio as u32);

/* Set the interrupt type (Edge or Level). */
// ----

/* Map the CPU interrupt ID to the peripheral. */
((0x600c2000 + intr_source * 4) as *mut u32).write_volatile(interrupt_no as u32);

// NO-OP
}

pub(crate) unsafe extern "C" fn interrupt_clear(_interrupt_source: i32, _interrupt_no: i32) {
Expand Down
2 changes: 2 additions & 0 deletions esp-wifi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#![no_std]
#![cfg_attr(target_arch = "xtensa", feature(asm_experimental_arch))]
#![feature(c_variadic)]
#![cfg_attr(feature = "async", feature(async_fn_in_trait))]
#![cfg_attr(feature = "async", allow(incomplete_features))]

use core::cell::RefCell;
use core::mem::MaybeUninit;
Expand Down

0 comments on commit 117ae63

Please sign in to comment.