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#[derive(Default, Clone, Copy, Eq, PartialEq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub enum TxPower {
18 N24,
20 N21,
22 N18,
24 N15,
26 N12,
28 N9,
30 N6,
32 N3,
34 N0,
36 P3,
38 P6,
40 #[default]
42 P9,
43 P12,
45 P15,
47 P18,
49 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#[derive(BuilderLite, Clone, Copy, Eq, PartialEq)]
100#[cfg_attr(feature = "defmt", derive(defmt::Format))]
101pub struct Config {
102 task_priority: u8,
104
105 task_stack_size: u16,
107
108 max_connections: u16,
112
113 qa_test_mode: bool,
115
116 bqb_test: bool,
118
119 ll_resolv_list_size: u16,
121
122 ll_sync_list_cnt: u8,
126
127 ll_sync_cnt: u8,
131
132 ll_rsp_dup_list_count: u16,
136
137 ll_adv_dup_list_count: u16,
141
142 verify_access_address: bool,
149
150 channel_assessment: bool,
152
153 default_tx_power: TxPower,
155
156 hci_high_buffer_count: u16,
158
159 hci_low_buffer_count: u16,
161
162 whitelist_size: u8,
164
165 acl_buf_size: u16,
167
168 acl_buf_count: u16,
170
171 hci_evt_buf_size: u16,
173
174 multi_adv_instances: u16,
176
177 ext_adv_max_size: u16,
181
182 dis_scan_backoff: bool,
184
185 scan_backoff_max: u16,
191
192 cca: bool,
194
195 cca_threshold: u8,
204
205 data_length_zero_aux: bool,
207
208 disconnect_llcp_conn_update: bool,
210
211 disconnect_llcp_chan_map_update: bool,
213
214 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 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, cca_low_tx_pwr: 0, main_xtal_freq: 32,
325 ignore_wl_for_direct_adv: 0,
326 cpu_freq_mhz: 96,
327 enable_pcl: 0,
328 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 }
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 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}