blob: 44f20362f7964633c0fee8dea06041ec325d1122 [file] [log] [blame]
/****************************************************************************
* arch/risc-v/src/esp32c3-legacy/esp32c3_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/kthread.h>
#include <nuttx/wdog.h>
#include <nuttx/wqueue.h>
#include <nuttx/semaphore.h>
#include <nuttx/sched.h>
#include <nuttx/signal.h>
#include "hardware/esp32c3_syscon.h"
#include "hardware/wdev_reg.h"
#include "rom/esp32c3_spiflash.h"
#include "espidf_wifi.h"
#include "esp32c3.h"
#include "esp32c3_attr.h"
#include "esp32c3_irq.h"
#include "esp32c3_rt_timer.h"
#include "esp32c3_spiflash.h"
#include "esp32c3_wireless.h"
#include "esp32c3_ble_adapter.h"
#include "esp32c3_wireless.h"
#ifdef CONFIG_ESP32C3_WIFI_BT_COEXIST
# include "esp_coexist_internal.h"
# include "esp_coexist_adapter.h"
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define OSI_FUNCS_TIME_BLOCKING 0xffffffff
#define OSI_VERSION 0x00010006
#define OSI_MAGIC_VALUE 0xfadebead
#ifdef CONFIG_PM
#define BTDM_MIN_TIMER_UNCERTAINTY_US (1800)
/* Sleep and wakeup interval control */
#define BTDM_MIN_SLEEP_DURATION (24) /* threshold of interval in half slots to allow to fall into modem sleep */
#define BTDM_MODEM_WAKE_UP_DELAY (8) /* delay in half slots of modem wake up procedure, including re-enable PHY/RF */
#endif
/****************************************************************************
* Private Types
****************************************************************************/
/* BLE message queue private data */
struct mq_adpt_s
{
struct file mq; /* Message queue handle */
uint32_t msgsize; /* Message size */
char name[16]; /* 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 enum btdm_lpclk_sel_e
{
BTDM_LPCLK_SEL_XTAL = 0,
BTDM_LPCLK_SEL_XTAL32K = 1,
BTDM_LPCLK_SEL_RTC_SLOW = 2,
BTDM_LPCLK_SEL_8M = 3,
} btdm_lpclk_sel_t;
typedef enum btdm_vnd_ol_sig_e
{
BTDM_VND_OL_SIG_WAKEUP_TMR,
BTDM_VND_OL_SIG_NUM,
} btdm_vnd_ol_sig_t;
typedef struct btdm_lpcntl_s
{
bool enable; /* whether low power mode is required */
bool wakeup_timer_required; /* whether system timer is needed */
btdm_lpclk_sel_t lpclk_sel; /* low power clock source */
} btdm_lpcntl_t;
/* low power control status */
typedef struct btdm_lpstat_s
{
bool pm_lock_released; /* whether power management lock is released */
bool phy_enabled; /* whether phy is switched on */
bool wakeup_timer_started; /* whether wakeup timer is started */
} btdm_lpstat_t;
struct bt_sem_s
{
sem_t sem;
#ifdef CONFIG_ESP32C3_SPIFLASH
struct esp32c3_wl_semcache_s sc;
#endif
};
#ifdef CONFIG_PM
/* wakeup request sources */
enum btdm_wakeup_src_e
{
BTDM_ASYNC_WAKEUP_SRC_VHCI,
BTDM_ASYNC_WAKEUP_SRC_DISA,
BTDM_ASYNC_WAKEUP_SRC_TMR,
BTDM_ASYNC_WAKEUP_SRC_MAX,
};
#endif
/* 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 _magic;
uint32_t _version;
void (*_interrupt_set)(int cpu_no, int intr_source,
int interrupt_no, int interrpt_prio);
void (*_interrupt_clear)(int interrupt_source, int interrupt_no);
void (*_interrupt_handler_set)(int interrupt_no, void * fn, void *arg);
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);
int (*_semphr_take_from_isr)(void *semphr, void *hptw);
int (*_semphr_give_from_isr)(void *semphr, void *hptw);
int (*_semphr_take)(void *semphr, uint32_t block_time_ms);
int (*_semphr_give)(void *semphr);
void *(*_mutex_create)(void);
void (*_mutex_delete)(void *mutex);
int (*_mutex_lock)(void *mutex);
int (*_mutex_unlock)(void *mutex);
void *(* _queue_create)(uint32_t queue_len, uint32_t item_size);
void (* _queue_delete)(void *queue);
int (* _queue_send)(void *queue, void *item, uint32_t block_time_ms);
int (* _queue_send_from_isr)(void *queue, void *item, void *hptw);
int (* _queue_recv)(void *queue, void *item, uint32_t block_time_ms);
int (* _queue_recv_from_isr)(void *queue, void *item, void *hptw);
int (* _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)(size_t size);
void *(* _malloc_internal)(size_t size);
void (* _free)(void *p);
int (* _read_efuse_mac)(uint8_t mac[6]);
void (* _srand)(unsigned int seed);
int (* _rand)(void);
uint32_t (* _btdm_lpcycles_2_hus)(uint32_t cycles, uint32_t *error_corr);
uint32_t (* _btdm_hus_2_lpcycles)(uint32_t us);
bool (* _btdm_sleep_check_duration)(int32_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 */
void (* _coex_wifi_sleep_set)(bool sleep);
int (* _coex_core_ble_conn_dyn_prio_get)(bool *low, bool *high);
void (* _coex_schm_status_bit_set)(uint32_t type, uint32_t status);
void (* _coex_schm_status_bit_clear)(uint32_t type, uint32_t status);
void (* _interrupt_on)(int intr_num);
void (* _interrupt_off)(int intr_num);
void (* _esp_hw_power_down)(void);
void (* _esp_hw_power_up)(void);
void (* _ets_backup_dma_copy)(uint32_t reg,
uint32_t mem_addr, uint32_t num,
bool to_rem);
};
/****************************************************************************
* Private Function
****************************************************************************/
static void interrupt_set_wrapper(int cpu_no, int intr_source,
int intr_num, int intr_prio);
static void interrupt_clear_wrapper(int intr_source, int intr_num);
static void interrupt_handler_set_wrapper(int n, void *fn, void *arg);
static void interrupt_disable(void);
static void interrupt_restore(void);
static void 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 semphr_take_from_isr_wrapper(void *semphr, void *hptw);
static int 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 queue_send_from_isr_wrapper(void *queue, void *item,
void *hptw);
static int 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 is_in_isr_wrapper(void);
static void *malloc_wrapper(size_t size);
static void *malloc_internal_wrapper(size_t size);
static int read_mac_wrapper(uint8_t mac[6]);
static void srand_wrapper(unsigned int seed);
static int rand_wrapper(void);
static uint32_t btdm_lpcycles_2_hus(uint32_t cycles,
uint32_t *error_corr);
static uint32_t btdm_hus_2_lpcycles(uint32_t us);
static void coex_wifi_sleep_set_hook(bool sleep);
static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status);
static void coex_schm_status_bit_clear_wrapper(uint32_t type,
uint32_t status);
static void interrupt_on_wrapper(int intr_num);
static void interrupt_off_wrapper(int intr_num);
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);
#ifdef CONFIG_PM
static bool 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
/****************************************************************************
* Extern Functions declaration and value
****************************************************************************/
extern int btdm_osi_funcs_register(void *osi_funcs);
extern void btdm_controller_rom_data_init(void);
/* Initialise and De-initialise */
extern int btdm_controller_init(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 uint8_t btdm_controller_get_sleep_mode(void);
extern bool btdm_power_state_active(void);
extern void btdm_wakeup_request(void);
extern void btdm_in_wakeup_requesting_set(bool in_wakeup_requesting);
/* vendor dependent tasks to be posted and handled by controller task */
extern int btdm_vnd_offload_task_register(btdm_vnd_ol_sig_t sig,
btdm_vnd_ol_task_func_t func);
extern int btdm_vnd_offload_task_deregister(btdm_vnd_ol_sig_t sig);
extern int btdm_vnd_offload_post_from_isr(btdm_vnd_ol_sig_t sig,
void *param, bool need_yield);
extern int btdm_vnd_offload_post(btdm_vnd_ol_sig_t sig, void *param);
/* 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 uint16_t l2c_ble_link_get_tx_buf_num(void);
extern int coex_core_ble_conn_dyn_prio_get(bool *low, bool *high);
extern bool btdm_deep_sleep_mem_init(void);
extern void btdm_deep_sleep_mem_deinit(void);
extern void btdm_ble_power_down_dma_copy(bool copy);
extern uint8_t btdm_sleep_clock_sync(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[];
/****************************************************************************
* 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 bool g_ble_irq_bind;
static irqstate_t g_inter_flags;
/****************************************************************************
* Public Data
****************************************************************************/
/* BLE OS adapter data */
static struct osi_funcs_s g_osi_funcs =
{
._magic = OSI_MAGIC_VALUE,
._version = OSI_VERSION,
._interrupt_set = interrupt_set_wrapper,
._interrupt_clear = interrupt_clear_wrapper,
._interrupt_handler_set = interrupt_handler_set_wrapper,
._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,
._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_hus = btdm_lpcycles_2_hus,
._btdm_hus_2_lpcycles = btdm_hus_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_wifi_sleep_set = coex_wifi_sleep_set_hook,
._coex_core_ble_conn_dyn_prio_get = coex_core_ble_conn_dyn_prio_get,
._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper,
._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper,
._interrupt_on = interrupt_on_wrapper,
._interrupt_off = interrupt_off_wrapper,
};
/****************************************************************************
* Private Functions and Public Functions only used by libraries
****************************************************************************/
/****************************************************************************
* 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;
pid = kthread_create(name, prio, stack_depth, entry,
(char * const *)param);
if (pid > 0)
{
if (task_handle)
{
*((int *)task_handle) = pid;
}
}
else
{
wlerr("Failed to create task\n");
}
return pid > 0;
}
/****************************************************************************
* Name: interrupt_set_wrapper
*
* Description:
* Bind IRQ and resource with given parameters.
*
* Input Parameters:
* cpu_no - The CPU which the interrupt number belongs.
* intr_source - The interrupt hardware source number.
* intr_num - The interrupt number CPU.
* intr_prio - The interrupt priority.
*
* Returned Value:
* None
*
****************************************************************************/
static void interrupt_set_wrapper(int cpu_no,
int intr_source,
int intr_num,
int intr_prio)
{
wlinfo("cpu_no=%d , intr_source=%d , intr_num=%d, intr_prio=%d\n",
cpu_no, intr_source, intr_num, intr_prio);
esp32c3_bind_irq(intr_num, intr_source, intr_prio, ESP32C3_INT_LEVEL);
#ifdef CONFIG_ESP32C3_SPIFLASH
esp32c3_spiflash_unmask_cpuint(intr_num);
#endif
}
/****************************************************************************
* Name: interrupt_clear_wrapper
*
* Description:
* Not supported
*
****************************************************************************/
static void IRAM_ATTR interrupt_clear_wrapper(int intr_source, int intr_num)
{
}
/****************************************************************************
* 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_handler_set_wrapper
*
* Description:
* Register interrupt function
*
* Input Parameters:
* n - Interrupt ID
* f - Interrupt function
* arg - Function private data
*
* Returned Value:
* None
*
****************************************************************************/
static void interrupt_handler_set_wrapper(int n, void *fn, void *arg)
{
int ret;
struct irq_adpt_s *adapter;
if (g_ble_irq_bind)
{
return;
}
adapter = kmm_malloc(sizeof(struct irq_adpt_s));
DEBUGASSERT(adapter);
adapter->func = fn;
adapter->arg = arg;
ret = irq_attach(n + ESP32C3_IRQ_FIRSTPERIPH, esp_int_adpt_cb, adapter);
DEBUGASSERT(ret == OK);
g_ble_irq_bind = true;
}
/****************************************************************************
* Name: esp32c3_ints_on
*
* Description:
* Enable Wi-Fi interrupt
*
* Input Parameters:
* intr_num - No mean
*
* Returned Value:
* None
*
****************************************************************************/
static void interrupt_on_wrapper(int intr_num)
{
up_enable_irq(intr_num + ESP32C3_IRQ_FIRSTPERIPH);
}
/****************************************************************************
* Name: esp32c3_ints_off
*
* Description:
* Disable Wi-Fi interrupt
*
* Input Parameters:
* intr_num - No mean
*
* Returned Value:
* None
*
****************************************************************************/
static void interrupt_off_wrapper(int intr_num)
{
up_disable_irq(intr_num + ESP32C3_IRQ_FIRSTPERIPH);
}
/****************************************************************************
* 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)
{
g_inter_flags = enter_critical_section();
}
/****************************************************************************
* 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)
{
leave_critical_section(g_inter_flags);
}
/****************************************************************************
* Name: task_yield_from_isr
*
* Description:
* Do nothing in NuttX
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void 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);
ret = nxsem_init(&bt_sem->sem, 0, init);
DEBUGASSERT(ret == OK);
#ifdef CONFIG_ESP32C3_SPIFLASH
esp32c3_wl_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;
nxsem_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
*
* Returned Value:
* True if success or false if fail
*
****************************************************************************/
static int semphr_take_from_isr_wrapper(void *semphr, void *hptw)
{
*(int *)hptw = 0;
return esp_errno_trans(nxsem_trywait(semphr));
}
/****************************************************************************
* 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_ESP32C3_SPIFLASH
if (spi_flash_cache_enabled())
{
ret = semphr_give_wrapper(&bt_sem->sem);
ret = esp_errno_trans(ret);
}
else
{
esp32c3_wl_post_semcache(&bt_sem->sc);
ret = true;
}
#else
ret = semphr_give_wrapper(&bt_sem->sem);
ret = esp_errno_trans(ret);
#endif
return ret;
}
/****************************************************************************
* Name: esp_update_time
*
* Description:
* Transform ticks to time and add this time to timespec value
*
* Input Parameters:
* timespec - Input timespec data pointer
* ticks - System ticks
*
* 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 %lu 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 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;
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\n");
return false;
}
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)
{
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 queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw)
{
DEBUGPANIC();
return false;
}
/****************************************************************************
* 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, UINT32_MAX);
}
/****************************************************************************
* 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:
* szie - buffer size
*
* Returned Value:
* None
*
****************************************************************************/
static void *malloc_wrapper(size_t size)
{
void * p = NULL;
p = kmm_malloc(size);
DEBUGASSERT(p);
return p;
}
/****************************************************************************
* 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 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 srand_wrapper(unsigned int seed)
{
/* empty function */
}
/****************************************************************************
* Name: rand_wrapper
*
* Description:
* Get random value
* Input Parameters:
* None
*
* Returned Value:
* Random value
*
****************************************************************************/
static IRAM_ATTR int rand_wrapper(void)
{
return getreg32(WDEV_RND_REG);
}
/****************************************************************************
* Name: btdm_lpcycles_2_hus
*
* Description:
* Converts a number of low power clock cycles into a duration in half us.
*
* Input Parameters:
* cycles
* error_corr
*
* Returned Value:
* us
*
****************************************************************************/
static uint32_t IRAM_ATTR btdm_lpcycles_2_hus(uint32_t cycles,
uint32_t *error_corr)
{
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_hus_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_hus_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)
{
DEBUGASSERT(g_lp_cntl.enable == true);
if (g_lp_stat.pm_lock_released)
{
esp32c3_pm_lockacquire();
g_lp_stat.pm_lock_released = false;
}
int event = (int) param;
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:
* ESP32C3 BLE lightsleep callback function.
*
* Input Parameters:
* lpcycles - light sleep cycles
*
* Returned Value:
* None
*
****************************************************************************/
static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles)
{
if (g_lp_cntl.wakeup_timer_required == false)
{
return;
}
/* start a timer to wake up and acquire the pm_lock before sleep awakes */
uint32_t us_to_sleep = btdm_lpcycles_2_hus(lpcycles, NULL) >> 1;
DEBUGASSERT(us_to_sleep > BTDM_MIN_TIMER_UNCERTAINTY_US);
uint32_t 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:
* ESP32C3 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)
{
esp32c3_pm_lockrelease();
g_lp_stat.pm_lock_released = true;
}
}
}
/****************************************************************************
* Name: btdm_sleep_exit_phase3_wrapper
*
* Description:
* ESP32C3 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)
{
esp32c3_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: coex_schm_status_bit_set_wrapper
*
* Description:
*
* Input Parameters:
* type
* status
*
* Returned Value:
* None
*
****************************************************************************/
static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status)
{
#ifdef CONFIG_ESP32C3_WIFI_BT_COEXIST
coex_schm_status_bit_set(type, status);
#endif
}
/****************************************************************************
* Name: coex_schm_status_bit_clear_wrapper
*
* Description:
*
* Input Parameters:
* szie
* status
*
* Returned Value:
* None
*
****************************************************************************/
static void coex_schm_status_bit_clear_wrapper(uint32_t type,
uint32_t status)
{
#ifdef CONFIG_ESP32C3_WIFI_BT_COEXIST
coex_schm_status_bit_clear(type, status);
#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)
{
btdm_controller_rom_data_init();
}
/****************************************************************************
* Name: phy_printf
*
* Description:
* Output format string and its arguments
*
* Input Parameters:
* format - format string
*
* Returned Value:
* 0
*
****************************************************************************/
#ifndef CONFIG_ESP32C3_WIFI
int phy_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;
}
#endif
/****************************************************************************
* Name: bt_phy_disable
*
* Description:
* Disable BT phy.
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void bt_phy_disable(void)
{
esp32c3_phy_disable();
}
/****************************************************************************
* Name: bt_phy_enable
*
* Description:
* Enable BT phy.
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void bt_phy_enable(void)
{
esp32c3_phy_enable();
}
/****************************************************************************
* Name: coex_wifi_sleep_set_hook
*
* Description:
* Don't support
*
****************************************************************************/
static void coex_wifi_sleep_set_hook(bool sleep)
{
}
/****************************************************************************
* 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\n");
kmm_free(mq_adpt);
return NULL;
}
mq_adpt->msgsize = item_size;
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 - Message data pointerint
* 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\n");
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);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp32c3_bt_controller_init
*
* Description:
* Init BT controller.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
int esp32c3_bt_controller_init(void)
{
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
esp_bt_controller_config_t *cfg = &bt_cfg;
#ifdef CONFIG_PM
bool select_src_ret;
bool set_div_ret;
#endif
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE)
{
wlerr("Invalid controller status");
return -1;
}
cfg->controller_task_stack_size = CONFIG_ESP32C3_BLE_TASK_STACK_SIZE;
cfg->controller_task_prio = CONFIG_ESP32C3_BLE_TASK_PRIORITY;
cfg->controller_task_run_cpu = 0;
cfg->ble_max_act = 10;
cfg->sleep_mode = 0;
cfg->coex_phy_coded_tx_rx_time_limit = 0;
cfg->bluetooth_mode = 1;
cfg->sleep_clock = 0;
cfg->ble_st_acl_tx_buf_nb = 0;
cfg->ble_hw_cca_check = 0;
cfg->ble_adv_dup_filt_max = 30;
cfg->ce_len_type = 0;
cfg->hci_tl_type = 1;
cfg->hci_tl_funcs = NULL;
cfg->txant_dft = 0;
cfg->rxant_dft = 0;
cfg->txpwr_dft = 7;
cfg->cfg_mask = 1;
cfg->scan_duplicate_mode = 0;
cfg->scan_duplicate_type = 0;
cfg->normal_adv_size = 20;
cfg->mesh_adv_size = 0;
btdm_controller_mem_init();
if (btdm_osi_funcs_register(&g_osi_funcs) != 0)
{
return -EINVAL;
}
wlinfo("BT controller compile version [%s]\n",
btdm_controller_get_compile_version());
#ifdef CONFIG_PM
/* init low-power control resources */
memset(&g_lp_cntl, 0x0, sizeof(btdm_lpcntl_t));
memset(&g_lp_stat, 0x0, sizeof(btdm_lpstat_t));
g_wakeup_req_sem = NULL;
g_btdm_slp_tmr = NULL;
/* configure and initialize resources */
g_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? true : false;
if (g_lp_cntl.enable)
{
g_lp_cntl.wakeup_timer_required = true;
g_wakeup_req_sem = semphr_create_wrapper(1, 0);
if (g_wakeup_req_sem == NULL)
{
goto error;
}
btdm_vnd_offload_task_register(BTDM_VND_OL_SIG_WAKEUP_TMR,
btdm_sleep_exit_phase0);
}
if (g_lp_cntl.wakeup_timer_required)
{
esp_timer_create_args_t create_args =
{
.callback = btdm_slp_tmr_callback,
.arg = NULL,
.name = "btSlp",
};
if ((err = esp_timer_create(&create_args, &g_btdm_slp_tmr)) != ESP_OK)
{
goto error;
}
}
g_btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
g_btdm_lpcycle_us = 2 << (g_btdm_lpcycle_us_frac);
if (esp32c3_rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL)
{
g_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K;
}
else
{
wlwarn("32.768kHz XTAL not detected");
g_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL;
}
if (g_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_XTAL)
{
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL);
set_div_ret = btdm_lpclk_set_div(esp32c3_rtc_clk_xtal_freq_get() * 2);
DEBUGASSERT(select_src_ret && set_div_ret);
g_btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
g_btdm_lpcycle_us = 2 << (g_btdm_lpcycle_us_frac);
}
else if (g_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_XTAL32K)
{
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL32K);
set_div_ret = btdm_lpclk_set_div(0);
DEBUGASSERT(select_src_ret && set_div_ret);
g_btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
g_btdm_lpcycle_us = (RTC_CLK_CAL_FRACT > 15) ?
(1000000 << (RTC_CLK_CAL_FRACT - 15)) :
(1000000 >> (15 - RTC_CLK_CAL_FRACT));
DEBUGASSERT(g_btdm_lpcycle_us != 0);
}
else if (g_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_RTC_SLOW)
{
select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_RTC_SLOW);
set_div_ret = btdm_lpclk_set_div(0);
DEBUGASSERT(select_src_ret && set_div_ret);
g_btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
g_btdm_lpcycle_us = esp_clk_slowclk_cal_get_wrapper();
}
else
{
goto error;
}
g_lp_stat.pm_lock_released = true;
#endif
#ifdef CONFIG_ESP32C3_WIFI_BT_COEXIST
coex_init();
#endif
modifyreg32(SYSTEM_WIFI_CLK_EN_REG, 0, UINT32_MAX);
bt_phy_enable();
g_lp_stat.phy_enabled = true;
if (btdm_controller_init(cfg) != 0)
{
bt_phy_disable();
g_lp_stat.phy_enabled = false;
return -EIO;
}
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
#ifdef CONFIG_ESP32C3_SPIFLASH
if (esp32c3_wl_init() < 0)
{
return -EIO;
}
#endif
return 0;
#ifdef CONFIG_PM
error:
if (g_lp_stat.phy_enabled)
{
bt_phy_disable();
g_lp_stat.phy_enabled = false;
}
g_lp_stat.pm_lock_released = false;
if (g_lp_cntl.wakeup_timer_required && g_btdm_slp_tmr != NULL)
{
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);
if (g_wakeup_req_sem != NULL)
{
semphr_delete_wrapper(g_wakeup_req_sem);
g_wakeup_req_sem = NULL;
}
}
return ENOMEM;
#endif
}
/****************************************************************************
* Name: esp32c3_bt_controller_deinit
*
* Description:
* Deinit BT controller.
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
int esp32c3_bt_controller_deinit(void)
{
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED)
{
return -1;
}
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 0;
}
/****************************************************************************
* Name: esp32c3_bt_controller_disable
*
* Description:
* disable BT controller.
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
int esp32c3_bt_controller_disable(void)
{
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED)
{
return -1;
}
while (!btdm_power_state_active())
{
nxsig_usleep(1000); /* wait */
}
btdm_controller_disable();
#ifdef CONFIG_ESP32C3_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)
{
esp32c3_pm_lockrelease();
g_lp_stat.pm_lock_released = true;
}
else
{
DEBUGPANIC();
}
#endif
return 0;
}
/****************************************************************************
* Name: esp32c3_bt_controller_enable
*
* Description:
* Enable BT controller.
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
int esp32c3_bt_controller_enable(esp_bt_mode_t mode)
{
int ret = 0;
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED)
{
return -1;
}
if (mode != btdm_controller_get_mode())
{
wlerr("invalid mode %d, controller support mode is %d",
mode, btdm_controller_get_mode());
return -1;
}
#ifdef CONFIG_ESP32C3_WIFI_BT_COEXIST
coex_enable();
#endif
#ifdef CONFIG_PM
/* enable low power mode */
esp32c3_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 = -1;
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)
{
esp32c3_pm_lockrelease();
g_lp_stat.pm_lock_released = true;
}
#endif
return ret;
}
esp_bt_controller_status_t esp32c3_bt_controller_get_status(void)
{
return btdm_controller_status;
}
/****************************************************************************
* Name: esp32c3_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 esp32c3_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: esp32c3_vhci_host_send_packet
*
* Description:
* host send packet to controller.
* Input Parameters:
* data - the packet point
* len - the packet length
*
* Returned Value:
* None
*
****************************************************************************/
void esp32c3_vhci_host_send_packet(uint8_t *data, uint16_t len)
{
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED)
{
return;
}
api_vhci_host_send_packet(data, len);
}
/****************************************************************************
* Name: esp32c3_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 esp32c3_vhci_register_callback(const esp_vhci_host_callback_t *callback)
{
int ret = -1;
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;
}