Skip to main content

esp_radio/ble/
os_adapter_esp32h2.rs

1use procmacros::BuilderLite;
2
3use super::*;
4use crate::{
5    ble::InvalidConfigError,
6    hal::{interrupt, peripherals::BT},
7    interrupt_dispatch::Handler,
8    sys::include::esp_bt_controller_config_t,
9};
10
11static ISR_INTERRUPT_3: Handler = Handler::new();
12static ISR_INTERRUPT_15: Handler = Handler::new();
13
14/// Transmission Power Level
15#[derive(Default, Clone, Copy, Eq, PartialEq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub enum TxPower {
18    /// -24 dBm
19    N24,
20    /// -21 dBm
21    N21,
22    /// -18 dBm
23    N18,
24    /// -15 dBm
25    N15,
26    /// -12 dBm
27    N12,
28    /// -9 dBm
29    N9,
30    /// -6 dBm
31    N6,
32    /// -3 dBm
33    N3,
34    /// 0 dBm
35    N0,
36    /// 3 dBm
37    P3,
38    /// 6 dBm
39    P6,
40    /// 9 dBm
41    #[default]
42    P9,
43    /// 12 dBm
44    P12,
45    /// 15 dBm
46    P15,
47    /// 18 dBm
48    P18,
49    /// 20 dBm
50    P20,
51}
52
53#[allow(dead_code)]
54impl TxPower {
55    fn idx(self) -> esp_power_level_t {
56        match self {
57            Self::N24 => esp_power_level_t_ESP_PWR_LVL_N24,
58            Self::N21 => esp_power_level_t_ESP_PWR_LVL_N21,
59            Self::N18 => esp_power_level_t_ESP_PWR_LVL_N18,
60            Self::N15 => esp_power_level_t_ESP_PWR_LVL_N15,
61            Self::N12 => esp_power_level_t_ESP_PWR_LVL_N12,
62            Self::N9 => esp_power_level_t_ESP_PWR_LVL_N9,
63            Self::N6 => esp_power_level_t_ESP_PWR_LVL_N6,
64            Self::N3 => esp_power_level_t_ESP_PWR_LVL_N3,
65            Self::N0 => esp_power_level_t_ESP_PWR_LVL_N0,
66            Self::P3 => esp_power_level_t_ESP_PWR_LVL_P3,
67            Self::P6 => esp_power_level_t_ESP_PWR_LVL_P6,
68            Self::P9 => esp_power_level_t_ESP_PWR_LVL_P9,
69            Self::P12 => esp_power_level_t_ESP_PWR_LVL_P12,
70            Self::P15 => esp_power_level_t_ESP_PWR_LVL_P15,
71            Self::P18 => esp_power_level_t_ESP_PWR_LVL_P18,
72            Self::P20 => esp_power_level_t_ESP_PWR_LVL_P20,
73        }
74    }
75
76    fn dbm(self) -> i8 {
77        match self {
78            Self::N24 => -24,
79            Self::N21 => -21,
80            Self::N18 => -18,
81            Self::N15 => -15,
82            Self::N12 => -12,
83            Self::N9 => -9,
84            Self::N6 => -6,
85            Self::N3 => -3,
86            Self::N0 => 0,
87            Self::P3 => 3,
88            Self::P6 => 6,
89            Self::P9 => 9,
90            Self::P12 => 12,
91            Self::P15 => 15,
92            Self::P18 => 18,
93            Self::P20 => 20,
94        }
95    }
96}
97
98/// Bluetooth controller configuration.
99#[derive(BuilderLite, Clone, Copy, Eq, PartialEq)]
100#[cfg_attr(feature = "defmt", derive(defmt::Format))]
101pub struct Config {
102    /// The priority of the RTOS task.
103    task_priority: u8,
104
105    /// The stack size of the RTOS task.
106    task_stack_size: u16,
107
108    /// The maximum number of simultaneous connections.
109    ///
110    /// Range: 1 - 35
111    max_connections: u16,
112
113    /// Enable QA test mode.
114    qa_test_mode: bool,
115
116    /// Enable BQB test mode.
117    bqb_test: bool,
118
119    /// Size of the resolvable private address list.
120    ll_resolv_list_size: u16,
121
122    /// Maximum number of periodic advertiser list.
123    ///
124    /// Range: 1 - 5
125    ll_sync_list_cnt: u8,
126
127    /// Maximum number of periodic advertising syncs.
128    ///
129    /// Range: 0 - 3
130    ll_sync_cnt: u8,
131
132    /// Count of duplicated lists for scan response packets
133    ///
134    /// Range: 1 - 100
135    ll_rsp_dup_list_count: u16,
136
137    /// Count of duplicated lists for advertising packets
138    ///
139    /// Range: 1 - 100
140    ll_adv_dup_list_count: u16,
141
142    /// Enables verification of the Access Address within the `CONNECT_IND` PDU.
143    ///
144    /// Enabling this option will add stricter verification of the Access Address in the
145    /// `CONNECT_IND` PDU. This improves security by ensuring that only connection requests with
146    /// valid Access Addresses are accepted. If disabled, only basic checks are applied,
147    /// improving compatibility.
148    verify_access_address: bool,
149
150    /// Enable BLE channel assessment.
151    channel_assessment: bool,
152
153    /// Default TX power.
154    default_tx_power: TxPower,
155
156    /// High Priority HCI Event Buffer count
157    hci_high_buffer_count: u16,
158
159    /// Low Priority HCI Event Buffer count
160    hci_low_buffer_count: u16,
161
162    /// Size of the whitelist.
163    whitelist_size: u8,
164
165    /// Buffer size of ACL (Asynchronous Connection-Less) data
166    acl_buf_size: u16,
167
168    /// Buffer count of ACL data
169    acl_buf_count: u16,
170
171    /// Buffer size for HCI event data
172    hci_evt_buf_size: u16,
173
174    /// Maximum number of extended advertising instances.
175    multi_adv_instances: u16,
176
177    /// Maximum size of extended advertising data
178    ///
179    /// Range: 0 - 1650
180    ext_adv_max_size: u16,
181
182    /// Disable scan backoff
183    dis_scan_backoff: bool,
184
185    /// The value of upperlimitmax during scan backoff procedure
186    ///
187    /// The value of upperlimitmax needs to be a power of 2.
188    ///
189    /// Range: 1 - 256
190    scan_backoff_max: u16,
191
192    /// Enable BLE Clear Channel Assessment (CCA).
193    cca: bool,
194
195    /// Absolute value of hardware-triggered CCA threshold.
196    ///
197    /// The CCA threshold is always negative.
198    ///
199    /// If the channel assessment result exceeds the CCA threshold (e.g. -75 dBm), indicating
200    /// the channel is busy, the hardware will not transmit packets on that channel.
201    ///
202    /// Range: 20 dBm - 100 dBm
203    cca_threshold: u8,
204
205    /// Enable / disable auxiliary packets when the extended ADV data length is zero.
206    data_length_zero_aux: bool,
207
208    /// Disconnect when Instant Passed (0x28) occurs during ACL connection update.
209    disconnect_llcp_conn_update: bool,
210
211    /// Disconnect when Instant Passed (0x28) occurs during ACL channel map update.
212    disconnect_llcp_chan_map_update: bool,
213
214    /// Disconnect when Instant Passed (0x28) occurs during ACL PHY update.
215    disconnect_llcp_phy_update: bool,
216}
217
218impl Default for Config {
219    fn default() -> Self {
220        Self {
221            task_priority: crate::preempt::max_task_priority()
222                .saturating_sub(2)
223                .min(255) as u8,
224            task_stack_size: CONFIG_BT_LE_CONTROLLER_TASK_STACK_SIZE as _,
225            max_connections: CONFIG_BT_LE_MAX_CONNECTIONS as _,
226            qa_test_mode: false,
227            bqb_test: false,
228            ll_resolv_list_size: CONFIG_BT_LE_LL_RESOLV_LIST_SIZE as _,
229            ll_sync_list_cnt: CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST as _,
230            ll_sync_cnt: CONFIG_BT_LE_MAX_PERIODIC_SYNCS as _,
231            ll_rsp_dup_list_count: CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT as _,
232            ll_adv_dup_list_count: CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT as _,
233            default_tx_power: TxPower::default(),
234            hci_high_buffer_count: CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT as _,
235            hci_low_buffer_count: CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT as _,
236            whitelist_size: CONFIG_BT_LE_WHITELIST_SIZE as _,
237            acl_buf_size: CONFIG_BT_LE_ACL_BUF_SIZE as _,
238            acl_buf_count: CONFIG_BT_LE_ACL_BUF_COUNT as _,
239            hci_evt_buf_size: CONFIG_BT_LE_HCI_EVT_BUF_SIZE as _,
240            multi_adv_instances: CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES as _,
241            ext_adv_max_size: CONFIG_BT_LE_EXT_ADV_MAX_SIZE as _,
242            dis_scan_backoff: false,
243            scan_backoff_max: CONFIG_BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX as _,
244            verify_access_address: false,
245            disconnect_llcp_conn_update: false,
246            disconnect_llcp_chan_map_update: false,
247            disconnect_llcp_phy_update: false,
248            cca_threshold: 65,
249            cca: false,
250            channel_assessment: false,
251            data_length_zero_aux: false,
252        }
253    }
254}
255
256impl Config {
257    pub(crate) fn validate(&self) -> Result<(), InvalidConfigError> {
258        crate::ble::validate_range!(
259            self,
260            task_priority,
261            0,
262            crate::preempt::max_task_priority().min(255) as u8
263        );
264        crate::ble::validate_range!(self, max_connections, 1, 35);
265        crate::ble::validate_range!(self, ll_rsp_dup_list_count, 1, 100);
266        crate::ble::validate_range!(self, ll_adv_dup_list_count, 1, 100);
267        crate::ble::validate_range!(self, whitelist_size, 1, 31);
268        crate::ble::validate_range!(self, multi_adv_instances, 0, 4);
269        crate::ble::validate_range!(self, ext_adv_max_size, 0, 1650);
270        crate::ble::validate_range!(self, scan_backoff_max, 1, 256);
271        crate::ble::validate_range!(self, cca_threshold, 20, 100);
272        Ok(())
273    }
274}
275
276pub(crate) fn create_ble_config(config: &Config) -> esp_bt_controller_config_t {
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: 32000,
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_tx_cca: config.cca as u8,
317        cca_rssi_thresh: (256 - config.cca_threshold as u32) as u8,
318        sleep_en: 0,
319        coex_phy_coded_tx_rx_time_limit: CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF as _,
320        dis_scan_backoff: config.dis_scan_backoff as u8,
321        ble_scan_classify_filter_enable: 1,
322        cca_drop_mode: 0,  //???
323        cca_low_tx_pwr: 0, //???
324        main_xtal_freq: 32,
325        ignore_wl_for_direct_adv: 0,
326        cpu_freq_mhz: 96,
327        enable_pcl: 0,
328        // version_num: esp_hal::efuse::minor_chip_version(),
329        csa2_select: CONFIG_BT_LE_50_FEATURE_SUPPORT as _,
330        enable_csr: 0,
331        ble_aa_check: config.verify_access_address as u8,
332        ble_llcp_disc_flag: config.disconnect_llcp_conn_update as u8
333            | ((config.disconnect_llcp_chan_map_update as u8) << 1)
334            | ((config.disconnect_llcp_phy_update as u8) << 2),
335        scan_backoff_upperlimitmax: config.scan_backoff_max,
336        ble_chan_ass_en: config.channel_assessment as u8,
337        ble_data_lenth_zero_aux: config.data_length_zero_aux as u8,
338        vhci_enabled: CONFIG_BT_LE_HCI_INTERFACE_USE_RAM as _,
339        ptr_check_enabled: 0,
340        ble_adv_tx_options: 0,
341        skip_unnecessary_checks_en: 0,
342        fast_conn_data_tx_en: 0,
343        ch39_txpwr: 9,
344        adv_rsv_cnt: 1,
345        conn_rsv_cnt: 2,
346        priority_level_cfg: 1 << 4 | 1 << 2,
347        slv_fst_rx_lat_en: 0,
348        dl_itvl_phy_sync_en: 0,
349        scan_allow_adi_filter: 0,
350        config_magic: CONFIG_MAGIC,
351    }
352}
353
354pub(crate) fn bt_periph_module_enable() {
355    crate::radio_clocks::clocks_ll::enable_bt(true);
356}
357
358pub(crate) fn disable_sleep_mode() {
359    // nothing
360}
361
362pub(super) unsafe extern "C" fn esp_intr_alloc(
363    source: u32,
364    flags: u32,
365    handler: *mut c_void,
366    arg: *mut c_void,
367    ret_handle: *mut *mut c_void,
368) -> i32 {
369    trace!(
370        "esp_intr_alloc {} {} {:?} {:?} {:?}",
371        source, flags, handler, arg, ret_handle
372    );
373
374    match source {
375        3 => unsafe {
376            ISR_INTERRUPT_3.set(handler, arg);
377            BT::steal().enable_lp_timer_interrupt(interrupt::Priority::Priority1);
378        },
379        15 => unsafe {
380            ISR_INTERRUPT_15.set(handler, arg);
381            BT::steal().enable_mac_interrupt(interrupt::Priority::Priority1);
382        },
383        _ => panic!("Unexpected interrupt source {}", source),
384    }
385
386    0
387}
388
389pub(super) fn ble_rtc_clk_init() {
390    // stealing BT is safe, since it is passed into the initialization function of the BLE
391    // controller.
392    crate::radio_clocks::clocks_ll::ble_rtc_clk_init();
393}
394
395pub(super) unsafe extern "C" fn reset_modem(_mdl_opts: u8, _start: u8) {
396    todo!()
397}
398
399#[unsafe(no_mangle)]
400#[crate::hal::ram]
401extern "C" fn LP_BLE_TIMER() {
402    ISR_INTERRUPT_3.dispatch();
403}
404
405#[unsafe(no_mangle)]
406#[crate::hal::ram]
407extern "C" fn BT_MAC() {
408    ISR_INTERRUPT_15.dispatch();
409}
410
411pub(crate) fn shutdown_ble_isr() {
412    unsafe {
413        BT::steal().disable_lp_timer_interrupt_on_all_cores();
414        BT::steal().disable_mac_interrupt_on_all_cores();
415    }
416}