Skip to main content

esp_radio/ble/controller/
mod.rs

1//! BLE controller
2use alloc::boxed::Box;
3use core::{future::Future, task::Poll};
4
5use bt_hci::{
6    ControllerToHostPacket,
7    FromHciBytes,
8    FromHciBytesError,
9    HostToControllerPacket,
10    WriteHci,
11};
12use bt_hci_transport::{PacketKind, PacketToController, PacketToHost};
13use docsplay::Display;
14use esp_phy::PhyInitGuard;
15
16use crate::{
17    RadioRefGuard,
18    asynch::AtomicWaker,
19    ble::{
20        Config,
21        InvalidConfigError,
22        have_hci_packet,
23        have_hci_read_data,
24        read_hci,
25        read_next,
26        send_hci,
27        send_hci_async,
28        take_next,
29    },
30};
31
32#[derive(Display, Debug, Copy, Clone, Eq, PartialEq, Hash)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34/// Error enum for BLE initialization failures.
35pub enum BleInitError {
36    /// Failure during initial validation of the provided configuration: {0}.
37    Config(InvalidConfigError),
38}
39
40impl core::error::Error for BleInitError {}
41
42// Implement the From trait for cleaner error mapping
43impl From<InvalidConfigError> for BleInitError {
44    fn from(err: InvalidConfigError) -> Self {
45        BleInitError::Config(err)
46    }
47}
48
49/// A blocking HCI connector
50#[instability::unstable]
51pub struct BleConnector<'d> {
52    _phy_init_guard: PhyInitGuard<'d>,
53    _device: crate::hal::peripherals::BT<'d>,
54    _guard: RadioRefGuard,
55}
56
57impl Drop for BleConnector<'_> {
58    fn drop(&mut self) {
59        crate::ble::ble_deinit();
60        crate::ble::clear_bt_state();
61    }
62}
63impl<'d> BleConnector<'d> {
64    /// Create and init a new BLE connector.
65    #[instability::unstable]
66    pub fn new(
67        device: crate::hal::peripherals::BT<'d>,
68        config: Config,
69    ) -> Result<BleConnector<'d>, BleInitError> {
70        let _guard = RadioRefGuard::new();
71
72        config.validate()?;
73
74        Ok(Self {
75            _phy_init_guard: crate::ble::ble_init(&config),
76            _device: device,
77            _guard,
78        })
79    }
80
81    /// Read the next HCI packet from the BLE controller.
82    #[instability::unstable]
83    pub fn next(&mut self, buf: &mut [u8]) -> Result<usize, BleConnectorError> {
84        Ok(read_next(buf))
85    }
86
87    /// Read from HCI.
88    #[instability::unstable]
89    pub fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, BleConnectorError> {
90        let mut total = 0;
91        while !buf.is_empty() {
92            let len = read_hci(buf);
93            if len == 0 {
94                break;
95            }
96
97            buf = &mut buf[len..];
98            total += len;
99        }
100        Ok(total)
101    }
102
103    /// Read from HCI.
104    #[instability::unstable]
105    pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, BleConnectorError> {
106        if buf.is_empty() {
107            return Ok(0);
108        }
109
110        HciAnyDataReadyEventFuture.await;
111
112        self.read(buf)
113    }
114
115    /// Write to HCI.
116    ///
117    /// Returns the number of bytes written, which is at most one packet.
118    #[instability::unstable]
119    pub fn write(&mut self, buf: &[u8]) -> Result<usize, BleConnectorError> {
120        Ok(send_hci(buf))
121    }
122
123    /// Write to HCI asynchronously.
124    ///
125    /// Returns the number of bytes written, which is at most one packet.
126    #[instability::unstable]
127    pub async fn write_async(&mut self, buf: &[u8]) -> Result<usize, BleConnectorError> {
128        Ok(send_hci_async(buf).await)
129    }
130}
131
132#[derive(Display, Debug, Copy, Clone, Eq, PartialEq, Hash)]
133#[cfg_attr(feature = "defmt", derive(defmt::Format))]
134/// Error type for the BLE connector.
135#[instability::unstable]
136pub enum BleConnectorError {
137    /// Unknown BLE error occurred.
138    Unknown,
139}
140
141impl embedded_io_06::Error for BleConnectorError {
142    fn kind(&self) -> embedded_io_06::ErrorKind {
143        embedded_io_06::ErrorKind::Other
144    }
145}
146
147impl embedded_io_07::Error for BleConnectorError {
148    fn kind(&self) -> embedded_io_07::ErrorKind {
149        embedded_io_07::ErrorKind::Other
150    }
151}
152
153impl core::error::Error for BleConnectorError {}
154
155impl embedded_io_06::ErrorType for BleConnector<'_> {
156    type Error = BleConnectorError;
157}
158
159impl embedded_io_06::Read for BleConnector<'_> {
160    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
161        self.read(buf)
162    }
163}
164
165impl embedded_io_06::Write for BleConnector<'_> {
166    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
167        self.write(buf)
168    }
169
170    fn flush(&mut self) -> Result<(), Self::Error> {
171        // nothing to do
172        Ok(())
173    }
174}
175
176impl embedded_io_07::ErrorType for BleConnector<'_> {
177    type Error = BleConnectorError;
178}
179
180impl embedded_io_07::Read for BleConnector<'_> {
181    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
182        self.read(buf)
183    }
184}
185
186impl embedded_io_07::Write for BleConnector<'_> {
187    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
188        self.write(buf)
189    }
190
191    fn flush(&mut self) -> Result<(), Self::Error> {
192        // nothing to do
193        Ok(())
194    }
195}
196
197static HCI_WAKER: AtomicWaker = AtomicWaker::new();
198
199pub(crate) fn hci_read_data_available() {
200    HCI_WAKER.wake();
201}
202
203impl embedded_io_async_06::Read for BleConnector<'_> {
204    fn read(&mut self, buf: &mut [u8]) -> impl Future<Output = Result<usize, BleConnectorError>> {
205        self.read_async(buf)
206    }
207}
208
209impl embedded_io_async_06::Write for BleConnector<'_> {
210    async fn write(&mut self, buf: &[u8]) -> Result<usize, BleConnectorError> {
211        self.write_async(buf).await
212    }
213
214    async fn flush(&mut self) -> Result<(), BleConnectorError> {
215        // nothing to do
216        Ok(())
217    }
218}
219
220impl embedded_io_async_07::Read for BleConnector<'_> {
221    fn read(&mut self, buf: &mut [u8]) -> impl Future<Output = Result<usize, BleConnectorError>> {
222        self.read_async(buf)
223    }
224}
225
226impl embedded_io_async_07::Write for BleConnector<'_> {
227    async fn write(&mut self, buf: &[u8]) -> Result<usize, BleConnectorError> {
228        self.write_async(buf).await
229    }
230
231    async fn flush(&mut self) -> Result<(), BleConnectorError> {
232        // nothing to do
233        Ok(())
234    }
235}
236
237impl From<FromHciBytesError> for BleConnectorError {
238    fn from(_e: FromHciBytesError) -> Self {
239        BleConnectorError::Unknown
240    }
241}
242
243/// Completes once any HCI data is available, including a part-read packet.
244pub(crate) struct HciAnyDataReadyEventFuture;
245
246impl core::future::Future for HciAnyDataReadyEventFuture {
247    type Output = ();
248
249    fn poll(
250        self: core::pin::Pin<&mut Self>,
251        cx: &mut core::task::Context<'_>,
252    ) -> Poll<Self::Output> {
253        HCI_WAKER.register(cx.waker());
254
255        if have_hci_read_data() {
256            Poll::Ready(())
257        } else {
258            Poll::Pending
259        }
260    }
261}
262
263/// Completes once the receive queue holds a complete packet.
264pub(crate) struct HciPacketReadyEventFuture;
265
266impl core::future::Future for HciPacketReadyEventFuture {
267    type Output = ();
268
269    fn poll(
270        self: core::pin::Pin<&mut Self>,
271        cx: &mut core::task::Context<'_>,
272    ) -> Poll<Self::Output> {
273        HCI_WAKER.register(cx.waker());
274
275        if have_hci_packet() {
276            Poll::Ready(())
277        } else {
278            Poll::Pending
279        }
280    }
281}
282
283/// The HCI output of the BLE controller.
284///
285/// The transport implementations use this zero-sized writer to serialize packets directly into the
286/// controller.
287struct HciWriter;
288
289impl embedded_io_07::ErrorType for HciWriter {
290    type Error = BleConnectorError;
291}
292
293impl embedded_io_async_07::Write for HciWriter {
294    async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
295        Ok(send_hci_async(buf).await)
296    }
297
298    async fn flush(&mut self) -> Result<(), Self::Error> {
299        // nothing to do
300        Ok(())
301    }
302}
303
304impl<E: embedded_io_07::Error> From<bt_hci_transport::ReadHciError<E>> for BleConnectorError {
305    fn from(_e: bt_hci_transport::ReadHciError<E>) -> Self {
306        BleConnectorError::Unknown
307    }
308}
309
310fn parse_hci(data: &[u8]) -> Result<ControllerToHostPacket<'_>, BleConnectorError> {
311    match ControllerToHostPacket::from_hci_bytes_complete(data) {
312        Ok(p) => Ok(p),
313        Err(e) => {
314            warn!("[hci] error parsing packet: {:?}", e);
315            Err(BleConnectorError::Unknown)
316        }
317    }
318}
319
320/// Waits for a packet from the controller, then removes it from the receive queue.
321async fn next_packet() -> Box<[u8]> {
322    loop {
323        HciPacketReadyEventFuture.await;
324
325        if let Some(packet) = take_next() {
326            return packet;
327        }
328    }
329}
330
331impl bt_hci::transport::Transport for BleConnector<'_> {
332    /// Read a complete HCI packet into the rx buffer
333    async fn read<'a>(&self, rx: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, Self::Error> {
334        // Workaround for borrow checker.
335        // Safety: we only return a reference to x once, if parsing is successful.
336        let rx = unsafe { &mut *core::ptr::slice_from_raw_parts_mut(rx.as_mut_ptr(), rx.len()) };
337
338        // `ControllerToHostPacket` borrows `rx`, so the packet has to be copied there.
339        HciPacketReadyEventFuture.await;
340        let len = read_next(rx);
341        parse_hci(&rx[..len])
342    }
343
344    /// Write a complete HCI packet from the tx buffer
345    async fn write<T: HostToControllerPacket>(&self, val: &T) -> Result<(), Self::Error> {
346        bt_hci::transport::WithIndicator::new(val)
347            .write_hci_async(HciWriter)
348            .await
349    }
350}
351
352impl bt_hci_transport::Transport for BleConnector<'_> {
353    /// Read a complete HCI packet into the rx buffer
354    async fn read<'a, P: PacketToHost<'a>>(&self, rx: &'a mut [u8]) -> Result<P, Self::Error> {
355        // `P::read_hci` deserializes from a reader into `rx`, so the packet must be read from a
356        // buffer other than `rx`. The queued packet itself is that buffer.
357        let packet = next_packet().await;
358
359        let mut reader = &packet[..];
360        let kind = PacketKind::read(&mut reader)?;
361        Ok(P::read_hci(kind, &mut reader, rx)?)
362    }
363
364    /// Write a complete HCI packet from the tx buffer
365    async fn write<P: PacketToController>(&self, tx: &P) -> Result<(), Self::Error> {
366        bt_hci_transport::WithIndicator::new(tx)
367            .write_hci_async(HciWriter)
368            .await
369    }
370}