esp_wifi/ble/
mod.rs

1//! Bluetooth Low Energy HCI interface
2//!
3//! The usage of BLE is currently incompatible with the usage of IEEE 802.15.4.
4
5#[cfg(any(esp32, esp32c3, esp32s3))]
6pub(crate) mod btdm;
7
8#[cfg(any(esp32c2, esp32c6, esp32h2))]
9pub(crate) mod npl;
10
11use alloc::{boxed::Box, collections::vec_deque::VecDeque, vec::Vec};
12use core::{cell::RefCell, mem::MaybeUninit};
13
14pub(crate) use ble::{ble_deinit, ble_init, send_hci};
15use critical_section::Mutex;
16
17#[cfg(any(esp32, esp32c3, esp32s3))]
18use self::btdm as ble;
19#[cfg(any(esp32c2, esp32c6, esp32h2))]
20use self::npl as ble;
21
22pub mod controller;
23
24pub(crate) unsafe extern "C" fn malloc(size: u32) -> *mut crate::binary::c_types::c_void {
25    unsafe { crate::compat::malloc::malloc(size as usize).cast() }
26}
27
28#[cfg(any(esp32, esp32c3, esp32s3))]
29pub(crate) unsafe extern "C" fn malloc_internal(size: u32) -> *mut crate::binary::c_types::c_void {
30    unsafe { crate::compat::malloc::malloc(size as usize).cast() }
31}
32
33pub(crate) unsafe extern "C" fn free(ptr: *mut crate::binary::c_types::c_void) {
34    unsafe { crate::compat::malloc::free(ptr.cast()) }
35}
36
37// Stores received packets until the the BLE stack dequeues them
38static BT_RECEIVE_QUEUE: Mutex<RefCell<VecDeque<ReceivedPacket>>> =
39    Mutex::new(RefCell::new(VecDeque::new()));
40
41static mut HCI_OUT_COLLECTOR: MaybeUninit<HciOutCollector> = MaybeUninit::uninit();
42
43#[derive(PartialEq, Debug)]
44enum HciOutType {
45    Unknown,
46    Acl,
47    Command,
48}
49
50struct HciOutCollector {
51    data: [u8; 256],
52    index: usize,
53    ready: bool,
54    kind: HciOutType,
55}
56
57impl HciOutCollector {
58    fn new() -> HciOutCollector {
59        HciOutCollector {
60            data: [0u8; 256],
61            index: 0,
62            ready: false,
63            kind: HciOutType::Unknown,
64        }
65    }
66
67    fn is_ready(&self) -> bool {
68        self.ready
69    }
70
71    fn push(&mut self, data: &[u8]) {
72        self.data[self.index..(self.index + data.len())].copy_from_slice(data);
73        self.index += data.len();
74
75        if self.kind == HciOutType::Unknown {
76            self.kind = match self.data[0] {
77                1 => HciOutType::Command,
78                2 => HciOutType::Acl,
79                _ => HciOutType::Unknown,
80            };
81        }
82
83        if !self.ready {
84            if self.kind == HciOutType::Command && self.index >= 4 {
85                if self.index == self.data[3] as usize + 4 {
86                    self.ready = true;
87                }
88            } else if self.kind == HciOutType::Acl
89                && self.index >= 5
90                && self.index == (self.data[3] as usize) + ((self.data[4] as usize) << 8) + 5
91            {
92                self.ready = true;
93            }
94        }
95    }
96
97    fn reset(&mut self) {
98        self.index = 0;
99        self.ready = false;
100        self.kind = HciOutType::Unknown;
101    }
102
103    fn packet(&self) -> &[u8] {
104        &self.data[0..self.index]
105    }
106}
107
108static BLE_HCI_READ_DATA: Mutex<RefCell<Vec<u8>>> = Mutex::new(RefCell::new(Vec::new()));
109
110#[derive(Debug, Clone)]
111pub struct ReceivedPacket {
112    pub data: Box<[u8]>,
113}
114
115#[cfg(feature = "defmt")]
116impl defmt::Format for ReceivedPacket {
117    fn format(&self, fmt: defmt::Formatter<'_>) {
118        defmt::write!(fmt, "ReceivedPacket {}", &self.data[..])
119    }
120}
121
122pub fn have_hci_read_data() -> bool {
123    critical_section::with(|cs| {
124        let queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs);
125        let hci_read_data = BLE_HCI_READ_DATA.borrow_ref(cs);
126        !queue.is_empty() || !hci_read_data.is_empty()
127    })
128}
129
130pub(crate) fn read_next(data: &mut [u8]) -> usize {
131    critical_section::with(|cs| {
132        let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs);
133
134        match queue.pop_front() {
135            Some(packet) => {
136                data[..packet.data.len()].copy_from_slice(&packet.data[..packet.data.len()]);
137                packet.data.len()
138            }
139            None => 0,
140        }
141    })
142}
143
144pub fn read_hci(data: &mut [u8]) -> usize {
145    critical_section::with(|cs| {
146        let mut hci_read_data = BLE_HCI_READ_DATA.borrow_ref_mut(cs);
147
148        if hci_read_data.is_empty() {
149            let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs);
150
151            if let Some(packet) = queue.pop_front() {
152                hci_read_data.extend_from_slice(&packet.data);
153            }
154        }
155
156        let l = usize::min(hci_read_data.len(), data.len());
157        data[..l].copy_from_slice(&hci_read_data[..l]);
158        hci_read_data.drain(..l);
159        l
160    })
161}
162
163fn dump_packet_info(_buffer: &[u8]) {
164    #[cfg(dump_packets)]
165    critical_section::with(|_cs| {
166        info!("@HCIFRAME {:?}", _buffer);
167    });
168}