use procmacros::BuilderLite;
use super::*;
#[cfg(multi_core)]
use crate::hal::system::Cpu;
use crate::{
ble::InvalidConfigError,
common_adapter::*,
hal::{interrupt::Priority, peripherals::BT},
interrupt_dispatch::Handler,
};
static ISR_INTERRUPT_5: Handler = Handler::new();
static ISR_INTERRUPT_8: Handler = Handler::new();
#[repr(C)]
pub(super) struct osi_funcs_s {
magic: u32,
version: u32,
interrupt_alloc: Option<
unsafe extern "C" fn(i32, i32, extern "C" fn(*const ()), *const (), *mut *const ()) -> i32,
>,
interrupt_free: Option<unsafe extern "C" fn(*const ()) -> i32>,
interrupt_handler_set: Option<unsafe extern "C" fn(i32, extern "C" fn(*const ()), *const ())>,
interrupt_disable: Option<unsafe extern "C" fn()>,
interrupt_restore: Option<unsafe extern "C" fn()>,
task_yield: Option<unsafe extern "C" fn()>,
task_yield_from_isr: Option<unsafe extern "C" fn()>,
semphr_create: Option<unsafe extern "C" fn(u32, u32) -> *mut c_void>,
semphr_delete: Option<unsafe extern "C" fn(*mut c_void)>,
semphr_take_from_isr: Option<unsafe extern "C" fn(*mut c_void, *mut bool) -> i32>,
semphr_give_from_isr: Option<unsafe extern "C" fn(*mut c_void, *mut bool) -> i32>,
semphr_take: Option<unsafe extern "C" fn(*mut c_void, u32) -> i32>,
semphr_give: Option<unsafe extern "C" fn(*mut c_void) -> i32>,
mutex_create: Option<unsafe extern "C" fn() -> *const ()>,
mutex_delete: Option<unsafe extern "C" fn(*const ())>,
mutex_lock: Option<unsafe extern "C" fn(*const ()) -> i32>,
mutex_unlock: Option<unsafe extern "C" fn(*const ()) -> i32>,
queue_create: Option<unsafe extern "C" fn(u32, u32) -> *mut c_void>,
queue_delete: Option<unsafe extern "C" fn(*mut c_void)>,
queue_send: Option<unsafe extern "C" fn(*mut c_void, *mut c_void, u32) -> i32>,
queue_send_from_isr: Option<unsafe extern "C" fn(*mut c_void, *mut c_void, *mut c_void) -> i32>,
queue_recv: Option<unsafe extern "C" fn(*mut c_void, *mut c_void, u32) -> i32>,
queue_recv_from_isr: Option<unsafe extern "C" fn(*mut c_void, *mut c_void, *mut c_void) -> i32>,
task_create: Option<
unsafe extern "C" fn(
*mut c_void,
*const c_char,
u32,
*mut c_void,
u32,
*mut c_void,
u32,
) -> i32,
>,
task_delete: Option<unsafe extern "C" fn(*mut ())>,
is_in_isr: Option<unsafe extern "C" fn() -> i32>,
cause_sw_intr_to_core: Option<unsafe extern "C" fn(i32, i32) -> i32>,
malloc: Option<unsafe extern "C" fn(u32) -> *mut c_void>,
malloc_internal: Option<unsafe extern "C" fn(u32) -> *mut c_void>,
free: Option<unsafe extern "C" fn(*mut c_void)>,
read_efuse_mac: Option<unsafe extern "C" fn(*const ()) -> i32>,
srand: Option<unsafe extern "C" fn(u32)>,
rand: Option<unsafe extern "C" fn() -> i32>,
btdm_lpcycles_2_hus: Option<unsafe extern "C" fn(u32, u32) -> u32>,
btdm_hus_2_lpcycles: Option<unsafe extern "C" fn(u32) -> u32>,
btdm_sleep_check_duration: Option<unsafe extern "C" fn(i32) -> i32>,
btdm_sleep_enter_phase1: Option<unsafe extern "C" fn(i32)>,
btdm_sleep_enter_phase2: Option<unsafe extern "C" fn()>,
btdm_sleep_exit_phase1: Option<unsafe extern "C" fn()>,
btdm_sleep_exit_phase2: Option<unsafe extern "C" fn()>,
btdm_sleep_exit_phase3: Option<unsafe extern "C" fn()>,
coex_wifi_sleep_set: Option<unsafe extern "C" fn(i32)>,
coex_core_ble_conn_dyn_prio_get: Option<unsafe extern "C" fn(*mut i32, *mut i32) -> i32>,
coex_schm_register_btdm_callback: Option<unsafe extern "C" fn(*mut c_void) -> i32>,
coex_schm_status_bit_set: Option<unsafe extern "C" fn(i32, i32)>,
coex_schm_status_bit_clear: Option<unsafe extern "C" fn(i32, i32)>,
coex_schm_interval_get: Option<unsafe extern "C" fn() -> u32>,
coex_schm_curr_period_get: Option<unsafe extern "C" fn() -> u8>,
coex_schm_curr_phase_get: Option<unsafe extern "C" fn() -> *mut c_void>,
interrupt_on: Option<unsafe extern "C" fn(i32) -> i32>,
interrupt_off: Option<unsafe extern "C" fn(i32) -> i32>,
esp_hw_power_down: Option<unsafe extern "C" fn()>,
esp_hw_power_up: Option<unsafe extern "C" fn()>,
ets_backup_dma_copy: Option<unsafe extern "C" fn(u32, u32, u32, i32)>,
ets_delay_us: Option<unsafe extern "C" fn(u32)>,
btdm_rom_table_ready: Option<unsafe extern "C" fn()>,
coex_bt_wakeup_request: Option<unsafe extern "C" fn()>,
coex_bt_wakeup_request_end: Option<unsafe extern "C" fn()>,
get_time_us: Option<unsafe extern "C" fn() -> u64>,
assert: Option<unsafe extern "C" fn()>,
}
pub(super) static G_OSI_FUNCS: osi_funcs_s = osi_funcs_s {
magic: 0xfadebead,
version: 0x0001000A,
interrupt_alloc: Some(interrupt_set),
interrupt_free: Some(interrupt_clear),
interrupt_handler_set: Some(interrupt_handler_set),
interrupt_disable: Some(interrupt_disable),
interrupt_restore: Some(interrupt_enable),
task_yield: Some(task_yield),
task_yield_from_isr: Some(task_yield_from_isr),
semphr_create: Some(semphr_create),
semphr_delete: Some(semphr_delete),
semphr_take_from_isr: Some(semphr_take_from_isr),
semphr_give_from_isr: Some(semphr_give_from_isr),
semphr_take: Some(semphr_take),
semphr_give: Some(semphr_give),
mutex_create: Some(mutex_create),
mutex_delete: Some(mutex_delete),
mutex_lock: Some(mutex_lock),
mutex_unlock: Some(mutex_unlock),
queue_create: Some(queue_create),
queue_delete: Some(queue_delete),
queue_send: Some(queue_send),
queue_send_from_isr: Some(queue_send_from_isr),
queue_recv: Some(queue_recv),
queue_recv_from_isr: Some(queue_recv_from_isr),
task_create: Some(task_create),
task_delete: Some(task_delete),
is_in_isr: Some(is_in_isr),
cause_sw_intr_to_core: None,
malloc: Some(crate::ble::malloc),
malloc_internal: Some(crate::ble::malloc_internal),
free: Some(crate::ble::free),
read_efuse_mac: Some(read_efuse_mac),
srand: Some(crate::ble::btdm::srand),
rand: Some(crate::ble::btdm::rand),
btdm_lpcycles_2_hus: Some(btdm_lpcycles_2_hus),
btdm_hus_2_lpcycles: Some(btdm_hus_2_lpcycles),
btdm_sleep_check_duration: Some(btdm_sleep_check_duration),
btdm_sleep_enter_phase1: Some(btdm_sleep_enter_phase1),
btdm_sleep_enter_phase2: Some(btdm_sleep_enter_phase2),
btdm_sleep_exit_phase1: Some(btdm_sleep_exit_phase1),
btdm_sleep_exit_phase2: Some(btdm_sleep_exit_phase2),
btdm_sleep_exit_phase3: Some(btdm_sleep_exit_phase3),
coex_wifi_sleep_set: Some(coex_wifi_sleep_set),
coex_core_ble_conn_dyn_prio_get: Some(coex_core_ble_conn_dyn_prio_get),
coex_schm_register_btdm_callback: Some(coex_schm_register_btdm_callback),
coex_schm_status_bit_set: Some(coex_schm_status_bit_set),
coex_schm_status_bit_clear: Some(coex_schm_status_bit_clear),
coex_schm_interval_get: Some(coex_schm_interval_get),
coex_schm_curr_period_get: Some(coex_schm_curr_period_get),
coex_schm_curr_phase_get: Some(coex_schm_curr_phase_get),
interrupt_on: Some(interrupt_on),
interrupt_off: Some(interrupt_off),
esp_hw_power_down: Some(esp_hw_power_down),
esp_hw_power_up: Some(esp_hw_power_up),
ets_backup_dma_copy: Some(ets_backup_dma_copy),
ets_delay_us: Some(ets_delay_us_wrapper),
btdm_rom_table_ready: Some(btdm_rom_table_ready_wrapper),
coex_bt_wakeup_request: Some(coex_bt_wakeup_request),
coex_bt_wakeup_request_end: Some(coex_bt_wakeup_request_end),
get_time_us: Some(get_time_us_wrapper),
assert: Some(assert_wrapper),
};
extern "C" fn get_time_us_wrapper() -> u64 {
crate::preempt::now()
}
extern "C" fn assert_wrapper() {
panic!("assert_wrapper called - inspect the logs");
}
extern_coex_fns! {
fn coex_core_ble_conn_dyn_prio_get(low: *mut i32, high: *mut i32) -> i32;
}
coex_fns! {
fn coex_schm_interval_get() -> u32;
fn coex_schm_curr_period_get() -> u8;
fn coex_schm_curr_phase_get() -> *mut c_void;
}
extern "C" fn coex_schm_register_btdm_callback(_callback: *mut c_void) -> i32 {
trace!("coex_schm_register_btdm_callback");
cfg_if::cfg_if! {
if #[cfg(feature = "coex")] {
unsafe {
const COEX_SCHM_CALLBACK_TYPE_BT: u32 = 1;
coex_schm_register_callback(COEX_SCHM_CALLBACK_TYPE_BT, _callback)
}
} else {
0
}
}
}
extern "C" fn coex_bt_wakeup_request() {
trace!("coex_bt_wakeup_request");
unsafe extern "C" {
fn btdm_wakeup_request();
}
unsafe {
btdm_wakeup_request();
}
}
extern "C" fn coex_bt_wakeup_request_end() {
trace!("coex_bt_wakeup_request_end");
unsafe extern "C" {
fn btdm_in_wakeup_requesting_set(set: bool);
}
unsafe {
btdm_in_wakeup_requesting_set(false);
}
}
extern "C" fn ets_delay_us_wrapper(us: u32) {
unsafe extern "C" {
fn ets_delay_us(us: u32);
}
unsafe {
ets_delay_us(us);
}
}
extern "C" fn btdm_rom_table_ready_wrapper() {
trace!("btdm_rom_table_ready_wrapper");
unsafe extern "C" {
fn ble_dtm_funcs_reset();
fn ble_42_adv_funcs_reset();
fn ble_init_funcs_reset();
fn ble_con_funcs_reset();
fn ble_scan_funcs_reset();
fn ble_ext_adv_funcs_reset();
fn ble_ext_scan_funcs_reset();
fn ble_base_funcs_reset();
fn ble_enc_funcs_reset();
}
unsafe {
ble_base_funcs_reset();
ble_42_adv_funcs_reset();
ble_ext_adv_funcs_reset();
ble_dtm_funcs_reset();
ble_scan_funcs_reset();
ble_ext_scan_funcs_reset();
ble_enc_funcs_reset();
ble_init_funcs_reset();
ble_con_funcs_reset();
}
}
unsafe extern "C" {
fn btdm_controller_rom_data_init() -> i32;
}
#[derive(Default, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Antenna {
#[default]
Antenna0 = 0,
Antenna1 = 1,
}
#[derive(Default, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TxPower {
N15,
N12,
N9,
N6,
N3,
N0,
P3,
P6,
#[default]
P9,
P12,
P15,
P18,
P20,
}
#[allow(dead_code)]
impl TxPower {
fn idx(self) -> esp_power_level_t {
match self {
Self::N15 => esp_power_level_t_ESP_PWR_LVL_N15,
Self::N12 => esp_power_level_t_ESP_PWR_LVL_N12,
Self::N9 => esp_power_level_t_ESP_PWR_LVL_N9,
Self::N6 => esp_power_level_t_ESP_PWR_LVL_N6,
Self::N3 => esp_power_level_t_ESP_PWR_LVL_N3,
Self::N0 => esp_power_level_t_ESP_PWR_LVL_N0,
Self::P3 => esp_power_level_t_ESP_PWR_LVL_P3,
Self::P6 => esp_power_level_t_ESP_PWR_LVL_P6,
Self::P9 => esp_power_level_t_ESP_PWR_LVL_P9,
Self::P12 => esp_power_level_t_ESP_PWR_LVL_P12,
Self::P15 => esp_power_level_t_ESP_PWR_LVL_P15,
Self::P18 => esp_power_level_t_ESP_PWR_LVL_P18,
Self::P20 => esp_power_level_t_ESP_PWR_LVL_P20,
}
}
fn dbm(self) -> i8 {
match self {
Self::N15 => -15,
Self::N12 => -12,
Self::N9 => -9,
Self::N6 => -6,
Self::N3 => -3,
Self::N0 => 0,
Self::P3 => 3,
Self::P6 => 6,
Self::P9 => 9,
Self::P12 => 12,
Self::P15 => 15,
Self::P18 => 18,
Self::P20 => 20,
}
}
}
#[derive(Default, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CcaMode {
#[default]
Disabled = 0,
HardwareTriggered = 1,
SoftwareTriggered = 2,
}
#[derive(BuilderLite, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Config {
task_priority: u8,
task_stack_size: u16,
#[cfg(multi_core)]
task_cpu: Cpu,
max_connections: u8,
qa_test_mode: bool,
scan_duplicate_list_count: u16,
scan_duplicate_refresh_period: u16,
verify_access_address: bool,
channel_assessment: bool,
ping: bool,
default_tx_antenna: Antenna,
default_rx_antenna: Antenna,
default_tx_power: TxPower,
limit_time_for_coded_phy_connection: bool,
hw_recorrect_en: bool,
cca_mode: CcaMode,
cca_threshold: u8,
data_length_zero_aux: bool,
dtm: bool,
encryption: bool,
connection: bool,
scan: bool,
adv: bool,
disconnect_llcp_conn_update: bool,
disconnect_llcp_chan_map_update: bool,
disconnect_llcp_phy_update: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
task_priority: crate::preempt::max_task_priority()
.saturating_sub(2)
.min(255) as u8,
task_stack_size: 8192, #[cfg(multi_core)]
task_cpu: Cpu::ProCpu,
max_connections: 6,
qa_test_mode: false,
scan_duplicate_list_count: 100,
scan_duplicate_refresh_period: 0,
verify_access_address: true,
channel_assessment: false,
ping: false,
default_tx_antenna: Antenna::default(),
default_rx_antenna: Antenna::default(),
default_tx_power: TxPower::default(),
limit_time_for_coded_phy_connection: false,
hw_recorrect_en: AGC_RECORRECT_EN != 0,
cca_threshold: 75, cca_mode: CcaMode::default(),
data_length_zero_aux: false,
dtm: true,
encryption: true,
connection: true,
scan: true,
adv: true,
disconnect_llcp_conn_update: false,
disconnect_llcp_chan_map_update: false,
disconnect_llcp_phy_update: false,
}
}
}
impl Config {
pub(crate) fn validate(&self) -> Result<(), InvalidConfigError> {
crate::ble::validate_range!(
self,
task_priority,
0,
crate::preempt::max_task_priority().min(255) as u8
);
crate::ble::validate_range!(self, max_connections, 1, 10);
crate::ble::validate_range!(self, scan_duplicate_list_count, 10, 1000);
crate::ble::validate_range!(self, scan_duplicate_refresh_period, 0, 1000);
crate::ble::validate_range!(self, cca_threshold, 20, 100);
Ok(())
}
}
pub(crate) fn create_ble_config(config: &Config) -> esp_bt_controller_config_t {
esp_bt_controller_config_t {
version: 0x02509280,
controller_task_stack_size: config.task_stack_size,
controller_task_prio: config.task_priority,
#[cfg(multi_core)]
controller_task_run_cpu: config.task_cpu as u8,
#[cfg(single_core)]
controller_task_run_cpu: 0,
bluetooth_mode: esp_bt_mode_t_ESP_BT_MODE_BLE as _,
ble_max_act: config.max_connections,
sleep_mode: 0,
sleep_clock: 0,
ble_st_acl_tx_buf_nb: 0,
ble_hw_cca_check: 0,
ble_adv_dup_filt_max: 30,
coex_param_en: false,
ce_len_type: 0,
coex_use_hooks: false,
hci_tl_type: 1,
hci_tl_funcs: core::ptr::null_mut(),
txant_dft: config.default_tx_antenna as u8,
rxant_dft: config.default_rx_antenna as u8,
txpwr_dft: config.default_tx_power as u8,
cfg_mask: CFG_MASK,
scan_duplicate_mode: 0, scan_duplicate_type: 0,
mesh_adv_size: 0,
normal_adv_size: config.scan_duplicate_list_count,
coex_phy_coded_tx_rx_time_limit: if cfg!(feature = "coex") {
config.limit_time_for_coded_phy_connection as u8
} else {
0
},
hw_target_code: if cfg!(esp32c3) {
0x01010000
} else {
0x02010000
},
slave_ce_len_min: SLAVE_CE_LEN_MIN_DEFAULT as _,
hw_recorrect_en: config.hw_recorrect_en as u8,
cca_thresh: config.cca_threshold,
dup_list_refresh_period: config.scan_duplicate_refresh_period,
scan_backoff_upperlimitmax: 0,
ble_50_feat_supp: BT_CTRL_50_FEATURE_SUPPORT != 0,
ble_cca_mode: config.cca_mode as u8,
ble_chan_ass_en: config.channel_assessment as u8,
ble_data_lenth_zero_aux: config.data_length_zero_aux as u8,
ble_ping_en: config.ping as u8,
ble_llcp_disc_flag: config.disconnect_llcp_conn_update as u8
| ((config.disconnect_llcp_chan_map_update as u8) << 1)
| ((config.disconnect_llcp_phy_update as u8) << 2),
run_in_flash: false,
dtm_en: config.dtm,
enc_en: config.encryption,
qa_test: config.qa_test_mode,
connect_en: config.connection,
scan_en: config.scan,
ble_aa_check: config.verify_access_address,
adv_en: config.adv,
magic: ESP_BT_CTRL_CONFIG_MAGIC_VAL,
}
}
pub(crate) unsafe extern "C" fn interrupt_on(intr_num: i32) -> i32 {
trace!("interrupt_on {}", intr_num);
0
}
pub(crate) unsafe extern "C" fn interrupt_off(_intr_num: i32) -> i32 {
todo!();
}
pub(crate) fn btdm_controller_mem_init() {
unsafe {
btdm_controller_rom_data_init();
}
}
pub(crate) fn bt_periph_module_enable() {
}
pub(crate) fn disable_sleep_mode() {
}
pub(crate) unsafe extern "C" fn interrupt_set(
cpu_no: i32,
intr_source: i32,
handler: extern "C" fn(*const ()),
arg: *const (),
ret_handle: *mut *const (),
) -> i32 {
trace!(
"interrupt_set {} {} {} {} {}",
cpu_no, intr_source, handler as usize, arg as u32, ret_handle as usize,
);
unsafe {
interrupt_handler_set(intr_source, handler, arg);
}
0
}
pub(crate) unsafe extern "C" fn interrupt_clear(_handler: *const ()) -> i32 {
todo!();
}
pub(crate) unsafe extern "C" fn interrupt_handler_set(
interrupt_no: i32,
func: extern "C" fn(*const ()),
arg: *const (),
) {
trace!(
"interrupt_handler_set {} {:?} {:?}",
interrupt_no, func, arg
);
match interrupt_no {
5 => unsafe {
ISR_INTERRUPT_5.set(func as *const c_void, arg.cast());
#[cfg(esp32c3)]
BT::steal().enable_rwbt_interrupt(Priority::Priority1);
BT::steal().enable_bb_interrupt(Priority::Priority1);
},
8 => unsafe {
ISR_INTERRUPT_8.set(func as *const c_void, arg.cast());
BT::steal().enable_rwble_interrupt(Priority::Priority1);
},
_ => panic!("Unsupported interrupt number {}", interrupt_no),
}
}
pub(crate) unsafe extern "C" fn coex_wifi_sleep_set(sleep: i32) {
trace!(
"ignored coex_wifi_sleep_set {} - because original implementation does the same",
sleep
);
}
pub(crate) unsafe extern "C" fn esp_hw_power_down() {
todo!();
}
pub(crate) unsafe extern "C" fn esp_hw_power_up() {
todo!();
}
pub(crate) unsafe extern "C" fn ets_backup_dma_copy(
_reg: u32,
_mem_addr: u32,
_num: u32,
_to_rem: i32,
) {
todo!();
}
#[cfg(esp32c3)]
#[unsafe(no_mangle)]
#[crate::hal::ram]
extern "C" fn RWBT() {
ISR_INTERRUPT_5.dispatch();
}
#[unsafe(no_mangle)]
#[crate::hal::ram]
extern "C" fn RWBLE() {
ISR_INTERRUPT_8.dispatch();
}
#[unsafe(no_mangle)]
#[crate::hal::ram]
extern "C" fn BT_BB() {
ISR_INTERRUPT_5.dispatch();
}
pub(crate) fn shutdown_ble_isr() {
unsafe {
#[cfg(esp32c3)]
BT::steal().disable_rwbt_interrupt_on_all_cores();
BT::steal().disable_rwble_interrupt_on_all_cores();
BT::steal().disable_bb_interrupt_on_all_cores();
}
}