esp_radio/ble/
os_adapter_esp32c2.rs

1use procmacros::BuilderLite;
2
3use super::*;
4use crate::{
5    binary::include::esp_bt_controller_config_t,
6    ble::InvalidConfigError,
7    hal::{
8        clock::{Clock, RtcClock},
9        efuse::Efuse,
10        interrupt,
11        peripherals::{BT, Interrupt},
12    },
13};
14
15pub(crate) static mut ISR_INTERRUPT_4: (*mut c_void, *mut c_void) =
16    (core::ptr::null_mut(), core::ptr::null_mut());
17
18pub(crate) static mut ISR_INTERRUPT_7: (*mut c_void, *mut c_void) =
19    (core::ptr::null_mut(), core::ptr::null_mut());
20
21/// Transmission Power Level
22#[derive(Default, Clone, Copy, Eq, PartialEq)]
23#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25pub enum TxPower {
26    /// -24 dBm
27    N24,
28    /// -21 dBm
29    N21,
30    /// -18 dBm
31    N18,
32    /// -15 dBm
33    N15,
34    /// -12 dBm
35    N12,
36    /// -9 dBm
37    N9,
38    /// -6 dBm
39    N6,
40    /// -3 dBm
41    N3,
42    /// 0 dBm
43    N0,
44    /// 3 dBm
45    P3,
46    /// 6 dBm
47    P6,
48    /// 9 dBm
49    #[default]
50    P9,
51    /// 12 dBm
52    P12,
53    /// 15 dBm
54    P15,
55    /// 18 dBm
56    P18,
57    /// 20 dBm
58    P20,
59}
60
61#[allow(dead_code)]
62impl TxPower {
63    fn idx(self) -> esp_power_level_t {
64        match self {
65            Self::N24 => esp_power_level_t_ESP_PWR_LVL_N24,
66            Self::N21 => esp_power_level_t_ESP_PWR_LVL_N21,
67            Self::N18 => esp_power_level_t_ESP_PWR_LVL_N18,
68            Self::N15 => esp_power_level_t_ESP_PWR_LVL_N15,
69            Self::N12 => esp_power_level_t_ESP_PWR_LVL_N12,
70            Self::N9 => esp_power_level_t_ESP_PWR_LVL_N9,
71            Self::N6 => esp_power_level_t_ESP_PWR_LVL_N6,
72            Self::N3 => esp_power_level_t_ESP_PWR_LVL_N3,
73            Self::N0 => esp_power_level_t_ESP_PWR_LVL_N0,
74            Self::P3 => esp_power_level_t_ESP_PWR_LVL_P3,
75            Self::P6 => esp_power_level_t_ESP_PWR_LVL_P6,
76            Self::P9 => esp_power_level_t_ESP_PWR_LVL_P9,
77            Self::P12 => esp_power_level_t_ESP_PWR_LVL_P12,
78            Self::P15 => esp_power_level_t_ESP_PWR_LVL_P15,
79            Self::P18 => esp_power_level_t_ESP_PWR_LVL_P18,
80            Self::P20 => esp_power_level_t_ESP_PWR_LVL_P20,
81        }
82    }
83
84    fn dbm(self) -> i8 {
85        match self {
86            Self::N24 => -24,
87            Self::N21 => -21,
88            Self::N18 => -18,
89            Self::N15 => -15,
90            Self::N12 => -12,
91            Self::N9 => -9,
92            Self::N6 => -6,
93            Self::N3 => -3,
94            Self::N0 => 0,
95            Self::P3 => 3,
96            Self::P6 => 6,
97            Self::P9 => 9,
98            Self::P12 => 12,
99            Self::P15 => 15,
100            Self::P18 => 18,
101            Self::P20 => 20,
102        }
103    }
104}
105
106/// Bluetooth controller configuration.
107#[derive(BuilderLite, Clone, Copy, Eq, PartialEq)]
108#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
109#[cfg_attr(feature = "defmt", derive(defmt::Format))]
110pub struct Config {
111    /// The priority of the RTOS task.
112    task_priority: u8,
113
114    /// The stack size of the RTOS task.
115    task_stack_size: u16,
116
117    /// The maximum number of simultaneous connections.
118    ///
119    /// Range: 1 - 2
120    max_connections: u16,
121
122    /// Enable QA test mode.
123    qa_test_mode: bool,
124
125    /// Enable BQB test mode.
126    bqb_test: bool,
127
128    /// Size of the resolvable private address list.
129    ll_resolv_list_size: u16,
130
131    /// Maximum number of periodic advertiser list.
132    ///
133    /// Range: 1 - 5
134    ll_sync_list_cnt: u8,
135
136    /// Maximum number of periodic advertising syncs.
137    ///
138    /// Range: 0 - 3
139    ll_sync_cnt: u8,
140
141    /// Count of duplicated lists for scan response packets
142    ///
143    /// Range: 1 - 100
144    ll_rsp_dup_list_count: u16,
145
146    /// Count of duplicated lists for advertising packets
147    ///
148    /// Range: 1 - 100
149    ll_adv_dup_list_count: u16,
150
151    /// Default TX power.
152    default_tx_power: TxPower,
153
154    /// High Priority HCI Event Buffer count
155    hci_high_buffer_count: u16,
156
157    /// Low Priority HCI Event Buffer count
158    hci_low_buffer_count: u16,
159
160    /// Size of the whitelist.
161    whitelist_size: u8,
162
163    /// Buffer size of ACL (Asynchronous Connection-Less) data
164    acl_buf_size: u16,
165
166    /// Buffer count of ACL data
167    acl_buf_count: u16,
168
169    /// Buffer size for HCI event data
170    hci_evt_buf_size: u16,
171
172    /// Maximum number of extended advertising instances.
173    multi_adv_instances: u16,
174
175    /// Maximum size of extended advertising data
176    ///
177    /// Range: 0 - 1650
178    ext_adv_max_size: u16,
179
180    /// Disable scan backoff
181    dis_scan_backoff: bool,
182
183    /// The value of upperlimitmax during scan backoff procedure
184    ///
185    /// The value of upperlimitmax needs to be a power of 2.
186    ///
187    /// Range: 1 - 256
188    scan_backoff_max: u16,
189
190    /// Enables verification of the Access Address within the `CONNECT_IND` PDU.
191    ///
192    /// Enabling this option will add stricter verification of the Access Address in the
193    /// `CONNECT_IND` PDU. This improves security by ensuring that only connection requests with
194    /// valid Access Addresses are accepted. If disabled, only basic checks are applied,
195    /// improving compatibility.
196    verify_access_address: bool,
197
198    /// Enable BLE Clear Channel Assessment (CCA).
199    cca: bool,
200
201    /// Absolute value of hardware-triggered CCA threshold.
202    ///
203    /// The CCA threshold is always negative.
204    ///
205    /// If the channel assessment result exceeds the CCA threshold (e.g. -75 dBm), indicating
206    /// the channel is busy, the hardware will not transmit packets on that channel.
207    ///
208    /// Range: 20 dBm - 100 dBm
209    cca_threshold: u8,
210
211    /// Disconnect when Instant Passed (0x28) occurs during ACL connection update.
212    disconnect_llcp_conn_update: bool,
213
214    /// Disconnect when Instant Passed (0x28) occurs during ACL channel map update.
215    disconnect_llcp_chan_map_update: bool,
216
217    /// Disconnect when Instant Passed (0x28) occurs during ACL PHY update.
218    disconnect_llcp_phy_update: bool,
219}
220
221impl Default for Config {
222    fn default() -> Self {
223        Self {
224            // same priority as the wifi task, when using esp-rtos (I'm assuming it's MAX_PRIO - 2)
225            task_priority: 29,
226            task_stack_size: CONFIG_BT_LE_CONTROLLER_TASK_STACK_SIZE as _,
227            max_connections: CONFIG_BT_LE_MAX_CONNECTIONS as _,
228            qa_test_mode: false,
229            bqb_test: false,
230            ll_resolv_list_size: CONFIG_BT_LE_LL_RESOLV_LIST_SIZE as _,
231            ll_sync_list_cnt: CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST as _,
232            ll_sync_cnt: CONFIG_BT_LE_MAX_PERIODIC_SYNCS as _,
233            ll_rsp_dup_list_count: CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT as _,
234            ll_adv_dup_list_count: CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT as _,
235            default_tx_power: TxPower::default(),
236            hci_high_buffer_count: CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT as _,
237            hci_low_buffer_count: CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT as _,
238            whitelist_size: CONFIG_BT_LE_WHITELIST_SIZE as _,
239            acl_buf_size: CONFIG_BT_LE_ACL_BUF_SIZE as _,
240            acl_buf_count: CONFIG_BT_LE_ACL_BUF_COUNT as _,
241            hci_evt_buf_size: CONFIG_BT_LE_HCI_EVT_BUF_SIZE as _,
242            multi_adv_instances: CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES as _,
243            ext_adv_max_size: CONFIG_BT_LE_EXT_ADV_MAX_SIZE as _,
244            dis_scan_backoff: false,
245            scan_backoff_max: CONFIG_BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX as _,
246            verify_access_address: false,
247            disconnect_llcp_conn_update: false,
248            disconnect_llcp_chan_map_update: false,
249            disconnect_llcp_phy_update: false,
250            cca_threshold: 65,
251            cca: false,
252        }
253    }
254}
255
256impl Config {
257    pub(crate) fn validate(&self) -> Result<(), InvalidConfigError> {
258        crate::ble::validate_range!(self, max_connections, 1, 2);
259        crate::ble::validate_range!(self, ll_sync_cnt, 0, 3);
260        crate::ble::validate_range!(self, ll_sync_list_cnt, 1, 5);
261        crate::ble::validate_range!(self, ll_rsp_dup_list_count, 1, 100);
262        crate::ble::validate_range!(self, ll_adv_dup_list_count, 1, 100);
263        crate::ble::validate_range!(self, whitelist_size, 1, 31);
264        crate::ble::validate_range!(self, multi_adv_instances, 0, 4);
265        crate::ble::validate_range!(self, ext_adv_max_size, 0, 1650);
266        crate::ble::validate_range!(self, scan_backoff_max, 1, 256);
267        crate::ble::validate_range!(self, cca_threshold, 20, 100);
268        Ok(())
269    }
270}
271
272pub(crate) fn create_ble_config(config: &Config) -> esp_bt_controller_config_t {
273    let main_xtal_freq = RtcClock::xtal_freq().mhz() as u8;
274
275    let rtc_freq = if main_xtal_freq == 26 { 40000 } else { 32000 };
276
277    // keep them aligned with BT_CONTROLLER_INIT_CONFIG_DEFAULT in ESP-IDF
278    // ideally _some_ of these values should be configurable
279    esp_bt_controller_config_t {
280        config_version: CONFIG_VERSION,
281        ble_ll_resolv_list_size: config.ll_resolv_list_size,
282        ble_hci_evt_hi_buf_count: config.hci_high_buffer_count,
283        ble_hci_evt_lo_buf_count: config.hci_low_buffer_count,
284        ble_ll_sync_list_cnt: config.ll_sync_list_cnt,
285        ble_ll_sync_cnt: config.ll_sync_cnt,
286        ble_ll_rsp_dup_list_count: config.ll_rsp_dup_list_count,
287        ble_ll_adv_dup_list_count: config.ll_adv_dup_list_count,
288        ble_ll_tx_pwr_dbm: config.default_tx_power.dbm() as u8,
289        rtc_freq,
290        ble_ll_sca: CONFIG_BT_LE_LL_SCA as _,
291        ble_ll_scan_phy_number: if CONFIG_BT_LE_LL_CFG_FEAT_LE_CODED_PHY != 0 {
292            2
293        } else {
294            1
295        },
296        ble_ll_conn_def_auth_pyld_tmo: 3000,
297        ble_ll_jitter_usecs: 16,
298        ble_ll_sched_max_adv_pdu_usecs: 376,
299        ble_ll_sched_direct_adv_max_usecs: 502,
300        ble_ll_sched_adv_max_usecs: 852,
301        ble_scan_rsp_data_max_len: 31,
302        ble_ll_cfg_num_hci_cmd_pkts: 1,
303        ble_ll_ctrl_proc_timeout_ms: 40000,
304        nimble_max_connections: config.max_connections,
305        ble_whitelist_size: config.whitelist_size,
306        ble_acl_buf_size: config.acl_buf_size,
307        ble_acl_buf_count: config.acl_buf_count,
308        ble_hci_evt_buf_size: config.hci_evt_buf_size,
309        ble_multi_adv_instances: config.multi_adv_instances,
310        ble_ext_adv_max_size: config.ext_adv_max_size,
311        controller_task_stack_size: config.task_stack_size,
312        controller_task_prio: config.task_priority,
313        controller_run_cpu: 0,
314        enable_qa_test: config.qa_test_mode as u8,
315        enable_bqb_test: config.bqb_test as u8,
316        enable_uart_hci: 0,
317        ble_hci_uart_port: 0,
318        ble_hci_uart_baud: 0,
319        ble_hci_uart_data_bits: 0,
320        ble_hci_uart_stop_bits: 0,
321        ble_hci_uart_flow_ctrl: 0,
322        ble_hci_uart_uart_parity: 0,
323        enable_tx_cca: config.cca as u8,
324        cca_rssi_thresh: (256 - config.cca_threshold as u32) as u8,
325        sleep_en: 0, // CONFIG_BT_LE_SLEEP_ENABLE unset
326        coex_phy_coded_tx_rx_time_limit: CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF as _,
327        dis_scan_backoff: config.dis_scan_backoff as u8,
328        ble_scan_classify_filter_enable: 0,
329        cca_drop_mode: 0,  //???
330        cca_low_tx_pwr: 0, //???
331        main_xtal_freq,
332        version_num: Efuse::minor_chip_version(),
333        ignore_wl_for_direct_adv: 0,
334        csa2_select: CONFIG_BT_LE_50_FEATURE_SUPPORT as _,
335        ble_aa_check: config.verify_access_address as u8,
336        ble_llcp_disc_flag: config.disconnect_llcp_conn_update as u8
337            | ((config.disconnect_llcp_chan_map_update as u8) << 1)
338            | ((config.disconnect_llcp_phy_update as u8) << 2),
339        scan_backoff_upperlimitmax: config.scan_backoff_max,
340        vhci_enabled: CONFIG_BT_LE_HCI_INTERFACE_USE_RAM as _,
341        config_magic: CONFIG_MAGIC,
342    }
343}
344
345pub(crate) fn bt_periph_module_enable() {
346    // nothing
347}
348
349pub(crate) fn disable_sleep_mode() {
350    // nothing
351}
352
353pub(super) unsafe extern "C" fn esp_intr_alloc(
354    source: u32,
355    flags: u32,
356    handler: *mut c_void,
357    arg: *mut c_void,
358    ret_handle: *mut *mut c_void,
359) -> i32 {
360    trace!(
361        "esp_intr_alloc {} {} {:?} {:?} {:?}",
362        source, flags, handler, arg, ret_handle
363    );
364
365    unsafe {
366        match source {
367            4 => {
368                ISR_INTERRUPT_4 = (handler, arg);
369                unwrap!(interrupt::enable(
370                    Interrupt::BT_MAC,
371                    interrupt::Priority::Priority1
372                ));
373            }
374            7 => {
375                ISR_INTERRUPT_7 = (handler, arg);
376                unwrap!(interrupt::enable(
377                    Interrupt::LP_TIMER,
378                    interrupt::Priority::Priority1
379                ));
380            }
381            _ => panic!("Unexpected interrupt source {}", source),
382        }
383    }
384
385    0
386}
387
388pub(super) fn ble_rtc_clk_init() {
389    // stealing BT is safe, since it is passed into the initialization function of the BLE
390    // controller.
391    let mut bt = unsafe { BT::steal() };
392    bt.ble_rtc_clk_init();
393}
394
395pub(super) unsafe extern "C" fn esp_reset_rpa_moudle() {
396    trace!("esp_reset_rpa_moudle");
397    // stealing BT is safe, since it is passed into the initialization function of the BLE
398    // controller.
399    let mut bt = unsafe { BT::steal() };
400    bt.reset_rpa();
401}
402
403// Provide the symbol for < eco4 to make the linker happy
404#[unsafe(no_mangle)]
405unsafe fn g_ble_lll_rfmgmt_env_p() -> *mut esp_wifi_sys::c_types::c_void {
406    // prevent "undefined symbol: g_ble_lll_rfmgmt_env_p" for ESP32-C2 < eco4
407    unreachable!()
408}