esp_radio/ble/
os_adapter_esp32h2.rs

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