| /**************************************************************************** |
| * arch/xtensa/src/esp32/esp32_ble_adapter.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| #include <stddef.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <assert.h> |
| #include <debug.h> |
| #include <pthread.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <clock/clock.h> |
| #include <sys/time.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| |
| #include <nuttx/kmalloc.h> |
| #include <nuttx/mqueue.h> |
| #include <nuttx/spinlock.h> |
| #include <nuttx/irq.h> |
| #include <nuttx/semaphore.h> |
| #include <nuttx/kthread.h> |
| #include <nuttx/wdog.h> |
| #include <nuttx/wqueue.h> |
| #include <nuttx/sched.h> |
| #include <nuttx/signal.h> |
| #include <irq/irq.h> |
| |
| #include "hardware/esp32_dport.h" |
| #include "hardware/wdev_reg.h" |
| #include "espidf_wifi.h" |
| #include "xtensa.h" |
| #include "xtensa_attr.h" |
| #include "esp32_rt_timer.h" |
| #include "esp32_ble_adapter.h" |
| #include "esp32_wireless.h" |
| #include "esp32_irq.h" |
| #include "esp32_spicache.h" |
| |
| #ifdef CONFIG_ESP32_WIFI_BT_COEXIST |
| # include "esp_coexist_internal.h" |
| #endif |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| typedef void (*xt_handler)(void *); |
| typedef void (*coex_func_cb_t)(uint32_t event, int sched_cnt); |
| |
| #define XTHAL_SET_INTSET(v) \ |
| do {\ |
| int __interrupt = (int)(v);\ |
| __asm__ __volatile__("wsr.intset %0" :: "a"(__interrupt):"memory");\ |
| } while(0) |
| |
| #define MSG_QUEUE_NAME_SIZE 16 |
| |
| #define OSI_FUNCS_TIME_BLOCKING 0xffffffff |
| #define OSI_VERSION 0x00010002 |
| #define OSI_MAGIC_VALUE 0xfadebead |
| |
| #define BTDM_ASYNC_WAKEUP_REQ_HCI 0 |
| #define BTDM_ASYNC_WAKEUP_REQ_COEX 1 |
| #define BTDM_ASYNC_WAKEUP_REQMAX 2 |
| |
| #ifdef CONFIG_PM |
| #define BTDM_MIN_TIMER_UNCERTAINTY_US (1800) |
| |
| /* Low Power Clock Selection */ |
| |
| #define BTDM_LPCLK_SEL_XTAL (0) |
| #define BTDM_LPCLK_SEL_XTAL32K (1) |
| #define BTDM_LPCLK_SEL_RTC_SLOW (2) |
| #define BTDM_LPCLK_SEL_8M (3) |
| |
| /* Sleep and wakeup interval control */ |
| |
| #define BTDM_MIN_SLEEP_DURATION (24) /* Threshold of interval in half slots to allow to fall into sleep mode */ |
| #define BTDM_MODEM_WAKE_UP_DELAY (8) /* delay in half slots of modem wake up procedure, including re-enable PHY/RF */ |
| #endif |
| |
| #define BTDM_MODEM_SLEEP_MODE_NONE 0 |
| |
| #define ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL 0x20200622 |
| |
| #ifdef CONFIG_ESP32_SPIFLASH |
| # define BLE_TASK_EVENT_QUEUE_ITEM_SIZE 8 |
| # define BLE_TASK_EVENT_QUEUE_LEN 8 |
| #endif |
| |
| #ifdef CONFIG_ESP32_BLE_INTERRUPT_SAVE_STATUS |
| # define NR_IRQSTATE_FLAGS CONFIG_ESP32_BLE_INTERRUPT_SAVE_STATUS |
| #else |
| # define NR_IRQSTATE_FLAGS 3 |
| #endif |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| /* Number of fractional bits in values returned by rtc_clk_cal */ |
| |
| #define RTC_CLK_CAL_FRACT 19 |
| |
| /* BLE message queue private data */ |
| |
| struct mq_adpt_s |
| { |
| struct file mq; /* Message queue handle */ |
| uint32_t msgsize; /* Message size */ |
| char name[MSG_QUEUE_NAME_SIZE]; /* Message queue name */ |
| }; |
| |
| /* BLE interrupt adapter private data */ |
| |
| struct irq_adpt_s |
| { |
| void (*func)(void *arg); /* Interrupt callback function */ |
| void *arg; /* Interrupt private data */ |
| }; |
| |
| /* BLE low power control struct */ |
| |
| typedef struct btdm_lpcntl_s |
| { |
| bool enable; /* whether low power mode is required */ |
| bool lpclk_sel; /* low power clock source */ |
| bool mac_bb_pd; /* whether hardware(MAC, BB) force-power-down is required during sleep */ |
| bool wakeup_timer_required; /* whether system timer is needed */ |
| bool no_light_sleep; /* do not allow system to enter light sleep after bluetooth is enabled */ |
| } btdm_lpcntl_t; |
| |
| /* low power control status */ |
| |
| typedef struct btdm_lpstat_s |
| { |
| bool pm_lock_released; /* whether power management lock is released */ |
| bool mac_bb_pd; /* whether hardware(MAC, BB) is powered down */ |
| bool phy_enabled; /* whether phy is switched on */ |
| bool wakeup_timer_started; /* whether wakeup timer is started */ |
| } btdm_lpstat_t; |
| |
| /* vendor dependent signals to be posted to controller task */ |
| |
| typedef enum |
| { |
| BTDM_VND_OL_SIG_WAKEUP_TMR, |
| BTDM_VND_OL_SIG_NUM, |
| } btdm_vnd_ol_sig_t; |
| |
| #ifdef CONFIG_PM |
| /* wakeup request sources */ |
| |
| typedef enum |
| { |
| BTDM_ASYNC_WAKEUP_SRC_VHCI, |
| BTDM_ASYNC_WAKEUP_SRC_DISA, |
| BTDM_ASYNC_WAKEUP_SRC_TMR, |
| BTDM_ASYNC_WAKEUP_SRC_MAX, |
| } btdm_wakeup_src_t; |
| #endif |
| |
| /* Superseded semaphore definition */ |
| |
| struct bt_sem_s |
| { |
| sem_t sem; |
| #ifdef CONFIG_ESP32_SPIFLASH |
| struct esp_semcache_s sc; |
| #endif |
| }; |
| |
| typedef enum |
| { |
| PERIPH_LEDC_MODULE = 0, |
| PERIPH_UART0_MODULE, |
| PERIPH_UART1_MODULE, |
| PERIPH_UART2_MODULE, |
| PERIPH_I2C0_MODULE, |
| PERIPH_I2C1_MODULE, |
| PERIPH_I2S0_MODULE, |
| PERIPH_I2S1_MODULE, |
| PERIPH_TIMG0_MODULE, |
| PERIPH_TIMG1_MODULE, |
| PERIPH_PWM0_MODULE, |
| PERIPH_PWM1_MODULE, |
| PERIPH_PWM2_MODULE, |
| PERIPH_PWM3_MODULE, |
| PERIPH_UHCI0_MODULE, |
| PERIPH_UHCI1_MODULE, |
| PERIPH_RMT_MODULE, |
| PERIPH_PCNT_MODULE, |
| PERIPH_SPI_MODULE, |
| PERIPH_HSPI_MODULE, |
| PERIPH_VSPI_MODULE, |
| PERIPH_SPI_DMA_MODULE, |
| PERIPH_SDMMC_MODULE, |
| PERIPH_SDIO_SLAVE_MODULE, |
| PERIPH_CAN_MODULE, |
| PERIPH_EMAC_MODULE, |
| PERIPH_RNG_MODULE, |
| PERIPH_WIFI_MODULE, |
| PERIPH_BT_MODULE, |
| PERIPH_WIFI_BT_COMMON_MODULE, |
| PERIPH_BT_BASEBAND_MODULE, |
| PERIPH_BT_LC_MODULE, |
| PERIPH_AES_MODULE, |
| PERIPH_SHA_MODULE, |
| PERIPH_RSA_MODULE, |
| } periph_module_e; |
| |
| /* prototype of function to handle vendor dependent signals */ |
| |
| typedef void (*btdm_vnd_ol_task_func_t)(void *param); |
| |
| /* VHCI function interface */ |
| |
| typedef struct vhci_host_callback_s |
| { |
| void (*notify_host_send_available)(void); /* callback used to notify that the host can send packet to controller */ |
| int (*notify_host_recv)(uint8_t *data, uint16_t len); /* callback used to notify that the controller has a packet to send to the host */ |
| } vhci_host_callback_t; |
| |
| /* DRAM region */ |
| |
| typedef struct btdm_dram_available_region_s |
| { |
| esp_bt_mode_t mode; |
| intptr_t start; |
| intptr_t end; |
| } btdm_dram_available_region_t; |
| |
| typedef void (*osi_intr_handler)(void); |
| |
| /* BLE OS function */ |
| |
| struct osi_funcs_s |
| { |
| uint32_t _version; |
| xt_handler (*_set_isr)(int n, xt_handler f, void *arg); |
| void (*_ints_on)(unsigned int mask); |
| void (*_interrupt_disable)(void); |
| void (*_interrupt_restore)(void); |
| void (*_task_yield)(void); |
| void (*_task_yield_from_isr)(void); |
| void *(*_semphr_create)(uint32_t max, uint32_t init); |
| void (*_semphr_delete)(void *semphr); |
| int32_t (*_semphr_take_from_isr)(void *semphr, void *hptw); |
| int32_t (*_semphr_give_from_isr)(void *semphr, void *hptw); |
| int32_t (*_semphr_take)(void *semphr, uint32_t block_time_ms); |
| int32_t (*_semphr_give)(void *semphr); |
| void *(*_mutex_create)(void); |
| void (*_mutex_delete)(void *mutex); |
| int32_t (*_mutex_lock)(void *mutex); |
| int32_t (*_mutex_unlock)(void *mutex); |
| void *(* _queue_create)(uint32_t queue_len, uint32_t item_size); |
| void (* _queue_delete)(void *queue); |
| int32_t (* _queue_send)(void *queue, void *item, uint32_t block_time_ms); |
| int32_t (* _queue_send_from_isr)(void *queue, void *item, void *hptw); |
| int32_t (* _queue_recv)(void *queue, void *item, uint32_t block_time_ms); |
| int32_t (* _queue_recv_from_isr)(void *queue, void *item, void *hptw); |
| int32_t (* _task_create)(void *task_func, |
| const char *name, |
| uint32_t stack_depth, |
| void *param, |
| uint32_t prio, |
| void *task_handle, |
| uint32_t core_id); |
| void (* _task_delete)(void *task_handle); |
| bool (* _is_in_isr)(void); |
| int (* _cause_sw_intr_to_core)(int core_id, int intr_no); |
| void *(* _malloc)(uint32_t size); |
| void *(* _malloc_internal)(uint32_t size); |
| void (* _free)(void *p); |
| int32_t (* _read_efuse_mac)(uint8_t mac[6]); |
| void (* _srand)(unsigned int seed); |
| int (* _rand)(void); |
| uint32_t (* _btdm_lpcycles_2_us)(uint32_t cycles); |
| uint32_t (* _btdm_us_2_lpcycles)(uint32_t us); |
| bool (* _btdm_sleep_check_duration)(uint32_t *slot_cnt); |
| void (* _btdm_sleep_enter_phase1)(uint32_t lpcycles); /* called when interrupt is disabled */ |
| void (* _btdm_sleep_enter_phase2)(void); |
| void (* _btdm_sleep_exit_phase1)(void); /* called from ISR */ |
| void (* _btdm_sleep_exit_phase2)(void); /* called from ISR */ |
| void (* _btdm_sleep_exit_phase3)(void); /* called from task */ |
| bool (* _coex_bt_wakeup_request)(void); |
| void (* _coex_bt_wakeup_request_end)(void); |
| int (* _coex_bt_request)(uint32_t event, |
| uint32_t latency, |
| uint32_t duration); |
| int (* _coex_bt_release)(uint32_t event); |
| int (* _coex_register_bt_cb)(coex_func_cb_t cb); |
| uint32_t (* _coex_bb_reset_lock)(void); |
| void (* _coex_bb_reset_unlock)(uint32_t restore); |
| int (* _coex_schm_register_btdm_callback)(void *callback); |
| void (* _coex_schm_status_bit_clear)(uint32_t type, uint32_t status); |
| void (* _coex_schm_status_bit_set)(uint32_t type, uint32_t status); |
| uint32_t (* _coex_schm_interval_get)(void); |
| uint8_t (* _coex_schm_curr_period_get)(void); |
| void *(* _coex_schm_curr_phase_get)(void); |
| int (* _coex_wifi_channel_get)(uint8_t *primary, uint8_t *secondary); |
| int (* _coex_register_wifi_channel_change_callback)(void *cb); |
| uint32_t _magic; |
| }; |
| |
| /* List of nested IRQ status flags */ |
| |
| struct irqstate_list_s |
| { |
| struct irqstate_list_s *flink; |
| irqstate_t flags; |
| }; |
| |
| /**************************************************************************** |
| * Private Function |
| ****************************************************************************/ |
| |
| static xt_handler esp_ble_set_isr(int n, xt_handler f, void *arg); |
| static void IRAM_ATTR interrupt_disable(void); |
| static void IRAM_ATTR interrupt_restore(void); |
| static void IRAM_ATTR task_yield_from_isr(void); |
| static void *semphr_create_wrapper(uint32_t max, uint32_t init); |
| static void semphr_delete_wrapper(void *semphr); |
| static int IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw); |
| static int IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw); |
| static int semphr_take_wrapper(void *semphr, uint32_t block_time_ms); |
| static int semphr_give_wrapper(void *semphr); |
| static void *mutex_create_wrapper(void); |
| static void mutex_delete_wrapper(void *mutex); |
| static int mutex_lock_wrapper(void *mutex); |
| static int mutex_unlock_wrapper(void *mutex); |
| static int IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, |
| void *hptw); |
| static int IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, |
| void *hptw); |
| static int task_create_wrapper(void *task_func, const char *name, |
| uint32_t stack_depth, void *param, |
| uint32_t prio, void *task_handle, |
| uint32_t core_id); |
| static void task_delete_wrapper(void *task_handle); |
| static bool IRAM_ATTR is_in_isr_wrapper(void); |
| static void *malloc_wrapper(size_t size); |
| static void IRAM_ATTR cause_sw_intr(void *arg); |
| static int IRAM_ATTR cause_sw_intr_to_core_wrapper(int core_id, int intr_no); |
| static void *malloc_internal_wrapper(size_t size); |
| static int IRAM_ATTR read_mac_wrapper(uint8_t mac[6]); |
| static void IRAM_ATTR srand_wrapper(unsigned int seed); |
| static int IRAM_ATTR rand_wrapper(void); |
| static uint32_t IRAM_ATTR btdm_lpcycles_2_us(uint32_t cycles); |
| static uint32_t IRAM_ATTR btdm_us_2_lpcycles(uint32_t us); |
| static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size); |
| static int queue_send_wrapper(void *queue, void *item, |
| uint32_t block_time_ms); |
| static int queue_recv_wrapper(void *queue, void *item, |
| uint32_t block_time_ms); |
| static void queue_delete_wrapper(void *queue); |
| static void esp32_ints_on(uint32_t mask); |
| static int adapter_coex_register_bt_cb_wrapper(coex_func_cb_t cb); |
| static int adapter_coex_schm_register_btdm_callback(void *callback); |
| static int adapter_coex_register_wifi_channel_change_callback(void *cb); |
| static int adapter_coex_wifi_channel_get(uint8_t *primary, |
| uint8_t *secondary); |
| static void adapter_coex_schm_status_bit_clear(uint32_t type, |
| uint32_t status); |
| static void adapter_coex_schm_status_bit_set(uint32_t type, uint32_t status); |
| static uint32_t adapter_coex_schm_interval_get(void); |
| static uint8_t adapter_coex_schm_curr_period_get(void); |
| static void *adapter_coex_schm_curr_phase_get(void); |
| |
| #ifdef CONFIG_PM |
| static bool IRAM_ATTR btdm_sleep_check_duration(int32_t *half_slot_cnt); |
| static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles); |
| static void btdm_sleep_enter_phase2_wrapper(void); |
| static void btdm_sleep_exit_phase3_wrapper(void); |
| #endif |
| |
| static bool coex_bt_wakeup_request(void); |
| static void coex_bt_wakeup_request_end(void); |
| static int esp_int_adpt_cb(int irq, void *context, void *arg); |
| |
| /**************************************************************************** |
| * Extern Functions declaration and value |
| ****************************************************************************/ |
| |
| extern int btdm_osi_funcs_register(void *osi_funcs); |
| extern void btdm_controller_rom_data_init(void); |
| extern void coex_bt_high_prio(void); |
| |
| /* Initialise and De-initialise */ |
| |
| extern int btdm_controller_init(uint32_t config_mask, |
| esp_bt_controller_config_t *config_opts); |
| extern void btdm_controller_deinit(void); |
| extern int btdm_controller_enable(esp_bt_mode_t mode); |
| extern void btdm_controller_disable(void); |
| extern uint8_t btdm_controller_get_mode(void); |
| extern const char *btdm_controller_get_compile_version(void); |
| extern void btdm_rf_bb_init_phase2(void); /* shall be called after PHY/RF is enabled */ |
| |
| /* Sleep */ |
| |
| extern void btdm_controller_enable_sleep(bool enable); |
| extern void btdm_controller_set_sleep_mode(uint8_t mode); |
| extern uint8_t btdm_controller_get_sleep_mode(void); |
| extern bool btdm_power_state_active(void); |
| extern void btdm_wakeup_request(bool request_lock); |
| extern void btdm_wakeup_request_end(void); |
| |
| /* Low Power Clock */ |
| |
| extern bool btdm_lpclk_select_src(uint32_t sel); |
| extern bool btdm_lpclk_set_div(uint32_t div); |
| extern int btdm_hci_tl_io_event_post(int event); |
| |
| /* VHCI */ |
| |
| extern bool api_vhci_host_check_send_available(void); /* Functions in bt lib */ |
| extern void api_vhci_host_send_packet(uint8_t * data, uint16_t len); |
| extern int api_vhci_host_register_callback(const vhci_host_callback_t |
| *callback); |
| |
| /* TX power */ |
| |
| extern int ble_txpwr_set(int power_type, int power_level); |
| extern int ble_txpwr_get(int power_type); |
| extern int bredr_txpwr_set(int min_power_level, int max_power_level); |
| extern int bredr_txpwr_get(int *min_power_level, int *max_power_level); |
| extern void bredr_sco_datapath_set(uint8_t data_path); |
| extern void btdm_controller_scan_duplicate_list_clear(void); |
| |
| /* Coexistence */ |
| |
| int coex_bt_request_wrapper(uint32_t event, |
| uint32_t latency, |
| uint32_t duration); |
| int coex_bt_release_wrapper(uint32_t event); |
| uint32_t coex_bb_reset_lock_wrapper(void); |
| void coex_bb_reset_unlock_wrapper(uint32_t restore); |
| extern void coex_ble_adv_priority_high_set(bool high); |
| extern int coex_bt_request(uint32_t event, |
| uint32_t latency, |
| uint32_t duration); |
| extern int coex_bt_release(uint32_t event); |
| extern int coex_enable(void); |
| extern int coex_register_bt_cb(coex_func_cb_t cb); |
| extern int coex_schm_register_btdm_callback(void *callback); |
| extern int coex_register_wifi_channel_change_callback(void *cb); |
| extern int coex_wifi_channel_get(uint8_t *primary, |
| uint8_t *secondary); |
| extern int coex_register_bt_cb(coex_func_cb_t cb); |
| extern void coex_bb_reset_unlock(uint32_t restore); |
| extern uint32_t coex_bb_reset_lock(void); |
| |
| extern uint8_t _bss_start_btdm[]; |
| extern uint8_t _bss_end_btdm[]; |
| extern uint8_t _data_start_btdm[]; |
| extern uint8_t _data_end_btdm[]; |
| extern const uint32_t _data_start_btdm_rom; |
| extern const uint32_t _data_end_btdm_rom; |
| |
| extern uint8_t _bt_bss_start[]; |
| extern uint8_t _bt_bss_end[]; |
| extern uint8_t _btdm_bss_start[]; |
| extern uint8_t _btdm_bss_end[]; |
| extern uint8_t _bt_data_start[]; |
| extern uint8_t _bt_data_end[]; |
| extern uint8_t _btdm_data_start[]; |
| extern uint8_t _btdm_data_end[]; |
| |
| extern uint8_t _bt_tmp_bss_start[]; |
| extern uint8_t _bt_tmp_bss_end[]; |
| |
| void intr_matrix_set(int cpu_no, uint32_t model_num, uint32_t intr_num); |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| /* Controller status */ |
| |
| static DRAM_ATTR esp_bt_controller_status_t btdm_controller_status = |
| ESP_BT_CONTROLLER_STATUS_IDLE; |
| |
| /* low power control struct */ |
| |
| static DRAM_ATTR btdm_lpcntl_t g_lp_cntl; |
| |
| /* low power status struct */ |
| |
| static DRAM_ATTR btdm_lpstat_t g_lp_stat; |
| |
| /* measured average low power clock period in micro seconds */ |
| |
| static DRAM_ATTR uint32_t g_btdm_lpcycle_us = 0; |
| |
| /* number of fractional bit for g_btdm_lpcycle_us */ |
| |
| static DRAM_ATTR uint8_t g_btdm_lpcycle_us_frac = 0; |
| |
| #ifdef CONFIG_PM |
| /* semaphore used for blocking VHCI API to wait for controller to wake up */ |
| |
| static DRAM_ATTR void * g_wakeup_req_sem = NULL; |
| |
| /* wakeup timer */ |
| |
| static DRAM_ATTR esp_timer_handle_t g_btdm_slp_tmr; |
| #endif |
| |
| /* BT interrupt private data */ |
| |
| static sq_queue_t g_int_flags_free; |
| |
| static sq_queue_t g_int_flags_used; |
| |
| static struct irqstate_list_s g_int_flags[NR_IRQSTATE_FLAGS]; |
| |
| /* Cached queue control variables */ |
| |
| #ifdef CONFIG_ESP32_SPIFLASH |
| static struct esp_queuecache_s g_esp_queuecache[BLE_TASK_EVENT_QUEUE_LEN]; |
| static uint8_t g_esp_queuecache_buffer[BLE_TASK_EVENT_QUEUE_ITEM_SIZE]; |
| #endif |
| |
| /**************************************************************************** |
| * Public Data |
| ****************************************************************************/ |
| |
| /* BLE OS adapter data */ |
| |
| static struct osi_funcs_s g_osi_funcs = |
| { |
| ._magic = OSI_MAGIC_VALUE, |
| ._version = OSI_VERSION, |
| ._set_isr = esp_ble_set_isr, |
| ._ints_on = esp32_ints_on, |
| ._interrupt_disable = interrupt_disable, |
| ._interrupt_restore = interrupt_restore, |
| ._task_yield = task_yield_from_isr, |
| ._task_yield_from_isr = task_yield_from_isr, |
| ._semphr_create = semphr_create_wrapper, |
| ._semphr_delete = semphr_delete_wrapper, |
| ._semphr_take_from_isr = semphr_take_from_isr_wrapper, |
| ._semphr_give_from_isr = semphr_give_from_isr_wrapper, |
| ._semphr_take = semphr_take_wrapper, |
| ._semphr_give = semphr_give_wrapper, |
| ._mutex_create = mutex_create_wrapper, |
| ._mutex_delete = mutex_delete_wrapper, |
| ._mutex_lock = mutex_lock_wrapper, |
| ._mutex_unlock = mutex_unlock_wrapper, |
| ._queue_create = queue_create_wrapper, |
| ._queue_delete = queue_delete_wrapper, |
| ._queue_send = queue_send_wrapper, |
| ._queue_send_from_isr = queue_send_from_isr_wrapper, |
| ._queue_recv = queue_recv_wrapper, |
| ._queue_recv_from_isr = queue_recv_from_isr_wrapper, |
| ._task_create = task_create_wrapper, |
| ._task_delete = task_delete_wrapper, |
| ._is_in_isr = is_in_isr_wrapper, |
| ._cause_sw_intr_to_core = cause_sw_intr_to_core_wrapper, |
| ._malloc = malloc_wrapper, |
| ._malloc_internal = malloc_internal_wrapper, |
| ._free = free, |
| ._read_efuse_mac = read_mac_wrapper, |
| ._srand = srand_wrapper, |
| ._rand = rand_wrapper, |
| ._btdm_lpcycles_2_us = btdm_lpcycles_2_us, |
| ._btdm_us_2_lpcycles = btdm_us_2_lpcycles, |
| #ifdef CONFIG_PM |
| ._btdm_sleep_check_duration = btdm_sleep_check_duration, |
| ._btdm_sleep_enter_phase1 = btdm_sleep_enter_phase1_wrapper, |
| ._btdm_sleep_enter_phase2 = btdm_sleep_enter_phase2_wrapper, |
| ._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper, |
| #endif |
| ._coex_bt_wakeup_request = coex_bt_wakeup_request, |
| ._coex_bt_wakeup_request_end = coex_bt_wakeup_request_end, |
| ._coex_bt_request = coex_bt_request_wrapper, |
| ._coex_bt_release = coex_bt_release_wrapper, |
| ._coex_register_bt_cb = adapter_coex_register_bt_cb_wrapper, |
| ._coex_register_wifi_channel_change_callback = |
| adapter_coex_register_wifi_channel_change_callback, |
| ._coex_wifi_channel_get = adapter_coex_wifi_channel_get, |
| ._coex_schm_status_bit_clear = adapter_coex_schm_status_bit_clear, |
| ._coex_schm_status_bit_set = adapter_coex_schm_status_bit_set, |
| ._coex_schm_interval_get = adapter_coex_schm_interval_get, |
| ._coex_schm_curr_period_get = adapter_coex_schm_curr_period_get, |
| ._coex_schm_curr_phase_get = adapter_coex_schm_curr_phase_get, |
| ._coex_schm_register_btdm_callback = |
| adapter_coex_schm_register_btdm_callback, |
| ._coex_bb_reset_lock = coex_bb_reset_lock_wrapper, |
| ._coex_bb_reset_unlock = coex_bb_reset_unlock_wrapper, |
| }; |
| |
| /* The mode column will be modified by release function to indicate the |
| * available region |
| */ |
| |
| static btdm_dram_available_region_t btdm_dram_available_region[] = |
| { |
| /* following is .data */ |
| |
| { |
| ESP_BT_MODE_BTDM, |
| SOC_MEM_BT_DATA_START, |
| SOC_MEM_BT_DATA_END |
| }, |
| |
| /* following is memory which HW will use */ |
| |
| { |
| ESP_BT_MODE_BTDM, |
| SOC_MEM_BT_EM_BTDM0_START, |
| SOC_MEM_BT_EM_BTDM0_END |
| }, |
| { |
| ESP_BT_MODE_BLE, |
| SOC_MEM_BT_EM_BLE_START, |
| SOC_MEM_BT_EM_BLE_END |
| }, |
| { |
| ESP_BT_MODE_BTDM, |
| SOC_MEM_BT_EM_BTDM1_START, |
| SOC_MEM_BT_EM_BTDM1_END |
| }, |
| { |
| ESP_BT_MODE_CLASSIC_BT, |
| SOC_MEM_BT_EM_BREDR_START, |
| SOC_MEM_BT_EM_BREDR_REAL_END |
| }, |
| |
| /* following is .bss */ |
| |
| { |
| ESP_BT_MODE_BTDM, |
| SOC_MEM_BT_BSS_START, |
| SOC_MEM_BT_BSS_END |
| }, |
| { |
| ESP_BT_MODE_BTDM, |
| SOC_MEM_BT_MISC_START, |
| SOC_MEM_BT_MISC_END |
| }, |
| }; |
| |
| extern void btdm_controller_set_sleep_mode(uint8_t mode); |
| |
| /**************************************************************************** |
| * Private Functions and Public Functions only used by libraries |
| ****************************************************************************/ |
| |
| static int adapter_coex_register_bt_cb_wrapper(coex_func_cb_t cb) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| return coex_register_bt_cb(cb); |
| #else |
| return 0; |
| #endif |
| } |
| |
| static int adapter_coex_schm_register_btdm_callback(void *callback) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| return coex_schm_register_btdm_callback(callback); |
| #else |
| return 0; |
| #endif |
| } |
| |
| static int adapter_coex_register_wifi_channel_change_callback(void *cb) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| return coex_register_wifi_channel_change_callback(cb); |
| #else |
| return -1; |
| #endif |
| } |
| |
| static int adapter_coex_wifi_channel_get(uint8_t *primary, |
| uint8_t *secondary) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| return coex_wifi_channel_get(primary, secondary); |
| #else |
| return -1; |
| #endif |
| } |
| |
| static void adapter_coex_schm_status_bit_clear(uint32_t type, |
| uint32_t status) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| coex_schm_status_bit_clear(type, status); |
| #endif |
| } |
| |
| static void adapter_coex_schm_status_bit_set(uint32_t type, uint32_t status) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| coex_schm_status_bit_set(type, status); |
| #endif |
| } |
| |
| static uint32_t adapter_coex_schm_interval_get(void) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| return coex_schm_interval_get(); |
| #else |
| return 0; |
| #endif |
| } |
| |
| static uint8_t adapter_coex_schm_curr_period_get(void) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| return coex_schm_interval_get(); |
| #else |
| return 0; |
| #endif |
| } |
| |
| static void *adapter_coex_schm_curr_phase_get(void) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| return coex_schm_curr_phase_get(); |
| #else |
| return NULL; |
| #endif |
| } |
| |
| /**************************************************************************** |
| * Name: esp_errno_trans |
| * |
| * Description: |
| * Transform from nuttx error code to Wi-Fi adapter error code |
| * |
| * Input Parameters: |
| * ret - NuttX error code |
| * |
| * Returned Value: |
| * Wi-Fi adapter error code |
| * |
| ****************************************************************************/ |
| |
| static inline int32_t esp_errno_trans(int ret) |
| { |
| if (!ret) |
| { |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: esp_task_create_pinned_to_core |
| * |
| * Description: |
| * Create task and bind it to target CPU, the task will run when it |
| * is created |
| * |
| * Input Parameters: |
| * entry - Task entry |
| * name - Task name |
| * stack_depth - Task stack size |
| * param - Task private data |
| * prio - Task priority |
| * task_handle - Task handle pointer which is used to pause, resume |
| * and delete the task |
| * core_id - CPU which the task runs in |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int32_t esp_task_create_pinned_to_core(void *entry, |
| const char *name, |
| uint32_t stack_depth, |
| void *param, |
| uint32_t prio, |
| void *task_handle, |
| uint32_t core_id) |
| { |
| int pid; |
| #ifdef CONFIG_SMP |
| int ret; |
| cpu_set_t cpuset; |
| #endif |
| |
| DEBUGASSERT(task_handle != NULL); |
| |
| #ifdef CONFIG_SMP |
| ret = sched_lock(); |
| if (ret) |
| { |
| wlerr("Failed to lock scheduler before creating pinned thread\n"); |
| return false; |
| } |
| #endif |
| |
| pid = kthread_create(name, prio, stack_depth, entry, |
| (char * const *)param); |
| if (pid > 0) |
| { |
| if (task_handle) |
| { |
| *((int *)task_handle) = pid; |
| } |
| |
| #ifdef CONFIG_SMP |
| if (core_id < CONFIG_SMP_NCPUS) |
| { |
| CPU_ZERO(&cpuset); |
| CPU_SET(core_id, &cpuset); |
| ret = nxsched_set_affinity(pid, sizeof(cpuset), &cpuset); |
| if (ret) |
| { |
| wlerr("Failed to set affinity error=%d\n", ret); |
| return false; |
| } |
| } |
| #endif |
| } |
| else |
| { |
| wlerr("Failed to create task, error %d\n", pid); |
| } |
| |
| #ifdef CONFIG_SMP |
| ret = sched_unlock(); |
| if (ret) |
| { |
| wlerr("Failed to unlock scheduler after creating pinned thread\n"); |
| return false; |
| } |
| #endif |
| |
| return pid > 0; |
| } |
| |
| /**************************************************************************** |
| * Name: esp_set_isr |
| * |
| * Description: |
| * Register interrupt function |
| * |
| * Input Parameters: |
| * n - Interrupt ID |
| * f - Interrupt function |
| * arg - Function private data |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static xt_handler esp_ble_set_isr(int n, xt_handler f, void *arg) |
| { |
| int ret; |
| uint32_t tmp; |
| struct irq_adpt_s *adapter; |
| int irq = esp32_getirq(0, n); |
| |
| wlinfo("n=%d f=%p arg=%p irq=%d\n", n, f, arg, irq); |
| |
| if (g_irqvector[irq].handler && |
| g_irqvector[irq].handler != irq_unexpected_isr) |
| { |
| wlinfo("irq=%d has been set handler=%p\n", irq, |
| g_irqvector[irq].handler); |
| return NULL; |
| } |
| |
| tmp = sizeof(struct irq_adpt_s); |
| adapter = kmm_malloc(tmp); |
| if (!adapter) |
| { |
| wlerr("Failed to alloc %d memory\n", tmp); |
| DEBUGPANIC(); |
| return NULL; |
| } |
| |
| adapter->func = f; |
| adapter->arg = arg; |
| |
| ret = irq_attach(irq, esp_int_adpt_cb, adapter); |
| if (ret) |
| { |
| wlerr("Failed to attach IRQ %d\n", irq); |
| DEBUGPANIC(); |
| return NULL; |
| } |
| |
| return NULL; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32_ints_on |
| * |
| * Description: |
| * Enable BLE interrupt |
| * |
| * Input Parameters: |
| * mask - Mask used to indicate the bits to enable interrupt. |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void esp32_ints_on(uint32_t mask) |
| { |
| uint32_t bit; |
| int irq; |
| |
| for (int i = 0; i < 32; i++) |
| { |
| bit = 1 << i; |
| if (bit & mask) |
| { |
| irq = esp32_getirq(0, i); |
| DEBUGVERIFY(esp32_irq_set_iram_isr(irq)); |
| up_enable_irq(irq); |
| wlinfo("Enabled bit %d\n", irq); |
| } |
| } |
| |
| UNUSED(irq); |
| } |
| |
| /**************************************************************************** |
| * Name: is_wifi_clk_peripheral |
| * |
| * Description: |
| * Checks if the peripheral module needs Wi-Fi Clock. |
| * |
| * Input Parameters: |
| * periph - The peripheral module |
| * |
| * Returned Value: |
| * true if it depends on Wi-Fi clock or false otherwise. |
| * |
| ****************************************************************************/ |
| |
| static bool is_wifi_clk_peripheral(periph_module_e periph) |
| { |
| /* A small subset of peripherals use WIFI_CLK_EN_REG and |
| * CORE_RST_EN_REG for their clock & reset registers |
| */ |
| |
| switch (periph) |
| { |
| case PERIPH_SDMMC_MODULE: |
| case PERIPH_SDIO_SLAVE_MODULE: |
| case PERIPH_EMAC_MODULE: |
| case PERIPH_RNG_MODULE: |
| case PERIPH_WIFI_MODULE: |
| case PERIPH_BT_MODULE: |
| case PERIPH_WIFI_BT_COMMON_MODULE: |
| case PERIPH_BT_BASEBAND_MODULE: |
| case PERIPH_BT_LC_MODULE: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: get_clk_en_mask |
| * |
| * Description: |
| * Returns the WIFI_BT clock mask case it is BLE peripheral. |
| * |
| * Input Parameters: |
| * periph - The peripheral module |
| * |
| * Returned Value: |
| * The clock peripheral mask. |
| * |
| ****************************************************************************/ |
| |
| static uint32_t get_clk_en_mask(periph_module_e periph) |
| { |
| switch (periph) |
| { |
| case PERIPH_BT_MODULE: |
| return DPORT_WIFI_CLK_BT_EN_M; |
| default: |
| return 0; |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: get_rst_en_mask |
| * |
| * Description: |
| * Returns the WIFI_BT reset mask |
| * |
| * Input Parameters: |
| * periph - The peripheral module |
| * enable - Enable/Disable |
| * |
| * Returned Value: |
| * The reset peripheral mask. |
| * |
| ****************************************************************************/ |
| |
| static uint32_t get_rst_en_mask(periph_module_e periph, bool enable) |
| { |
| return 0; |
| } |
| |
| /**************************************************************************** |
| * Name: get_clk_en_reg |
| * |
| * Description: |
| * Returns the WIFI_BT clock register |
| * |
| * Input Parameters: |
| * periph - The peripheral module |
| * |
| * Returned Value: |
| * The clock peripheral register. |
| * |
| ****************************************************************************/ |
| |
| static uint32_t get_clk_en_reg(periph_module_e periph) |
| { |
| return is_wifi_clk_peripheral(periph) ? DPORT_WIFI_CLK_EN_REG : |
| DPORT_PERIP_CLK_EN_REG; |
| } |
| |
| /**************************************************************************** |
| * Name: get_rst_en_reg |
| * |
| * Description: |
| * Returns the WIFI_BT reset register |
| * |
| * Input Parameters: |
| * periph - The peripheral module |
| * |
| * Returned Value: |
| * The reset peripheral register. |
| * |
| ****************************************************************************/ |
| |
| static uint32_t get_rst_en_reg(periph_module_e periph) |
| { |
| return is_wifi_clk_peripheral(periph) ? DPORT_CORE_RST_EN_REG : |
| DPORT_PERIP_RST_EN_REG; |
| } |
| |
| /**************************************************************************** |
| * Name: bt_periph_module_enable |
| * |
| * Description: |
| * Enable the bluetooth module |
| * |
| * Input Parameters: |
| * periph - The peripheral module |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void bt_periph_module_enable(periph_module_e periph) |
| { |
| modifyreg32(get_clk_en_reg(periph), 0, get_clk_en_mask(periph)); |
| modifyreg32(get_rst_en_reg(periph), get_rst_en_mask(periph, true), 0); |
| } |
| |
| /**************************************************************************** |
| * Name: esp_int_adpt_cb |
| * |
| * Description: |
| * BT interrupt adapter callback function |
| * |
| * Input Parameters: |
| * arg - interrupt adapter private data |
| * |
| * Returned Value: |
| * NuttX error code |
| * |
| ****************************************************************************/ |
| |
| static int IRAM_ATTR esp_int_adpt_cb(int irq, void *context, void *arg) |
| { |
| struct irq_adpt_s *adapter = (struct irq_adpt_s *)arg; |
| |
| adapter->func(adapter->arg); |
| |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: interrupt_disable |
| * |
| * Description: |
| * Enter critical section by disabling interrupts and taking the spin lock |
| * if in SMP mode. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None. |
| * |
| ****************************************************************************/ |
| |
| static void IRAM_ATTR interrupt_disable(void) |
| { |
| struct irqstate_list_s *irqstate; |
| |
| irqstate = (struct irqstate_list_s *)sq_remlast(&g_int_flags_free); |
| |
| DEBUGASSERT(irqstate != NULL); |
| |
| irqstate->flags = enter_critical_section(); |
| |
| sq_addlast((sq_entry_t *)irqstate, &g_int_flags_used); |
| } |
| |
| /**************************************************************************** |
| * Name: interrupt_restore |
| * |
| * Description: |
| * Exit from critical section by enabling interrupts and releasing the spin |
| * lock if in SMP mode. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void IRAM_ATTR interrupt_restore(void) |
| { |
| struct irqstate_list_s *irqstate; |
| |
| irqstate = (struct irqstate_list_s *)sq_remlast(&g_int_flags_used); |
| |
| DEBUGASSERT(irqstate != NULL); |
| |
| leave_critical_section(irqstate->flags); |
| |
| sq_addlast((sq_entry_t *)irqstate, &g_int_flags_free); |
| } |
| |
| /**************************************************************************** |
| * Name: task_yield_from_isr |
| * |
| * Description: |
| * Do nothing in NuttX |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void IRAM_ATTR task_yield_from_isr(void) |
| { |
| } |
| |
| /**************************************************************************** |
| * Name: semphr_create_wrapper |
| * |
| * Description: |
| * Create and initialize semaphore |
| * |
| * Input Parameters: |
| * max - Unused |
| * init - semaphore initialization value |
| * |
| * Returned Value: |
| * Semaphore data pointer |
| * |
| ****************************************************************************/ |
| |
| static void *semphr_create_wrapper(uint32_t max, uint32_t init) |
| { |
| int ret; |
| struct bt_sem_s *bt_sem; |
| int tmp; |
| |
| tmp = sizeof(struct bt_sem_s); |
| bt_sem = kmm_malloc(tmp); |
| DEBUGASSERT(bt_sem); |
| if (!bt_sem) |
| { |
| wlerr("ERROR: Failed to alloc %d memory\n", tmp); |
| return NULL; |
| } |
| |
| ret = nxsem_init(&bt_sem->sem, 0, init); |
| DEBUGASSERT(ret == OK); |
| if (ret) |
| { |
| wlerr("ERROR: Failed to initialize sem error=%d\n", ret); |
| kmm_free(bt_sem); |
| return NULL; |
| } |
| |
| #ifdef CONFIG_ESP32_SPIFLASH |
| esp_init_semcache(&bt_sem->sc, &bt_sem->sem); |
| #endif |
| |
| return bt_sem; |
| } |
| |
| /**************************************************************************** |
| * Name: semphr_delete_wrapper |
| * |
| * Description: |
| * Delete semaphore |
| * |
| * Input Parameters: |
| * semphr - Semaphore data pointer |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void semphr_delete_wrapper(void *semphr) |
| { |
| struct bt_sem_s *bt_sem = (struct bt_sem_s *)semphr; |
| sem_destroy(&bt_sem->sem); |
| kmm_free(bt_sem); |
| } |
| |
| /**************************************************************************** |
| * Name: semphr_take_from_isr_wrapper |
| * |
| * Description: |
| * Take a semaphore from an ISR |
| * |
| * Input Parameters: |
| * semphr - Semaphore data pointer. |
| * hptw - Unused. |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw) |
| { |
| *(int *)hptw = 0; |
| |
| DEBUGPANIC(); |
| return 0; |
| } |
| |
| /**************************************************************************** |
| * Name: semphr_give_from_isr_wrapper |
| * |
| * Description: |
| * Post semaphore |
| * |
| * Input Parameters: |
| * semphr - Semaphore data pointer |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw) |
| { |
| int ret; |
| struct bt_sem_s *bt_sem = (struct bt_sem_s *)semphr; |
| |
| #ifdef CONFIG_ESP32_SPIFLASH |
| if (spi_flash_cache_enabled()) |
| { |
| ret = semphr_give_wrapper(bt_sem); |
| } |
| else |
| { |
| esp_post_semcache(&bt_sem->sc); |
| ret = 0; |
| } |
| #else |
| ret = semphr_give_wrapper(bt_sem); |
| #endif |
| |
| return esp_errno_trans(ret); |
| } |
| |
| /**************************************************************************** |
| * Name: esp_update_time |
| * |
| * Description: |
| * Transform ticks to time and add this time to timespec value |
| * |
| * Input Parameters: |
| * ticks - System ticks |
| * |
| * Output Parameters: |
| * timespec - Input timespec data pointer |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void esp_update_time(struct timespec *timespec, uint32_t ticks) |
| { |
| uint32_t tmp; |
| |
| tmp = TICK2SEC(ticks); |
| timespec->tv_sec += tmp; |
| |
| ticks -= SEC2TICK(tmp); |
| tmp = TICK2NSEC(ticks); |
| |
| timespec->tv_nsec += tmp; |
| } |
| |
| /**************************************************************************** |
| * Name: semphr_take_wrapper |
| * |
| * Description: |
| * Wait semaphore within a certain period of time |
| * |
| * Input Parameters: |
| * semphr - Semaphore data pointer |
| * block_time_ms - Wait time |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int semphr_take_wrapper(void *semphr, uint32_t block_time_ms) |
| { |
| int ret; |
| struct bt_sem_s *bt_sem = (struct bt_sem_s *)semphr; |
| |
| if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) |
| { |
| ret = nxsem_wait(&bt_sem->sem); |
| } |
| else |
| { |
| if (block_time_ms > 0) |
| { |
| ret = nxsem_tickwait(&bt_sem->sem, MSEC2TICK(block_time_ms)); |
| } |
| else |
| { |
| ret = nxsem_trywait(&bt_sem->sem); |
| } |
| } |
| |
| if (ret) |
| { |
| wlerr("ERROR: Failed to wait sem in %u ticks. Error=%d\n", |
| MSEC2TICK(block_time_ms), ret); |
| } |
| |
| return esp_errno_trans(ret); |
| } |
| |
| /**************************************************************************** |
| * Name: semphr_give_wrapper |
| * |
| * Description: |
| * Post semaphore |
| * |
| * Input Parameters: |
| * semphr - Semaphore data pointer |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int semphr_give_wrapper(void *semphr) |
| { |
| int ret; |
| struct bt_sem_s *bt_sem = (struct bt_sem_s *)semphr; |
| |
| ret = nxsem_post(&bt_sem->sem); |
| if (ret) |
| { |
| wlerr("Failed to post sem error=%d\n", ret); |
| } |
| |
| return esp_errno_trans(ret); |
| } |
| |
| /**************************************************************************** |
| * Name: mutex_create_wrapper |
| * |
| * Description: |
| * Create mutex |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * Mutex data pointer |
| * |
| ****************************************************************************/ |
| |
| static void *mutex_create_wrapper(void) |
| { |
| int ret; |
| pthread_mutex_t *mutex; |
| int tmp; |
| |
| tmp = sizeof(pthread_mutex_t); |
| mutex = kmm_malloc(tmp); |
| DEBUGASSERT(mutex); |
| |
| ret = pthread_mutex_init(mutex, NULL); |
| if (ret) |
| { |
| wlerr("Failed to initialize mutex error=%d\n", ret); |
| kmm_free(mutex); |
| return NULL; |
| } |
| |
| return mutex; |
| } |
| |
| /**************************************************************************** |
| * Name: mutex_delete_wrapper |
| * |
| * Description: |
| * Delete mutex |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * Mutex data pointer |
| * |
| ****************************************************************************/ |
| |
| static void mutex_delete_wrapper(void *mutex) |
| { |
| pthread_mutex_destroy(mutex); |
| kmm_free(mutex); |
| } |
| |
| /**************************************************************************** |
| * Name: mutex_lock_wrapper |
| * |
| * Description: |
| * Lock mutex |
| * |
| * Input Parameters: |
| * mutex_data - mutex data pointer |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int mutex_lock_wrapper(void *mutex) |
| { |
| int ret; |
| |
| ret = pthread_mutex_lock(mutex); |
| if (ret) |
| { |
| wlerr("Failed to lock mutex error=%d\n", ret); |
| } |
| |
| return esp_errno_trans(ret); |
| } |
| |
| /**************************************************************************** |
| * Name: mutex_unlock_wrapper |
| * |
| * Description: |
| * Unlock mutex |
| * |
| * Input Parameters: |
| * mutex_data - mutex data pointer |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int mutex_unlock_wrapper(void *mutex) |
| { |
| int ret; |
| |
| ret = pthread_mutex_unlock(mutex); |
| if (ret) |
| { |
| wlerr("Failed to unlock mutex error=%d\n", ret); |
| } |
| |
| return esp_errno_trans(ret); |
| } |
| |
| /**************************************************************************** |
| * Name: esp_queue_send_generic |
| * |
| * Description: |
| * Generic send message to queue within a certain period of time |
| * |
| * Input Parameters: |
| * queue - Message queue data pointer |
| * item - Message data pointer |
| * ticks - Wait ticks |
| * prio - Message priority |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static IRAM_ATTR int32_t esp_queue_send_generic(void *queue, void *item, |
| uint32_t ticks, int prio) |
| { |
| int ret; |
| struct timespec timeout; |
| struct mq_adpt_s *mq_adpt = (struct mq_adpt_s *)queue; |
| |
| #ifdef CONFIG_ESP32_SPIFLASH |
| if (!spi_flash_cache_enabled()) |
| { |
| esp_send_queuecache(queue, item, mq_adpt->msgsize); |
| return esp_errno_trans(OK); |
| } |
| #endif |
| |
| if (ticks == OSI_FUNCS_TIME_BLOCKING || ticks == 0) |
| { |
| /* BLE interrupt function will call this adapter function to send |
| * message to message queue, so here we should call kernel API |
| * instead of application API |
| */ |
| |
| ret = file_mq_send(&mq_adpt->mq, (const char *)item, |
| mq_adpt->msgsize, prio); |
| if (ret < 0) |
| { |
| wlerr("Failed to send message to mqueue error=%d\n", ret); |
| } |
| } |
| else |
| { |
| ret = clock_gettime(CLOCK_REALTIME, &timeout); |
| if (ret < 0) |
| { |
| wlerr("Failed to get time %d\n", ret); |
| return esp_errno_trans(ret); |
| } |
| |
| if (ticks) |
| { |
| esp_update_time(&timeout, ticks); |
| } |
| |
| ret = file_mq_timedsend(&mq_adpt->mq, (const char *)item, |
| mq_adpt->msgsize, prio, &timeout); |
| if (ret < 0) |
| { |
| wlerr("Failed to timedsend message to mqueue error=%d\n", ret); |
| } |
| } |
| |
| return esp_errno_trans(ret); |
| } |
| |
| /**************************************************************************** |
| * Name: queue_send_from_isr_wrapper |
| * |
| * Description: |
| * Send message of low priority to queue in ISR within |
| * a certain period of time |
| * |
| * Input Parameters: |
| * queue - Message queue data pointer |
| * item - Message data pointer |
| * hptw - Unused |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int IRAM_ATTR queue_send_from_isr_wrapper(void *queue, |
| void *item, |
| void *hptw) |
| { |
| *((int *)hptw) = false; |
| return esp_queue_send_generic(queue, item, 0, 0); |
| } |
| |
| /**************************************************************************** |
| * Name: queue_recv_from_isr_wrapper |
| * |
| * Description: |
| * Receive message from queue within a certain period of time |
| * |
| * Input Parameters: |
| * queue - Message queue data pointer |
| * item - Message data pointer |
| * hptw - Unused |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, |
| void *item, |
| void *hptw) |
| { |
| DEBUGPANIC(); |
| return 0; |
| } |
| |
| /**************************************************************************** |
| * Name: task_create_wrapper |
| * |
| * Description: |
| * Create task and the task will run when it is created |
| * |
| * Input Parameters: |
| * entry - Task entry |
| * name - Task name |
| * stack_depth - Task stack size |
| * param - Task private data |
| * prio - Task priority |
| * task_handle - Task handle pointer which is used to pause, resume |
| * and delete the task |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int task_create_wrapper(void *task_func, const char *name, |
| uint32_t stack_depth, void *param, |
| uint32_t prio, void *task_handle, |
| uint32_t core_id) |
| { |
| return esp_task_create_pinned_to_core(task_func, name, |
| stack_depth, param, |
| prio, task_handle, core_id); |
| } |
| |
| /**************************************************************************** |
| * Name: task_delete_wrapper |
| * |
| * Description: |
| * Delete the target task |
| * |
| * Input Parameters: |
| * task_handle - Task handle pointer which is used to pause, resume |
| * and delete the task |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void task_delete_wrapper(void *task_handle) |
| { |
| pid_t pid = (pid_t)((uintptr_t)task_handle); |
| kthread_delete(pid); |
| } |
| |
| /**************************************************************************** |
| * Name: is_in_isr_wrapper |
| * |
| * Description: |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static bool IRAM_ATTR is_in_isr_wrapper(void) |
| { |
| return false; |
| } |
| |
| /**************************************************************************** |
| * Name: malloc_wrapper |
| * |
| * Description: |
| * Malloc buffer |
| * |
| * Input Parameters: |
| * size - buffer size |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void *malloc_wrapper(size_t size) |
| { |
| void * p = NULL; |
| |
| p = kmm_malloc(size); |
| DEBUGASSERT(p); |
| |
| return p; |
| } |
| |
| /**************************************************************************** |
| * Name: cause_sw_intr |
| * |
| * Description: |
| * Set a software interrupt bit |
| * |
| * Input Parameters: |
| * arg - number of the bit as void pointer |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void IRAM_ATTR cause_sw_intr(void *arg) |
| { |
| /* just convert void * to int, because the width is the same */ |
| |
| uint32_t intr_no = (uint32_t)arg; |
| XTHAL_SET_INTSET((1 << intr_no)); |
| } |
| |
| /**************************************************************************** |
| * Name: cause_sw_intr_to_core_wrapper |
| * |
| * Description: |
| * Just a wrapper to cause_sw_intr |
| * |
| * Input Parameters: |
| * core_id - ID of the CPU core, not used. |
| * intr_no - Number of the software interrupt |
| * |
| * Returned Value: |
| * Always return OK. |
| * |
| ****************************************************************************/ |
| |
| static int IRAM_ATTR cause_sw_intr_to_core_wrapper(int core_id, int intr_no) |
| { |
| cause_sw_intr((void *)intr_no); |
| return ESP_OK; |
| } |
| |
| /**************************************************************************** |
| * Name: malloc_internal_wrapper |
| * |
| * Description: |
| * Malloc buffer in DRAM |
| * |
| * Input Parameters: |
| * szie - buffer size |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void *malloc_internal_wrapper(size_t size) |
| { |
| void * p = NULL; |
| |
| p = kmm_malloc(size); |
| DEBUGASSERT(p); |
| |
| return p; |
| } |
| |
| /**************************************************************************** |
| * Name: read_mac_wrapper |
| * |
| * Description: |
| * Get Mac Address |
| * |
| * Input Parameters: |
| * mac - mac address |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static int IRAM_ATTR read_mac_wrapper(uint8_t mac[6]) |
| { |
| return esp_read_mac(mac, ESP_MAC_BT); |
| } |
| |
| /**************************************************************************** |
| * Name: srand_wrapper |
| * |
| * Description: |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void IRAM_ATTR srand_wrapper(unsigned int seed) |
| { |
| /* empty function */ |
| } |
| |
| /**************************************************************************** |
| * Name: rand_wrapper |
| * |
| * Description: |
| * Get random value. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * Random value |
| * |
| ****************************************************************************/ |
| |
| static int IRAM_ATTR rand_wrapper(void) |
| { |
| return getreg32(WDEV_RND_REG); |
| } |
| |
| /**************************************************************************** |
| * Name: btdm_lpcycles_2_us |
| * |
| * Description: |
| * Converts a number of low power clock cycles into a duration in us |
| * |
| * Input Parameters: |
| * cycles - number of CPU cycles |
| * |
| * Returned Value: |
| * us - value equivalent to the CPU cycles |
| * |
| ****************************************************************************/ |
| |
| static uint32_t IRAM_ATTR btdm_lpcycles_2_us(uint32_t cycles) |
| { |
| uint64_t us = (uint64_t)g_btdm_lpcycle_us * cycles; |
| us = (us + (1 << (g_btdm_lpcycle_us_frac - 1))) >> g_btdm_lpcycle_us_frac; |
| return (uint32_t)us; |
| } |
| |
| /**************************************************************************** |
| * Name: btdm_us_2_lpcycles |
| * |
| * Description: |
| * Converts a duration in half us into a number of low power clock cycles. |
| * |
| * Input Parameters: |
| * us |
| * |
| * Returned Value: |
| * cycles |
| * |
| ****************************************************************************/ |
| |
| static uint32_t IRAM_ATTR btdm_us_2_lpcycles(uint32_t us) |
| { |
| uint64_t cycles; |
| cycles = ((uint64_t)(us) << g_btdm_lpcycle_us_frac) / g_btdm_lpcycle_us; |
| return (uint32_t)cycles; |
| } |
| |
| #ifdef CONFIG_PM |
| /**************************************************************************** |
| * Name: btdm_sleep_exit_phase0 |
| * |
| * Description: |
| * Acquire PM lock and stop esp timer. |
| * |
| * Input Parameters: |
| * param - wakeup event |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void IRAM_ATTR btdm_sleep_exit_phase0(void *param) |
| { |
| int event = (int)param; |
| |
| DEBUGASSERT(g_lp_cntl.enable == true); |
| |
| if (g_lp_stat.pm_lock_released) |
| { |
| esp32_pm_lockacquire(); |
| g_lp_stat.pm_lock_released = false; |
| } |
| |
| if (event == BTDM_ASYNC_WAKEUP_SRC_VHCI || |
| event == BTDM_ASYNC_WAKEUP_SRC_DISA) |
| { |
| btdm_wakeup_request(); |
| } |
| |
| if (g_lp_cntl.wakeup_timer_required && g_lp_stat.wakeup_timer_started) |
| { |
| esp_timer_stop(g_btdm_slp_tmr); |
| g_lp_stat.wakeup_timer_started = false; |
| } |
| |
| if (event == BTDM_ASYNC_WAKEUP_SRC_VHCI || |
| event == BTDM_ASYNC_WAKEUP_SRC_DISA) |
| { |
| semphr_give_wrapper(g_wakeup_req_sem); |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: btdm_slp_tmr_callback |
| * |
| * Description: |
| * ESP BLE sleep callback function. |
| * |
| * Input Parameters: |
| * arg - Unused |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void IRAM_ATTR btdm_slp_tmr_callback(void *arg) |
| { |
| btdm_vnd_offload_post(BTDM_VND_OL_SIG_WAKEUP_TMR, |
| (void *)BTDM_ASYNC_WAKEUP_SRC_TMR); |
| } |
| |
| /**************************************************************************** |
| * Name: btdm_sleep_check_duration |
| * |
| * Description: |
| * Wake up in advance considering the delay in enabling PHY/RF. |
| * |
| * Input Parameters: |
| * half_slot_cnt - half slots to allow to fall into modem sleep |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static bool IRAM_ATTR btdm_sleep_check_duration(int32_t *half_slot_cnt) |
| { |
| if (*half_slot_cnt < BTDM_MIN_SLEEP_DURATION) |
| { |
| return false; |
| } |
| |
| *half_slot_cnt -= BTDM_MODEM_WAKE_UP_DELAY; |
| return true; |
| } |
| |
| /**************************************************************************** |
| * Name: btdm_sleep_enter_phase1_wrapper |
| * |
| * Description: |
| * ESP32 BLE lightsleep callback function. |
| * |
| * Input Parameters: |
| * lpcycles - light sleep cycles |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles) |
| { |
| uint32_t us_to_sleep; |
| uint32_t uncertainty; |
| |
| if (g_lp_cntl.wakeup_timer_required == false) |
| { |
| return; |
| } |
| |
| /* start a timer to wake up and acquire the pm_lock before sleep awakes */ |
| |
| us_to_sleep = btdm_lpcycles_2_us(lpcycles, NULL); |
| |
| DEBUGASSERT(us_to_sleep > BTDM_MIN_TIMER_UNCERTAINTY_US); |
| uncertainty = (us_to_sleep >> 11); |
| |
| if (uncertainty < BTDM_MIN_TIMER_UNCERTAINTY_US) |
| { |
| uncertainty = BTDM_MIN_TIMER_UNCERTAINTY_US; |
| } |
| |
| DEBUGASSERT(g_lp_stat.wakeup_timer_started == false); |
| |
| if (esp_timer_start_once(g_btdm_slp_tmr, |
| us_to_sleep - uncertainty) == ESP_OK) |
| { |
| g_lp_stat.wakeup_timer_started = true; |
| } |
| else |
| { |
| wlerr("timer start failed"); |
| DEBUGPANIC(); |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: btdm_sleep_enter_phase2_wrapper |
| * |
| * Description: |
| * ESP32 BLE lightsleep callback function. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void btdm_sleep_enter_phase2_wrapper(void) |
| { |
| if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) |
| { |
| if (g_lp_stat.phy_enabled) |
| { |
| bt_phy_disable(); |
| g_lp_stat.phy_enabled = false; |
| } |
| else |
| { |
| DEBUGPANIC(); |
| } |
| |
| if (g_lp_stat.pm_lock_released == false) |
| { |
| esp32_pm_lockrelease(); |
| g_lp_stat.pm_lock_released = true; |
| } |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: btdm_sleep_exit_phase3_wrapper |
| * |
| * Description: |
| * ESP32 BLE lightsleep callback function.. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void btdm_sleep_exit_phase3_wrapper(void) |
| { |
| if (g_lp_stat.pm_lock_released) |
| { |
| esp32_pm_lockacquire(); |
| g_lp_stat.pm_lock_released = false; |
| } |
| |
| if (btdm_sleep_clock_sync()) |
| { |
| wlerr("sleep eco state err\n"); |
| DEBUGPANIC(); |
| } |
| |
| if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) |
| { |
| if (g_lp_stat.phy_enabled == false) |
| { |
| bt_phy_enable(); |
| g_lp_stat.phy_enabled = true; |
| } |
| } |
| |
| if (g_lp_cntl.wakeup_timer_required && g_lp_stat.wakeup_timer_started) |
| { |
| esp_timer_stop(g_btdm_slp_tmr); |
| g_lp_stat.wakeup_timer_started = false; |
| } |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: btdm_controller_mem_init |
| * |
| * Description: |
| * Initialize BT controller to allocate task and other resource. |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void btdm_controller_mem_init(void) |
| { |
| int btdm_dram_regions; |
| |
| /* initialise .data section */ |
| |
| memcpy(_data_start_btdm, (void *)_data_start_btdm_rom, |
| _data_end_btdm - _data_start_btdm); |
| |
| wlinfo(".data initialise [0x%08x] <== [0x%08x]\n", |
| (uint32_t)_data_start_btdm, _data_start_btdm_rom); |
| |
| /* initial em, .bss section */ |
| |
| btdm_dram_regions = sizeof(btdm_dram_available_region) |
| / sizeof(btdm_dram_available_region_t); |
| |
| for (int i = 1; i < btdm_dram_regions; i++) |
| { |
| if (btdm_dram_available_region[i].mode != ESP_BT_MODE_IDLE) |
| { |
| memset((void *)btdm_dram_available_region[i].start, 0x0, |
| btdm_dram_available_region[i].end - \ |
| btdm_dram_available_region[i].start); |
| wlinfo(".bss initialise [0x%08x] - [0x%08x]\n", |
| btdm_dram_available_region[i].start, |
| btdm_dram_available_region[i].end); |
| } |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: phy_printf_ble |
| * |
| * Description: |
| * Output format string and its arguments |
| * |
| * Input Parameters: |
| * format - format string |
| * |
| * Returned Value: |
| * 0 |
| * |
| ****************************************************************************/ |
| |
| int phy_printf_ble(const char *format, ...) |
| { |
| #ifdef CONFIG_DEBUG_WIRELESS_INFO |
| va_list arg; |
| |
| va_start(arg, format); |
| vsyslog(LOG_INFO, format, arg); |
| va_end(arg); |
| #endif |
| |
| return 0; |
| } |
| |
| int coexist_printf(const char *format, ...) |
| { |
| #ifdef CONFIG_DEBUG_WIRELESS_INFO |
| va_list arg; |
| |
| va_start(arg, format); |
| vsyslog(LOG_INFO, format, arg); |
| va_end(arg); |
| #endif |
| |
| return 0; |
| } |
| |
| /**************************************************************************** |
| * Name: bt_phy_disable |
| * |
| * Description: |
| * Disable BT phy. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void bt_phy_disable(void) |
| { |
| esp32_phy_disable(); |
| } |
| |
| /**************************************************************************** |
| * Name: bt_phy_enable |
| * |
| * Description: |
| * Enable BT phy. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void bt_phy_enable(void) |
| { |
| esp32_phy_enable(); |
| } |
| |
| /**************************************************************************** |
| * Name: queue_create_wrapper |
| * |
| * Description: |
| * Create message queue |
| * |
| * Input Parameters: |
| * queue_len - queue message number |
| * item_size - message size |
| * |
| * Returned Value: |
| * Message queue data pointer |
| * |
| ****************************************************************************/ |
| |
| static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size) |
| { |
| struct mq_attr attr; |
| struct mq_adpt_s *mq_adpt; |
| int ret; |
| |
| mq_adpt = kmm_malloc(sizeof(struct mq_adpt_s)); |
| DEBUGASSERT(mq_adpt); |
| |
| snprintf(mq_adpt->name, sizeof(mq_adpt->name), "/tmp/%p", mq_adpt); |
| |
| attr.mq_maxmsg = queue_len; |
| attr.mq_msgsize = item_size; |
| attr.mq_curmsgs = 0; |
| attr.mq_flags = 0; |
| |
| ret = file_mq_open(&mq_adpt->mq, mq_adpt->name, |
| O_RDWR | O_CREAT, 0644, &attr); |
| |
| if (ret < 0) |
| { |
| wlerr("Failed to create mqueue %d\n", ret); |
| kmm_free(mq_adpt); |
| return NULL; |
| } |
| |
| mq_adpt->msgsize = item_size; |
| |
| #ifdef CONFIG_ESP32_SPIFLASH |
| if (queue_len <= BLE_TASK_EVENT_QUEUE_LEN && |
| item_size == BLE_TASK_EVENT_QUEUE_ITEM_SIZE) |
| { |
| esp_init_queuecache(g_esp_queuecache, |
| &mq_adpt->mq, |
| g_esp_queuecache_buffer, |
| BLE_TASK_EVENT_QUEUE_LEN, |
| BLE_TASK_EVENT_QUEUE_ITEM_SIZE); |
| } |
| else |
| { |
| wlerr("Failed to create queue cache." |
| " Please incresase BLE_TASK_EVENT_QUEUE_LEN to, at least, %d", |
| queue_len); |
| return NULL; |
| } |
| #endif |
| |
| return (void *)mq_adpt; |
| } |
| |
| /**************************************************************************** |
| * Name: queue_send_wrapper |
| * |
| * Description: |
| * Generic send message to queue within a certain period of time |
| * |
| * Input Parameters: |
| * queue - Message queue data pointer |
| * item - Item to be sent. |
| * block_time_ms - Wait time |
| * |
| * Returned Value:uint32_t |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int queue_send_wrapper(void *queue, void *item, |
| uint32_t block_time_ms) |
| { |
| return esp_queue_send_generic(queue, item, block_time_ms, 0); |
| } |
| |
| /**************************************************************************** |
| * Name: queue_recv_wrapper |
| * |
| * Description: |
| * Receive message from queue within a certain period of time |
| * |
| * Input Parameters: |
| * queue - Message queue data pointer |
| * item - Message data pointer |
| * block_time_ms - Wait time |
| * |
| * Returned Value: |
| * True if success or false if fail |
| * |
| ****************************************************************************/ |
| |
| static int queue_recv_wrapper(void *queue, void *item, |
| uint32_t block_time_ms) |
| { |
| ssize_t ret; |
| struct timespec timeout; |
| unsigned int prio; |
| struct mq_adpt_s *mq_adpt = (struct mq_adpt_s *)queue; |
| |
| if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) |
| { |
| ret = file_mq_receive(&mq_adpt->mq, (char *)item, |
| mq_adpt->msgsize, &prio); |
| |
| if (ret < 0) |
| { |
| wlerr("Failed to receive from mqueue error=%d\n", ret); |
| } |
| } |
| else |
| { |
| ret = clock_gettime(CLOCK_REALTIME, &timeout); |
| |
| if (ret < 0) |
| { |
| wlerr("Failed to get time %d\n", ret); |
| return false; |
| } |
| |
| if (block_time_ms) |
| { |
| esp_update_time(&timeout, MSEC2TICK(block_time_ms)); |
| } |
| |
| ret = file_mq_timedreceive(&mq_adpt->mq, (char *)item, |
| mq_adpt->msgsize, &prio, &timeout); |
| |
| if (ret < 0) |
| { |
| wlerr("Failed to timedreceive from mqueue error=%d\n", ret); |
| } |
| } |
| |
| return ret > 0 ? true : false; |
| } |
| |
| /**************************************************************************** |
| * Name: queue_delete_wrapper |
| * |
| * Description: |
| * Delete message queue |
| * |
| * Input Parameters: |
| * queue - Message queue data pointer |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void queue_delete_wrapper(void *queue) |
| { |
| struct mq_adpt_s *mq_adpt = (struct mq_adpt_s *)queue; |
| |
| file_mq_close(&mq_adpt->mq); |
| file_mq_unlink(mq_adpt->name); |
| kmm_free(mq_adpt); |
| } |
| |
| /**************************************************************************** |
| * Name: btdm_config_mask_load |
| * |
| * Description: |
| * Create a mask with all ESP32 BLE supported features |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * The uint32_t mask |
| * |
| ****************************************************************************/ |
| |
| static uint32_t btdm_config_mask_load(void) |
| { |
| uint32_t mask = 0x0; |
| |
| #ifdef CONFIG_UART_BTH4 |
| mask |= BTDM_CFG_HCI_UART; |
| #endif |
| |
| #ifdef CONFIG_ESP32_BLE_RUN_APP_CPU |
| mask |= BTDM_CFG_CONTROLLER_RUN_APP_CPU; |
| #endif |
| |
| #ifdef CONFIG_ESP32_BLE_FULL_SCAN |
| mask |= BTDM_CFG_BLE_FULL_SCAN_SUPPORTED; |
| #endif |
| |
| mask |= BTDM_CFG_SCAN_DUPLICATE_OPTIONS; |
| |
| mask |= BTDM_CFG_SEND_ADV_RESERVED_SIZE; |
| |
| return mask; |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: esp32_bt_controller_init |
| * |
| * Description: |
| * Init BT controller. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| int esp32_bt_controller_init(void) |
| { |
| esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); |
| esp_bt_controller_config_t *cfg = &bt_cfg; |
| int err; |
| uint32_t btdm_cfg_mask = 0; |
| int i; |
| |
| sq_init(&g_int_flags_free); |
| sq_init(&g_int_flags_used); |
| |
| for (i = 0; i < NR_IRQSTATE_FLAGS; i++) |
| { |
| sq_addlast((sq_entry_t *)&g_int_flags[i], &g_int_flags_free); |
| } |
| |
| if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) |
| { |
| wlerr("Invalid controller status"); |
| return ERROR; |
| } |
| |
| #ifdef CONFIG_ESP32_SPIFLASH |
| if (esp_wireless_init() != OK) |
| { |
| return -EIO; |
| } |
| #endif |
| |
| if (btdm_osi_funcs_register(&g_osi_funcs) != 0) |
| { |
| wlerr("Error, probably invalid OSI Functions\n"); |
| return -EINVAL; |
| } |
| |
| wlinfo("BT controller compile version [%s]\n", |
| btdm_controller_get_compile_version()); |
| |
| /* If all the bt available memory was already released, |
| * cannot initialize bluetooth controller |
| */ |
| |
| if (btdm_dram_available_region[0].mode == ESP_BT_MODE_IDLE) |
| { |
| wlerr("Error, bt available memory was released\n"); |
| return -EIO; |
| } |
| |
| if (cfg == NULL) |
| { |
| wlerr("%s %d\n", __func__, __LINE__); |
| return -EINVAL; |
| } |
| |
| cfg->controller_task_stack_size = CONFIG_ESP32_BLE_TASK_STACK_SIZE; |
| cfg->controller_task_prio = CONFIG_ESP32_BLE_TASK_PRIORITY; |
| |
| cfg->bt_max_sync_conn = CONFIG_ESP32_BLE_MAX_CONN; |
| cfg->magic = ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL; |
| |
| if (((cfg->mode & ESP_BT_MODE_BLE) && (cfg->ble_max_conn <= 0 || |
| cfg->ble_max_conn > BTDM_CONTROLLER_BLE_MAX_CONN_LIMIT)) || |
| ((cfg->mode & ESP_BT_MODE_CLASSIC_BT) && (cfg->bt_max_acl_conn <= 0 || |
| cfg->bt_max_acl_conn > BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_LIMIT)) || |
| ((cfg->mode & ESP_BT_MODE_CLASSIC_BT) && |
| (cfg->bt_max_sync_conn > BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_LIMIT))) |
| { |
| wlerr("%s %d\n", __func__, __LINE__); |
| return -EINVAL; |
| } |
| |
| wlinfo("BT controller compile version [%s]", |
| btdm_controller_get_compile_version()); |
| |
| btdm_controller_mem_init(); |
| |
| wlinfo("Memory initialized!\n"); |
| |
| bt_periph_module_enable(PERIPH_BT_MODULE); |
| |
| /* set default sleep clock cycle and its fractional bits */ |
| |
| g_btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; |
| g_btdm_lpcycle_us = 2 << (g_btdm_lpcycle_us_frac); |
| |
| btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_NONE); |
| |
| btdm_cfg_mask = btdm_config_mask_load(); |
| |
| wlinfo("Going to call btdm_controller_init\n"); |
| |
| if (btdm_controller_init(btdm_cfg_mask, cfg) != 0) |
| { |
| wlerr("Failed to initialize the BLE Controller\n"); |
| err = -ENOMEM; |
| goto error; |
| } |
| |
| wlinfo("The btdm_controller_init was initialized\n"); |
| |
| #ifdef CONFIG_BTDM_COEX_BLE_ADV_HIGH_PRIORITY |
| coex_ble_adv_priority_high_set(true); |
| #else |
| coex_ble_adv_priority_high_set(false); |
| #endif |
| |
| btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; |
| |
| return OK; |
| |
| error: |
| return err; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32_bt_controller_deinit |
| * |
| * Description: |
| * Deinit BT controller. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| int esp32_bt_controller_deinit(void) |
| { |
| if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) |
| { |
| return ERROR; |
| } |
| |
| btdm_controller_deinit(); |
| |
| if (g_lp_stat.phy_enabled) |
| { |
| bt_phy_disable(); |
| g_lp_stat.phy_enabled = false; |
| } |
| else |
| { |
| DEBUGPANIC(); |
| } |
| |
| #ifdef CONFIG_PM |
| /* deinit low power control resources */ |
| |
| g_lp_stat.pm_lock_released = false; |
| |
| if (g_lp_cntl.wakeup_timer_required) |
| { |
| if (g_lp_stat.wakeup_timer_started) |
| { |
| esp_timer_stop(g_btdm_slp_tmr); |
| } |
| |
| g_lp_stat.wakeup_timer_started = false; |
| esp_timer_delete(g_btdm_slp_tmr); |
| g_btdm_slp_tmr = NULL; |
| } |
| |
| if (g_lp_cntl.enable) |
| { |
| btdm_vnd_offload_task_deregister(BTDM_VND_OL_SIG_WAKEUP_TMR); |
| semphr_delete_wrapper(g_wakeup_req_sem); |
| g_wakeup_req_sem = NULL; |
| } |
| #endif |
| |
| btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; |
| g_btdm_lpcycle_us = 0; |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32_bt_controller_disable |
| * |
| * Description: |
| * Disable BT controller. |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| int esp32_bt_controller_disable(void) |
| { |
| if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) |
| { |
| return ERROR; |
| } |
| |
| while (!btdm_power_state_active()) |
| { |
| nxsig_usleep(1000); /* wait */ |
| } |
| |
| btdm_controller_disable(); |
| |
| #ifdef CONFIG_ESP32_WIFI_BT_COEXIST |
| coex_disable(); |
| #endif |
| |
| btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; |
| |
| #ifdef CONFIG_PM |
| /* disable low power mode */ |
| |
| if (g_lp_stat.pm_lock_released == false) |
| { |
| esp32_pm_lockrelease(); |
| g_lp_stat.pm_lock_released = true; |
| } |
| else |
| { |
| DEBUGPANIC(); |
| } |
| #endif |
| |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32_bt_controller_enable |
| * |
| * Description: |
| * Enable BT controller. |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| int esp32_bt_controller_enable(esp_bt_mode_t mode) |
| { |
| int ret = OK; |
| |
| if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) |
| { |
| return ERROR; |
| } |
| |
| if (mode != btdm_controller_get_mode()) |
| { |
| wlerr("invalid mode %d, controller support mode is %d", |
| mode, btdm_controller_get_mode()); |
| return ERROR; |
| } |
| |
| bt_phy_enable(); |
| |
| btdm_rf_bb_init_phase2(); |
| |
| coex_bt_high_prio(); |
| |
| #ifdef CONFIG_ESP32_WIFI_BT_COEXIST |
| coex_enable(); |
| #endif |
| |
| #ifdef CONFIG_PM |
| /* enable low power mode */ |
| |
| esp32_pm_lockacquire(); |
| g_lp_stat.pm_lock_released = false; |
| |
| if (g_lp_cntl.enable) |
| { |
| btdm_controller_enable_sleep(true); |
| } |
| #endif |
| |
| if (g_lp_cntl.enable) |
| { |
| btdm_controller_enable_sleep(true); |
| } |
| |
| if (btdm_controller_enable(mode) != 0) |
| { |
| ret = ERROR; |
| goto error; |
| } |
| |
| btdm_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED; |
| |
| return ret; |
| |
| error: |
| |
| /* disable low power mode */ |
| |
| btdm_controller_enable_sleep(false); |
| |
| #ifdef CONFIG_PM |
| if (g_lp_stat.pm_lock_released == false) |
| { |
| esp32_pm_lockrelease(); |
| g_lp_stat.pm_lock_released = true; |
| } |
| #endif |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32_bt_controller_get_status |
| * |
| * Description: |
| * Returns the status of the BT Controller |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * The current status (type esp_bt_controller_status_t) |
| * |
| ****************************************************************************/ |
| |
| esp_bt_controller_status_t esp32_bt_controller_get_status(void) |
| { |
| return btdm_controller_status; |
| } |
| |
| /**************************************************************************** |
| * Name: async_wakeup_request |
| * |
| * Description: |
| * Request the BLE Controller to wakeup |
| * |
| * Input Parameters: |
| * event - the event that triggered the wakeup |
| * |
| * Returned Value: |
| * true if request lock is needed, false otherwise |
| * |
| ****************************************************************************/ |
| |
| static bool async_wakeup_request(int event) |
| { |
| bool request_lock = false; |
| bool do_wakeup_request = false; |
| |
| switch (event) |
| { |
| case BTDM_ASYNC_WAKEUP_REQ_HCI: |
| request_lock = true; |
| break; |
| case BTDM_ASYNC_WAKEUP_REQ_COEX: |
| request_lock = false; |
| break; |
| default: |
| return false; |
| } |
| |
| if (!btdm_power_state_active()) |
| { |
| do_wakeup_request = true; |
| btdm_wakeup_request(request_lock); |
| } |
| |
| return do_wakeup_request; |
| } |
| |
| /**************************************************************************** |
| * Name: async_wakeup_request_end |
| * |
| * Description: |
| * Finish a wakeup request |
| * |
| * Input Parameters: |
| * event - the event that triggered the wakeup |
| * |
| * Returned Value: |
| * true if request lock is needed, false otherwise |
| * |
| ****************************************************************************/ |
| |
| static void async_wakeup_request_end(int event) |
| { |
| bool request_lock = false; |
| |
| switch (event) |
| { |
| case BTDM_ASYNC_WAKEUP_REQ_HCI: |
| request_lock = true; |
| break; |
| case BTDM_ASYNC_WAKEUP_REQ_COEX: |
| request_lock = false; |
| break; |
| default: |
| return; |
| } |
| |
| if (request_lock) |
| { |
| btdm_wakeup_request_end(); |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: coex_bt_wakeup_request |
| * |
| * Description: |
| * Request a Wi-Fi/BLE Coex wakeup request |
| * |
| * Input Parameters: |
| * none |
| * |
| * Returned Value: |
| * true if request lock is needed, false otherwise |
| * |
| ****************************************************************************/ |
| |
| static bool coex_bt_wakeup_request(void) |
| { |
| return async_wakeup_request(BTDM_ASYNC_WAKEUP_REQ_COEX); |
| } |
| |
| /**************************************************************************** |
| * Name: coex_bt_wakeup_request_end |
| * |
| * Description: |
| * Finish Wi-Fi/BLE Coex wakeup request |
| * |
| * Input Parameters: |
| * none |
| * |
| * Returned Value: |
| * none |
| * |
| ****************************************************************************/ |
| |
| static void coex_bt_wakeup_request_end(void) |
| { |
| async_wakeup_request_end(BTDM_ASYNC_WAKEUP_REQ_COEX); |
| } |
| |
| /**************************************************************************** |
| * Name: esp32_vhci_host_check_send_available |
| * |
| * Description: |
| * Check if the host can send packet to controller or not. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * bool - true or false |
| * |
| ****************************************************************************/ |
| |
| bool esp32_vhci_host_check_send_available(void) |
| { |
| if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) |
| { |
| return false; |
| } |
| |
| return api_vhci_host_check_send_available(); |
| } |
| |
| /**************************************************************************** |
| * Name: esp32_vhci_host_send_packet |
| * |
| * Description: |
| * Host send packet to controller. |
| * Input Parameters: |
| * data - the packet pointer |
| * len - the packet length |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| void esp32_vhci_host_send_packet(uint8_t *data, uint16_t len) |
| { |
| wlinfo("len: %d\n", len); |
| for (uint16_t i = 0; i < len; i++) |
| { |
| wlinfo("%02x\n", data[i]); |
| } |
| |
| if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) |
| { |
| return; |
| } |
| |
| api_vhci_host_send_packet(data, len); |
| } |
| |
| /**************************************************************************** |
| * Name: esp32_vhci_register_callback |
| * |
| * Description: |
| * Register the vhci reference callback. |
| * |
| * Input Parameters: |
| * callback - struct defined by vhci_host_callback structure. |
| * |
| * Returned Value: |
| * status - success or fail |
| * |
| ****************************************************************************/ |
| |
| int esp32_vhci_register_callback(const esp_vhci_host_callback_t *callback) |
| { |
| int ret = ERROR; |
| if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) |
| { |
| return ret; |
| } |
| |
| ret = api_vhci_host_register_callback( |
| (const vhci_host_callback_t *)callback) == 0 ? 0 : -1; |
| return ret; |
| } |
| |
| int IRAM_ATTR coex_bt_request_wrapper(uint32_t event, |
| uint32_t latency, |
| uint32_t duration) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| return coex_bt_request(event, latency, duration); |
| #else |
| return 0; |
| #endif |
| } |
| |
| int IRAM_ATTR coex_bt_release_wrapper(uint32_t event) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| return coex_bt_release(event); |
| #else |
| return 0; |
| #endif |
| } |
| |
| uint32_t IRAM_ATTR coex_bb_reset_lock_wrapper(void) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| return coex_bb_reset_lock(); |
| #else |
| return 0; |
| #endif |
| } |
| |
| void IRAM_ATTR coex_bb_reset_unlock_wrapper(uint32_t restore) |
| { |
| #if defined(CONFIG_ESP32_WIFI_BT_COEXIST) |
| coex_bb_reset_unlock(restore); |
| #endif |
| } |