esp_radio/ble/
os_adapter_esp32c6.rs

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