Skip to main content

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