Kirill Mikhailov 8ca0f94715
Get rid of EspRadio prefix in esp-radio structs (#3869)
* get rid of `EspRadio` prefix in esp-radio structs

* changelog entry + migration guide entry

* reword entries

* fmt run

* Fix migration guide entry

* edit the changelog entry to still reflect `esp-wifi` changes
2025-07-28 11:40:56 +00:00

215 lines
5.9 KiB
Rust

use embedded_io::{Error, ErrorType, Read, Write};
use super::{read_hci, read_next, send_hci};
use crate::Controller;
/// A blocking HCI connector
pub struct BleConnector<'d> {
_device: crate::hal::peripherals::BT<'d>,
}
impl Drop for BleConnector<'_> {
fn drop(&mut self) {
crate::ble::ble_deinit();
}
}
impl<'d> BleConnector<'d> {
pub fn new(
_init: &'d Controller<'d>,
device: crate::hal::peripherals::BT<'d>,
) -> BleConnector<'d> {
crate::ble::ble_init();
Self { _device: device }
}
pub fn next(&mut self, buf: &mut [u8]) -> Result<usize, BleConnectorError> {
Ok(read_next(buf))
}
}
#[derive(Debug)]
pub enum BleConnectorError {
Unknown,
}
impl Error for BleConnectorError {
fn kind(&self) -> embedded_io::ErrorKind {
embedded_io::ErrorKind::Other
}
}
impl ErrorType for BleConnector<'_> {
type Error = BleConnectorError;
}
impl Read for BleConnector<'_> {
fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Self::Error> {
let mut total = 0;
while !buf.is_empty() {
let len = read_hci(buf);
if len == 0 {
break;
}
buf = &mut buf[len..];
total += len;
}
Ok(total)
}
}
impl Write for BleConnector<'_> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
for b in buf {
send_hci(&[*b]);
}
Ok(buf.len())
}
fn flush(&mut self) -> Result<(), Self::Error> {
// nothing to do
Ok(())
}
}
/// Async Interface
pub(crate) mod asynch {
use core::task::Poll;
use bt_hci::{
ControllerToHostPacket,
FromHciBytes,
HostToControllerPacket,
WriteHci,
transport::{Transport, WithIndicator},
};
use esp_hal::asynch::AtomicWaker;
use super::*;
use crate::ble::have_hci_read_data;
static HCI_WAKER: AtomicWaker = AtomicWaker::new();
pub(crate) fn hci_read_data_available() {
HCI_WAKER.wake();
}
impl embedded_io_async::Read for BleConnector<'_> {
async fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, BleConnectorError> {
if buf.is_empty() {
return Ok(0);
}
let mut total = 0;
if !have_hci_read_data() {
HciReadyEventFuture.await;
}
while !buf.is_empty() {
let len = read_hci(buf);
if len == 0 {
break;
}
buf = &mut buf[len..];
total += len;
}
Ok(total)
}
}
impl embedded_io_async::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(())
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
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
}
}
}
fn parse_hci(data: &[u8]) -> Result<Option<ControllerToHostPacket<'_>>, BleConnectorError> {
match ControllerToHostPacket::from_hci_bytes_complete(data) {
Ok(p) => Ok(Some(p)),
Err(e) => {
if e == bt_hci::FromHciBytesError::InvalidSize {
use bt_hci::{PacketKind, event::EventPacketHeader};
// Some controllers emit a suprious command complete event at startup.
let (kind, data) =
PacketKind::from_hci_bytes(data).map_err(|_| BleConnectorError::Unknown)?;
if kind == PacketKind::Event {
let (header, _) = EventPacketHeader::from_hci_bytes(data)
.map_err(|_| BleConnectorError::Unknown)?;
const COMMAND_COMPLETE: u8 = 0x0E;
if header.code == COMMAND_COMPLETE && header.params_len < 4 {
return Ok(None);
}
}
}
warn!("[hci] error parsing packet: {:?}", e);
Err(BleConnectorError::Unknown)
}
}
}
impl Transport for BleConnector<'_> {
/// Read a complete HCI packet into the rx buffer
async fn read<'a>(
&self,
rx: &'a mut [u8],
) -> Result<ControllerToHostPacket<'a>, Self::Error> {
loop {
if !have_hci_read_data() {
HciReadyEventFuture.await;
}
// Workaround for borrow checker.
// Safety: we only return a reference to x once, if parsing is successful.
let rx =
unsafe { &mut *core::ptr::slice_from_raw_parts_mut(rx.as_mut_ptr(), rx.len()) };
let len = crate::ble::read_next(rx);
if let Some(packet) = parse_hci(&rx[..len])? {
return Ok(packet);
}
}
}
/// Write a complete HCI packet from the tx buffer
async fn write<T: HostToControllerPacket>(&self, val: &T) -> Result<(), Self::Error> {
let mut buf: [u8; 259] = [0; 259];
let w = WithIndicator::new(val);
let len = w.size();
w.write_hci(&mut buf[..])
.map_err(|_| BleConnectorError::Unknown)?;
send_hci(&buf[..len]);
Ok(())
}
}
}