blob: 6c414936e257fc340c03d1ac484595ee5f6060a3 [file] [log] [blame]
/****************************************************************************
* 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
}