diff options
| author | ailurux <ailuruxx@gmail.com> | 2024-04-02 11:13:50 +1100 |
|---|---|---|
| committer | ailurux <ailuruxx@gmail.com> | 2024-04-02 11:13:50 +1100 |
| commit | e20ebe7574db5aedc73f07b7bb3a0a01eae93c84 (patch) | |
| tree | 34c93ec8a80e282f3ce3e47dd60c41e46de0f8b3 /lib/bt/controller | |
| parent | a750af35aa6afda40aadca8f7cf8db75f41a43b2 (diff) | |
| parent | 0d0c4b2307cac8436fea7276956f293262b265ed (diff) | |
| download | tangara-fw-e20ebe7574db5aedc73f07b7bb3a0a01eae93c84.tar.gz | |
Merge branch 'main' into lua-volume
Diffstat (limited to 'lib/bt/controller')
39 files changed, 11982 insertions, 0 deletions
diff --git a/lib/bt/controller/esp32/Kconfig.in b/lib/bt/controller/esp32/Kconfig.in new file mode 100644 index 00000000..2d7cbf85 --- /dev/null +++ b/lib/bt/controller/esp32/Kconfig.in @@ -0,0 +1,446 @@ +choice BTDM_CTRL_MODE + prompt "Bluetooth controller mode (BR/EDR/BLE/DUALMODE)" + help + Specify the bluetooth controller mode (BR/EDR, BLE or dual mode). + + config BTDM_CTRL_MODE_BLE_ONLY + bool "BLE Only" + + config BTDM_CTRL_MODE_BR_EDR_ONLY + bool "BR/EDR Only" + + config BTDM_CTRL_MODE_BTDM + bool "Bluetooth Dual Mode" + +endchoice + +config BTDM_CTRL_BLE_MAX_CONN + int "BLE Max Connections" + depends on BTDM_CTRL_MODE_BLE_ONLY || BTDM_CTRL_MODE_BTDM + default 3 + range 1 9 + help + BLE maximum connections of bluetooth controller. + Each connection uses 1KB static DRAM whenever the BT controller is enabled. + +config BTDM_CTRL_BR_EDR_MAX_ACL_CONN + int "BR/EDR ACL Max Connections" + depends on BTDM_CTRL_MODE_BR_EDR_ONLY || BTDM_CTRL_MODE_BTDM + default 2 + range 1 7 + help + BR/EDR ACL maximum connections of bluetooth controller. + Each connection uses 1.2 KB DRAM whenever the BT controller is enabled. + +config BTDM_CTRL_BR_EDR_MAX_SYNC_CONN + int "BR/EDR Sync(SCO/eSCO) Max Connections" + depends on BTDM_CTRL_MODE_BR_EDR_ONLY || BTDM_CTRL_MODE_BTDM + default 0 + range 0 3 + help + BR/EDR Synchronize maximum connections of bluetooth controller. + Each connection uses 2 KB DRAM whenever the BT controller is enabled. + + + +choice BTDM_CTRL_BR_EDR_SCO_DATA_PATH + prompt "BR/EDR Sync(SCO/eSCO) default data path" + depends on BTDM_CTRL_MODE_BR_EDR_ONLY || BTDM_CTRL_MODE_BTDM + default BTDM_CTRL_BR_EDR_SCO_DATA_PATH_PCM + help + SCO data path, i.e. HCI or PCM. + SCO data can be sent/received through HCI synchronous packets, or the data + can be routed to on-chip PCM module on ESP32. PCM input/output signals can + be "matrixed" to GPIOs. The default data path can also be set using API + "esp_bredr_sco_datapath_set" + + config BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI + bool "HCI" + config BTDM_CTRL_BR_EDR_SCO_DATA_PATH_PCM + bool "PCM" +endchoice + +config BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF + int + default 0 if BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI + default 1 if BTDM_CTRL_BR_EDR_SCO_DATA_PATH_PCM + default 0 + +menuconfig BTDM_CTRL_PCM_ROLE_EDGE_CONFIG + bool "PCM Signal Config (Role and Polar)" + depends on BTDM_CTRL_BR_EDR_SCO_DATA_PATH_PCM + default y + +choice BTDM_CTRL_PCM_ROLE + prompt "PCM Role" + depends on BTDM_CTRL_PCM_ROLE_EDGE_CONFIG + help + PCM role can be configured as PCM master or PCM slave + + config BTDM_CTRL_PCM_ROLE_MASTER + bool "PCM Master" + config BTDM_CTRL_PCM_ROLE_SLAVE + bool "PCM Slave" +endchoice + +choice BTDM_CTRL_PCM_POLAR + prompt "PCM Polar" + depends on BTDM_CTRL_PCM_ROLE_EDGE_CONFIG + help + PCM polarity can be configured as Falling Edge or Rising Edge + + config BTDM_CTRL_PCM_POLAR_FALLING_EDGE + bool "Falling Edge" + config BTDM_CTRL_PCM_POLAR_RISING_EDGE + bool "Rising Edge" +endchoice + +config BTDM_CTRL_PCM_ROLE_EFF + int + default 0 if BTDM_CTRL_PCM_ROLE_MASTER + default 1 if BTDM_CTRL_PCM_ROLE_SLAVE + default 0 + +config BTDM_CTRL_PCM_POLAR_EFF + int + default 0 if BTDM_CTRL_PCM_POLAR_FALLING_EDGE + default 1 if BTDM_CTRL_PCM_POLAR_RISING_EDGE + default 0 + +config BTDM_CTRL_AUTO_LATENCY + bool "Auto latency" + depends on BTDM_CTRL_MODE_BTDM + default n + help + BLE auto latency, used to enhance classic BT performance + while classic BT and BLE are enabled at the same time. + +config BTDM_CTRL_AUTO_LATENCY_EFF + bool + default BTDM_CTRL_AUTO_LATENCY if BTDM_CTRL_MODE_BTDM + default n + +config BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT + bool "Legacy Authentication Vendor Specific Event Enable" + depends on BTDM_CTRL_MODE_BR_EDR_ONLY || BTDM_CTRL_MODE_BTDM + default y + help + To protect from BIAS attack during Legacy authentication, + Legacy authentication Vendor specific event should be enabled + +config BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF + bool + default BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT if BTDM_CTRL_MODE_BR_EDR_ONLY || BTDM_CTRL_MODE_BTDM + default 0 + + +config BTDM_CTRL_BLE_MAX_CONN_EFF + int + default BTDM_CTRL_BLE_MAX_CONN if BTDM_CTRL_MODE_BLE_ONLY || BTDM_CTRL_MODE_BTDM + default 0 + +config BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF + int + default BTDM_CTRL_BR_EDR_MAX_ACL_CONN if BTDM_CTRL_MODE_BR_EDR_ONLY || BTDM_CTRL_MODE_BTDM + default 0 + +config BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF + int + default BTDM_CTRL_BR_EDR_MAX_SYNC_CONN if BTDM_CTRL_MODE_BR_EDR_ONLY || BTDM_CTRL_MODE_BTDM + default 0 + +choice BTDM_CTRL_PINNED_TO_CORE_CHOICE + prompt "The cpu core which bluetooth controller run" + depends on !FREERTOS_UNICORE + help + Specify the cpu core to run bluetooth controller. + Can not specify no-affinity. + + config BTDM_CTRL_PINNED_TO_CORE_0 + bool "Core 0 (PRO CPU)" + config BTDM_CTRL_PINNED_TO_CORE_1 + bool "Core 1 (APP CPU)" + depends on !FREERTOS_UNICORE +endchoice + +config BTDM_CTRL_PINNED_TO_CORE + int + default 0 if BTDM_CTRL_PINNED_TO_CORE_0 + default 1 if BTDM_CTRL_PINNED_TO_CORE_1 + default 0 + +choice BTDM_CTRL_HCI_MODE_CHOICE + prompt "HCI mode" + help + Speicify HCI mode as VHCI or UART(H4) + + config BTDM_CTRL_HCI_MODE_VHCI + bool "VHCI" + help + Normal option. Mostly, choose this VHCI when bluetooth host run on ESP32, too. + + config BTDM_CTRL_HCI_MODE_UART_H4 + bool "UART(H4)" + help + If use external bluetooth host which run on other hardware and use UART as the HCI interface, + choose this option. +endchoice + +menu "HCI UART(H4) Options" + visible if BTDM_CTRL_HCI_MODE_UART_H4 + + config BTDM_CTRL_HCI_UART_NO + int "UART Number for HCI" + depends on BTDM_CTRL_HCI_MODE_UART_H4 + range 1 2 + default 1 + help + Uart number for HCI. The available uart is UART1 and UART2. + + config BTDM_CTRL_HCI_UART_BAUDRATE + int "UART Baudrate for HCI" + depends on BTDM_CTRL_HCI_MODE_UART_H4 + range 115200 921600 + default 921600 + help + UART Baudrate for HCI. Please use standard baudrate. + + config BTDM_CTRL_HCI_UART_FLOW_CTRL_EN + bool "Enable UART flow control" + depends on BTDM_CTRL_HCI_MODE_UART_H4 + default y + +endmenu + +menu "MODEM SLEEP Options" + config BTDM_CTRL_MODEM_SLEEP + bool "Bluetooth modem sleep" + default y + help + Enable/disable bluetooth controller low power mode. + + choice BTDM_CTRL_MODEM_SLEEP_MODE + prompt "Bluetooth Modem sleep mode" + depends on BTDM_CTRL_MODEM_SLEEP + help + To select which strategy to use for modem sleep + + config BTDM_CTRL_MODEM_SLEEP_MODE_ORIG + bool "ORIG Mode(sleep with low power clock)" + help + ORIG mode is a bluetooth sleep mode that can be used for dual mode controller. In this mode, + bluetooth controller sleeps between BR/EDR frames and BLE events. A low power clock is used to + maintain bluetooth reference clock. + + config BTDM_CTRL_MODEM_SLEEP_MODE_EVED + bool "EVED Mode(For internal test only)" + help + EVED mode is for BLE only and is only for internal test. Do not use it for production. this + mode is not compatible with DFS nor light sleep + endchoice + + choice BTDM_CTRL_LOW_POWER_CLOCK + prompt "Bluetooth low power clock" + depends on BTDM_CTRL_MODEM_SLEEP_MODE_ORIG + help + Select the low power clock source for bluetooth controller. Bluetooth low power clock is + the clock source to maintain time in sleep mode. + + - "Main crystal" option provides good accuracy and can support Dynamic Frequency Scaling + to be used with Bluetooth modem sleep. Light sleep is not supported. + - "External 32kHz crystal" option allows user to use a 32.768kHz crystal as Bluetooth low + power clock. This option is allowed as long as External 32kHz crystal is configured as + the system RTC clock source. This option provides good accuracy and supports Bluetooth + modem sleep to be used alongside Dynamic Frequency Scaling or light sleep. + + config BTDM_CTRL_LPCLK_SEL_MAIN_XTAL + bool "Main crystal" + help + Main crystal can be used as low power clock for bluetooth modem sleep. If this option is + selected, bluetooth modem sleep can work under Dynamic Frequency Scaling(DFS) enabled, but + cannot work when light sleep is enabled. Main crystal has a good performance in accuracy as + the bluetooth low power clock source. + + config BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL + bool "External 32kHz crystal" + depends on RTC_CLK_SRC_EXT_CRYS + help + External 32kHz crystal has a nominal frequency of 32.768kHz and provides good frequency + stability. If used as Bluetooth low power clock, External 32kHz can support Bluetooth + modem sleep to be used with both DFS and light sleep. + endchoice + +endmenu + +choice BTDM_BLE_SLEEP_CLOCK_ACCURACY + prompt "BLE Sleep Clock Accuracy" + depends on BTDM_CTRL_MODE_BLE_ONLY || BTDM_CTRL_MODE_BTDM + default BTDM_BLE_DEFAULT_SCA_250PPM + help + BLE Sleep Clock Accuracy(SCA) for the local device is used to estimate window widening in BLE + connection events. With a lower level of clock accuracy(e.g. 500ppm over 250ppm), the slave + needs a larger RX window to synchronize with master in each anchor point, thus resulting in an + increase of power consumption but a higher level of robustness in keeping connected. According + to the requirements of Bluetooth Core specification 4.2, the worst-case accuracy of Classic + Bluetooth low power oscialltor(LPO) is +/-250ppm in STANDBY and in low power modes such as + sniff. For BLE the worst-case SCA is +/-500ppm. + + - "151ppm to 250ppm" option is the default value for Bluetooth Dual mode + - "251ppm to 500ppm" option can be used in BLE only mode when using external 32kHz crystal as + low power clock. This option is provided in case that BLE sleep clock has a lower level of + accuracy, or other error sources contribute to the inaccurate timing during sleep. + + config BTDM_BLE_DEFAULT_SCA_500PPM + bool "251ppm to 500ppm" + depends on BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL && BTDM_CTRL_MODE_BLE_ONLY + config BTDM_BLE_DEFAULT_SCA_250PPM + bool "151ppm to 250ppm" +endchoice +config BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF + int + default 0 if BTDM_BLE_DEFAULT_SCA_500PPM + default 1 if BTDM_BLE_DEFAULT_SCA_250PPM + default 1 + +config BTDM_BLE_SCAN_DUPL + bool "BLE Scan Duplicate Options" + depends on (BTDM_CTRL_MODE_BTDM || BTDM_CTRL_MODE_BLE_ONLY) + default y + help + This select enables parameters setting of BLE scan duplicate. + +choice BTDM_SCAN_DUPL_TYPE + prompt "Scan Duplicate Type" + default BTDM_SCAN_DUPL_TYPE_DEVICE + depends on BTDM_BLE_SCAN_DUPL + help + Scan duplicate have three ways. one is "Scan Duplicate By Device Address", This way is to use + advertiser address filtering. The adv packet of the same address is only allowed to be reported once. + Another way is "Scan Duplicate By Device Address And Advertising Data". This way is to use advertising + data and device address filtering. All different adv packets with the same address are allowed to be + reported. The last way is "Scan Duplicate By Advertising Data". This way is to use advertising data + filtering. All same advertising data only allow to be reported once even though they are from + different devices. + + config BTDM_SCAN_DUPL_TYPE_DEVICE + bool "Scan Duplicate By Device Address" + help + This way is to use advertiser address filtering. The adv packet of the same address is only + allowed to be reported once + + config BTDM_SCAN_DUPL_TYPE_DATA + bool "Scan Duplicate By Advertising Data" + help + This way is to use advertising data filtering. All same advertising data only allow to be reported + once even though they are from different devices. + + config BTDM_SCAN_DUPL_TYPE_DATA_DEVICE + bool "Scan Duplicate By Device Address And Advertising Data" + help + This way is to use advertising data and device address filtering. All different adv packets with + the same address are allowed to be reported. +endchoice + +config BTDM_SCAN_DUPL_TYPE + int + depends on BTDM_BLE_SCAN_DUPL + default 0 if BTDM_SCAN_DUPL_TYPE_DEVICE + default 1 if BTDM_SCAN_DUPL_TYPE_DATA + default 2 if BTDM_SCAN_DUPL_TYPE_DATA_DEVICE + default 0 + +config BTDM_SCAN_DUPL_CACHE_SIZE + int "Maximum number of devices in scan duplicate filter" + depends on BTDM_BLE_SCAN_DUPL + range 10 1000 + default 100 + help + Maximum number of devices which can be recorded in scan duplicate filter. + When the maximum amount of device in the filter is reached, the oldest device will be refreshed. + +config BTDM_SCAN_DUPL_CACHE_REFRESH_PERIOD + int "Duplicate scan list refresh period (seconds)" + depends on BTDM_BLE_SCAN_DUPL + range 0 1000 + default 0 + help + If the period value is non-zero, the controller will periodically clear the device information + stored in the scan duuplicate filter. If it is 0, the scan duuplicate filter will not be cleared + until the scanning is disabled. Duplicate advertisements for this period should not be sent to the + Host in advertising report events. + There are two scenarios where the ADV packet will be repeatedly reported: + 1. The duplicate scan cache is full, the controller will delete the oldest device information and + add new device information. + 2. When the refresh period is up, the controller will clear all device information and start filtering + again. + +config BTDM_BLE_MESH_SCAN_DUPL_EN + bool "Special duplicate scan mechanism for BLE Mesh scan" + depends on BTDM_BLE_SCAN_DUPL + default n + help + This enables the BLE scan duplicate for special BLE Mesh scan. + +config BTDM_MESH_DUPL_SCAN_CACHE_SIZE + int "Maximum number of Mesh adv packets in scan duplicate filter" + depends on BTDM_BLE_MESH_SCAN_DUPL_EN + range 10 1000 + default 100 + help + Maximum number of adv packets which can be recorded in duplicate scan cache for BLE Mesh. + When the maximum amount of device in the filter is reached, the cache will be refreshed. + +config BTDM_CTRL_FULL_SCAN_SUPPORTED + bool "BLE full scan feature supported" + depends on BTDM_CTRL_MODE_BLE_ONLY || BTDM_CTRL_MODE_BTDM + default y + help + The full scan function is mainly used to provide BLE scan performance. + This is required for scenes with high scan performance requirements, such as BLE Mesh scenes. + +config BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP + bool "BLE adv report flow control supported" + depends on (BTDM_CTRL_MODE_BTDM || BTDM_CTRL_MODE_BLE_ONLY) + default y + help + The function is mainly used to enable flow control for advertising reports. When it is enabled, + advertising reports will be discarded by the controller if the number of unprocessed advertising + reports exceeds the size of BLE adv report flow control. + +config BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM + int "BLE adv report flow control number" + depends on BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 50 1000 + default 100 + help + The number of unprocessed advertising report that Bluedroid can save.If you set + `BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a small value, this may cause adv packets lost. + If you set `BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a large value, Bluedroid may cache a + lot of adv packets and this may cause system memory run out. For example, if you set + it to 50, the maximum memory consumed by host is 35 * 50 bytes. Please set + `BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM` according to your system free memory and handle adv + packets as fast as possible, otherwise it will cause adv packets lost. + +config BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD + int "BLE adv lost event threshold value" + depends on BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 1 1000 + default 20 + help + When adv report flow control is enabled, The ADV lost event will be generated when the number + of ADV packets lost in the controller reaches this threshold. It is better to set a larger value. + If you set `BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it + may cause adv packets lost more. + + +config BTDM_RESERVE_DRAM + hex + default 0xdb5c if BT_ENABLED + default 0 + +config BTDM_CTRL_HLI + bool "High level interrupt" + depends on BT_ENABLED + default y + help + Using Level 4 interrupt for Bluetooth. diff --git a/lib/bt/controller/esp32/bt.c b/lib/bt/controller/esp32/bt.c new file mode 100644 index 00000000..d8792e0f --- /dev/null +++ b/lib/bt/controller/esp32/bt.c @@ -0,0 +1,1851 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "sdkconfig.h" +#include "esp_heap_caps.h" +#include "esp_heap_caps_init.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "freertos/portmacro.h" +#include "xtensa_api.h" // Replace with interrupt allocator API (IDF-3891) +#include "xtensa/core-macros.h" +#include "esp_types.h" +#include "esp_mac.h" +#include "esp_random.h" +#include "esp_task.h" +#include "esp_intr_alloc.h" +#include "esp_attr.h" +#include "esp_phy_init.h" +#include "esp_bt.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_pm.h" +#include "esp_private/esp_clk.h" +#include "esp_private/periph_ctrl.h" +#include "soc/rtc.h" +#include "soc/soc_memory_layout.h" +#include "soc/dport_reg.h" +#include "private/esp_coexist_internal.h" +#include "esp_timer.h" +#if !CONFIG_FREERTOS_UNICORE +#include "esp_ipc.h" +#endif + +#include "esp_rom_sys.h" +#include "hli_api.h" + +#if CONFIG_BT_ENABLED + +/* Macro definition + ************************************************************************ + */ + +#define UNUSED(x) (void)(x) +#define BTDM_LOG_TAG "BTDM_INIT" + +#define BTDM_INIT_PERIOD (5000) /* ms */ + +/* Bluetooth system and controller config */ +#define BTDM_CFG_BT_DATA_RELEASE (1<<0) +#define BTDM_CFG_HCI_UART (1<<1) +#define BTDM_CFG_CONTROLLER_RUN_APP_CPU (1<<2) +#define BTDM_CFG_SCAN_DUPLICATE_OPTIONS (1<<3) +#define BTDM_CFG_SEND_ADV_RESERVED_SIZE (1<<4) +#define BTDM_CFG_BLE_FULL_SCAN_SUPPORTED (1<<5) + +/* Sleep mode */ +#define BTDM_MODEM_SLEEP_MODE_NONE (0) +#define BTDM_MODEM_SLEEP_MODE_ORIG (1) +#define BTDM_MODEM_SLEEP_MODE_EVED (2) // sleep mode for BLE controller, used only for internal test. + +/* 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 (12) // threshold of interval in slots to allow to fall into modem sleep +#define BTDM_MODEM_WAKE_UP_DELAY (4) // delay in slots of modem wake up procedure, including re-enable PHY/RF + +#define BT_DEBUG(...) +#define BT_API_CALL_CHECK(info, api_call, ret) \ +do{\ + esp_err_t __err = (api_call);\ + if ((ret) != __err) {\ + BT_DEBUG("%s %d %s ret=0x%X\n", __FUNCTION__, __LINE__, (info), __err);\ + return __err;\ + }\ +} while(0) + +#define OSI_FUNCS_TIME_BLOCKING 0xffffffff +#define OSI_VERSION 0x00010004 +#define OSI_MAGIC_VALUE 0xFADEBEAD + +/* Types definition + ************************************************************************ + */ + +/* VHCI function interface */ +typedef struct vhci_host_callback { + 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 { + esp_bt_mode_t mode; + intptr_t start; + intptr_t end; +} btdm_dram_available_region_t; + +typedef struct { + void *handle; +} btdm_queue_item_t; + +/* OSI function */ +struct osi_funcs_t { + 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)(size_t size); + void *(* _malloc_internal)(size_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); + xt_handler (*_set_isr_l3)(int n, xt_handler f, void *arg); + void (*_interrupt_l3_disable)(void); + void (*_interrupt_l3_restore)(void); + void *(* _customer_queue_create)(uint32_t queue_len, uint32_t item_size); + int (* _coex_version_get)(unsigned int *major, unsigned int *minor, unsigned int *patch); + uint32_t _magic; +}; + +typedef void (*workitem_handler_t)(void* arg); + +/* External functions or values + ************************************************************************ + */ + +/* not for user call, so don't put to include file */ +/* OSI */ +extern int btdm_osi_funcs_register(void *osi_funcs); +/* 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 +extern int btdm_dispatch_work_to_controller(workitem_handler_t callback, void *arg, bool blocking); +/* 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(void); +extern void btdm_in_wakeup_requesting_set(bool in_wakeup_requesting); +/* Low Power Clock */ +extern bool btdm_lpclk_select_src(uint32_t sel); +extern bool btdm_lpclk_set_div(uint32_t div); +/* VHCI */ +extern bool API_vhci_host_check_send_available(void); +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); +/* Shutdown */ +extern void esp_bt_controller_shutdown(void); +extern void sdk_config_set_bt_pll_track_enable(bool enable); +extern void sdk_config_set_uart_flow_ctrl_enable(bool enable); + +extern char _bss_start_btdm; +extern char _bss_end_btdm; +extern char _data_start_btdm; +extern char _data_end_btdm; +extern uint32_t _data_start_btdm_rom; +extern uint32_t _data_end_btdm_rom; + +extern uint32_t _bt_bss_start; +extern uint32_t _bt_bss_end; +extern uint32_t _nimble_bss_start; +extern uint32_t _nimble_bss_end; +extern uint32_t _btdm_bss_start; +extern uint32_t _btdm_bss_end; +extern uint32_t _bt_data_start; +extern uint32_t _bt_data_end; +extern uint32_t _nimble_data_start; +extern uint32_t _nimble_data_end; +extern uint32_t _btdm_data_start; +extern uint32_t _btdm_data_end; + +/* Local Function Declare + ********************************************************************* + */ +#if CONFIG_BTDM_CTRL_HLI +static xt_handler set_isr_hlevel_wrapper(int n, xt_handler f, void *arg); +static void interrupt_hlevel_disable(void); +static void interrupt_hlevel_restore(void); +#endif /* CONFIG_BTDM_CTRL_HLI */ +static void task_yield(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 int32_t semphr_take_from_isr_wrapper(void *semphr, void *hptw); +static int32_t semphr_give_from_isr_wrapper(void *semphr, void *hptw); +static int32_t semphr_take_wrapper(void *semphr, uint32_t block_time_ms); +static int32_t semphr_give_wrapper(void *semphr); +static void *mutex_create_wrapper(void); +static void mutex_delete_wrapper(void *mutex); +static int32_t mutex_lock_wrapper(void *mutex); +static int32_t mutex_unlock_wrapper(void *mutex); +#if CONFIG_BTDM_CTRL_HLI +static void *queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size); +static void queue_delete_hlevel_wrapper(void *queue); +static int32_t queue_send_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms); +static int32_t queue_send_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw); +static int32_t queue_recv_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms); +static int32_t queue_recv_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw); +#else +static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size); +static void queue_delete_wrapper(void *queue); +static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms); +static int32_t queue_send_from_isr_wrapper(void *queue, void *item, void *hptw); +static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms); +static int32_t queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw); +#endif /* CONFIG_BTDM_CTRL_HLI */ +static int32_t 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 cause_sw_intr(void *arg); +static int cause_sw_intr_to_core_wrapper(int core_id, int intr_no); +static void *malloc_internal_wrapper(size_t size); +static int32_t 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_us(uint32_t cycles); +static uint32_t btdm_us_2_lpcycles(uint32_t us); +static bool btdm_sleep_check_duration(uint32_t *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); +static bool coex_bt_wakeup_request(void); +static void coex_bt_wakeup_request_end(void); +static int coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration); +static int coex_bt_release_wrapper(uint32_t event); +static int coex_register_bt_cb_wrapper(coex_func_cb_t cb); +static uint32_t coex_bb_reset_lock_wrapper(void); +static void coex_bb_reset_unlock_wrapper(uint32_t restore); +static int coex_schm_register_btdm_callback_wrapper(void *callback); +static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status); +static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status); +static uint32_t coex_schm_interval_get_wrapper(void); +static uint8_t coex_schm_curr_period_get_wrapper(void); +static void * coex_schm_curr_phase_get_wrapper(void); +static int coex_wifi_channel_get_wrapper(uint8_t *primary, uint8_t *secondary); +static int coex_register_wifi_channel_change_callback_wrapper(void *cb); +static int coex_version_get_wrapper(unsigned int *major, unsigned int *minor, unsigned int *patch); +#if CONFIG_BTDM_CTRL_HLI +static void *customer_queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size); +#endif /* CONFIG_BTDM_CTRL_HLI */ +static void interrupt_l3_disable(void); +static void interrupt_l3_restore(void); +static void bt_controller_deinit_internal(void); + +/* Local variable definition + *************************************************************************** + */ +/* OSI funcs */ +static const struct osi_funcs_t osi_funcs_ro = { + ._version = OSI_VERSION, +#if CONFIG_BTDM_CTRL_HLI + ._set_isr = set_isr_hlevel_wrapper, + ._ints_on = xt_ints_on, + ._interrupt_disable = interrupt_hlevel_disable, + ._interrupt_restore = interrupt_hlevel_restore, +#else + ._set_isr = xt_set_interrupt_handler, + ._ints_on = xt_ints_on, + ._interrupt_disable = interrupt_l3_disable, + ._interrupt_restore = interrupt_l3_restore, +#endif /* CONFIG_BTDM_CTRL_HLI */ + ._task_yield = task_yield, + ._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, +#if CONFIG_BTDM_CTRL_HLI + ._queue_create = queue_create_hlevel_wrapper, + ._queue_delete = queue_delete_hlevel_wrapper, + ._queue_send = queue_send_hlevel_wrapper, + ._queue_send_from_isr = queue_send_from_isr_hlevel_wrapper, + ._queue_recv = queue_recv_hlevel_wrapper, + ._queue_recv_from_isr = queue_recv_from_isr_hlevel_wrapper, +#else + ._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, +#endif /* CONFIG_BTDM_CTRL_HLI */ + ._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, + ._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, + ._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_phase1 = NULL, + ._btdm_sleep_exit_phase2 = NULL, + ._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper, + ._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 = coex_register_bt_cb_wrapper, + ._coex_bb_reset_lock = coex_bb_reset_lock_wrapper, + ._coex_bb_reset_unlock = coex_bb_reset_unlock_wrapper, + ._coex_schm_register_btdm_callback = coex_schm_register_btdm_callback_wrapper, + ._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper, + ._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper, + ._coex_schm_interval_get = coex_schm_interval_get_wrapper, + ._coex_schm_curr_period_get = coex_schm_curr_period_get_wrapper, + ._coex_schm_curr_phase_get = coex_schm_curr_phase_get_wrapper, + ._coex_wifi_channel_get = coex_wifi_channel_get_wrapper, + ._coex_register_wifi_channel_change_callback = coex_register_wifi_channel_change_callback_wrapper, + ._set_isr_l3 = xt_set_interrupt_handler, + ._interrupt_l3_disable = interrupt_l3_disable, + ._interrupt_l3_restore = interrupt_l3_restore, +#if CONFIG_BTDM_CTRL_HLI + ._customer_queue_create = customer_queue_create_hlevel_wrapper, +#else + ._customer_queue_create = NULL, +#endif /* CONFIG_BTDM_CTRL_HLI */ + ._coex_version_get = coex_version_get_wrapper, + ._magic = OSI_MAGIC_VALUE, +}; + +/* 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 }, +}; + +/* Reserve the full memory region used by Bluetooth Controller, + * some may be released later at runtime. */ +SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_EM_START, SOC_MEM_BT_EM_BREDR_REAL_END, rom_bt_em); +SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_BSS_START, SOC_MEM_BT_BSS_END, rom_bt_bss); +SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_MISC_START, SOC_MEM_BT_MISC_END, rom_bt_misc); +SOC_RESERVE_MEMORY_REGION(SOC_MEM_BT_DATA_START, SOC_MEM_BT_DATA_END, rom_bt_data); + +static DRAM_ATTR struct osi_funcs_t *osi_funcs_p; + +/* Static variable declare */ +// timestamp when PHY/RF was switched on +static DRAM_ATTR int64_t s_time_phy_rf_just_enabled = 0; +static DRAM_ATTR esp_bt_controller_status_t btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + +static DRAM_ATTR portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED; + +// measured average low power clock period in micro seconds +static DRAM_ATTR uint32_t btdm_lpcycle_us = 0; +static DRAM_ATTR uint8_t btdm_lpcycle_us_frac = 0; // number of fractional bit for btdm_lpcycle_us + +#if CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG +// used low power clock +static DRAM_ATTR uint8_t btdm_lpclk_sel; +#endif /* #ifdef CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG */ + +static DRAM_ATTR QueueHandle_t s_wakeup_req_sem = NULL; +#ifdef CONFIG_PM_ENABLE +static DRAM_ATTR esp_timer_handle_t s_btdm_slp_tmr; +static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock; +static bool s_pm_lock_acquired = true; +static DRAM_ATTR bool s_btdm_allow_light_sleep; +// pm_lock to prevent light sleep when using main crystal as Bluetooth low power clock +static DRAM_ATTR esp_pm_lock_handle_t s_light_sleep_pm_lock; +static void btdm_slp_tmr_callback(void *arg); +#endif /* #ifdef CONFIG_PM_ENABLE */ + + +static inline void esp_bt_power_domain_on(void) +{ + // Bluetooth module power up + esp_wifi_bt_power_domain_on(); +} + +static inline void esp_bt_power_domain_off(void) +{ + // Bluetooth module power down + esp_wifi_bt_power_domain_off(); +} + +static inline void btdm_check_and_init_bb(void) +{ + /* init BT-BB if PHY/RF has been switched off since last BT-BB init */ + int64_t latest_ts = esp_phy_rf_get_on_ts(); + if (latest_ts != s_time_phy_rf_just_enabled || + s_time_phy_rf_just_enabled == 0) { + btdm_rf_bb_init_phase2(); + s_time_phy_rf_just_enabled = latest_ts; + } +} + +#if CONFIG_BTDM_CTRL_HLI +struct interrupt_hlevel_cb{ + uint32_t status; + uint8_t nested; +}; + +static DRAM_ATTR struct interrupt_hlevel_cb hli_cb = { + .status = 0, + .nested = 0, +}; + +static xt_handler set_isr_hlevel_wrapper(int mask, xt_handler f, void *arg) +{ + esp_err_t err = hli_intr_register((intr_handler_t) f, arg, DPORT_PRO_INTR_STATUS_0_REG, mask); + if (err == ESP_OK) { + return f; + } else { + return 0; + } + } + +static void IRAM_ATTR interrupt_hlevel_disable(void) +{ + assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE); + assert(hli_cb.nested != UCHAR_MAX); + uint32_t status = hli_intr_disable(); + if (hli_cb.nested++ == 0) { + hli_cb.status = status; + } +} + +static void IRAM_ATTR interrupt_hlevel_restore(void) +{ + assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE); + assert(hli_cb.nested > 0); + if (--hli_cb.nested == 0) { + hli_intr_restore(hli_cb.status); + } +} +#endif /* CONFIG_BTDM_CTRL_HLI */ + +static void IRAM_ATTR interrupt_l3_disable(void) +{ + if (xPortInIsrContext()) { + portENTER_CRITICAL_ISR(&global_int_mux); + } else { + portENTER_CRITICAL(&global_int_mux); + } +} + +static void IRAM_ATTR interrupt_l3_restore(void) +{ + if (xPortInIsrContext()) { + portEXIT_CRITICAL_ISR(&global_int_mux); + } else { + portEXIT_CRITICAL(&global_int_mux); + } +} + +static void IRAM_ATTR task_yield(void) +{ + vPortYield(); +} + + +static void IRAM_ATTR task_yield_from_isr(void) +{ + portYIELD_FROM_ISR(); +} + +static void *semphr_create_wrapper(uint32_t max, uint32_t init) +{ + btdm_queue_item_t *semphr = heap_caps_calloc(1, sizeof(btdm_queue_item_t), MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL); + assert(semphr); + + void *handle = NULL; + + /* IDF FreeRTOS guarantees that all dynamic memory allocation goes to internal RAM. */ + handle = (void *)xSemaphoreCreateCounting(max, init); + assert(handle); + +#if CONFIG_BTDM_CTRL_HLI + SemaphoreHandle_t downstream_semaphore = handle; + assert(downstream_semaphore); + hli_queue_handle_t s_semaphore = hli_semaphore_create(max, downstream_semaphore); + assert(s_semaphore); + semphr->handle = (void *)s_semaphore; +#else + semphr->handle = handle; +#endif /* CONFIG_BTDM_CTRL_HLI */ + + return semphr; +} + +static void semphr_delete_wrapper(void *semphr) +{ + if (semphr == NULL) { + return; + } + + btdm_queue_item_t *semphr_item = (btdm_queue_item_t *)semphr; + void *handle = NULL; +#if CONFIG_BTDM_CTRL_HLI + if (semphr_item->handle) { + handle = ((hli_queue_handle_t)(semphr_item->handle))->downstream; + hli_queue_delete((hli_queue_handle_t)(semphr_item->handle)); + } +#else + handle = semphr_item->handle; +#endif /* CONFIG_BTDM_CTRL_HLI */ + + if (handle) { + vSemaphoreDelete(handle); + } + + free(semphr); +} + +static int32_t IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw) +{ +#if CONFIG_BTDM_CTRL_HLI + // Not support it + assert(0); + return 0; +#else + void *handle = ((btdm_queue_item_t *)semphr)->handle; + return (int32_t)xSemaphoreTakeFromISR(handle, hptw); +#endif /* CONFIG_BTDM_CTRL_HLI */ +} + +static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw) +{ + void *handle = ((btdm_queue_item_t *)semphr)->handle; +#if CONFIG_BTDM_CTRL_HLI + UNUSED(hptw); + assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE); + return hli_semaphore_give(handle); +#else + return (int32_t)xSemaphoreGiveFromISR(handle, hptw); +#endif /* CONFIG_BTDM_CTRL_HLI */ +} + +static int32_t semphr_take_wrapper(void *semphr, uint32_t block_time_ms) +{ + bool ret; + void *handle = ((btdm_queue_item_t *)semphr)->handle; +#if CONFIG_BTDM_CTRL_HLI + if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) { + ret = xSemaphoreTake(((hli_queue_handle_t)handle)->downstream, portMAX_DELAY); + } else { + ret = xSemaphoreTake(((hli_queue_handle_t)handle)->downstream, block_time_ms / portTICK_PERIOD_MS); + } +#else + if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) { + ret = xSemaphoreTake(handle, portMAX_DELAY); + } else { + ret = xSemaphoreTake(handle, block_time_ms / portTICK_PERIOD_MS); + } +#endif /* CONFIG_BTDM_CTRL_HLI */ + return (int32_t)ret; +} + +static int32_t semphr_give_wrapper(void *semphr) +{ + void *handle = ((btdm_queue_item_t *)semphr)->handle; +#if CONFIG_BTDM_CTRL_HLI + return (int32_t)xSemaphoreGive(((hli_queue_handle_t)handle)->downstream); +#else + return (int32_t)xSemaphoreGive(handle); +#endif /* CONFIG_BTDM_CTRL_HLI */ +} + +static void *mutex_create_wrapper(void) +{ + return (void *)xSemaphoreCreateMutex(); +} + +static void mutex_delete_wrapper(void *mutex) +{ + vSemaphoreDelete(mutex); +} + +static int32_t mutex_lock_wrapper(void *mutex) +{ + return (int32_t)xSemaphoreTake(mutex, portMAX_DELAY); +} + +static int32_t mutex_unlock_wrapper(void *mutex) +{ + return (int32_t)xSemaphoreGive(mutex); +} + +static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size) +{ + btdm_queue_item_t *queue = NULL; + + queue = (btdm_queue_item_t*)heap_caps_malloc(sizeof(btdm_queue_item_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + assert(queue); + + /* IDF FreeRTOS guarantees that all dynamic memory allocation goes to internal RAM. */ + queue->handle = xQueueCreate( queue_len, item_size); + assert(queue->handle); + + return queue; +} + +static void queue_delete_wrapper(void *queue) +{ + btdm_queue_item_t *queue_item = (btdm_queue_item_t *)queue; + if (queue_item) { + if(queue_item->handle){ + vQueueDelete(queue_item->handle); + } + free(queue_item); + } +} + +#if CONFIG_BTDM_CTRL_HLI +static void *queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size) +{ + btdm_queue_item_t *queue_item = queue_create_wrapper(queue_len, item_size); + assert(queue_item); + QueueHandle_t downstream_queue = queue_item->handle; + assert(queue_item->handle); + hli_queue_handle_t queue = hli_queue_create(queue_len, item_size, downstream_queue); + assert(queue); + queue_item->handle = queue; + return (void *)queue_item; +} + +static void *customer_queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size) +{ + btdm_queue_item_t *queue_item = queue_create_wrapper(queue_len, item_size); + assert(queue_item); + QueueHandle_t downstream_queue = queue_item->handle; + assert(queue_item->handle); + hli_queue_handle_t queue = hli_customer_queue_create(queue_len, item_size, downstream_queue); + assert(queue); + queue_item->handle = queue; + return (void *)queue_item; +} + +static void queue_delete_hlevel_wrapper(void *queue) +{ + if (queue == NULL) { + return; + } + + btdm_queue_item_t *queue_item = (btdm_queue_item_t *)queue; + + if (queue_item->handle) { + void *handle = ((hli_queue_handle_t)(queue_item->handle))->downstream; + hli_queue_delete(queue_item->handle); + queue_item->handle = handle; + queue_delete_wrapper(queue_item); + } +} + +static int32_t queue_send_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms) +{ + void *handle = ((btdm_queue_item_t *)queue)->handle; + if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) { + return (int32_t)xQueueSend(((hli_queue_handle_t)handle)->downstream, item, portMAX_DELAY); + } else { + return (int32_t)xQueueSend(((hli_queue_handle_t)handle)->downstream, item, block_time_ms / portTICK_PERIOD_MS); + } +} + +/** + * Queue send from isr + * @param queue The queue which will send to + * @param item The message which will be send + * @param hptw need do task yield or not + * @return send success or not + * There is an issue here: When the queue is full, it may reture true but it send fail to the queue, sometimes. + * But in Bluetooth controller's isr, We don't care about the return value. + * It only required tp send success when the queue is empty all the time. + * So, this function meets the requirement. + */ +static int32_t IRAM_ATTR queue_send_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw) +{ + UNUSED(hptw); + assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE); + void *handle = ((btdm_queue_item_t *)queue)->handle; + return hli_queue_put(handle, item); +} + +static int32_t queue_recv_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms) +{ + bool ret; + void *handle = ((btdm_queue_item_t *)queue)->handle; + if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) { + ret = xQueueReceive(((hli_queue_handle_t)handle)->downstream, item, portMAX_DELAY); + } else { + ret = xQueueReceive(((hli_queue_handle_t)handle)->downstream, item, block_time_ms / portTICK_PERIOD_MS); + } + + return (int32_t)ret; +} + +static int32_t IRAM_ATTR queue_recv_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw) +{ + // Not support it + assert(0); + return 0; +} + +#else + +static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms) +{ + if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) { + return (int32_t)xQueueSend(((btdm_queue_item_t*)queue)->handle, item, portMAX_DELAY); + } else { + return (int32_t)xQueueSend(((btdm_queue_item_t*)queue)->handle, item, block_time_ms / portTICK_PERIOD_MS); + } +} + +static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, void *hptw) +{ + return (int32_t)xQueueSendFromISR(((btdm_queue_item_t*)queue)->handle, item, hptw); +} + +static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms) + { + bool ret; + if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) { + ret = xQueueReceive(((btdm_queue_item_t*)queue)->handle, item, portMAX_DELAY); + } else { + ret = xQueueReceive(((btdm_queue_item_t*)queue)->handle, item, block_time_ms / portTICK_PERIOD_MS); + } + + return (int32_t)ret; + } + +static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw) +{ + return (int32_t)xQueueReceiveFromISR(((btdm_queue_item_t*)queue)->handle, item, hptw); +} +#endif /* CONFIG_BTDM_CTRL_HLI */ + + +static int32_t 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 (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); +} + +static void task_delete_wrapper(void *task_handle) +{ + vTaskDelete(task_handle); +} + +static bool IRAM_ATTR is_in_isr_wrapper(void) +{ + return !xPortCanYield(); +} + +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)); +} + +static int IRAM_ATTR cause_sw_intr_to_core_wrapper(int core_id, int intr_no) +{ + esp_err_t err = ESP_OK; + +#if CONFIG_FREERTOS_UNICORE + cause_sw_intr((void *)intr_no); +#else /* CONFIG_FREERTOS_UNICORE */ + if (xPortGetCoreID() == core_id) { + cause_sw_intr((void *)intr_no); + } else { + err = esp_ipc_call(core_id, cause_sw_intr, (void *)intr_no); + } +#endif /* !CONFIG_FREERTOS_UNICORE */ + return err; +} + +static void *malloc_internal_wrapper(size_t size) +{ + return heap_caps_malloc(size, MALLOC_CAP_8BIT|MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL); +} + +static int32_t IRAM_ATTR read_mac_wrapper(uint8_t mac[6]) +{ + int ret = esp_read_mac(mac, ESP_MAC_BT); + ESP_LOGI(BTDM_LOG_TAG, "Bluetooth MAC: %02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + return ret; +} + +static void IRAM_ATTR srand_wrapper(unsigned int seed) +{ + /* empty function */ +} + +static int IRAM_ATTR rand_wrapper(void) +{ + return (int)esp_random(); +} + +static uint32_t IRAM_ATTR btdm_lpcycles_2_us(uint32_t cycles) +{ + // The number of lp cycles should not lead to overflow. Thrs: 100s + // clock measurement is conducted + uint64_t us = (uint64_t)btdm_lpcycle_us * cycles; + us = (us + (1 << (btdm_lpcycle_us_frac - 1))) >> btdm_lpcycle_us_frac; + return (uint32_t)us; +} + +/* + * @brief Converts a duration in slots into a number of low power clock cycles. + */ +static uint32_t IRAM_ATTR btdm_us_2_lpcycles(uint32_t us) +{ + // The number of sleep duration(us) should not lead to overflow. Thrs: 100s + // Compute the sleep duration in us to low power clock cycles, with calibration result applied + // clock measurement is conducted + uint64_t cycles = ((uint64_t)(us) << btdm_lpcycle_us_frac) / btdm_lpcycle_us; + + return (uint32_t)cycles; +} + +static bool IRAM_ATTR btdm_sleep_check_duration(uint32_t *slot_cnt) +{ + if (*slot_cnt < BTDM_MIN_SLEEP_DURATION) { + return false; + } + /* wake up in advance considering the delay in enabling PHY/RF */ + *slot_cnt -= BTDM_MODEM_WAKE_UP_DELAY; + return true; +} + +static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles) +{ +#ifdef CONFIG_PM_ENABLE + // start a timer to wake up and acquire the pm_lock before modem_sleep awakes + uint32_t us_to_sleep = btdm_lpcycles_2_us(lpcycles); + +#define BTDM_MIN_TIMER_UNCERTAINTY_US (500) + assert(us_to_sleep > BTDM_MIN_TIMER_UNCERTAINTY_US); + // allow a maximum time uncertainty to be about 488ppm(1/2048) at least as clock drift + // and set the timer in advance + uint32_t uncertainty = (us_to_sleep >> 11); + if (uncertainty < BTDM_MIN_TIMER_UNCERTAINTY_US) { + uncertainty = BTDM_MIN_TIMER_UNCERTAINTY_US; + } + + if (esp_timer_start_once(s_btdm_slp_tmr, us_to_sleep - uncertainty) != ESP_OK) { + ESP_LOGW(BTDM_LOG_TAG, "timer start failed"); + } +#endif +} + +static void btdm_sleep_enter_phase2_wrapper(void) +{ + if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_ORIG) { + esp_phy_disable(PHY_MODEM_BT); +#ifdef CONFIG_PM_ENABLE + if (s_pm_lock_acquired) { + esp_pm_lock_release(s_pm_lock); + s_pm_lock_acquired = false; + } +#endif + } else if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_EVED) { + esp_phy_disable(PHY_MODEM_BT); + // pause bluetooth baseband + periph_module_disable(PERIPH_BT_BASEBAND_MODULE); + } +} + +static void btdm_sleep_exit_phase3_wrapper(void) +{ +#ifdef CONFIG_PM_ENABLE + if (!s_pm_lock_acquired) { + s_pm_lock_acquired = true; + esp_pm_lock_acquire(s_pm_lock); + } +#endif + + if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_ORIG) { + esp_phy_enable(PHY_MODEM_BT); + btdm_check_and_init_bb(); +#ifdef CONFIG_PM_ENABLE + esp_timer_stop(s_btdm_slp_tmr); +#endif + } else if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_EVED) { + // resume bluetooth baseband + periph_module_enable(PERIPH_BT_BASEBAND_MODULE); + esp_phy_enable(PHY_MODEM_BT); + } +} + +#ifdef CONFIG_PM_ENABLE +static void btdm_slp_tmr_customer_callback(void * arg) +{ + (void)(arg); + + if (!s_pm_lock_acquired) { + s_pm_lock_acquired = true; + esp_pm_lock_acquire(s_pm_lock); + } +} + +static void IRAM_ATTR btdm_slp_tmr_callback(void *arg) +{ + (void)(arg); + btdm_dispatch_work_to_controller(btdm_slp_tmr_customer_callback, NULL, true); +} +#endif + +#define BTDM_ASYNC_WAKEUP_REQ_HCI 0 +#define BTDM_ASYNC_WAKEUP_REQ_COEX 1 +#define BTDM_ASYNC_WAKEUP_REQ_CTRL_DISA 2 +#define BTDM_ASYNC_WAKEUP_REQMAX 3 + +static void btdm_wakeup_request_callback(void * arg) +{ + (void)(arg); + +#if CONFIG_PM_ENABLE + if (!s_pm_lock_acquired) { + s_pm_lock_acquired = true; + esp_pm_lock_acquire(s_pm_lock); + } + esp_timer_stop(s_btdm_slp_tmr); +#endif + btdm_wakeup_request(); + + semphr_give_wrapper(s_wakeup_req_sem); +} + +static bool async_wakeup_request(int event) +{ + bool do_wakeup_request = false; + + switch (event) { + case BTDM_ASYNC_WAKEUP_REQ_HCI: + btdm_in_wakeup_requesting_set(true); + // NO break + case BTDM_ASYNC_WAKEUP_REQ_CTRL_DISA: + if (!btdm_power_state_active()) { + do_wakeup_request = true; + + btdm_dispatch_work_to_controller(btdm_wakeup_request_callback, NULL, true); + semphr_take_wrapper(s_wakeup_req_sem, OSI_FUNCS_TIME_BLOCKING); + } + break; + case BTDM_ASYNC_WAKEUP_REQ_COEX: + if (!btdm_power_state_active()) { + do_wakeup_request = true; +#if CONFIG_PM_ENABLE + if (!s_pm_lock_acquired) { + s_pm_lock_acquired = true; + esp_pm_lock_acquire(s_pm_lock); + } + esp_timer_stop(s_btdm_slp_tmr); +#endif + btdm_wakeup_request(); + } + break; + default: + return false; + } + + return do_wakeup_request; +} + +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: + case BTDM_ASYNC_WAKEUP_REQ_CTRL_DISA: + request_lock = false; + break; + default: + return; + } + + if (request_lock) { + btdm_in_wakeup_requesting_set(false); + } + + return; +} + +static bool coex_bt_wakeup_request(void) +{ + return async_wakeup_request(BTDM_ASYNC_WAKEUP_REQ_COEX); +} + +static void coex_bt_wakeup_request_end(void) +{ + async_wakeup_request_end(BTDM_ASYNC_WAKEUP_REQ_COEX); + return; +} + +static int IRAM_ATTR coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_bt_request(event, latency, duration); +#else + return 0; +#endif +} + +static int IRAM_ATTR coex_bt_release_wrapper(uint32_t event) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_bt_release(event); +#else + return 0; +#endif +} + +static int coex_register_bt_cb_wrapper(coex_func_cb_t cb) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_register_bt_cb(cb); +#else + return 0; +#endif +} + +static uint32_t IRAM_ATTR coex_bb_reset_lock_wrapper(void) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_bb_reset_lock(); +#else + return 0; +#endif +} + +static void IRAM_ATTR coex_bb_reset_unlock_wrapper(uint32_t restore) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_bb_reset_unlock(restore); +#endif +} + +static int coex_schm_register_btdm_callback_wrapper(void *callback) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_register_callback(COEX_SCHM_CALLBACK_TYPE_BT, callback); +#else + return 0; +#endif +} + +static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_clear(type, status); +#endif +} + +static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_set(type, status); +#endif +} + +static uint32_t coex_schm_interval_get_wrapper(void) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_interval_get(); +#else + return 0; +#endif +} + +static uint8_t coex_schm_curr_period_get_wrapper(void) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_curr_period_get(); +#else + return 1; +#endif +} + +static void * coex_schm_curr_phase_get_wrapper(void) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_curr_phase_get(); +#else + return NULL; +#endif +} + +static int coex_wifi_channel_get_wrapper(uint8_t *primary, uint8_t *secondary) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_wifi_channel_get(primary, secondary); +#else + return -1; +#endif +} + +static int coex_register_wifi_channel_change_callback_wrapper(void *cb) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_register_wifi_channel_change_callback(cb); +#else + return -1; +#endif +} + +static int coex_version_get_wrapper(unsigned int *major, unsigned int *minor, unsigned int *patch) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_version_t version; + ESP_ERROR_CHECK(coex_version_get_value(&version)); + *major = (unsigned int)version.major; + *minor = (unsigned int)version.minor; + *patch = (unsigned int)version.patch; + return 0; +#endif + return -1; +} + +bool esp_vhci_host_check_send_available(void) +{ + return API_vhci_host_check_send_available(); +} + +void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) +{ + async_wakeup_request(BTDM_ASYNC_WAKEUP_REQ_HCI); + + API_vhci_host_send_packet(data, len); + + async_wakeup_request_end(BTDM_ASYNC_WAKEUP_REQ_HCI); +} + +esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) +{ + return API_vhci_host_register_callback((const vhci_host_callback_t *)callback) == 0 ? ESP_OK : ESP_FAIL; +} + +static uint32_t btdm_config_mask_load(void) +{ + uint32_t mask = 0x0; + +#if CONFIG_BTDM_CTRL_HCI_MODE_UART_H4 + mask |= BTDM_CFG_HCI_UART; +#endif +#if CONFIG_BTDM_CTRL_PINNED_TO_CORE == 1 + mask |= BTDM_CFG_CONTROLLER_RUN_APP_CPU; +#endif +#if CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED + mask |= BTDM_CFG_BLE_FULL_SCAN_SUPPORTED; +#endif /* CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED */ + mask |= BTDM_CFG_SCAN_DUPLICATE_OPTIONS; + + mask |= BTDM_CFG_SEND_ADV_RESERVED_SIZE; + + return mask; +} + +static void btdm_controller_mem_init(void) +{ + /* initialise .data section */ + memcpy(&_data_start_btdm, (void *)_data_start_btdm_rom, &_data_end_btdm - &_data_start_btdm); + ESP_LOGD(BTDM_LOG_TAG, ".data initialise [0x%08x] <== [0x%08x]", (uint32_t)&_data_start_btdm, _data_start_btdm_rom); + + //initial em, .bss section + for (int i = 1; i < sizeof(btdm_dram_available_region)/sizeof(btdm_dram_available_region_t); 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); + ESP_LOGD(BTDM_LOG_TAG, ".bss initialise [0x%08x] - [0x%08x]", btdm_dram_available_region[i].start, btdm_dram_available_region[i].end); + } + } +} + +static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) +{ + int ret = heap_caps_add_region(start, end); + /* heap_caps_add_region() returns ESP_ERR_INVALID_SIZE if the memory region is + * is too small to fit a heap. This cannot be termed as a fatal error and hence + * we replace it by ESP_OK + */ + if (ret == ESP_ERR_INVALID_SIZE) { + return ESP_OK; + } + return ret; +} + +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +{ + bool update = true; + intptr_t mem_start=(intptr_t) NULL, mem_end=(intptr_t) NULL; + + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; + } + + //already released + if (!(mode & btdm_dram_available_region[0].mode)) { + return ESP_ERR_INVALID_STATE; + } + + for (int i = 0; i < sizeof(btdm_dram_available_region)/sizeof(btdm_dram_available_region_t); i++) { + //skip the share mode, idle mode and other mode + if (btdm_dram_available_region[i].mode == ESP_BT_MODE_IDLE + || (mode & btdm_dram_available_region[i].mode) != btdm_dram_available_region[i].mode) { + //clear the bit of the mode which will be released + btdm_dram_available_region[i].mode &= ~mode; + continue; + } else { + //clear the bit of the mode which will be released + btdm_dram_available_region[i].mode &= ~mode; + } + + if (update) { + mem_start = btdm_dram_available_region[i].start; + mem_end = btdm_dram_available_region[i].end; + update = false; + } + + if (i < sizeof(btdm_dram_available_region)/sizeof(btdm_dram_available_region_t) - 1) { + mem_end = btdm_dram_available_region[i].end; + if (btdm_dram_available_region[i+1].mode != ESP_BT_MODE_IDLE + && (mode & btdm_dram_available_region[i+1].mode) == btdm_dram_available_region[i+1].mode + && mem_end == btdm_dram_available_region[i+1].start) { + continue; + } else { + ESP_LOGD(BTDM_LOG_TAG, "Release DRAM [0x%08x] - [0x%08x]", mem_start, mem_end); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + update = true; + } + } else { + mem_end = btdm_dram_available_region[i].end; + ESP_LOGD(BTDM_LOG_TAG, "Release DRAM [0x%08x] - [0x%08x]", mem_start, mem_end); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + update = true; + } + } + + if (mode == ESP_BT_MODE_BTDM) { + mem_start = (intptr_t)&_btdm_bss_start; + mem_end = (intptr_t)&_btdm_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(BTDM_LOG_TAG, "Release BTDM BSS [0x%08x] - [0x%08x]", mem_start, mem_end); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + mem_start = (intptr_t)&_btdm_data_start; + mem_end = (intptr_t)&_btdm_data_end; + if (mem_start != mem_end) { + ESP_LOGD(BTDM_LOG_TAG, "Release BTDM Data [0x%08x] - [0x%08x]", mem_start, mem_end); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + return ESP_OK; +} + +esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) +{ + int ret; + intptr_t mem_start, mem_end; + + ret = esp_bt_controller_mem_release(mode); + if (ret != ESP_OK) { + return ret; + } + + if (mode == ESP_BT_MODE_BTDM) { + mem_start = (intptr_t)&_bt_bss_start; + mem_end = (intptr_t)&_bt_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(BTDM_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x]", mem_start, mem_end); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + mem_start = (intptr_t)&_bt_data_start; + mem_end = (intptr_t)&_bt_data_end; + if (mem_start != mem_end) { + ESP_LOGD(BTDM_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x]", mem_start, mem_end); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + + mem_start = (intptr_t)&_nimble_bss_start; + mem_end = (intptr_t)&_nimble_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(BTDM_LOG_TAG, "Release NimBLE BSS [0x%08x] - [0x%08x]", mem_start, mem_end); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + mem_start = (intptr_t)&_nimble_data_start; + mem_end = (intptr_t)&_nimble_data_end; + if (mem_start != mem_end) { + ESP_LOGD(BTDM_LOG_TAG, "Release NimBLE Data [0x%08x] - [0x%08x]", mem_start, mem_end); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + return ESP_OK; +} + +#if CONFIG_BTDM_CTRL_HLI +static void hli_queue_setup_cb(void* arg) +{ + hli_queue_setup(); +} + +static void hli_queue_setup_pinned_to_core(int core_id) +{ +#if CONFIG_FREERTOS_UNICORE + hli_queue_setup_cb(NULL); +#else /* CONFIG_FREERTOS_UNICORE */ + if (xPortGetCoreID() == core_id) { + hli_queue_setup_cb(NULL); + } else { + esp_ipc_call(core_id, hli_queue_setup_cb, NULL); + } +#endif /* !CONFIG_FREERTOS_UNICORE */ +} +#endif /* CONFIG_BTDM_CTRL_HLI */ + +esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) +{ + esp_err_t err; + uint32_t btdm_cfg_mask = 0; + +#if CONFIG_BTDM_CTRL_HLI + hli_queue_setup_pinned_to_core(CONFIG_BTDM_CTRL_PINNED_TO_CORE); +#endif /* CONFIG_BTDM_CTRL_HLI */ + + //if all the bt available memory was already released, cannot initialize bluetooth controller + if (btdm_dram_available_region[0].mode == ESP_BT_MODE_IDLE) { + return ESP_ERR_INVALID_STATE; + } + + osi_funcs_p = (struct osi_funcs_t *)malloc_internal_wrapper(sizeof(struct osi_funcs_t)); + if (osi_funcs_p == NULL) { + return ESP_ERR_NO_MEM; + } + + memcpy(osi_funcs_p, &osi_funcs_ro, sizeof(struct osi_funcs_t)); + if (btdm_osi_funcs_register(osi_funcs_p) != 0) { + return ESP_ERR_INVALID_ARG; + } + + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; + } + + if (cfg == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (cfg->controller_task_prio != ESP_TASK_BT_CONTROLLER_PRIO + || cfg->controller_task_stack_size < ESP_TASK_BT_CONTROLLER_STACK) { + return ESP_ERR_INVALID_ARG; + } + + //overwrite some parameters + cfg->bt_max_sync_conn = CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF; + 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))) { + return ESP_ERR_INVALID_ARG; + } + + ESP_LOGI(BTDM_LOG_TAG, "BT controller compile version [%s]", btdm_controller_get_compile_version()); + + s_wakeup_req_sem = semphr_create_wrapper(1, 0); + if (s_wakeup_req_sem == NULL) { + err = ESP_ERR_NO_MEM; + goto error; + } + + esp_phy_modem_init(); + + esp_bt_power_domain_on(); + + btdm_controller_mem_init(); + + periph_module_enable(PERIPH_BT_MODULE); + +#ifdef CONFIG_PM_ENABLE + s_btdm_allow_light_sleep = false; +#endif + + // set default sleep clock cycle and its fractional bits + btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; + btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac); + +#if CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG + + btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value +#if CONFIG_BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL + // check whether or not EXT_CRYS is working + if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32kHz XTAL +#ifdef CONFIG_PM_ENABLE + s_btdm_allow_light_sleep = true; +#endif + } else { + ESP_LOGW(BTDM_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock\n" + "light sleep mode will not be able to apply when bluetooth is enabled"); + btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value + } +#else + btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value +#endif + + bool select_src_ret __attribute__((unused)); + bool set_div_ret __attribute__((unused)); + if (btdm_lpclk_sel == BTDM_LPCLK_SEL_XTAL) { + select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL); + set_div_ret = btdm_lpclk_set_div(esp_clk_xtal_freq() * 2 / MHZ - 1); + assert(select_src_ret && set_div_ret); + btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; + btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac); + } else { // btdm_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); + assert(select_src_ret && set_div_ret); + btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; + btdm_lpcycle_us = (RTC_CLK_CAL_FRACT > 15) ? (1000000 << (RTC_CLK_CAL_FRACT - 15)) : + (1000000 >> (15 - RTC_CLK_CAL_FRACT)); + assert(btdm_lpcycle_us != 0); + } + btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_ORIG); + +#elif CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_EVED + btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_EVED); +#else + btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_NONE); +#endif + +#if CONFIG_BTDM_CTRL_HCI_UART_FLOW_CTRL_EN + sdk_config_set_uart_flow_ctrl_enable(true); +#else + sdk_config_set_uart_flow_ctrl_enable(false); +#endif + +#ifdef CONFIG_PM_ENABLE + if (!s_btdm_allow_light_sleep) { + if ((err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "btLS", &s_light_sleep_pm_lock)) != ESP_OK) { + goto error; + } + } + if ((err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock)) != ESP_OK) { + goto error; + } + esp_timer_create_args_t create_args = { + .callback = btdm_slp_tmr_callback, + .arg = NULL, + .name = "btSlp" + }; + if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) { + goto error; + } + + s_pm_lock_acquired = true; +#endif + +#if CONFIG_SW_COEXIST_ENABLE + coex_init(); +#endif + + btdm_cfg_mask = btdm_config_mask_load(); + + if (btdm_controller_init(btdm_cfg_mask, cfg) != 0) { + err = ESP_ERR_NO_MEM; + goto error; + } + + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + + return ESP_OK; + +error: + + bt_controller_deinit_internal(); + + return err; +} + +esp_err_t esp_bt_controller_deinit(void) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) { + return ESP_ERR_INVALID_STATE; + } + + btdm_controller_deinit(); + + bt_controller_deinit_internal(); + + return ESP_OK; +} + +static void bt_controller_deinit_internal(void) +{ + periph_module_disable(PERIPH_BT_MODULE); + +#ifdef CONFIG_PM_ENABLE + if (!s_btdm_allow_light_sleep) { + esp_pm_lock_delete(s_light_sleep_pm_lock); + s_light_sleep_pm_lock = NULL; + } + + if (s_pm_lock != NULL) { + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; + } + + if (s_btdm_slp_tmr != NULL) { + esp_timer_stop(s_btdm_slp_tmr); + esp_timer_delete(s_btdm_slp_tmr); + s_btdm_slp_tmr = NULL; + } + + s_pm_lock_acquired = false; +#endif + + if (s_wakeup_req_sem) { + semphr_delete_wrapper(s_wakeup_req_sem); + s_wakeup_req_sem = NULL; + } + + if (osi_funcs_p) { + free(osi_funcs_p); + osi_funcs_p = NULL; + } + + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + + btdm_lpcycle_us = 0; + btdm_controller_set_sleep_mode(BTDM_MODEM_SLEEP_MODE_NONE); + + esp_bt_power_domain_off(); + + esp_phy_modem_deinit(); +} + +static void bt_controller_shutdown(void* arg) +{ + esp_bt_controller_shutdown(); +} + +static void bt_shutdown(void) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return; + } +#if !CONFIG_FREERTOS_UNICORE + esp_ipc_call_blocking(CONFIG_BTDM_CTRL_PINNED_TO_CORE, bt_controller_shutdown, NULL); +#else + bt_controller_shutdown(NULL); +#endif + esp_phy_disable(PHY_MODEM_BT); + + return; +} + + +esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) +{ + int ret; + + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) { + return ESP_ERR_INVALID_STATE; + } + + //As the history reason, mode should be equal to the mode which set in esp_bt_controller_init() + if (mode != btdm_controller_get_mode()) { + return ESP_ERR_INVALID_ARG; + } + +#ifdef CONFIG_PM_ENABLE + if (!s_btdm_allow_light_sleep) { + esp_pm_lock_acquire(s_light_sleep_pm_lock); + } + esp_pm_lock_acquire(s_pm_lock); +#endif + + esp_phy_enable(PHY_MODEM_BT); + +#if CONFIG_SW_COEXIST_ENABLE + coex_enable(); +#endif + + if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_ORIG) { + btdm_controller_enable_sleep(true); + } + + sdk_config_set_bt_pll_track_enable(true); + + // inititalize bluetooth baseband + btdm_check_and_init_bb(); + + ret = btdm_controller_enable(mode); + if (ret != 0) { +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + esp_phy_disable(PHY_MODEM_BT); +#ifdef CONFIG_PM_ENABLE + if (!s_btdm_allow_light_sleep) { + esp_pm_lock_release(s_light_sleep_pm_lock); + } + esp_pm_lock_release(s_pm_lock); +#endif + return ESP_ERR_INVALID_STATE; + } + + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED; + ret = esp_register_shutdown_handler(bt_shutdown); + if (ret != ESP_OK) { + ESP_LOGW(BTDM_LOG_TAG, "Register shutdown handler failed, ret = 0x%x", ret); + } + + return ESP_OK; +} + +esp_err_t esp_bt_controller_disable(void) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + // disable modem sleep and wake up from sleep mode + if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_ORIG) { + btdm_controller_enable_sleep(false); + async_wakeup_request(BTDM_ASYNC_WAKEUP_REQ_CTRL_DISA); + while (!btdm_power_state_active()) { + esp_rom_delay_us(1000); + } + } + + btdm_controller_disable(); + +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + + esp_phy_disable(PHY_MODEM_BT); + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + esp_unregister_shutdown_handler(bt_shutdown); + +#ifdef CONFIG_PM_ENABLE + if (!s_btdm_allow_light_sleep) { + esp_pm_lock_release(s_light_sleep_pm_lock); + } + esp_pm_lock_release(s_pm_lock); +#endif + + return ESP_OK; +} + +esp_bt_controller_status_t esp_bt_controller_get_status(void) +{ + return btdm_controller_status; +} + +/* extra functions */ +esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_t power_level) +{ + if (ble_txpwr_set(power_type, power_level) != 0) { + return ESP_ERR_INVALID_ARG; + } + + return ESP_OK; +} + +esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) +{ + return (esp_power_level_t)ble_txpwr_get(power_type); +} + +esp_err_t esp_bredr_tx_power_set(esp_power_level_t min_power_level, esp_power_level_t max_power_level) +{ + esp_err_t err; + int ret; + + ret = bredr_txpwr_set(min_power_level, max_power_level); + + if (ret == 0) { + err = ESP_OK; + } else if (ret == -1) { + err = ESP_ERR_INVALID_ARG; + } else { + err = ESP_ERR_INVALID_STATE; + } + + return err; +} + +esp_err_t esp_bredr_tx_power_get(esp_power_level_t *min_power_level, esp_power_level_t *max_power_level) +{ + if (bredr_txpwr_get((int *)min_power_level, (int *)max_power_level) != 0) { + return ESP_ERR_INVALID_ARG; + } + + return ESP_OK; +} + +esp_err_t esp_bt_sleep_enable (void) +{ + esp_err_t status; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_ORIG || + btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_EVED) { + btdm_controller_enable_sleep (true); + status = ESP_OK; + } else { + status = ESP_ERR_NOT_SUPPORTED; + } + + return status; +} + +esp_err_t esp_bt_sleep_disable (void) +{ + esp_err_t status; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + if (btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_ORIG || + btdm_controller_get_sleep_mode() == BTDM_MODEM_SLEEP_MODE_EVED) { + btdm_controller_enable_sleep (false); + status = ESP_OK; + } else { + status = ESP_ERR_NOT_SUPPORTED; + } + + return status; +} + +esp_err_t esp_bredr_sco_datapath_set(esp_sco_data_path_t data_path) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + bredr_sco_datapath_set(data_path); + return ESP_OK; +} + +esp_err_t esp_ble_scan_dupilcate_list_flush(void) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + btdm_controller_scan_duplicate_list_clear(); + return ESP_OK; +} + +/** + * This function re-write controller's function, + * As coredump can not show paramerters in function which is in a .a file. + * + * After coredump fixing this issue, just delete this function. + */ +void IRAM_ATTR r_assert(const char *condition, int param0, int param1, const char *file, int line) +{ + __asm__ __volatile__("ill\n"); +} + +#endif /* CONFIG_BT_ENABLED */ diff --git a/lib/bt/controller/esp32/hli_api.c b/lib/bt/controller/esp32/hli_api.c new file mode 100644 index 00000000..30e16fa0 --- /dev/null +++ b/lib/bt/controller/esp32/hli_api.c @@ -0,0 +1,297 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <string.h> +#include "esp_log.h" +#include "esp_heap_caps.h" +#include "xtensa/core-macros.h" +#include "soc/dport_reg.h" +#include "hli_api.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" + +#if CONFIG_BTDM_CTRL_HLI +#define HLI_MAX_HANDLERS 4 + +typedef struct { + intr_handler_t handler; + void* arg; + uint32_t intr_reg; + uint32_t intr_mask; +} hli_handler_info_t; + +typedef struct { +#define CUSTOMER_TYPE_REQUEST (0) +#define CUSTOMER_TYPE_RELEASE (1) + struct { + uint32_t cb_type; + union { + int (* request)(uint32_t, uint32_t, uint32_t); + int (* release)(uint32_t); + } cb; + } customer_cb; + uint32_t arg0, arg1, arg2; +} customer_swisr_t; + +static void IRAM_ATTR customer_swisr_handle(customer_swisr_t *cus_swisr) +{ + if (cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_REQUEST) { + if (cus_swisr->customer_cb.cb.request != NULL) { + cus_swisr->customer_cb.cb.request(cus_swisr->arg0, cus_swisr->arg1, cus_swisr->arg2); + } + } else if(cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_RELEASE) { + if (cus_swisr->customer_cb.cb.release != NULL) { + cus_swisr->customer_cb.cb.release(cus_swisr->arg0); + } + } +} + +static DRAM_ATTR hli_handler_info_t s_hli_handlers[HLI_MAX_HANDLERS]; + +esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask) +{ + for (hli_handler_info_t* hip = s_hli_handlers; + hip < s_hli_handlers + HLI_MAX_HANDLERS; + ++hip) { + if (hip->handler == NULL) { + hip->arg = arg; + hip->intr_reg = intr_reg; + hip->intr_mask = intr_mask; + hip->handler = handler; /* set last, indicates the entry as valid */ + return ESP_OK; + } + } + return ESP_ERR_NO_MEM; +} + +void IRAM_ATTR hli_c_handler(void) +{ + bool handled = false; + /* Iterate over registered interrupt handlers, + * and check if the expected mask is present in the interrupt status register. + */ + for (hli_handler_info_t* hip = s_hli_handlers; + hip < s_hli_handlers + HLI_MAX_HANDLERS; + ++hip) { + if (hip->handler == NULL) { + continue; + } + uint32_t reg = hip->intr_reg; + uint32_t val; + if (reg == 0) { /* special case for CPU internal interrupts */ + val = XTHAL_GET_INTERRUPT(); + } else { + /* "reg" might not be in DPORT, but this will work in any case */ + val = DPORT_REG_READ(reg); + } + if ((val & hip->intr_mask) != 0) { + handled = true; + (*hip->handler)(hip->arg); + } + } + if (!handled) { + /* no handler found, it is OK in this case. */ + } +} + +uint32_t IRAM_ATTR hli_intr_disable(void) +{ + /* disable level 4 and below */ + return XTOS_SET_INTLEVEL(XCHAL_DEBUGLEVEL - 2); +} + +void IRAM_ATTR hli_intr_restore(uint32_t state) +{ + XTOS_RESTORE_JUST_INTLEVEL(state); +} + +#define HLI_META_QUEUE_SIZE 16 +#define HLI_QUEUE_MAX_ELEM_SIZE 32 +#define HLI_QUEUE_SW_INT_NUM 29 + +#define HLI_QUEUE_FLAG_SEMAPHORE BIT(0) +#define HLI_QUEUE_FLAG_CUSTOMER BIT(1) + +static DRAM_ATTR struct hli_queue_t *s_meta_queue_ptr = NULL; +static intr_handle_t ret_handle; + +static inline char* IRAM_ATTR wrap_ptr(hli_queue_handle_t queue, char *ptr) +{ + return (ptr == queue->bufend) ? queue->buf : ptr; +} + +static inline bool IRAM_ATTR queue_empty(hli_queue_handle_t queue) +{ + return queue->begin == queue->end; +} + +static inline bool IRAM_ATTR queue_full(hli_queue_handle_t queue) +{ + return wrap_ptr(queue, queue->end + queue->elem_size) == queue->begin; +} + +static void IRAM_ATTR queue_isr_handler(void* arg) +{ + int do_yield = pdFALSE; + XTHAL_SET_INTCLEAR(BIT(HLI_QUEUE_SW_INT_NUM)); + hli_queue_handle_t queue; + + while (hli_queue_get(s_meta_queue_ptr, &queue)) { + static DRAM_ATTR char scratch[HLI_QUEUE_MAX_ELEM_SIZE]; + while (hli_queue_get(queue, scratch)) { + int res = pdPASS; + if ((queue->flags & HLI_QUEUE_FLAG_CUSTOMER) != 0) { + customer_swisr_handle((customer_swisr_t *)scratch); + } else if ((queue->flags & HLI_QUEUE_FLAG_SEMAPHORE) != 0) { + res = xSemaphoreGiveFromISR((SemaphoreHandle_t) queue->downstream, &do_yield); + } else { + res = xQueueSendFromISR(queue->downstream, scratch, &do_yield); + } + if (res == pdFAIL) { + /* Failed to send to downstream queue, it is OK in this case. */ + } + } + } + if (do_yield) { + portYIELD_FROM_ISR(); + } +} + +/* Notify the level 3 handler that an element is added to the given hli queue. + * Do this by placing the queue handle onto s_meta_queue, and raising a SW interrupt. + * + * This function must be called with HL interrupts disabled! + */ +static void IRAM_ATTR queue_signal(hli_queue_handle_t queue) +{ + /* See if the queue is already in s_meta_queue, before adding */ + bool found = false; + const hli_queue_handle_t *end = (hli_queue_handle_t*) s_meta_queue_ptr->end; + hli_queue_handle_t *item = (hli_queue_handle_t*) s_meta_queue_ptr->begin; + for (;item != end; item = (hli_queue_handle_t*) wrap_ptr(s_meta_queue_ptr, (char*) (item + 1))) { + if (*item == queue) { + found = true; + break; + } + } + if (!found) { + bool res = hli_queue_put(s_meta_queue_ptr, &queue); + if (!res) { + esp_rom_printf(DRAM_STR("Fatal error in queue_signal: s_meta_queue full\n")); + abort(); + } + XTHAL_SET_INTSET(BIT(HLI_QUEUE_SW_INT_NUM)); + } +} + +static void queue_init(hli_queue_handle_t queue, size_t buf_size, size_t elem_size, QueueHandle_t downstream) +{ + queue->elem_size = elem_size; + queue->begin = queue->buf; + queue->end = queue->buf; + queue->bufend = queue->buf + buf_size; + queue->downstream = downstream; + queue->flags = 0; +} + +void hli_queue_setup(void) +{ + if (s_meta_queue_ptr == NULL) { + s_meta_queue_ptr = hli_queue_create(HLI_META_QUEUE_SIZE, sizeof(void*), NULL); + ESP_ERROR_CHECK(esp_intr_alloc(ETS_INTERNAL_SW1_INTR_SOURCE, ESP_INTR_FLAG_IRAM, queue_isr_handler, NULL, &ret_handle)); + xt_ints_on(BIT(HLI_QUEUE_SW_INT_NUM)); + } +} + +void hli_queue_shutdown(void) +{ + if (s_meta_queue_ptr != NULL) { + hli_queue_delete(s_meta_queue_ptr); + s_meta_queue_ptr = NULL; + esp_intr_free(ret_handle); + xt_ints_off(BIT(HLI_QUEUE_SW_INT_NUM)); + } +} + +hli_queue_handle_t hli_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream) +{ + const size_t buf_elem = nelem + 1; + if (elem_size > HLI_QUEUE_MAX_ELEM_SIZE) { + return NULL; + } + size_t buf_size = buf_elem * elem_size; + hli_queue_handle_t res = (hli_queue_handle_t) heap_caps_malloc(sizeof(struct hli_queue_t) + buf_size, + MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (res == NULL) { + return NULL; + } + queue_init(res, buf_size, elem_size, downstream); + return res; +} + +hli_queue_handle_t hli_customer_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream) +{ + hli_queue_handle_t res = hli_queue_create(nelem, elem_size, (QueueHandle_t) downstream); + if (res == NULL) { + return NULL; + } + res->flags |= HLI_QUEUE_FLAG_CUSTOMER; + return res; +} + +hli_queue_handle_t hli_semaphore_create(size_t max_count, SemaphoreHandle_t downstream) +{ + const size_t elem_size = 1; + hli_queue_handle_t res = hli_queue_create(max_count, elem_size, (QueueHandle_t) downstream); + if (res == NULL) { + return NULL; + } + res->flags |= HLI_QUEUE_FLAG_SEMAPHORE; + return res; +} + +void hli_queue_delete(hli_queue_handle_t queue) +{ + free(queue); +} + +bool IRAM_ATTR hli_queue_get(hli_queue_handle_t queue, void* out) +{ + uint32_t int_state = hli_intr_disable(); + bool res = false; + if (!queue_empty(queue)) { + memcpy(out, queue->begin, queue->elem_size); + queue->begin = wrap_ptr(queue, queue->begin + queue->elem_size); + res = true; + } + hli_intr_restore(int_state); + return res; +} + +bool IRAM_ATTR hli_queue_put(hli_queue_handle_t queue, const void* data) +{ + uint32_t int_state = hli_intr_disable(); + bool res = false; + bool was_empty = queue_empty(queue); + if (!queue_full(queue)) { + memcpy(queue->end, data, queue->elem_size); + queue->end = wrap_ptr(queue, queue->end + queue->elem_size); + if (was_empty && queue != s_meta_queue_ptr) { + queue_signal(queue); + } + res = true; + } + hli_intr_restore(int_state); + return res; +} + +bool IRAM_ATTR hli_semaphore_give(hli_queue_handle_t queue) +{ + uint8_t data = 0; + return hli_queue_put(queue, &data); +} + +#endif /* CONFIG_BTDM_CTRL_HLI */ diff --git a/lib/bt/controller/esp32/hli_api.h b/lib/bt/controller/esp32/hli_api.h new file mode 100644 index 00000000..3b69156b --- /dev/null +++ b/lib/bt/controller/esp32/hli_api.h @@ -0,0 +1,167 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include <stdint.h> +#include "esp_err.h" +#include "esp_intr_alloc.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_BTDM_CTRL_HLI + +/*** Queues ***/ + +struct hli_queue_t +{ + size_t elem_size; + char* begin; + char* end; + const char* bufend; + QueueHandle_t downstream; + int flags; + char buf[0]; +}; + +/** + * @brief Register a high level interrupt function + * + * @param handler interrupt handler function + * @param arg argument to pass to the interrupt handler + * @param intr_reg address of the peripheral register containing the interrupt status, + * or value 0 to get the status from CPU INTERRUPT register + * @param intr_mask mask of the interrupt, in the interrupt status register + * @return + * - ESP_OK on success + * - ESP_ERR_NO_MEM if too many handlers are registered + */ +esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask); + +/** + * @brief Mask all interrupts (including high level ones) on the current CPU + * + * @return uint32_t interrupt status, pass it to hli_intr_restore + */ +uint32_t hli_intr_disable(void); + +/** + * @brief Re-enable interrupts + * + * @param state value returned by hli_intr_disable + */ +void hli_intr_restore(uint32_t state); + +/** + * @brief Type of a hli queue + */ +typedef struct hli_queue_t* hli_queue_handle_t; + +/** + * @brief Initialize hli_queue module. Must be called once before using hli queue APIs. + */ +void hli_queue_setup(void); + +/** + * @brief Shutdown hli_queue module. + */ +void hli_queue_shutdown(void); + +/** + * @brief Create a hli queue, wrapping a FreeRTOS queue + * + * This queue can be used from high level interrupts, + * but **ONLY ON THE CPU WHERE hli_queue_setup WAS CALLED**. Values sent to this + * queue are automatically forwarded to "downstream" FreeRTOS queue using a level 3 + * software interrupt. + * + * @param nelem number of elements in the queue + * @param elem_size size of one element; must match element size of a downstream queue + * @param downstream FreeRTOS queue to send the values to + * @return hli_queue_handle_t handle of the created queue, or NULL on failure + */ +hli_queue_handle_t hli_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream); + +/** + * @brief Create a customer hli queue, wrapping a FreeRTOS queue + * + * This queue can be used from high level interrupts, + * but **ONLY ON THE CPU WHERE hli_queue_setup WAS CALLED**. Values sent to this + * queue are automatically forwarded to "downstream" FreeRTOS queue using a level 3 + * software interrupt. + * + * @param nelem number of elements in the queue + * @param elem_size size of one element; must match element size of a downstream queue + * @param downstream FreeRTOS queue to send the values to + * @return hli_queue_handle_t handle of the created queue, or NULL on failure + */ +hli_queue_handle_t hli_customer_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream); + +/** + * @brief Create a hli queue, wrapping a FreeRTOS semaphore + * + * See notes on hli_queue_create. + * + * @param max_count maximum semaphore count + * @param downstream FreeRTOS semaphore to forward the calls to + * @return hli_queue_handle_t handle of the created queue, or NULL on failure + */ +hli_queue_handle_t hli_semaphore_create(size_t max_count, SemaphoreHandle_t downstream); + +/** + * @brief Delete a hli queue + * + * Make sure noone is using the queue before deleting it. + * + * @param queue handle returned by hli_queue_create or hli_semaphore_create + */ +void hli_queue_delete(hli_queue_handle_t queue); + +/** + * @brief Get one element from a hli queue + * + * Usually not used, values get sent to a downstream FreeRTOS queue automatically. + * However if downstream queue is NULL, this API can be used to get values from a hli queue. + * + * @param queue handle of a queue + * @param out pointer where to store the element + * @return true if the element was successfully read from the queue + */ +bool hli_queue_get(hli_queue_handle_t queue, void* out); + +/** + * @brief Put one element into a hli queue + * + * This puts copies an element into the queue and raises a software interrupt (level 3). + * In the interrupt, the value is copied to a FreeRTOS "downstream" queue. + * + * Note that if the value does not fit into a downstream queue, no error is returned, + * and the value is lost. + * + * @param queue handle of a queue + * @param data pointer to the element to be sent + * @return true if data was placed into the hli queue successfully + */ +bool hli_queue_put(hli_queue_handle_t queue, const void* data); + +/** + * @brief "Give" a semaphore wrapped by a hli queue + * + * @param queue handle returned by hli_semaphore_create + * @return true if the event was sent to a hli queue successfully + */ +bool hli_semaphore_give(hli_queue_handle_t queue); + +#endif /* CONFIG_BTDM_CTRL_HLI */ + +#ifdef __cplusplus +} +#endif diff --git a/lib/bt/controller/esp32/hli_vectors.S b/lib/bt/controller/esp32/hli_vectors.S new file mode 100644 index 00000000..2af6ffae --- /dev/null +++ b/lib/bt/controller/esp32/hli_vectors.S @@ -0,0 +1,267 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include <xtensa/coreasm.h> +#include <xtensa/corebits.h> +#include <xtensa/config/system.h> +#include "xtensa_context.h" +#include "sdkconfig.h" +#include "soc/soc.h" + +#if CONFIG_BTDM_CTRL_HLI + +/* Interrupt stack size, for C code. + * TODO: reduce and make configurable. + */ +#define L4_INTR_STACK_SIZE 4096 + +/* Save area for the CPU state: + * - 64 words for the general purpose registers + * - 7 words for some of the special registers: + * - WINDOWBASE, WINDOWSTART — only WINDOWSTART is truly needed + * - SAR, LBEG, LEND, LCOUNT — since the C code might use these + * - EPC1 — since the C code might cause window overflow exceptions + * This is not laid out as standard exception frame structure + * for simplicity of the save/restore code. + */ +#define REG_FILE_SIZE (64 * 4) +#define SPECREG_OFFSET REG_FILE_SIZE +#define SPECREG_SIZE (7 * 4) +#define REG_SAVE_AREA_SIZE (SPECREG_OFFSET + SPECREG_SIZE) + + .data +_l4_intr_stack: + .space L4_INTR_STACK_SIZE +_l4_save_ctx: + .space REG_SAVE_AREA_SIZE + + .section .iram1,"ax" + .global xt_highint4 + .type xt_highint4,@function + .align 4 + +xt_highint4: + +#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX + /* + Here, Timer2 is used to count a little time(50us). + The subsequent dram0 write operation is blocked due to live lock, which will + cause timer2 to timeout and trigger a level 5 interrupt. + */ + rsr.ccount a0 + addmi a0, a0, (CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ*50) + wsr a0, CCOMPARE2 + + /* Enable Timer 2 interrupt */ + rsr a0, INTENABLE + extui a0, a0, 16, 1 + bnez a0, 1f + movi a0, 0 + xsr a0, INTENABLE /* disable all interrupts */ + /* And a0 with (1 << 16) for Timer 2 interrupt mask */ + addmi a0, a0, (1<<14) + addmi a0, a0, (1<<14) + addmi a0, a0, (1<<14) + addmi a0, a0, (1<<14) + wsr a0, INTENABLE /* Enable Timer 2 */ +1: +#endif + + movi a0, _l4_save_ctx + /* save 4 lower registers */ + s32i a1, a0, 4 + s32i a2, a0, 8 + s32i a3, a0, 12 + rsr a2, EXCSAVE_4 /* holds the value of a0 */ + s32i a2, a0, 0 + + /* Save special registers */ + addi a0, a0, SPECREG_OFFSET + rsr a2, WINDOWBASE + s32i a2, a0, 0 + rsr a2, WINDOWSTART + s32i a2, a0, 4 + rsr a2, SAR + s32i a2, a0, 8 + rsr a2, LBEG + s32i a2, a0, 12 + rsr a2, LEND + s32i a2, a0, 16 + rsr a2, LCOUNT + s32i a2, a0, 20 + rsr a2, EPC1 + s32i a2, a0, 24 + +#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX + movi a0, 0 + xsr a0, INTENABLE /* disable all interrupts */ + movi a2, ~(1<<16) + and a0, a2, a0 + wsr a0, INTENABLE +#endif + + /* disable exception mode, window overflow */ + movi a0, PS_INTLEVEL(5) | PS_EXCM + wsr a0, PS + rsync + + /* Save the remaining physical registers. + * 4 registers are already saved, which leaves 60 registers to save. + * (FIXME: consider the case when the CPU is configured with physical 32 registers) + * These 60 registers are saved in 5 iterations, 12 registers at a time. + */ + movi a1, 5 + movi a3, _l4_save_ctx + 4 * 4 + + /* This is repeated 5 times, each time the window is shifted by 12 registers. + * We come here with a1 = downcounter, a3 = save pointer, a2 and a0 unused. + */ +1: + s32i a4, a3, 0 + s32i a5, a3, 4 + s32i a6, a3, 8 + s32i a7, a3, 12 + s32i a8, a3, 16 + s32i a9, a3, 20 + s32i a10, a3, 24 + s32i a11, a3, 28 + s32i a12, a3, 32 + s32i a13, a3, 36 + s32i a14, a3, 40 + s32i a15, a3, 44 + + /* We are about to rotate the window, so that a12-a15 will become the new a0-a3. + * Copy a0-a3 to a12-15 to still have access to these values. + * At the same time we can decrement the counter and adjust the save area pointer + */ + + /* a0 is constant (_l4_save_ctx), no need to copy */ + addi a13, a1, -1 /* copy and decrement the downcounter */ + /* a2 is scratch so no need to copy */ + addi a15, a3, 48 /* copy and adjust the save area pointer */ + beqz a13, 2f /* have saved all registers ? */ + rotw 3 /* rotate the window and go back */ + j 1b + + /* the loop is complete */ +2: + rotw 4 /* this brings us back to the original window */ + /* a0 still points to _l4_save_ctx */ + + /* Can clear WINDOWSTART now, all registers are saved */ + rsr a2, WINDOWBASE + /* WINDOWSTART = (1 << WINDOWBASE) */ + movi a3, 1 + ssl a2 + sll a3, a3 + wsr a3, WINDOWSTART + +_highint4_stack_switch: + movi a0, 0 + movi sp, _l4_intr_stack + L4_INTR_STACK_SIZE - 16 + s32e a0, sp, -12 /* For GDB: set null SP */ + s32e a0, sp, -16 /* For GDB: set null PC */ + movi a0, _highint4_stack_switch /* For GDB: cosmetics, for the frame where stack switch happened */ + + /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */ + movi a6, PS_INTLEVEL(4) | PS_UM | PS_WOE + wsr a6, PS + rsync + + /* Call C handler */ + mov a6, sp + call4 hli_c_handler + + l32e sp, sp, -12 /* switch back to the original stack */ + + /* Done with C handler; re-enable exception mode, disabling window overflow */ + movi a2, PS_INTLEVEL(5) | PS_EXCM /* TOCHECK */ + wsr a2, PS + rsync + + /* Restore the special registers. + * WINDOWSTART will be restored near the end. + */ + movi a0, _l4_save_ctx + SPECREG_OFFSET + l32i a2, a0, 8 + wsr a2, SAR + l32i a2, a0, 12 + wsr a2, LBEG + l32i a2, a0, 16 + wsr a2, LEND + l32i a2, a0, 20 + wsr a2, LCOUNT + l32i a2, a0, 24 + wsr a2, EPC1 + + /* Restoring the physical registers. + * This is the reverse to the saving process above. + */ + + /* Rotate back to the final window, then start loading 12 registers at a time, + * in 5 iterations. + * Again, a1 is the downcounter and a3 is the save area pointer. + * After each rotation, a1 and a3 are copied from a13 and a15. + * To simplify the loop, we put the initial values into a13 and a15. + */ + rotw -4 + movi a15, _l4_save_ctx + 64 * 4 /* point to the end of the save area */ + movi a13, 5 + +1: + /* Copy a1 and a3 from their previous location, + * at the same time decrementing and adjusting the save area pointer. + */ + addi a1, a13, -1 + addi a3, a15, -48 + + /* Load 12 registers */ + l32i a4, a3, 0 + l32i a5, a3, 4 + l32i a6, a3, 8 + l32i a7, a3, 12 + l32i a8, a3, 16 + l32i a9, a3, 20 + l32i a10, a3, 24 + l32i a11, a3, 28 /* ensure PS and EPC written */ + l32i a12, a3, 32 + l32i a13, a3, 36 + l32i a14, a3, 40 + l32i a15, a3, 44 + + /* Done with the loop? */ + beqz a1, 2f + /* If no, rotate the window and repeat */ + rotw -3 + j 1b + +2: + /* Done with the loop. Only 4 registers (a0-a3 in the original window) remain + * to be restored. Also need to restore WINDOWSTART, since all the general + * registers are now in place. + */ + movi a0, _l4_save_ctx + + l32i a2, a0, SPECREG_OFFSET + 4 + wsr a2, WINDOWSTART + + l32i a1, a0, 4 + l32i a2, a0, 8 + l32i a3, a0, 12 + rsr a0, EXCSAVE_4 /* holds the value of a0 before the interrupt handler */ + + /* Return from the interrupt, restoring PS from EPS_4 */ + rfi 4 + +#endif /* CONFIG_BTDM_CTRL_HLI */ + +/* The linker has no reason to link in this file; all symbols it exports are already defined + (weakly!) in the default int handler. Define a symbol here so we can use it to have the + linker inspect this anyway. */ + + .global ld_include_hli_vectors_bt +ld_include_hli_vectors_bt: diff --git a/lib/bt/controller/esp32c2/Kconfig.in b/lib/bt/controller/esp32c2/Kconfig.in new file mode 100644 index 00000000..05e15708 --- /dev/null +++ b/lib/bt/controller/esp32c2/Kconfig.in @@ -0,0 +1,466 @@ + +menu "HCI Config" + + choice BT_LE_HCI_INTERFACE + prompt "Select HCI interface" + default BT_LE_HCI_INTERFACE_USE_RAM + + config BT_LE_HCI_INTERFACE_USE_RAM + bool "ram" + help + Use RAM as HCI interface + config BT_LE_HCI_INTERFACE_USE_UART + bool "uart" + help + Use UART as HCI interface + endchoice + + config BT_LE_HCI_UART_PORT + int "HCI UART port" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 1 + help + Set the port number of HCI UART + + config BT_LE_HCI_UART_FLOWCTRL + bool "HCI uart Hardware Flow ctrl" + depends on BT_LE_HCI_INTERFACE_USE_UART + default n + + config BT_LE_HCI_UART_TX_PIN + int "HCI uart Tx gpio" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 19 + + config BT_LE_HCI_UART_RX_PIN + int "HCI uart Rx gpio" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 10 + + config BT_LE_HCI_UART_RTS_PIN + int "HCI uart RTS gpio" + depends on BT_LE_HCI_UART_FLOWCTRL + default 4 + + config BT_LE_HCI_UART_CTS_PIN + int "HCI uart CTS gpio" + depends on BT_LE_HCI_UART_FLOWCTRL + default 5 + + config BT_LE_HCI_UART_BAUD + int "HCI uart baudrate" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 921600 + help + HCI uart baud rate 115200 ~ 1000000 + + choice BT_LE_HCI_UART_PARITY + prompt "select uart parity" + depends on BT_LE_HCI_INTERFACE_USE_UART + default BT_LE_HCI_UART_UART_PARITY_DISABLE + + config BT_LE_HCI_UART_UART_PARITY_DISABLE + bool "PARITY_DISABLE" + help + UART_PARITY_DISABLE + config BT_LE_HCI_UART_UART_PARITY_EVEN + bool "PARITY_EVEN" + help + UART_PARITY_EVEN + config BT_LE_HCI_UART_UART_PARITY_ODD + bool "PARITY_ODD" + help + UART_PARITY_ODD + endchoice + + config BT_LE_HCI_UART_TASK_STACK_SIZE + int "HCI uart task stack size" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 1000 + help + Set the size of uart task stack +endmenu + +config BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT + bool + default y + help + Enable NPL porting for controller. + + +menuconfig BT_LE_50_FEATURE_SUPPORT + bool "Enable BLE 5 feature" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable BLE 5 feature + +config BT_LE_LL_CFG_FEAT_LE_2M_PHY + bool "Enable 2M Phy" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable 2M-PHY + +config BT_LE_LL_CFG_FEAT_LE_CODED_PHY + bool "Enable coded Phy" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable coded-PHY + +config BT_LE_EXT_ADV + bool "Enable extended advertising" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable this option to do extended advertising. Extended advertising + will be supported from BLE 5.0 onwards. + +if BT_LE_EXT_ADV + config BT_LE_MAX_EXT_ADV_INSTANCES + int "Maximum number of extended advertising instances." + range 0 4 + default 1 + depends on BT_LE_EXT_ADV + help + Change this option to set maximum number of extended advertising + instances. Minimum there is always one instance of + advertising. Enter how many more advertising instances you + want. + Each extended advertising instance will take about 0.5k DRAM. + + config BT_LE_EXT_ADV_MAX_SIZE + int "Maximum length of the advertising data." + range 0 1650 + default 1650 + depends on BT_LE_EXT_ADV + help + Defines the length of the extended adv data. The value should not + exceed 1650. + + config BT_LE_ENABLE_PERIODIC_ADV + bool "Enable periodic advertisement." + default y + depends on BT_LE_EXT_ADV + help + Enable this option to start periodic advertisement. + + config BT_LE_PERIODIC_ADV_SYNC_TRANSFER + bool "Enable Transer Sync Events" + depends on BT_LE_ENABLE_PERIODIC_ADV + default y + help + This enables controller transfer periodic sync events to host + +endif + +config BT_LE_MAX_PERIODIC_SYNCS + int "Maximum number of periodic advertising syncs" + depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED + + range 0 3 + default 1 if BT_LE_ENABLE_PERIODIC_ADV + default 0 + help + Set this option to set the upper limit for number of periodic sync + connections. This should be less than maximum connections allowed by + controller. + +config BT_LE_MAX_PERIODIC_ADVERTISER_LIST + int "Maximum number of periodic advertiser list" + depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED + range 1 5 + default 5 + help + Set this option to set the upper limit for number of periodic advertiser list. + +menu "Memory Settings" + depends on !BT_NIMBLE_ENABLED + + config BT_LE_MSYS_1_BLOCK_COUNT + int "MSYS_1 Block Count" + default 12 + help + MSYS is a system level mbuf registry. For prepare write & prepare + responses MBUFs are allocated out of msys_1 pool. For NIMBLE_MESH + enabled cases, this block count is increased by 8 than user defined + count. + + config BT_LE_MSYS_1_BLOCK_SIZE + int "MSYS_1 Block Size" + default 256 + help + Dynamic memory size of block 1 + + config BT_LE_MSYS_2_BLOCK_COUNT + int "MSYS_2 Block Count" + default 24 + help + Dynamic memory count + + config BT_LE_MSYS_2_BLOCK_SIZE + int "MSYS_2 Block Size" + default 320 + help + Dynamic memory size of block 2 + + config BT_LE_ACL_BUF_COUNT + int "ACL Buffer count" + default 10 + help + The number of ACL data buffers. + + config BT_LE_ACL_BUF_SIZE + int "ACL Buffer size" + default 517 + help + This is the maximum size of the data portion of HCI ACL data packets. + It does not include the HCI data header (of 4 bytes) + + config BT_LE_HCI_EVT_BUF_SIZE + int "HCI Event Buffer size" + default 257 if BT_LE_EXT_ADV + default 70 + help + This is the size of each HCI event buffer in bytes. In case of + extended advertising, packets can be fragmented. 257 bytes is the + maximum size of a packet. + + config BT_LE_HCI_EVT_HI_BUF_COUNT + int "High Priority HCI Event Buffer count" + default 30 + help + This is the high priority HCI events' buffer size. High-priority + event buffers are for everything except advertising reports. If there + are no free high-priority event buffers then host will try to allocate a + low-priority buffer instead + + config BT_LE_HCI_EVT_LO_BUF_COUNT + int "Low Priority HCI Event Buffer count" + default 8 + help + This is the low priority HCI events' buffer size. Low-priority event + buffers are only used for advertising reports. If there are no free + low-priority event buffers, then an incoming advertising report will + get dropped +endmenu + +config BT_LE_CONTROLLER_TASK_STACK_SIZE + int "Controller task stack size" + default 5120 if BLE_MESH + default 4096 + help + This configures stack size of NimBLE controller task + +menuconfig BT_LE_CONTROLLER_LOG_ENABLED + bool "Controller log enable" + default n + help + Enable controller log + +config BT_LE_CONTROLLER_LOG_CTRL_ENABLED + bool "enable controller log module" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Enable controller log module + +config BT_LE_CONTROLLER_LOG_HCI_ENABLED + bool "enable HCI log module" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Enable hci log module + +config BT_LE_CONTROLLER_LOG_DUMP_ONLY + bool "Controller log dump mode only" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Only operate in dump mode + +config BT_LE_LOG_CTRL_BUF1_SIZE + int "size of the first BLE controller LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 4096 + help + Configure the size of the first BLE controller LOG buffer. + +config BT_LE_LOG_CTRL_BUF2_SIZE + int "size of the second BLE controller LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 1024 + help + Configure the size of the second BLE controller LOG buffer. + +config BT_LE_LOG_HCI_BUF_SIZE + int "size of the BLE HCI LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 4096 + help + Configure the size of the BLE HCI LOG buffer. + +config BT_LE_LL_RESOLV_LIST_SIZE + int "BLE LL Resolving list size" + range 1 5 + default 4 + help + Configure the size of resolving list used in link layer. + +menuconfig BT_LE_SECURITY_ENABLE + bool "Enable BLE SM feature" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable BLE sm feature + +config BT_LE_SM_LEGACY + bool "Security manager legacy pairing" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable security manager legacy pairing + +config BT_LE_SM_SC + bool "Security manager secure connections (4.2)" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable security manager secure connections + +config BT_LE_SM_SC_DEBUG_KEYS + bool "Use predefined public-private key pair" + default n + depends on BT_LE_SECURITY_ENABLE && BT_LE_SM_SC + help + If this option is enabled, SM uses predefined DH key pair as described + in Core Specification, Vol. 3, Part H, 2.3.5.6.1. This allows to + decrypt air traffic easily and thus should only be used for debugging. + +config BT_LE_LL_CFG_FEAT_LE_ENCRYPTION + bool "Enable LE encryption" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable encryption connection + +config BT_LE_CRYPTO_STACK_MBEDTLS + bool "Override TinyCrypt with mbedTLS for crypto computations" + default y + depends on !BT_NIMBLE_ENABLED + select MBEDTLS_ECP_RESTARTABLE + select MBEDTLS_CMAC_C + help + Enable this option to choose mbedTLS instead of TinyCrypt for crypto + computations. + +config BT_LE_WHITELIST_SIZE + int "BLE white list size" + range 1 15 + default 12 + depends on !BT_NIMBLE_ENABLED + + help + BLE list size + +config BT_LE_LL_DUP_SCAN_LIST_COUNT + int "BLE duplicate scan list count" + range 1 100 + default 20 + help + config the max count of duplicate scan list + +config BT_LE_LL_SCA + int "BLE Sleep clock accuracy" + range 0 500 + default 60 + help + Sleep clock accuracy of our device (in ppm) + +config BT_LE_MAX_CONNECTIONS + int "Maximum number of concurrent connections" + depends on !BT_NIMBLE_ENABLED + range 1 2 + default 2 + help + Defines maximum number of concurrent BLE connections. For ESP32, user + is expected to configure BTDM_CTRL_BLE_MAX_CONN from controller menu + along with this option. Similarly for ESP32-C3 or ESP32-S3, user is expected to + configure BT_CTRL_BLE_MAX_ACT from controller menu. + Each connection will take about 1k DRAM. + +choice BT_LE_COEX_PHY_CODED_TX_RX_TLIM + prompt "Coexistence: limit on MAX Tx/Rx time for coded-PHY connection" + default BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + depends on ESP_COEX_SW_COEXIST_ENABLE + help + When using PHY-Coded in BLE connection, limitation on max tx/rx time can be applied to + better avoid dramatic performance deterioration of Wi-Fi. + + config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EN + bool "Force Enable" + help + Always enable the limitation on max tx/rx time for Coded-PHY connection + + config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + bool "Force Disable" + help + Disable the limitation on max tx/rx time for Coded-PHY connection +endchoice + +config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF + int + default 0 if !ESP_COEX_SW_COEXIST_ENABLE + default 1 if BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EN + default 0 if BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + +config BT_LE_SLEEP_ENABLE + bool "Enable BLE sleep" + default n + help + Enable BLE sleep + +config BT_LE_USE_ESP_TIMER + bool "Use Esp Timer for callout" + depends on !BT_NIMBLE_ENABLED + default y + help + Set this option to use Esp Timer which has higher priority timer instead of FreeRTOS timer + +config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + bool "BLE adv report flow control supported" + default y + help + The function is mainly used to enable flow control for advertising reports. When it is enabled, + advertising reports will be discarded by the controller if the number of unprocessed advertising + reports exceeds the size of BLE adv report flow control. + +config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM + int "BLE adv report flow control number" + depends on BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 50 1000 + default 100 + help + The number of unprocessed advertising report that bluetooth host can save.If you set + `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a small value, this may cause adv packets lost. + If you set `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a large value, bluetooth host may cache a + lot of adv packets and this may cause system memory run out. For example, if you set + it to 50, the maximum memory consumed by host is 35 * 50 bytes. Please set + `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` according to your system free memory and handle adv + packets as fast as possible, otherwise it will cause adv packets lost. + +config BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD + int "BLE adv lost event threshold value" + depends on BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 1 1000 + default 20 + help + When adv report flow control is enabled, The ADV lost event will be generated when the number + of ADV packets lost in the controller reaches this threshold. It is better to set a larger value. + If you set `BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it + may cause adv packets lost more. + +config BT_LE_RELEASE_IRAM_SUPPORTED + bool + default y diff --git a/lib/bt/controller/esp32c2/bt.c b/lib/bt/controller/esp32c2/bt.c new file mode 100644 index 00000000..c1eff194 --- /dev/null +++ b/lib/bt/controller/esp32c2/bt.c @@ -0,0 +1,1238 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "esp_random.h" +#include "esp_heap_caps.h" +#include "esp_heap_caps_init.h" +#include <esp_mac.h> + +#include "sdkconfig.h" + +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" + +#ifdef ESP_PLATFORM +#include "esp_log.h" +#endif + +#if CONFIG_SW_COEXIST_ENABLE +#include "private/esp_coexist_internal.h" +#endif + +#include "nimble/nimble_npl_os.h" +#include "nimble/ble_hci_trans.h" +#include "os/endian.h" + +#include "esp_bt.h" +#include "esp_intr_alloc.h" +#include "esp_sleep.h" +#include "esp_pm.h" +#include "esp_phy_init.h" +#include "soc/syscon_reg.h" +#include "soc/modem_clkrst_reg.h" +#include "esp_private/periph_ctrl.h" +#include "hci_uart.h" +#include "bt_osi_mem.h" + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +#include "hci/hci_hal.h" +#endif + +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +#include "esp_private/sleep_modem.h" +#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_private/periph_ctrl.h" +#include "esp_sleep.h" + +#include "soc/syscon_reg.h" +#include "soc/dport_access.h" + +#include "hal/efuse_ll.h" +/* Macro definition + ************************************************************************ + */ + +#define NIMBLE_PORT_LOG_TAG "BLE_INIT" +#define OSI_COEX_VERSION 0x00010006 +#define OSI_COEX_MAGIC_VALUE 0xFADEBEAD + +#define EXT_FUNC_VERSION 0x20221122 +#define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5 + +#define BT_ASSERT_PRINT ets_printf + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +/* ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data */ +#define ACL_DATA_MBUF_LEADINGSPCAE 4 +#endif // CONFIG_BT_BLUEDROID_ENABLED + +/* Types definition + ************************************************************************ + */ +struct osi_coex_funcs_t { + uint32_t _magic; + uint32_t _version; + 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); +}; + +struct ext_funcs_t { + uint32_t ext_version; + int (*_esp_intr_alloc)(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle); + int (*_esp_intr_free)(void **ret_handle); + void *(* _malloc)(size_t size); + void (*_free)(void *p); + void (*_hal_uart_start_tx)(int); + int (*_hal_uart_init_cbs)(int, hci_uart_tx_char, hci_uart_tx_done, hci_uart_rx_char, void *); + int (*_hal_uart_config)(int, int32_t, uint8_t, uint8_t, uart_parity_t, uart_hw_flowcontrol_t); + int (*_hal_uart_close)(int); + void (*_hal_uart_blocking_tx)(int, uint8_t); + int (*_hal_uart_init)(int, void *); + 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); + void (*_osi_assert)(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2); + uint32_t (* _os_random)(void); + int (* _ecc_gen_key_pair)(uint8_t *public, uint8_t *priv); + int (* _ecc_gen_dh_key)(const uint8_t *remote_pub_key_x, const uint8_t *remote_pub_key_y, const uint8_t *local_priv_key, uint8_t *dhkey); + void (* _esp_reset_rpa_moudle)(void); + void (* _esp_bt_track_pll_cap)(void); + uint32_t magic; +}; + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +typedef void (*interface_func_t) (uint32_t len, const uint8_t*addr, bool end); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +/* External functions or variables + ************************************************************************ + */ +extern int ble_osi_coex_funcs_register(struct osi_coex_funcs_t *coex_funcs); +extern int ble_controller_init(esp_bt_controller_config_t *cfg); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +extern int ble_log_init_async(interface_func_t bt_controller_log_interface, bool task_create, uint8_t buffers, uint32_t *bufs_size); +extern int ble_log_deinit_async(void); +extern void ble_log_async_output_dump_all(bool output); +extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +extern int ble_controller_deinit(void); +extern int ble_controller_enable(uint8_t mode); +extern int ble_controller_disable(void); +extern int esp_register_ext_funcs (struct ext_funcs_t *); +extern void esp_unregister_ext_funcs (void); +extern int esp_ble_ll_set_public_addr(const uint8_t *addr); +extern int esp_register_npl_funcs (struct npl_funcs_t *p_npl_func); +extern void esp_unregister_npl_funcs (void); +extern void npl_freertos_mempool_deinit(void); +extern void bt_bb_v2_init_cmplx(uint8_t i); +extern int os_msys_buf_alloc(void); +extern uint32_t r_os_cputime_get32(void); +extern uint32_t r_os_cputime_ticks_to_usecs(uint32_t ticks); +extern void r_ble_lll_rfmgmt_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, void *w_arg, uint32_t us_to_enabled); +extern void r_ble_rtc_wake_up_state_clr(void); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +extern void esp_ble_set_wakeup_overhead(uint32_t overhead); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ +extern int os_msys_init(void); +extern void os_msys_buf_free(void); +extern int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, + const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey); +extern int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); +extern int ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); +extern int ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); +extern int ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); +extern void bt_track_pll_cap(void); + +#if CONFIG_BT_RELEASE_IRAM +extern uint32_t _iram_bt_text_start; +extern uint32_t _bss_bt_end; +#else +extern uint32_t _bt_bss_end; +extern uint32_t _bt_controller_data_start; +#endif + +/* Local Function Declaration + ********************************************************************* + */ +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 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); +#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static void hci_uart_start_tx_wrapper(int uart_no); +static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, + hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg); +static int hci_uart_config_wrapper(int uart_no, int32_t speed, uint8_t databits, uint8_t stopbits, + uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl); +static int hci_uart_close_wrapper(int uart_no); +static void hci_uart_blocking_tx_wrapper(int port, uint8_t data); +static int hci_uart_init_wrapper(int uart_no, void *cfg); +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, + void *arg, void **ret_handle_in); +static int esp_intr_free_wrapper(void **ret_handle); +static void osi_assert_wrapper(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2); +static uint32_t osi_random_wrapper(void); +static void esp_reset_rpa_moudle(void); +static int esp_ecc_gen_key_pair(uint8_t *pub, uint8_t *priv); +static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +/* Local variable definition + *************************************************************************** + */ +/* Static variable declare */ +static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +/* This variable tells if BLE is running */ +static bool s_ble_active = false; +#ifdef CONFIG_PM_ENABLE +static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock = NULL; +#define BTDM_MIN_TIMER_UNCERTAINTY_US (200) +#endif // CONFIG_PM_ENABLE + +#define BLE_RTC_DELAY_US (1800) + + +static const struct osi_coex_funcs_t s_osi_coex_funcs_ro = { + ._magic = OSI_COEX_MAGIC_VALUE, + ._version = OSI_COEX_VERSION, + ._coex_wifi_sleep_set = NULL, + ._coex_core_ble_conn_dyn_prio_get = NULL, + ._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper, + ._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper, +}; + +struct ext_funcs_t ext_funcs_ro = { + .ext_version = EXT_FUNC_VERSION, + ._esp_intr_alloc = esp_intr_alloc_wrapper, + ._esp_intr_free = esp_intr_free_wrapper, + ._malloc = bt_osi_mem_malloc_internal, + ._free = bt_osi_mem_free, +#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART + ._hal_uart_start_tx = hci_uart_start_tx_wrapper, + ._hal_uart_init_cbs = hci_uart_init_cbs_wrapper, + ._hal_uart_config = hci_uart_config_wrapper, + ._hal_uart_close = hci_uart_close_wrapper, + ._hal_uart_blocking_tx = hci_uart_blocking_tx_wrapper, + ._hal_uart_init = hci_uart_init_wrapper, +#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART + ._task_create = task_create_wrapper, + ._task_delete = task_delete_wrapper, + ._osi_assert = osi_assert_wrapper, + ._os_random = osi_random_wrapper, + ._ecc_gen_key_pair = esp_ecc_gen_key_pair, + ._ecc_gen_dh_key = esp_ecc_gen_dh_key, + ._esp_reset_rpa_moudle = esp_reset_rpa_moudle, + ._esp_bt_track_pll_cap = NULL, + .magic = EXT_FUNC_MAGIC_VALUE, +}; + +static void IRAM_ATTR esp_reset_rpa_moudle(void) +{ + DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, BLE_RPA_REST_BIT); + DPORT_CLEAR_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, BLE_RPA_REST_BIT); +} + +static void IRAM_ATTR osi_assert_wrapper(const uint32_t ln, const char *fn, + uint32_t param1, uint32_t param2) +{ + BT_ASSERT_PRINT("BLE assert: line %d in function %s, param: 0x%x, 0x%x", ln, fn, param1, param2); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + esp_ble_controller_log_dump_all(true); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + assert(0); +} + +static uint32_t IRAM_ATTR osi_random_wrapper(void) +{ + return esp_random(); +} + +static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_set(type, status); +#endif // CONFIG_SW_COEXIST_ENABLE +} + +static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_clear(type, status); +#endif // CONFIG_SW_COEXIST_ENABLE +} + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +bool esp_vhci_host_check_send_available(void) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return false; + } + return true; +} + +/** + * Allocates an mbuf for use by the nimble host. + */ +static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space) +{ + struct os_mbuf *om; + int rc; + + om = os_msys_get_pkthdr(0, 0); + if (om == NULL) { + return NULL; + } + + if (om->om_omp->omp_databuf_len < leading_space) { + rc = os_mbuf_free_chain(om); + assert(rc == 0); + return NULL; + } + + om->om_data += leading_space; + + return om; +} + +/** + * Allocates an mbuf suitable for an HCI ACL data packet. + * + * @return An empty mbuf on success; null on memory + * exhaustion. + */ +struct os_mbuf *ble_hs_mbuf_acl_pkt(void) +{ + return ble_hs_mbuf_gen_pkt(4 + 1); +} + +void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return; + } + + if (*(data) == DATA_TYPE_COMMAND) { + struct ble_hci_cmd *cmd = NULL; + cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + assert(cmd); + memcpy((uint8_t *)cmd, data + 1, len - 1); + ble_hci_trans_hs_cmd_tx((uint8_t *)cmd); + } + + if (*(data) == DATA_TYPE_ACL) { + struct os_mbuf *om = os_msys_get_pkthdr(len, ACL_DATA_MBUF_LEADINGSPCAE); + assert(om); + assert(os_mbuf_append(om, &data[1], len - 1) == 0); + ble_hci_trans_hs_acl_tx(om); + } +} + +esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_FAIL; + } + + ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL); + + return ESP_OK; +} +#endif // CONFIG_BT_BLUEDROID_ENABLED +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 (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); +} + +static void task_delete_wrapper(void *task_handle) +{ + vTaskDelete(task_handle); +} + +static int esp_ecc_gen_key_pair(uint8_t *pub, uint8_t *priv) +{ + int rc = -1; +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + rc = ble_sm_alg_gen_key_pair(pub, priv); +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + return rc; +} + +static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey) +{ + int rc = -1; +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + rc = ble_sm_alg_gen_dhkey(peer_pub_key_x, peer_pub_key_y, our_priv_key, out_dhkey); +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + return rc; +} + +#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static void hci_uart_start_tx_wrapper(int uart_no) +{ + hci_uart_start_tx(uart_no); +} + +static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, + hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg) +{ + int rc = -1; + rc = hci_uart_init_cbs(uart_no, tx_func, tx_done, rx_func, arg); + return rc; +} + + +static int hci_uart_config_wrapper(int port_num, int32_t baud_rate, uint8_t data_bits, + uint8_t stop_bits,uart_parity_t parity, + uart_hw_flowcontrol_t flow_ctl) +{ + int rc = -1; + rc = hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl); + return rc; +} + +static int hci_uart_close_wrapper(int uart_no) +{ + int rc = -1; + rc = hci_uart_close(uart_no); + return rc; +} + +static void hci_uart_blocking_tx_wrapper(int port, uint8_t data) +{ + //This function is nowhere to use. +} + +static int hci_uart_init_wrapper(int uart_no, void *cfg) +{ + //This function is nowhere to use. + return 0; +} + +#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART + +static int ble_hci_unregistered_hook(void*, void*) +{ + ESP_LOGD(NIMBLE_PORT_LOG_TAG,"%s ble hci rx_evt is not registered.",__func__); + return 0; +} + +static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle_in) +{ + int rc = esp_intr_alloc(source, flags | ESP_INTR_FLAG_IRAM, handler, arg, (intr_handle_t *)ret_handle_in); + return rc; +} + +static int esp_intr_free_wrapper(void **ret_handle) +{ + int rc = 0; + rc = esp_intr_free((intr_handle_t) * ret_handle); + *ret_handle = NULL; + return rc; +} + +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +void sleep_modem_light_sleep_overhead_set(uint32_t overhead) +{ + esp_ble_set_wakeup_overhead(overhead); +} +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + +IRAM_ATTR void controller_sleep_cb(uint32_t enable_tick, void *arg) +{ + if (!s_ble_active) { + return; + } +#ifdef CONFIG_PM_ENABLE + r_ble_rtc_wake_up_state_clr(); + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + esp_phy_disable(PHY_MODEM_BT); + s_ble_active = false; +} + +IRAM_ATTR void controller_wakeup_cb(void *arg) +{ + if (s_ble_active) { + return; + } + esp_phy_enable(PHY_MODEM_BT); + // need to check if need to call pm lock here +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_acquire(s_pm_lock); +#endif //CONFIG_PM_ENABLE + s_ble_active = true; +} + +esp_err_t controller_sleep_init(void) +{ + esp_err_t rc = 0; +#ifdef CONFIG_BT_LE_SLEEP_ENABLE + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "BLE modem sleep is enabled\n"); + r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, 500 + BLE_RTC_DELAY_US); + +#ifdef CONFIG_PM_ENABLE + esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); +#endif // CONFIG_PM_ENABLE + +#endif // CONFIG_BT_LE_SLEEP_ENABLE + + // enable light sleep +#ifdef CONFIG_PM_ENABLE + rc = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "bt", &s_pm_lock); + if (rc != ESP_OK) { + goto error; + } +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + esp_sleep_enable_bt_wakeup(); + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "Enable light sleep, the wake up source is BLE timer"); + + rc = esp_pm_register_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); + if (rc != ESP_OK) { + goto error; + } +#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE + return rc; + +error: +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + esp_sleep_disable_bt_wakeup(); + esp_pm_unregister_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + /*lock should release first and then delete*/ + if (s_pm_lock != NULL) { + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; + } +#endif //CONFIG_PM_ENABLE + return rc; +} + +void controller_sleep_deinit(void) +{ +#ifdef CONFIG_FREERTOS_USE_TICKLESS_IDLE + r_ble_rtc_wake_up_state_clr(); + esp_sleep_disable_bt_wakeup(); + esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_AUTO); + esp_pm_unregister_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); +#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE +#ifdef CONFIG_PM_ENABLE + /*lock should release first and then delete*/ + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; +#endif //CONFIG_PM_ENABLE +} + +void ble_rtc_clk_init(void) +{ + // modem_clkrst_reg + // LP_TIMER_SEL_XTAL32K -> 0 + // LP_TIMER_SEL_XTAL -> 1 + // LP_TIMER_SEL_8M -> 0 + // LP_TIMER_SEL_RTC_SLOW -> 0 + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_XTAL32K_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 1, MODEM_CLKRST_LP_TIMER_SEL_XTAL_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_8M_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_RTC_SLOW_S); + +#ifdef CONFIG_XTAL_FREQ_26 + // LP_TIMER_CLK_DIV_NUM -> 130 + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM, 129, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM_S); +#else + // LP_TIMER_CLK_DIV_NUM -> 250 + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM, 249, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM_S); +#endif // CONFIG_XTAL_FREQ_26 + + // MODEM_CLKRST_ETM_CLK_ACTIVE -> 1 + // MODEM_CLKRST_ETM_CLK_SEL -> 0 + SET_PERI_REG_BITS(MODEM_CLKRST_ETM_CLK_CONF_REG, 1, 1, MODEM_CLKRST_ETM_CLK_ACTIVE_S); + SET_PERI_REG_BITS(MODEM_CLKRST_ETM_CLK_CONF_REG, 1, 0, MODEM_CLKRST_ETM_CLK_SEL_S); + +} + +esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) +{ + esp_err_t ret = ESP_OK; + ble_npl_count_info_t npl_info; + memset(&npl_info, 0, sizeof(ble_npl_count_info_t)); + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_ERR_INVALID_STATE; + } + + if (!cfg) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "cfg is NULL"); + return ESP_ERR_INVALID_ARG; + } + + ble_rtc_clk_init(); + + ret = esp_register_ext_funcs(&ext_funcs_ro); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "register extend functions failed"); + return ret; + } + + /* Initialize the function pointers for OS porting */ + npl_freertos_funcs_init(); + struct npl_funcs_t *p_npl_funcs = npl_freertos_funcs_get(); + if (!p_npl_funcs) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl functions get failed"); + return ESP_ERR_INVALID_ARG; + } + + ret = esp_register_npl_funcs(p_npl_funcs); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl functions register failed"); + goto free_mem; + } + + ble_get_npl_element_info(cfg, &npl_info); + npl_freertos_set_controller_npl_info(&npl_info); + if (npl_freertos_mempool_init() != 0) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl mempool init failed"); + ret = ESP_ERR_INVALID_ARG; + goto free_mem; + } + + /* Initialize the global memory pool */ + ret = os_msys_buf_alloc(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "os msys alloc failed"); + goto free_mem; + } + + os_msys_init(); +#if CONFIG_BT_NIMBLE_ENABLED + // ble_npl_eventq_init() need to use npl function in rom and must be called after esp_bt_controller_init() + /* Initialize default event queue */ + ble_npl_eventq_init(nimble_port_get_dflt_eventq()); +#endif + esp_phy_modem_init(); + periph_module_enable(PERIPH_BT_MODULE); + periph_module_reset(PERIPH_BT_MODULE); + + if (ble_osi_coex_funcs_register((struct osi_coex_funcs_t *)&s_osi_coex_funcs_ro) != 0) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "osi coex funcs reg failed"); + ret = ESP_ERR_INVALID_ARG; + goto modem_deint; + } + +#if CONFIG_SW_COEXIST_ENABLE + coex_init(); +#endif + + ret = ble_controller_init(cfg); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_init failed %d", ret); + goto modem_deint; + } + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + interface_func_t bt_controller_log_interface; + bt_controller_log_interface = esp_bt_controller_log_interface; + uint8_t buffers = 0; +#if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED + buffers |= ESP_BLE_LOG_BUF_CONTROLLER; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED +#if CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED + buffers |= ESP_BLE_LOG_BUF_HCI; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED +#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY + ret = ble_log_init_async(bt_controller_log_interface, false, buffers, (uint32_t *)log_bufs_size); +#else + ret = ble_log_init_async(bt_controller_log_interface, true, buffers, (uint32_t *)log_bufs_size); +#endif // CONFIG_BT_CONTROLLER_LOG_DUMP + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); + goto controller_init_err; + } +#endif // CONFIG_BT_CONTROLLER_LOG_ENABLED + + ret = controller_sleep_init(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "controller_sleep_init failed %d", ret); + goto free_controller; + } + + uint8_t mac[6]; + ESP_ERROR_CHECK(esp_read_mac((uint8_t *)mac, ESP_MAC_BT)); + + swap_in_place(mac, 6); + + esp_ble_ll_set_public_addr(mac); + + ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + + ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hci_unregistered_hook,NULL, + (ble_hci_trans_rx_acl_fn *)ble_hci_unregistered_hook,NULL); + return ESP_OK; +free_controller: + controller_sleep_deinit(); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +controller_init_err: + ble_log_deinit_async(); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + ble_controller_deinit(); +modem_deint: + esp_phy_modem_deinit(); + periph_module_disable(PERIPH_BT_MODULE); +#if CONFIG_BT_NIMBLE_ENABLED + ble_npl_eventq_deinit(nimble_port_get_dflt_eventq()); +#endif // CONFIG_BT_NIMBLE_ENABLED +free_mem: + os_msys_buf_free(); + npl_freertos_mempool_deinit(); + esp_unregister_npl_funcs(); + npl_freertos_funcs_deinit(); + esp_unregister_ext_funcs(); + return ret; +} + +esp_err_t esp_bt_controller_deinit(void) +{ + if ((ble_controller_status < ESP_BT_CONTROLLER_STATUS_INITED) || (ble_controller_status >= ESP_BT_CONTROLLER_STATUS_ENABLED)) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + + controller_sleep_deinit(); + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + ble_log_deinit_async(); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + ble_controller_deinit(); + + periph_module_disable(PERIPH_BT_MODULE); + +#if CONFIG_BT_NIMBLE_ENABLED + /* De-initialize default event queue */ + ble_npl_eventq_deinit(nimble_port_get_dflt_eventq()); +#endif + os_msys_buf_free(); + + esp_unregister_npl_funcs(); + + esp_unregister_ext_funcs(); + + /* De-initialize npl functions */ + npl_freertos_funcs_deinit(); + + npl_freertos_mempool_deinit(); + + esp_phy_modem_deinit(); + + ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + + return ESP_OK; +} + +esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) +{ + esp_err_t ret = ESP_OK; + + if (mode != ESP_BT_MODE_BLE) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller mode"); + return ESP_FAIL; + } + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + if (!s_ble_active) { +#if CONFIG_PM_ENABLE + esp_pm_lock_acquire(s_pm_lock); +#endif // CONFIG_PM_ENABLE + // init phy + esp_phy_enable(PHY_MODEM_BT); + s_ble_active = true; + } + // init bb + bt_bb_v2_init_cmplx(1); + +#if CONFIG_SW_COEXIST_ENABLE + coex_enable(); +#endif + if (ble_controller_enable(mode) != 0) { + ret = ESP_FAIL; + goto error; + } + + ble_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED; + return ESP_OK; + +error: +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + if (s_ble_active) { + esp_phy_disable(PHY_MODEM_BT); +#if CONFIG_PM_ENABLE + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + s_ble_active = false; + } + return ret; +} + +esp_err_t esp_bt_controller_disable(void) +{ + if (ble_controller_status < ESP_BT_CONTROLLER_STATUS_ENABLED) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + if (ble_controller_disable() != 0) { + return ESP_FAIL; + } + + if (s_ble_active) { + esp_phy_disable(PHY_MODEM_BT); +#if CONFIG_PM_ENABLE + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + s_ble_active = false; + } +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + return ESP_OK; +} + +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +{ + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "%s not implemented, return OK", __func__); + return ESP_OK; +} + +static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) +{ + int ret = heap_caps_add_region(start, end); + /* heap_caps_add_region() returns ESP_ERR_INVALID_SIZE if the memory region is + * is too small to fit a heap. This cannot be termed as a fatal error and hence + * we replace it by ESP_OK + */ + if (ret == ESP_ERR_INVALID_SIZE) { + return ESP_OK; + } + return ret; +} + +esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) +{ + intptr_t mem_start, mem_end; + +#if CONFIG_BT_RELEASE_IRAM && CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT + /* Release Bluetooth text section and merge Bluetooth data, bss & text into a large free heap + * region when esp_bt_mem_release is called, total saving ~21kB or more of IRAM. ESP32-C2 has + * only 3 configurable PMP entries available, rest of them are hard-coded. We cannot split the + * memory into 3 different regions (IRAM, BLE-IRAM, DRAM). So `ESP_SYSTEM_PMP_IDRAM_SPLIT` needs + * to be disabled. + */ + ESP_LOGE(NIMBLE_PORT_LOG_TAG, "`ESP_SYSTEM_PMP_IDRAM_SPLIT` should be disabled!"); + assert(0); +#endif // CONFIG_BT_RELEASE_IRAM && CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT + + if (mode & ESP_BT_MODE_BLE) { +#if CONFIG_BT_RELEASE_IRAM + mem_start = (intptr_t)MAP_IRAM_TO_DRAM((intptr_t)&_iram_bt_text_start); + mem_end = (intptr_t)&_bss_bt_end; +#else + mem_start = (intptr_t)&_bt_controller_data_start; + mem_end = (intptr_t)&_bt_bss_end; +#endif // CONFIG_BT_RELEASE_IRAM + if (mem_start != mem_end) { + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Release BLE [0x%08x] - [0x%08x], len %d", mem_start, + mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + + return ESP_OK; +} + + +esp_bt_controller_status_t esp_bt_controller_get_status(void) +{ + return ble_controller_status; +} + +/* extra functions */ +esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_t power_level) +{ + esp_err_t stat = ESP_FAIL; + + switch (power_type) { + case ESP_BLE_PWR_TYPE_DEFAULT: + case ESP_BLE_PWR_TYPE_ADV: + case ESP_BLE_PWR_TYPE_SCAN: + if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + stat = ESP_OK; + } + break; + case ESP_BLE_PWR_TYPE_CONN_HDL0: + case ESP_BLE_PWR_TYPE_CONN_HDL1: + case ESP_BLE_PWR_TYPE_CONN_HDL2: + case ESP_BLE_PWR_TYPE_CONN_HDL3: + case ESP_BLE_PWR_TYPE_CONN_HDL4: + case ESP_BLE_PWR_TYPE_CONN_HDL5: + case ESP_BLE_PWR_TYPE_CONN_HDL6: + case ESP_BLE_PWR_TYPE_CONN_HDL7: + case ESP_BLE_PWR_TYPE_CONN_HDL8: + if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { + stat = ESP_OK; + } + break; + default: + stat = ESP_ERR_NOT_SUPPORTED; + break; + } + + return stat; +} + +esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle, esp_power_level_t power_level) +{ + esp_err_t stat = ESP_FAIL; + switch (power_type) { + case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: + case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: + case ESP_BLE_ENHANCED_PWR_TYPE_INIT: + if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + stat = ESP_OK; + } + break; + case ESP_BLE_ENHANCED_PWR_TYPE_ADV: + case ESP_BLE_ENHANCED_PWR_TYPE_CONN: + if (ble_txpwr_set(power_type, handle, power_level) == 0) { + stat = ESP_OK; + } + break; + default: + stat = ESP_ERR_NOT_SUPPORTED; + break; + } + + return stat; +} + +esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) +{ + int tx_level = 0; + + switch (power_type) { + case ESP_BLE_PWR_TYPE_ADV: + case ESP_BLE_PWR_TYPE_SCAN: + case ESP_BLE_PWR_TYPE_DEFAULT: + tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + break; + case ESP_BLE_PWR_TYPE_CONN_HDL0: + case ESP_BLE_PWR_TYPE_CONN_HDL1: + case ESP_BLE_PWR_TYPE_CONN_HDL2: + case ESP_BLE_PWR_TYPE_CONN_HDL3: + case ESP_BLE_PWR_TYPE_CONN_HDL4: + case ESP_BLE_PWR_TYPE_CONN_HDL5: + case ESP_BLE_PWR_TYPE_CONN_HDL6: + case ESP_BLE_PWR_TYPE_CONN_HDL7: + case ESP_BLE_PWR_TYPE_CONN_HDL8: + tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); + break; + default: + return ESP_PWR_LVL_INVALID; + } + + if (tx_level < 0) { + return ESP_PWR_LVL_INVALID; + } + + return (esp_power_level_t)tx_level; +} + +esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle) +{ + int tx_level = 0; + + switch (power_type) { + case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: + case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: + case ESP_BLE_ENHANCED_PWR_TYPE_INIT: + tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + break; + case ESP_BLE_ENHANCED_PWR_TYPE_ADV: + case ESP_BLE_ENHANCED_PWR_TYPE_CONN: + tx_level = ble_txpwr_get(power_type, handle); + break; + default: + return ESP_PWR_LVL_INVALID; + } + + if (tx_level < 0) { + return ESP_PWR_LVL_INVALID; + } + + return (esp_power_level_t)tx_level; +} + +uint8_t esp_ble_get_chip_rev_version(void) +{ + return efuse_ll_get_chip_wafer_version_minor(); +} + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) +{ + for (int i = 0; i < len; i++) { + esp_rom_printf("%02x ", addr[i]); + } + if (end) { + esp_rom_printf("\n"); + } +} + +void esp_ble_controller_log_dump_all(bool output) +{ + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(5000); + BT_ASSERT_PRINT("\r\n[DUMP_START:"); + ble_log_async_output_dump_all(output); + BT_ASSERT_PRINT(":DUMP_END]\r\n"); + portEXIT_CRITICAL_SAFE(&spinlock); +} +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +#if (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC +#define BLE_SM_KEY_ERR 0x17 +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS +#include "mbedtls/aes.h" +#if CONFIG_BT_LE_SM_SC +#include "mbedtls/cipher.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/cmac.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/ecp.h" + +static mbedtls_ecp_keypair keypair; +#endif // CONFIG_BT_LE_SM_SC + +#else +#include "tinycrypt/aes.h" +#include "tinycrypt/constants.h" +#include "tinycrypt/utils.h" + +#if CONFIG_BT_LE_SM_SC +#include "tinycrypt/cmac_mode.h" +#include "tinycrypt/ecc_dh.h" +#endif // CONFIG_BT_LE_SM_SC +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + +/* Based on Core Specification 4.2 Vol 3. Part H 2.3.5.6.1 */ +static const uint8_t ble_sm_alg_dbg_priv_key[32] = { + 0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38, 0x74, 0xc9, 0xb3, 0xe3, + 0xd2, 0x10, 0x3f, 0x50, 0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99, + 0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd +}; + +int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey) +{ + uint8_t dh[32]; + uint8_t pk[64]; + uint8_t priv[32]; + int rc = BLE_SM_KEY_ERR; + + swap_buf(pk, peer_pub_key_x, 32); + swap_buf(&pk[32], peer_pub_key_y, 32); + swap_buf(priv, our_priv_key, 32); + +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + struct mbedtls_ecp_point pt = {0}, Q = {0}; + mbedtls_mpi z = {0}, d = {0}; + mbedtls_ctr_drbg_context ctr_drbg = {0}; + mbedtls_entropy_context entropy = {0}; + + uint8_t pub[65] = {0}; + /* Hardcoded first byte of pub key for MBEDTLS_ECP_PF_UNCOMPRESSED */ + pub[0] = 0x04; + memcpy(&pub[1], pk, 64); + + /* Initialize the required structures here */ + mbedtls_ecp_point_init(&pt); + mbedtls_ecp_point_init(&Q); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_entropy_init(&entropy); + mbedtls_mpi_init(&d); + mbedtls_mpi_init(&z); + + /* Below 3 steps are to validate public key on curve secp256r1 */ + if (mbedtls_ecp_group_load(&keypair.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1) != 0) { + goto exit; + } + + if (mbedtls_ecp_point_read_binary(&keypair.MBEDTLS_PRIVATE(grp), &pt, pub, 65) != 0) { + goto exit; + } + + if (mbedtls_ecp_check_pubkey(&keypair.MBEDTLS_PRIVATE(grp), &pt) != 0) { + goto exit; + } + + /* Set PRNG */ + if ((rc = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0)) != 0) { + goto exit; + } + + /* Prepare point Q from pub key */ + if (mbedtls_ecp_point_read_binary(&keypair.MBEDTLS_PRIVATE(grp), &Q, pub, 65) != 0) { + goto exit; + } + + if (mbedtls_mpi_read_binary(&d, priv, 32) != 0) { + goto exit; + } + + rc = mbedtls_ecdh_compute_shared(&keypair.MBEDTLS_PRIVATE(grp), &z, &Q, &d, + mbedtls_ctr_drbg_random, &ctr_drbg); + if (rc != 0) { + goto exit; + } + + rc = mbedtls_mpi_write_binary(&z, dh, 32); + if (rc != 0) { + goto exit; + } + +exit: + mbedtls_ecp_point_free(&pt); + mbedtls_mpi_free(&z); + mbedtls_mpi_free(&d); + mbedtls_ecp_point_free(&Q); + mbedtls_entropy_free(&entropy); + mbedtls_ctr_drbg_free(&ctr_drbg); + if (rc != 0) { + return BLE_SM_KEY_ERR; + } + +#else + if (uECC_valid_public_key(pk, &curve_secp256r1) < 0) { + return BLE_SM_KEY_ERR; + } + + rc = uECC_shared_secret(pk, priv, dh, &curve_secp256r1); + if (rc == TC_CRYPTO_FAIL) { + return BLE_SM_KEY_ERR; + } +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + + swap_buf(out_dhkey, dh, 32); + return 0; +} + +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS +static int mbedtls_gen_keypair(uint8_t *public_key, uint8_t *private_key) +{ + int rc = BLE_SM_KEY_ERR; + mbedtls_entropy_context entropy = {0}; + mbedtls_ctr_drbg_context ctr_drbg = {0}; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_ecp_keypair_init(&keypair); + + if ((rc = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + NULL, 0)) != 0) { + goto exit; + } + + if ((rc = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, &keypair, + mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { + goto exit; + } + + if ((rc = mbedtls_mpi_write_binary(&keypair.MBEDTLS_PRIVATE(d), private_key, 32)) != 0) { + goto exit; + } + + size_t olen = 0; + uint8_t pub[65] = {0}; + + if ((rc = mbedtls_ecp_point_write_binary(&keypair.MBEDTLS_PRIVATE(grp), &keypair.MBEDTLS_PRIVATE(Q), MBEDTLS_ECP_PF_UNCOMPRESSED, + &olen, pub, 65)) != 0) { + goto exit; + } + + memcpy(public_key, &pub[1], 64); + +exit: + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + if (rc != 0) { + mbedtls_ecp_keypair_free(&keypair); + return BLE_SM_KEY_ERR; + } + + return 0; +} +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + +/** + * pub: 64 bytes + * priv: 32 bytes + */ +int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv) +{ +#if CONFIG_BT_LE_SM_SC_DEBUG_KEYS + swap_buf(pub, ble_sm_alg_dbg_pub_key, 32); + swap_buf(&pub[32], &ble_sm_alg_dbg_pub_key[32], 32); + swap_buf(priv, ble_sm_alg_dbg_priv_key, 32); +#else + uint8_t pk[64]; + + do { +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + if (mbedtls_gen_keypair(pk, priv) != 0) { + return BLE_SM_KEY_ERR; + } +#else + if (uECC_make_key(pk, priv, &curve_secp256r1) != TC_CRYPTO_SUCCESS) { + return BLE_SM_KEY_ERR; + } +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + /* Make sure generated key isn't debug key. */ + } while (memcmp(priv, ble_sm_alg_dbg_priv_key, 32) == 0); + + swap_buf(pub, pk, 32); + swap_buf(&pub[32], &pk[32], 32); + swap_in_place(priv, 32); +#endif // CONFIG_BT_LE_SM_SC_DEBUG_KEYS + return 0; +} + +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC +#endif // (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) + diff --git a/lib/bt/controller/esp32c2/esp_bt_cfg.h b/lib/bt/controller/esp32c2/esp_bt_cfg.h new file mode 100644 index 00000000..308d79e3 --- /dev/null +++ b/lib/bt/controller/esp32c2/esp_bt_cfg.h @@ -0,0 +1,220 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ESP_BT_CFG_H__ +#define __ESP_BT_CFG_H__ + +#include <stdint.h> +#include <stdbool.h> +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_BT_NIMBLE_ENABLED +#include "syscfg/syscfg.h" +#endif + +#define NIMBLE_LL_STACK_SIZE CONFIG_BT_LE_CONTROLLER_TASK_STACK_SIZE + +#if CONFIG_BT_NIMBLE_ENABLED + + #if CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_CODED_PHY + #define BLE_LL_SCAN_PHY_NUMBER_N (2) + #else + #define BLE_LL_SCAN_PHY_NUMBER_N (1) + #endif + + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST MYNEWT_VAL(BLE_MAX_PERIODIC_ADVERTISER_LIST) + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS) + #define DEFAULT_BT_LE_MAX_CONNECTIONS MYNEWT_VAL(BLE_MAX_CONNECTIONS) + #define DEFAULT_BT_LE_ACL_BUF_SIZE MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE) + #define DEFAULT_BT_LE_ACL_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE) + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE MYNEWT_VAL(BLE_LL_WHITELIST_SIZE) + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT) + #if defined(CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT) + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (1) + #else + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) + #endif + +#else + + #if CONFIG_BT_LE_LL_CFG_FEAT_LE_CODED_PHY + #define BLE_LL_SCAN_PHY_NUMBER_N (2) + #else + #define BLE_LL_SCAN_PHY_NUMBER_N (1) + #endif + + #if defined(CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST) + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST (CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST) + #else + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST (5) + #endif + + #if defined(CONFIG_BT_LE_MAX_PERIODIC_SYNCS) + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS (CONFIG_BT_LE_MAX_PERIODIC_SYNCS) + #else + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS (1) + #endif + + #if defined(CONFIG_BT_LE_MAX_CONNECTIONS) + #define DEFAULT_BT_LE_MAX_CONNECTIONS (CONFIG_BT_LE_MAX_CONNECTIONS) + #else + #define DEFAULT_BT_LE_MAX_CONNECTIONS (2) + #endif + + #if defined(CONFIG_BT_LE_ACL_BUF_SIZE) + #define DEFAULT_BT_LE_ACL_BUF_SIZE (CONFIG_BT_LE_ACL_BUF_SIZE) + #else + #define DEFAULT_BT_LE_ACL_BUF_SIZE (255) + #endif + + #if defined(CONFIG_BT_LE_ACL_BUF_COUNT) + #define DEFAULT_BT_LE_ACL_BUF_COUNT (CONFIG_BT_LE_ACL_BUF_COUNT) + #else + #define DEFAULT_BT_LE_ACL_BUF_COUNT (24) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_BUF_SIZE) + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE (CONFIG_BT_LE_HCI_EVT_BUF_SIZE) + #else + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE (70) + #endif + + #if defined(CONFIG_BT_LE_EXT_ADV_MAX_SIZE) + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE (CONFIG_BT_LE_EXT_ADV_MAX_SIZE) + #else + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE (31) + #endif + + #if defined(CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES) + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES (CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES) + #else + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES (1) + #endif + + #if defined(CONFIG_BT_LE_WHITELIST_SIZE) + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE (CONFIG_BT_LE_WHITELIST_SIZE) + #else + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE (12) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT (CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT) + #else + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT (30) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT (CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT) + #else + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT (8) + #endif + #if defined(CONFIG_BT_LE_50_FEATURE_SUPPORT) + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (1) + #else + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) + #endif + +#endif + +#define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF + +#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART +#define HCI_UART_EN CONFIG_BT_LE_HCI_INTERFACE_USE_UART +#else +#define HCI_UART_EN 0 // hci ram mode +#endif + +#ifdef CONFIG_BT_LE_SLEEP_ENABLE +#define NIMBLE_SLEEP_ENABLE CONFIG_BT_LE_SLEEP_ENABLE +#else +#define NIMBLE_SLEEP_ENABLE 0 +#endif + + +#ifdef CONFIG_BT_LE_TX_CCA_ENABLED + #define DEFAULT_BT_LE_TX_CCA_ENABLED (CONFIG_BT_LE_TX_CCA_ENABLED) +#else + #define DEFAULT_BT_LE_TX_CCA_ENABLED (0) +#endif + +#ifdef CONFIG_BT_LE_CCA_RSSI_THRESH + #define DEFAULT_BT_LE_CCA_RSSI_THRESH (CONFIG_BT_LE_CCA_RSSI_THRESH) +#else + #define DEFAULT_BT_LE_CCA_RSSI_THRESH (50) +#endif + +#define DEFAULT_BT_LE_SCAN_RSP_DATA_MAX_LEN_N DEFAULT_BT_LE_EXT_ADV_MAX_SIZE + + +#if HCI_UART_EN + #define DEFAULT_BT_LE_HCI_UART_TX_PIN (CONFIG_BT_LE_HCI_UART_TX_PIN) + #define DEFAULT_BT_LE_HCI_UART_RX_PIN (CONFIG_BT_LE_HCI_UART_RX_PIN) + #define DEFAULT_BT_LE_HCI_UART_PORT (CONFIG_BT_LE_HCI_UART_PORT) + #define DEFAULT_BT_LE_HCI_UART_BAUD (CONFIG_BT_LE_HCI_UART_BAUD) + #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS) + #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1) + #define DEFAULT_BT_LE_HCI_UART_PARITY (0) + #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) +#else + #define DEFAULT_BT_LE_HCI_UART_TX_PIN (0) + #define DEFAULT_BT_LE_HCI_UART_RX_PIN (0) + #define DEFAULT_BT_LE_HCI_UART_PORT (0) + #define DEFAULT_BT_LE_HCI_UART_BAUD (0) + #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0) + #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0) + #define DEFAULT_BT_LE_HCI_UART_PARITY (0) + #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) +#endif + +/* Unchanged configuration */ + +#define BLE_LL_CTRL_PROC_TIMEOUT_MS_N (40000) /* ms */ + +#define BLE_LL_CFG_NUM_HCI_CMD_PKTS_N (1) + +#define BLE_LL_SCHED_ADV_MAX_USECS_N (852) + +#define BLE_LL_SCHED_DIRECT_ADV_MAX_USECS_N (502) + +#define BLE_LL_SCHED_MAX_ADV_PDU_USECS_N (376) + +#define BLE_LL_SUB_VERS_NR_N (0x0000) + +#define BLE_LL_JITTER_USECS_N (16) + +#define BLE_PHY_MAX_PWR_DBM_N (10) + +#define BLE_LL_CONN_DEF_AUTH_PYLD_TMO_N (3000) + +#ifdef CONFIG_XTAL_FREQ_26 + #define RTC_FREQ_N (40000) /* in Hz */ +#else + #define RTC_FREQ_N (32000) /* in Hz */ +#endif // CONFIG_XTAL_FREQ_26 + +#define BLE_LL_TX_PWR_DBM_N (9) + + +#define RUN_BQB_TEST (0) +#define RUN_QA_TEST (0) +#define NIMBLE_DISABLE_SCAN_BACKOFF (0) + + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_BT_CFG_H__ */ diff --git a/lib/bt/controller/esp32c3/Kconfig.in b/lib/bt/controller/esp32c3/Kconfig.in new file mode 100644 index 00000000..078b215f --- /dev/null +++ b/lib/bt/controller/esp32c3/Kconfig.in @@ -0,0 +1,477 @@ +config BT_CTRL_MODE_EFF + int + default 1 + +config BT_CTRL_BLE_MAX_ACT + int "BLE Max Instances" + default 6 + range 1 10 + help + BLE maximum activities of bluetooth controller,both of connections, + scan , sync and adv(periodic adv, multi-adv). Each instance needs to + consume 828 bytes, you can save RAM by modifying the instance value + according to actual needs. + +config BT_CTRL_BLE_MAX_ACT_EFF + int + default BT_CTRL_BLE_MAX_ACT + default 0 + +config BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB + int "BLE static ACL TX buffer numbers" + range 0 12 + default 0 + help + BLE ACL buffer have two methods to be allocated. One is persistent allocating + (alloate when controller initialise, never free until controller de-initialise) + another is dynamically allocating (allocate before TX and free after TX). + +choice BT_CTRL_PINNED_TO_CORE_CHOICE + prompt "The cpu core which bluetooth controller run" + depends on !FREERTOS_UNICORE + help + Specify the cpu core to run bluetooth controller. + Can not specify no-affinity. + + config BT_CTRL_PINNED_TO_CORE_0 + bool "Core 0 (PRO CPU)" + config BT_CTRL_PINNED_TO_CORE_1 + bool "Core 1 (APP CPU)" + depends on !FREERTOS_UNICORE +endchoice + +config BT_CTRL_PINNED_TO_CORE + int + default 0 if BT_CTRL_PINNED_TO_CORE_0 + default 1 if BT_CTRL_PINNED_TO_CORE_1 + default 0 + +choice BT_CTRL_HCI_MODE_CHOICE + prompt "HCI mode" + help + Specify HCI mode as VHCI or UART(H4) + + config BT_CTRL_HCI_MODE_VHCI + bool "VHCI" + help + Normal option. Mostly, choose this VHCI when bluetooth host run on ESP32S3 or ESP32C3. + + config BT_CTRL_HCI_MODE_UART_H4 + bool "UART(H4)" + help + If use external bluetooth host which run on other hardware and use UART as the HCI interface, + choose this option. +endchoice + +config BT_CTRL_HCI_TL + int + default 0 if BT_CTRL_HCI_MODE_UART_H4 + default 1 if BT_CTRL_HCI_M0DE_VHCI + default 1 + help + HCI mode as VHCI or UART(H4) + +config BT_CTRL_ADV_DUP_FILT_MAX + int "The maxinum number of 5.0 extend duplicate scan filter" + range 1 500 + default 30 + help + The maxinum number of suplicate scan filter + +choice BT_BLE_CCA_MODE + prompt "BLE CCA mode" + default BT_BLE_CCA_MODE_NONE + help + Define BT BLE CCA mode + + config BT_BLE_CCA_MODE_NONE + bool "NONE" + config BT_BLE_CCA_MODE_HW + bool "Hardware" + config BT_BLE_CCA_MODE_SW + bool "Software" +endchoice + +config BT_BLE_CCA_MODE + int + default 0 if BT_BLE_CCA_MODE_NONE + default 1 if BT_BLE_CCA_MODE_HW + default 2 if BT_BLE_CCA_MODE_SW + +config BT_CTRL_HW_CCA_VAL + int "CCA threshold value" + range 20 100 + default 20 + help + It is the threshold value of HW CCA, if the value is 30, it means CCA threshold is -30 dBm. + +config BT_CTRL_HW_CCA_EFF + int + default 1 if BT_CTRL_HW_CCA + default 0 + help + If other devices are sending packets in the air and the signal is strong, + the packet hw to be sent this time is cancelled. + +choice BT_CTRL_CE_LENGTH_TYPE + prompt "Connection event length determination method" + help + Specify connection event length determination + + config BT_CTRL_CE_LENGTH_TYPE_ORIG + bool "ORIGINAL" + config BT_CTRL_CE_LENGTH_TYPE_CE + bool "Use CE parameter for HCI command" + config BT_CTRL_CE_LENGTH_TYPE_SD + bool "Use Espressif self-defined method" +endchoice + +config BT_CTRL_CE_LENGTH_TYPE_EFF + int + default 0 if BT_CTRL_CE_LENGTH_TYPE_ORIG + default 1 if BT_CTRL_CE_LENGTH_TYPE_CE + default 2 if BT_CTRL_CE_LENGTH_TYPE_SD + +choice BT_CTRL_TX_ANTENNA_INDEX + prompt "default Tx anntena used" + help + Specify default Tx antenna used for bluetooth + + config BT_CTRL_TX_ANTENNA_INDEX_0 + bool "Antenna 0" + config BT_CTRL_TX_ANTENNA_INDEX_1 + bool "Antenna 1" +endchoice + +config BT_CTRL_TX_ANTENNA_INDEX_EFF + int + default 0 if BT_CTRL_TX_ANTENNA_INDEX_0 + default 1 if BT_CTRL_TX_ANTENNA_INDEX_1 + +choice BT_CTRL_RX_ANTENNA_INDEX + prompt "default Rx anntena used" + help + Specify default Rx antenna used for bluetooth + + config BT_CTRL_RX_ANTENNA_INDEX_0 + bool "Antenna 0" + config BT_CTRL_RX_ANTENNA_INDEX_1 + bool "Antenna 1" +endchoice + +config BT_CTRL_RX_ANTENNA_INDEX_EFF + int + default 0 if BT_CTRL_RX_ANTENNA_INDEX_0 + default 1 if BT_CTRL_RX_ANTENNA_INDEX_1 + +choice BT_CTRL_DFT_TX_POWER_LEVEL + prompt "BLE default Tx power level" + default BT_CTRL_DFT_TX_POWER_LEVEL_P9 + help + Specify default Tx power level + + config BT_CTRL_DFT_TX_POWER_LEVEL_N24 + bool "-24dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_N21 + bool "-21dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_N18 + bool "-18dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_N15 + bool "-15dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_N12 + bool "-12dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_N9 + bool "-9dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_N6 + bool "-6dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_N3 + bool "-3dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_N0 + bool "0dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_P3 + bool "+3dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_P6 + bool "+6dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_P9 + bool "+9dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_P12 + bool "+12dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_P15 + bool "+15dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_P18 + bool "+18dBm" + config BT_CTRL_DFT_TX_POWER_LEVEL_P21 + bool "+21dBm" +endchoice + +config BT_CTRL_DFT_TX_POWER_LEVEL_EFF + int + default 0 if BT_CTRL_DFT_TX_POWER_LEVEL_N24 + default 1 if BT_CTRL_DFT_TX_POWER_LEVEL_N21 + default 2 if BT_CTRL_DFT_TX_POWER_LEVEL_N18 + default 3 if BT_CTRL_DFT_TX_POWER_LEVEL_N15 + default 4 if BT_CTRL_DFT_TX_POWER_LEVEL_N12 + default 5 if BT_CTRL_DFT_TX_POWER_LEVEL_N9 + default 6 if BT_CTRL_DFT_TX_POWER_LEVEL_N6 + default 7 if BT_CTRL_DFT_TX_POWER_LEVEL_N3 + default 8 if BT_CTRL_DFT_TX_POWER_LEVEL_N0 + default 9 if BT_CTRL_DFT_TX_POWER_LEVEL_P3 + default 10 if BT_CTRL_DFT_TX_POWER_LEVEL_P6 + default 11 if BT_CTRL_DFT_TX_POWER_LEVEL_P9 + default 12 if BT_CTRL_DFT_TX_POWER_LEVEL_P12 + default 13 if BT_CTRL_DFT_TX_POWER_LEVEL_P15 + default 14 if BT_CTRL_DFT_TX_POWER_LEVEL_P18 + default 15 if BT_CTRL_DFT_TX_POWER_LEVEL_P21 + default 0 + +config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + bool "BLE adv report flow control supported" + default y + help + The function is mainly used to enable flow control for advertising reports. When it is enabled, + advertising reports will be discarded by the controller if the number of unprocessed advertising + reports exceeds the size of BLE adv report flow control. + +config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM + int "BLE adv report flow control number" + depends on BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 50 1000 + default 100 + help + The number of unprocessed advertising report that bluetooth host can save.If you set + `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a small value, this may cause adv packets lost. + If you set `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a large value, bluetooth host may cache a + lot of adv packets and this may cause system memory run out. For example, if you set + it to 50, the maximum memory consumed by host is 35 * 50 bytes. Please set + `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` according to your system free memory and handle adv + packets as fast as possible, otherwise it will cause adv packets lost. + +config BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD + int "BLE adv lost event threshold value" + depends on BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 1 1000 + default 20 + help + When adv report flow control is enabled, The ADV lost event will be generated when the number + of ADV packets lost in the controller reaches this threshold. It is better to set a larger value. + If you set `BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it + may cause adv packets lost more. + +config BT_CTRL_BLE_SCAN_DUPL + bool "BLE Scan Duplicate Options" + default y + help + This select enables parameters setting of BLE scan duplicate. + +choice BT_CTRL_SCAN_DUPL_TYPE + prompt "Scan Duplicate Type" + default BT_CTRL_SCAN_DUPL_TYPE_DEVICE + depends on BT_CTRL_BLE_SCAN_DUPL + help + Scan duplicate have three ways. one is "Scan Duplicate By Device Address", This way is to use + advertiser address filtering. The adv packet of the same address is only allowed to be reported once. + Another way is "Scan Duplicate By Device Address And Advertising Data". This way is to use advertising + data and device address filtering. All different adv packets with the same address are allowed to be + reported. The last way is "Scan Duplicate By Advertising Data". This way is to use advertising data + filtering. All same advertising data only allow to be reported once even though they are from + different devices. + + config BT_CTRL_SCAN_DUPL_TYPE_DEVICE + bool "Scan Duplicate By Device Address" + help + Advertising packets with the same address, address type, and advertising type are reported once. + + config BT_CTRL_SCAN_DUPL_TYPE_DATA + bool "Scan Duplicate By Advertising Data" + help + Advertising packets with identical advertising data, address type, and advertising type + are reported only once, even if they originate from different devices. + + config BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE + bool "Scan Duplicate By Device Address And Advertising Data" + help + Advertising packets with the same address, advertising data, address type, + and advertising type are reported only once. +endchoice + +config BT_CTRL_SCAN_DUPL_TYPE + int + depends on BT_CTRL_BLE_SCAN_DUPL + default 0 if BT_CTRL_SCAN_DUPL_TYPE_DEVICE + default 1 if BT_CTRL_SCAN_DUPL_TYPE_DATA + default 2 if BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE + default 0 + +config BT_CTRL_SCAN_DUPL_CACHE_SIZE + int "Maximum number of devices in scan duplicate filter" + depends on BT_CTRL_BLE_SCAN_DUPL + range 10 1000 + default 100 + help + Maximum number of devices which can be recorded in scan duplicate filter. + When the maximum amount of device in the filter is reached, the cache will be refreshed. + +config BT_CTRL_DUPL_SCAN_CACHE_REFRESH_PERIOD + int "Duplicate scan list refresh period (seconds)" + depends on BT_CTRL_BLE_SCAN_DUPL + range 0 1000 + default 0 + help + If the period value is non-zero, the controller will periodically clear the device information + stored in the scan duuplicate filter. If it is 0, the scan duuplicate filter will not be cleared + until the scanning is disabled. Duplicate advertisements for this period should not be sent to the + Host in advertising report events. + There are two scenarios where the ADV packet will be repeatedly reported: + 1. The duplicate scan cache is full, the controller will delete the oldest device information and + add new device information. + 2. When the refresh period is up, the controller will clear all device information and start filtering + again. + +config BT_CTRL_BLE_MESH_SCAN_DUPL_EN + bool "Special duplicate scan mechanism for BLE Mesh scan" + depends on BT_CTRL_BLE_SCAN_DUPL + default n + help + This enables the BLE scan duplicate for special BLE Mesh scan. + +config BT_CTRL_MESH_DUPL_SCAN_CACHE_SIZE + int "Maximum number of Mesh adv packets in scan duplicate filter" + depends on BT_CTRL_BLE_MESH_SCAN_DUPL_EN + range 10 1000 + default 100 + help + Maximum number of adv packets which can be recorded in duplicate scan cache for BLE Mesh. + When the maximum amount of device in the filter is reached, the cache will be refreshed. + +choice BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM + prompt "Coexistence: limit on MAX Tx/Rx time for coded-PHY connection" + default BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_DIS + depends on ESP_COEX_SW_COEXIST_ENABLE + help + When using PHY-Coded in BLE connection, limitation on max tx/rx time can be applied to + better avoid dramatic performance deterioration of Wi-Fi. + + config BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EN + bool "Force Enable" + help + Always enable the limitation on max tx/rx time for Coded-PHY connection + + config BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_DIS + bool "Force Disable" + help + Disable the limitation on max tx/rx time for Coded-PHY connection +endchoice + +config BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EFF + int + default 0 if !ESP_COEX_SW_COEXIST_ENABLE + default 1 if BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EN + default 0 if BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_DIS + +menu "MODEM SLEEP Options" + visible if BT_ENABLED + + config BT_CTRL_MODEM_SLEEP + bool "Bluetooth modem sleep" + depends on !BT_CTRL_HCI_MODE_UART_H4 + default n + help + Enable/disable bluetooth controller low power mode. + Modem sleep is not supported to be used with UART HCI. + + config BT_CTRL_MODEM_SLEEP_MODE_1 + bool "Bluetooth Modem sleep Mode 1" + depends on BT_CTRL_MODEM_SLEEP + default y + help + Mode 1 is the currently supported sleep mode. In this mode, + bluetooth controller sleeps between and BLE events. A low + power clock is used to maintain bluetooth reference clock. + + choice BT_CTRL_LOW_POWER_CLOCK + prompt "Bluetooth low power clock" + depends on BT_CTRL_MODEM_SLEEP_MODE_1 + help + Select the low power clock source for bluetooth controller + + config BT_CTRL_LPCLK_SEL_MAIN_XTAL + bool "Main crystal" + help + Main crystal can be used as low power clock for bluetooth modem sleep. If this option is + selected, bluetooth modem sleep can work under Dynamic Frequency Scaling(DFS) enabled, and + bluetooth can work under light sleep enabled. Main crystal has a relatively better performance + than other bluetooth low power clock sources. + config BT_CTRL_LPCLK_SEL_EXT_32K_XTAL + bool "External 32kHz crystal" + depends on RTC_CLK_SRC_EXT_CRYS + help + External 32kHz crystal has a nominal frequency of 32.768kHz and provides good frequency + stability. If used as Bluetooth low power clock, External 32kHz can support Bluetooth + modem sleep to be used with both DFS and light sleep. + + config BT_CTRL_LPCLK_SEL_RTC_SLOW + bool "Internal 150kHz RC oscillator" + depends on RTC_CLK_SRC_INT_RC + help + Internal 150kHz RC oscillator. The accuracy of this clock is a lot larger than 500ppm which is required + in Bluetooth communication, so don't select this option in scenarios such as BLE connection state. + endchoice + + config BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP + bool "power up main XTAL during light sleep" + depends on (BT_CTRL_LPCLK_SEL_MAIN_XTAL || BT_CTRL_LPCLK_SEL_EXT_32K_XTAL) && FREERTOS_USE_TICKLESS_IDLE + default n + help + If this option is selected, the main crystal will power up during light sleep when the low power clock + selects an external 32kHz crystal but the external 32kHz crystal does not exist or the low power clock + selects the main crystal. + +endmenu + +config BT_CTRL_SLEEP_MODE_EFF + int + default 1 if BT_CTRL_MODEM_SLEEP_MODE_1 + default 0 + +config BT_CTRL_SLEEP_CLOCK_EFF + int + default 1 if BT_CTRL_LPCLK_SEL_MAIN_XTAL + default 2 if BT_CTRL_LPCLK_SEL_EXT_32K_XTAL + default 3 if BT_CTRL_LPCLK_SEL_RTC_SLOW + + default 0 + +config BT_CTRL_HCI_TL_EFF + int + default 0 if BT_CTRL_HCI_MODE_UART_H4 + default 1 if BT_CTRL_HCI_M0DE_VHCI + default 1 + +config BT_CTRL_AGC_RECORRECT_EN + bool "Enable HW AGC recorrect" + default n + help + Enable uncoded phy AGC recorrect + +config BT_CTRL_CODED_AGC_RECORRECT_EN + bool "Enable coded phy AGC recorrect" + depends on BT_CTRL_AGC_RECORRECT_EN + default n + help + Enable coded phy AGC recorrect + +config BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX + bool "Disable active scan backoff" + default n + help + Disable active scan backoff. The bluetooth spec requires that scanners should run a backoff procedure to + minimize collision of scan request PDUs from nultiple scanners. If scan backoff is disabled, in active + scanning, scan request PDU will be sent every time when HW receives scannable ADV PDU. + +config BT_BLE_ADV_DATA_LENGTH_ZERO_AUX + bool "Enable aux packet when ext adv data length is zero" + default n + help + When this option is enabled, auxiliary packets will be present in the events of + 'Non-Connectable and Non-Scannable' regardless of whether the advertising length is 0. + If this option is not enabled, auxiliary packets will only be present when the advertising length is not 0. diff --git a/lib/bt/controller/esp32c3/bt.c b/lib/bt/controller/esp32c3/bt.c new file mode 100644 index 00000000..f1e045d3 --- /dev/null +++ b/lib/bt/controller/esp32c3/bt.c @@ -0,0 +1,1680 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "sdkconfig.h" +#include "esp_heap_caps.h" +#include "esp_heap_caps_init.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "freertos/portmacro.h" +#include "esp_types.h" +#include "esp_mac.h" +#include "esp_random.h" +#include "esp_task.h" +#include "esp_attr.h" +#include "esp_phy_init.h" +#include "esp_bt.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_pm.h" +#include "esp_ipc.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/esp_clk.h" +#include "soc/soc_caps.h" +#include "soc/rtc.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/soc_memory_layout.h" +#include "private/esp_coexist_internal.h" +#include "esp_timer.h" +#include "esp_sleep.h" +#include "esp_rom_sys.h" +#include "esp_private/phy.h" +#if CONFIG_IDF_TARGET_ESP32C3 +#include "riscv/interrupt.h" +#include "esp32c3/rom/rom_layout.h" +#else //CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/rom_layout.h" +#endif +#if CONFIG_BT_ENABLED + +/* Macro definition + ************************************************************************ + */ + +#define BT_LOG_TAG "BLE_INIT" + +#define BTDM_INIT_PERIOD (5000) /* ms */ + +/* 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) + +// wakeup request sources +enum { + BTDM_ASYNC_WAKEUP_SRC_VHCI = 0, + BTDM_ASYNC_WAKEUP_SRC_DISA, + BTDM_ASYNC_WAKEUP_SRC_TMR, + BTDM_ASYNC_WAKEUP_SRC_MAX, +}; + +// low power control struct +typedef union { + struct { + uint32_t enable : 1; // whether low power mode is required + uint32_t lpclk_sel : 2; // low power clock source + uint32_t mac_bb_pd : 1; // whether hardware(MAC, BB) force-power-down is required during sleep + uint32_t wakeup_timer_required : 1; // whether system timer is needed + uint32_t no_light_sleep : 1; // do not allow system to enter light sleep after bluetooth is enabled + uint32_t main_xtal_pu : 1; // power up main XTAL + uint32_t reserved : 25; // reserved + }; + uint32_t val; +} btdm_lpcntl_t; + +// low power control status +typedef union { + struct { + uint32_t pm_lock_released : 1; // whether power management lock is released + uint32_t mac_bb_pd : 1; // whether hardware(MAC, BB) is powered down + uint32_t phy_enabled : 1; // whether phy is switched on + uint32_t wakeup_timer_started : 1; // whether wakeup timer is started + uint32_t reserved : 28; // reserved + }; + uint32_t val; +} btdm_lpstat_t; + +/* 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 + +#define BT_DEBUG(...) +#define BT_API_CALL_CHECK(info, api_call, ret) \ +do{\ + esp_err_t __err = (api_call);\ + if ((ret) != __err) {\ + BT_DEBUG("%s %d %s ret=0x%X\n", __FUNCTION__, __LINE__, (info), __err);\ + return __err;\ + }\ +} while(0) + +#define OSI_FUNCS_TIME_BLOCKING 0xffffffff +#define OSI_VERSION 0x00010007 +#define OSI_MAGIC_VALUE 0xFADEBEAD + +/* Types definition + ************************************************************************ + */ +/* vendor dependent signals to be posted to controller task */ +typedef enum { + BTDM_VND_OL_SIG_WAKEUP_TMR = 0, + BTDM_VND_OL_SIG_NUM, +} btdm_vnd_ol_sig_t; + +/* 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 { + 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; + +typedef struct { + void *handle; +} btdm_queue_item_t; + +typedef void (* osi_intr_handler)(void); + +/* OSI function */ +struct osi_funcs_t { + 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, intr_handler_t 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 hus); + 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); + void (* _ets_delay_us)(uint32_t us); + void (* _btdm_rom_table_ready)(void); +}; + + +/* External functions or values + ************************************************************************ + */ + +/* not for user call, so don't put to include file */ +/* OSI */ +extern int btdm_osi_funcs_register(void *osi_funcs); +/* 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 r_btdm_vnd_offload_post_from_isr(btdm_vnd_ol_sig_t sig, void *param, bool need_yield); +extern int r_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); +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 void coex_pti_v2(void); + +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 void sdk_config_extend_set_pll_track(bool enable); + +#if CONFIG_MAC_BB_PD +extern void esp_mac_bb_power_down(void); +extern void esp_mac_bb_power_up(void); +extern void ets_backup_dma_copy(uint32_t reg, uint32_t mem_addr, uint32_t num, bool to_mem); +#endif + +extern void btdm_cca_feature_enable(void); + +extern uint32_t _bt_bss_start; +extern uint32_t _bt_bss_end; +extern uint32_t _btdm_bss_start; +extern uint32_t _btdm_bss_end; +extern uint32_t _nimble_bss_start; +extern uint32_t _nimble_bss_end; +extern uint32_t _bt_data_start; +extern uint32_t _bt_data_end; +extern uint32_t _btdm_data_start; +extern uint32_t _btdm_data_end; +extern uint32_t _nimble_data_start; +extern uint32_t _nimble_data_end; + +/* Local Function Declare + ********************************************************************* + */ +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, intr_handler_t 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 void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size); +static void queue_delete_wrapper(void *queue); +static int queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms); +static int queue_send_from_isr_wrapper(void *queue, void *item, void *hptw); +static int queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms); +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_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 hus); +static bool btdm_sleep_check_duration(int32_t *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); +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 btdm_hw_mac_power_up_wrapper(void); +static void btdm_hw_mac_power_down_wrapper(void); +static void btdm_backup_dma_copy_wrapper(uint32_t reg, uint32_t mem_addr, uint32_t num, bool to_mem); +static void btdm_funcs_table_ready_wrapper(void); + +static void btdm_slp_tmr_callback(void *arg); + +static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end); + +static void bt_controller_deinit_internal(void); + +/* Local variable definition + *************************************************************************** + */ +/* OSI funcs */ +static const struct osi_funcs_t osi_funcs_ro = { + ._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 = vPortYield, + ._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 = NULL, + ._malloc = malloc, + ._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, + ._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_phase1 = NULL, + ._btdm_sleep_exit_phase2 = NULL, + ._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper, + ._coex_wifi_sleep_set = coex_wifi_sleep_set_hook, + ._coex_core_ble_conn_dyn_prio_get = NULL, + ._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, + ._esp_hw_power_down = btdm_hw_mac_power_down_wrapper, + ._esp_hw_power_up = btdm_hw_mac_power_up_wrapper, + ._ets_backup_dma_copy = btdm_backup_dma_copy_wrapper, + ._ets_delay_us = esp_rom_delay_us, + ._btdm_rom_table_ready = btdm_funcs_table_ready_wrapper, +}; + +static DRAM_ATTR struct osi_funcs_t *osi_funcs_p; + +/* Static variable declare */ +static DRAM_ATTR esp_bt_controller_status_t btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + +static DRAM_ATTR portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED; + +// low power control struct +static DRAM_ATTR btdm_lpcntl_t s_lp_cntl; +// low power status struct +static DRAM_ATTR btdm_lpstat_t s_lp_stat; +// measured average low power clock period in micro seconds +static DRAM_ATTR uint32_t btdm_lpcycle_us = 0; +// number of fractional bit for btdm_lpcycle_us +static DRAM_ATTR uint8_t btdm_lpcycle_us_frac = 0; +// semaphore used for blocking VHCI API to wait for controller to wake up +static DRAM_ATTR QueueHandle_t s_wakeup_req_sem = NULL; +// wakeup timer +static DRAM_ATTR esp_timer_handle_t s_btdm_slp_tmr; + +#ifdef CONFIG_PM_ENABLE +static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock; +// pm_lock to prevent light sleep due to incompatibility currently +static DRAM_ATTR esp_pm_lock_handle_t s_light_sleep_pm_lock; +#endif + +void IRAM_ATTR btdm_hw_mac_power_down_wrapper(void) +{ +#if CONFIG_MAC_BB_PD +#if SOC_PM_SUPPORT_BT_PD + // Bluetooth module power down + SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_BT_FORCE_ISO); + SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_BT_FORCE_PD); +#endif + esp_mac_bb_power_down(); +#endif +} + +void IRAM_ATTR btdm_hw_mac_power_up_wrapper(void) +{ +#if CONFIG_MAC_BB_PD +#if SOC_PM_SUPPORT_BT_PD + // Bluetooth module power up + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_BT_FORCE_PD); + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_BT_FORCE_ISO); +#endif + esp_mac_bb_power_up(); +#endif +} + +void IRAM_ATTR btdm_backup_dma_copy_wrapper(uint32_t reg, uint32_t mem_addr, uint32_t num, bool to_mem) +{ +#if CONFIG_MAC_BB_PD + ets_backup_dma_copy(reg, mem_addr, num, to_mem); +#endif +} + +static inline void esp_bt_power_domain_on(void) +{ + // Bluetooth module power up +#if SOC_PM_SUPPORT_BT_PD + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_BT_FORCE_PD); + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_BT_FORCE_ISO); +#endif + esp_wifi_bt_power_domain_on(); +} + +static inline void esp_bt_power_domain_off(void) +{ + // Bluetooth module power down +#if SOC_PM_SUPPORT_BT_PD + SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_BT_FORCE_ISO); + SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_BT_FORCE_PD); +#endif + esp_wifi_bt_power_domain_off(); +} + +static void interrupt_set_wrapper(int cpu_no, int intr_source, int intr_num, int intr_prio) +{ + esp_rom_route_intr_matrix(cpu_no, intr_source, intr_num); +#if __riscv + esprv_intc_int_set_priority(intr_num, intr_prio); + //esprv_intc_int_enable_level(1 << intr_num); + esprv_intc_int_set_type(intr_num, 0); +#endif +} + +static void interrupt_clear_wrapper(int intr_source, int intr_num) +{ +} + +static void interrupt_handler_set_wrapper(int n, intr_handler_t fn, void *arg) +{ + esp_cpu_intr_set_handler(n, fn, arg); +} + +static void interrupt_on_wrapper(int intr_num) +{ + esp_cpu_intr_enable(1 << intr_num); +} + +static void interrupt_off_wrapper(int intr_num) +{ + esp_cpu_intr_disable(1<<intr_num); +} + +static void IRAM_ATTR interrupt_disable(void) +{ + if (xPortInIsrContext()) { + portENTER_CRITICAL_ISR(&global_int_mux); + } else { + portENTER_CRITICAL(&global_int_mux); + } +} + +static void IRAM_ATTR interrupt_restore(void) +{ + if (xPortInIsrContext()) { + portEXIT_CRITICAL_ISR(&global_int_mux); + } else { + portEXIT_CRITICAL(&global_int_mux); + } +} + +static void IRAM_ATTR task_yield_from_isr(void) +{ + portYIELD_FROM_ISR(); +} + +static void *semphr_create_wrapper(uint32_t max, uint32_t init) +{ + btdm_queue_item_t *semphr = heap_caps_calloc(1, sizeof(btdm_queue_item_t), MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL); + assert(semphr); + + /* IDF FreeRTOS guarantees that all dynamic memory allocation goes to internal RAM. */ + semphr->handle = (void *)xSemaphoreCreateCounting(max, init); + assert(semphr->handle); + + return semphr; +} + +static void semphr_delete_wrapper(void *semphr) +{ + if (semphr == NULL) { + return; + } + + btdm_queue_item_t *semphr_item = (btdm_queue_item_t *)semphr; + + if (semphr_item->handle) { + vSemaphoreDelete(semphr_item->handle); + } + + free(semphr); +} + +static int IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw) +{ + return (int)xSemaphoreTakeFromISR(((btdm_queue_item_t *)semphr)->handle, hptw); +} + +static int IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw) +{ + return (int)xSemaphoreGiveFromISR(((btdm_queue_item_t *)semphr)->handle, hptw); +} + +static int semphr_take_wrapper(void *semphr, uint32_t block_time_ms) +{ + if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) { + return (int)xSemaphoreTake(((btdm_queue_item_t *)semphr)->handle, portMAX_DELAY); + } else { + return (int)xSemaphoreTake(((btdm_queue_item_t *)semphr)->handle, block_time_ms / portTICK_PERIOD_MS); + } +} + +static int semphr_give_wrapper(void *semphr) +{ + return (int)xSemaphoreGive(((btdm_queue_item_t *)semphr)->handle); +} + +static void *mutex_create_wrapper(void) +{ + return (void *)xSemaphoreCreateMutex(); +} + +static void mutex_delete_wrapper(void *mutex) +{ + vSemaphoreDelete(mutex); +} + +static int mutex_lock_wrapper(void *mutex) +{ + return (int)xSemaphoreTake(mutex, portMAX_DELAY); +} + +static int mutex_unlock_wrapper(void *mutex) +{ + return (int)xSemaphoreGive(mutex); +} + +static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size) +{ + btdm_queue_item_t *queue = NULL; + + queue = (btdm_queue_item_t*)heap_caps_malloc(sizeof(btdm_queue_item_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + assert(queue); + + /* IDF FreeRTOS guarantees that all dynamic memory allocation goes to internal RAM. */ + queue->handle = xQueueCreate( queue_len, item_size); + assert(queue->handle); + + return queue; +} + +static void queue_delete_wrapper(void *queue) +{ + btdm_queue_item_t *queue_item = (btdm_queue_item_t *)queue; + if (queue_item) { + if(queue_item->handle){ + vQueueDelete(queue_item->handle); + } + free(queue_item); + } +} + +static int queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms) +{ + if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) { + return (int)xQueueSend(((btdm_queue_item_t*)queue)->handle, item, portMAX_DELAY); + } else { + return (int)xQueueSend(((btdm_queue_item_t*)queue)->handle, item, block_time_ms / portTICK_PERIOD_MS); + } +} + +static int IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, void *hptw) +{ + return (int)xQueueSendFromISR(((btdm_queue_item_t*)queue)->handle, item, hptw); +} + +static int queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms) +{ + if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) { + return (int)xQueueReceive(((btdm_queue_item_t*)queue)->handle, item, portMAX_DELAY); + } else { + return (int)xQueueReceive(((btdm_queue_item_t*)queue)->handle, item, block_time_ms / portTICK_PERIOD_MS); + } +} + +static int IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw) +{ + return (int)xQueueReceiveFromISR(((btdm_queue_item_t*)queue)->handle, item, 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) +{ + return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); +} + +static void task_delete_wrapper(void *task_handle) +{ + vTaskDelete(task_handle); +} + +static bool IRAM_ATTR is_in_isr_wrapper(void) +{ + return (bool)xPortInIsrContext(); +} + +static void *malloc_internal_wrapper(size_t size) +{ + void *p = heap_caps_malloc(size, MALLOC_CAP_INTERNAL|MALLOC_CAP_DMA); + if(p == NULL) { + ESP_LOGE(BT_LOG_TAG, "Malloc failed"); + } + return p; +} + +static int IRAM_ATTR read_mac_wrapper(uint8_t mac[6]) +{ + int ret = esp_read_mac(mac, ESP_MAC_BT); + ESP_LOGI(BT_LOG_TAG, "Bluetooth MAC: %02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + return ret; +} + +static void IRAM_ATTR srand_wrapper(unsigned int seed) +{ + /* empty function */ +} + +static int IRAM_ATTR rand_wrapper(void) +{ + return (int)esp_random(); +} + +static uint32_t IRAM_ATTR btdm_lpcycles_2_hus(uint32_t cycles, uint32_t *error_corr) +{ + uint64_t local_error_corr = (error_corr == NULL) ? 0 : (uint64_t)(*error_corr); + uint64_t res = (uint64_t)btdm_lpcycle_us * cycles * 2; + local_error_corr += res; + res = (local_error_corr >> btdm_lpcycle_us_frac); + local_error_corr -= (res << btdm_lpcycle_us_frac); + if (error_corr) { + *error_corr = (uint32_t) local_error_corr; + } + return (uint32_t)res; +} + +/* + * @brief Converts a duration in half us into a number of low power clock cycles. + */ +static uint32_t IRAM_ATTR btdm_hus_2_lpcycles(uint32_t hus) +{ + // The number of sleep duration(us) should not lead to overflow. Thrs: 100s + // Compute the sleep duration in us to low power clock cycles, with calibration result applied + // clock measurement is conducted + uint64_t cycles = ((uint64_t)(hus) << btdm_lpcycle_us_frac) / btdm_lpcycle_us; + cycles >>= 1; + + return (uint32_t)cycles; +} + +static bool IRAM_ATTR btdm_sleep_check_duration(int32_t *half_slot_cnt) +{ + if (*half_slot_cnt < BTDM_MIN_SLEEP_DURATION) { + return false; + } + /* wake up in advance considering the delay in enabling PHY/RF */ + *half_slot_cnt -= BTDM_MODEM_WAKE_UP_DELAY; + return true; +} + +static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles) +{ + if (s_lp_cntl.wakeup_timer_required == 0) { + return; + } + + uint32_t us_to_sleep = btdm_lpcycles_2_hus(lpcycles, NULL) >> 1; + +#define BTDM_MIN_TIMER_UNCERTAINTY_US (1800) +#define BTDM_RTC_SLOW_CLK_RC_DRIFT_PERCENT 7 + assert(us_to_sleep > BTDM_MIN_TIMER_UNCERTAINTY_US); + // allow a maximum time uncertainty to be about 488ppm(1/2048) at least as clock drift + // and set the timer in advance + uint32_t uncertainty = (us_to_sleep >> 11); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) { + uncertainty = us_to_sleep * BTDM_RTC_SLOW_CLK_RC_DRIFT_PERCENT / 100; + } +#endif + + if (uncertainty < BTDM_MIN_TIMER_UNCERTAINTY_US) { + uncertainty = BTDM_MIN_TIMER_UNCERTAINTY_US; + } + + assert (s_lp_stat.wakeup_timer_started == 0); + // start a timer to wake up and acquire the pm_lock before modem_sleep awakes + if (esp_timer_start_once(s_btdm_slp_tmr, us_to_sleep - uncertainty) == ESP_OK) { + s_lp_stat.wakeup_timer_started = 1; + } else { + ESP_LOGE(BT_LOG_TAG, "timer start failed"); + assert(0); + } +} + +static void btdm_sleep_enter_phase2_wrapper(void) +{ + if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) { + if (s_lp_stat.phy_enabled) { + esp_phy_disable(PHY_MODEM_BT); + s_lp_stat.phy_enabled = 0; + } else { + assert(0); + } + +#ifdef CONFIG_PM_ENABLE + if (s_lp_stat.pm_lock_released == 0) { + esp_pm_lock_release(s_pm_lock); + s_lp_stat.pm_lock_released = 1; + } +#endif + } +} + +static void btdm_sleep_exit_phase3_wrapper(void) +{ +#ifdef CONFIG_PM_ENABLE + // If BT wakeup before esp timer coming due to timer task have no chance to run. + // Then we will not run into `btdm_sleep_exit_phase0` and acquire PM lock, + // Do it again here to fix this issue. + if (s_lp_stat.pm_lock_released) { + esp_pm_lock_acquire(s_pm_lock); + s_lp_stat.pm_lock_released = 0; + } +#endif + + if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) { + if (s_lp_stat.phy_enabled == 0) { + esp_phy_enable(PHY_MODEM_BT); + s_lp_stat.phy_enabled = 1; + } + } + + // If BT wakeup before esp timer coming due to timer task have no chance to run. + // Then we will not run into `btdm_sleep_exit_phase0` and stop esp timer, + // Do it again here to fix this issue. + if (s_lp_cntl.wakeup_timer_required && s_lp_stat.wakeup_timer_started) { + esp_timer_stop(s_btdm_slp_tmr); + s_lp_stat.wakeup_timer_started = 0; + } + + // wait for the sleep state to change + // the procedure duration is at micro-second level or less + while (btdm_sleep_clock_sync()) { + ; + } +} + +static void IRAM_ATTR btdm_sleep_exit_phase0(void *param) +{ + assert(s_lp_cntl.enable == 1); + +#ifdef CONFIG_PM_ENABLE + if (s_lp_stat.pm_lock_released) { + esp_pm_lock_acquire(s_pm_lock); + s_lp_stat.pm_lock_released = 0; + } +#endif + + int event = (int) param; + if (event == BTDM_ASYNC_WAKEUP_SRC_VHCI || event == BTDM_ASYNC_WAKEUP_SRC_DISA) { + btdm_wakeup_request(); + } + + if (s_lp_cntl.wakeup_timer_required && s_lp_stat.wakeup_timer_started) { + esp_timer_stop(s_btdm_slp_tmr); + s_lp_stat.wakeup_timer_started = 0; + } + + if (event == BTDM_ASYNC_WAKEUP_SRC_VHCI || event == BTDM_ASYNC_WAKEUP_SRC_DISA) { + semphr_give_wrapper(s_wakeup_req_sem); + } +} + +static void IRAM_ATTR btdm_slp_tmr_callback(void *arg) +{ +#ifdef CONFIG_PM_ENABLE + r_btdm_vnd_offload_post(BTDM_VND_OL_SIG_WAKEUP_TMR, (void *)BTDM_ASYNC_WAKEUP_SRC_TMR); +#endif +} + + +static bool async_wakeup_request(int event) +{ + if (s_lp_cntl.enable == 0) { + return false; + } + + bool do_wakeup_request = false; + switch (event) { + case BTDM_ASYNC_WAKEUP_SRC_VHCI: + case BTDM_ASYNC_WAKEUP_SRC_DISA: + btdm_in_wakeup_requesting_set(true); + if (!btdm_power_state_active()) { + r_btdm_vnd_offload_post(BTDM_VND_OL_SIG_WAKEUP_TMR, (void *)event); + do_wakeup_request = true; + semphr_take_wrapper(s_wakeup_req_sem, OSI_FUNCS_TIME_BLOCKING); + } + break; + default: + break; + } + + return do_wakeup_request; +} + +static void async_wakeup_request_end(int event) +{ + if (s_lp_cntl.enable == 0) { + return; + } + + bool allow_to_sleep; + switch (event) { + case BTDM_ASYNC_WAKEUP_SRC_VHCI: + case BTDM_ASYNC_WAKEUP_SRC_DISA: + allow_to_sleep = true; + break; + default: + allow_to_sleep = true; + break; + } + + if (allow_to_sleep) { + btdm_in_wakeup_requesting_set(false); + } + + return; +} + +static void btdm_funcs_table_ready_wrapper(void) +{ +#if BT_BLE_CCA_MODE == 2 + btdm_cca_feature_enable(); +#endif +} + +static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_set(type, status); +#endif +} + +static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_clear(type, status); +#endif +} + +bool esp_vhci_host_check_send_available(void) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return false; + } + return API_vhci_host_check_send_available(); +} + +void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return; + } + async_wakeup_request(BTDM_ASYNC_WAKEUP_SRC_VHCI); + + API_vhci_host_send_packet(data, len); + + async_wakeup_request_end(BTDM_ASYNC_WAKEUP_SRC_VHCI); +} + +esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_FAIL; + } + return API_vhci_host_register_callback((const vhci_host_callback_t *)callback) == 0 ? ESP_OK : ESP_FAIL; +} + +static void btdm_controller_mem_init(void) +{ + extern void btdm_controller_rom_data_init(void ); + btdm_controller_rom_data_init(); +} + +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +{ + intptr_t mem_start=(intptr_t) NULL, mem_end=(intptr_t) NULL; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; + } + + if (mode & ESP_BT_MODE_BLE) { + /* if the addresses of rom btdm .data and .bss are consecutive, + they are registered in the system heap as a piece of memory + */ + if(ets_rom_layout_p->data_end_btdm == ets_rom_layout_p->bss_start_btdm) { + mem_start = (intptr_t)ets_rom_layout_p->data_start_btdm; + mem_end = (intptr_t)ets_rom_layout_p->bss_end_btdm; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release rom btdm [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } else { + mem_start = (intptr_t)ets_rom_layout_p->bss_start_btdm; + mem_end = (intptr_t)ets_rom_layout_p->bss_end_btdm; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release rom btdm BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + + mem_start = (intptr_t)ets_rom_layout_p->data_start_btdm; + mem_end = (intptr_t)ets_rom_layout_p->data_end_btdm; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release rom btdm Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + /* if the addresses of rom interface btdm .data and .bss are consecutive, + they are registered in the system heap as a piece of memory + */ + if(ets_rom_layout_p->data_end_interface_btdm == ets_rom_layout_p->bss_start_interface_btdm) { + mem_start = (intptr_t)ets_rom_layout_p->data_start_interface_btdm; + mem_end = (intptr_t)ets_rom_layout_p->bss_end_interface_btdm; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release rom interface btdm [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } else { + mem_start = (intptr_t)ets_rom_layout_p->data_start_interface_btdm; + mem_end = (intptr_t)ets_rom_layout_p->data_end_interface_btdm; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release rom interface btdm Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + + mem_start = (intptr_t)ets_rom_layout_p->bss_start_interface_btdm; + mem_end = (intptr_t)ets_rom_layout_p->bss_end_interface_btdm; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release rom interface btdm BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + + } + return ESP_OK; +} + +esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) +{ + int ret; + intptr_t mem_start, mem_end; + + ret = esp_bt_controller_mem_release(mode); + if (ret != ESP_OK) { + return ret; + } + + if (mode & ESP_BT_MODE_BLE) { + /* if the addresses of btdm .bss and bt .bss are consecutive, + they are registered in the system heap as a piece of memory + */ + if(_bt_bss_end == _btdm_bss_start) { + mem_start = (intptr_t)&_bt_bss_start; + mem_end = (intptr_t)&_btdm_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } else { + mem_start = (intptr_t)&_bt_bss_start; + mem_end = (intptr_t)&_bt_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + + mem_start = (intptr_t)&_btdm_bss_start; + mem_end = (intptr_t)&_btdm_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release BTDM BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + /* if the addresses of btdm .data and bt .data are consecutive, + they are registered in the system heap as a piece of memory + */ + if(_bt_data_end == _btdm_data_start) { + mem_start = (intptr_t)&_bt_data_start; + mem_end = (intptr_t)&_btdm_data_end; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } else { + mem_start = (intptr_t)&_bt_data_start; + mem_end = (intptr_t)&_bt_data_end; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + + mem_start = (intptr_t)&_btdm_data_start; + mem_end = (intptr_t)&_btdm_data_end; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release BTDM Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + + mem_start = (intptr_t)&_nimble_bss_start; + mem_end = (intptr_t)&_nimble_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release NimBLE BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + mem_start = (intptr_t)&_nimble_data_start; + mem_end = (intptr_t)&_nimble_data_end; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release NimBLE Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + return ESP_OK; +} + +static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) +{ + int ret = heap_caps_add_region(start, end); + /* heap_caps_add_region() returns ESP_ERR_INVALID_SIZE if the memory region is + * is too small to fit a heap. This cannot be termed as a fatal error and hence + * we replace it by ESP_OK + */ + + if (ret == ESP_ERR_INVALID_SIZE) { + return ESP_OK; + } + return ret; +} + +#if CONFIG_MAC_BB_PD +static void IRAM_ATTR btdm_mac_bb_power_down_cb(void) +{ + if (s_lp_cntl.mac_bb_pd && s_lp_stat.mac_bb_pd == 0) { + btdm_ble_power_down_dma_copy(true); + s_lp_stat.mac_bb_pd = 1; + } +} + +static void IRAM_ATTR btdm_mac_bb_power_up_cb(void) +{ + if (s_lp_cntl.mac_bb_pd && s_lp_stat.mac_bb_pd) { + btdm_ble_power_down_dma_copy(false); + s_lp_stat.mac_bb_pd = 0; + } +} +#endif + +esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) +{ + esp_err_t err = ESP_FAIL; + + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; + } + + if (cfg == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (cfg->controller_task_prio != ESP_TASK_BT_CONTROLLER_PRIO + || cfg->controller_task_stack_size < ESP_TASK_BT_CONTROLLER_STACK) { + ESP_LOGE(BT_LOG_TAG, "Invalid controller task prioriy or stack size"); + return ESP_ERR_INVALID_ARG; + } + + if (cfg->bluetooth_mode != ESP_BT_MODE_BLE) { + ESP_LOGE(BT_LOG_TAG, "%s controller only support BLE only mode", __func__); + return ESP_ERR_NOT_SUPPORTED; + } + + if (cfg->bluetooth_mode & ESP_BT_MODE_BLE) { + if ((cfg->ble_max_act <= 0) || (cfg->ble_max_act > BT_CTRL_BLE_MAX_ACT_LIMIT)) { + ESP_LOGE(BT_LOG_TAG, "Invalid value of ble_max_act"); + return ESP_ERR_INVALID_ARG; + } + } + + if (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) { + if (cfg->sleep_clock == ESP_BT_SLEEP_CLOCK_NONE) { + ESP_LOGE(BT_LOG_TAG, "SLEEP_MODE_1 enabled but sleep clock not configured"); + return ESP_ERR_INVALID_ARG; + } + } + + // overwrite some parameters + cfg->magic = ESP_BT_CTRL_CONFIG_MAGIC_VAL; + +#if CONFIG_MAC_BB_PD + esp_mac_bb_pd_mem_init(); +#endif + esp_phy_modem_init(); + esp_bt_power_domain_on(); + + btdm_controller_mem_init(); + + osi_funcs_p = (struct osi_funcs_t *)malloc_internal_wrapper(sizeof(struct osi_funcs_t)); + if (osi_funcs_p == NULL) { + return ESP_ERR_NO_MEM; + } + + memcpy(osi_funcs_p, &osi_funcs_ro, sizeof(struct osi_funcs_t)); + if (btdm_osi_funcs_register(osi_funcs_p) != 0) { + return ESP_ERR_INVALID_ARG; + } + + ESP_LOGI(BT_LOG_TAG, "BT controller compile version [%s]", btdm_controller_get_compile_version()); + + // init low-power control resources + do { + // set default values for global states or resources + s_lp_stat.val = 0; + s_lp_cntl.val = 0; + s_lp_cntl.main_xtal_pu = 0; + s_wakeup_req_sem = NULL; + s_btdm_slp_tmr = NULL; + + // configure and initialize resources + s_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? 1 : 0; + s_lp_cntl.no_light_sleep = 0; + + if (s_lp_cntl.enable) { +#if CONFIG_MAC_BB_PD + if (!btdm_deep_sleep_mem_init()) { + err = ESP_ERR_NO_MEM; + goto error; + } + s_lp_cntl.mac_bb_pd = 1; +#endif +#ifdef CONFIG_PM_ENABLE + s_lp_cntl.wakeup_timer_required = 1; +#endif + // async wakeup semaphore for VHCI + s_wakeup_req_sem = semphr_create_wrapper(1, 0); + if (s_wakeup_req_sem == NULL) { + err = ESP_ERR_NO_MEM; + goto error; + } + btdm_vnd_offload_task_register(BTDM_VND_OL_SIG_WAKEUP_TMR, btdm_sleep_exit_phase0); + } + + if (s_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, &s_btdm_slp_tmr)) != ESP_OK) { + goto error; + } + } + + // set default bluetooth sleep clock cycle and its fractional bits + btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; + btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac); + + // set default bluetooth sleep clock source + s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value +#if CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL + // check whether or not EXT_CRYS is working + if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32 kHz XTAL + } else { + ESP_LOGW(BT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock"); +#if !CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP + s_lp_cntl.no_light_sleep = 1; +#endif + } +#elif (CONFIG_BT_CTRL_LPCLK_SEL_MAIN_XTAL) + ESP_LOGI(BT_LOG_TAG, "Bluetooth will use main XTAL as Bluetooth sleep clock."); +#if !CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP + s_lp_cntl.no_light_sleep = 1; +#endif +#elif (CONFIG_BT_CTRL_LPCLK_SEL_RTC_SLOW) + // check whether or not internal 150 kHz RC oscillator is working + if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) { + s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // Internal 150 kHz RC oscillator + ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC osciallator. The accuracy of this clock is a lot larger than 500ppm which is " + "required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state."); + } else { + ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC oscillator not detected."); + assert(0); + } +#endif + + bool select_src_ret __attribute__((unused)); + bool set_div_ret __attribute__((unused)); + if (s_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_XTAL) { +#ifdef CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP + ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON)); + s_lp_cntl.main_xtal_pu = 1; +#endif + select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL); + set_div_ret = btdm_lpclk_set_div(esp_clk_xtal_freq() / MHZ); + assert(select_src_ret && set_div_ret); + btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; + btdm_lpcycle_us = 1 << (btdm_lpcycle_us_frac); + } else if (s_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); + assert(select_src_ret && set_div_ret); + btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; + btdm_lpcycle_us = (RTC_CLK_CAL_FRACT > 15) ? (1000000 << (RTC_CLK_CAL_FRACT - 15)) : + (1000000 >> (15 - RTC_CLK_CAL_FRACT)); + assert(btdm_lpcycle_us != 0); + } else if (s_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); + assert(select_src_ret && set_div_ret); + btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; + btdm_lpcycle_us = esp_clk_slowclk_cal_get(); + } else { + err = ESP_ERR_INVALID_ARG; + goto error; + } +#if CONFIG_SW_COEXIST_ENABLE + coex_update_lpclk_interval(); +#endif + +#ifdef CONFIG_PM_ENABLE + if (s_lp_cntl.no_light_sleep) { + if ((err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "btLS", &s_light_sleep_pm_lock)) != ESP_OK) { + err = ESP_ERR_NO_MEM; + goto error; + } + ESP_LOGW(BT_LOG_TAG, "light sleep mode will not be able to apply when bluetooth is enabled."); + } + if ((err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock)) != ESP_OK) { + err = ESP_ERR_NO_MEM; + goto error; + } else { + s_lp_stat.pm_lock_released = 1; + } +#endif + } while (0); + +#if CONFIG_SW_COEXIST_ENABLE + coex_init(); +#endif + + periph_module_enable(PERIPH_BT_MODULE); + periph_module_reset(PERIPH_BT_MODULE); + + if (btdm_controller_init(cfg) != 0) { + err = ESP_ERR_NO_MEM; + goto error; + } + + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + + return ESP_OK; + +error: + + bt_controller_deinit_internal(); + + return err; +} + +esp_err_t esp_bt_controller_deinit(void) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) { + return ESP_ERR_INVALID_STATE; + } + + btdm_controller_deinit(); + + bt_controller_deinit_internal(); + + return ESP_OK; +} + +static void bt_controller_deinit_internal(void) +{ + periph_module_disable(PERIPH_BT_MODULE); + + // deinit low power control resources + do { + +#if CONFIG_MAC_BB_PD + if (s_lp_cntl.mac_bb_pd) { + btdm_deep_sleep_mem_deinit(); + s_lp_cntl.mac_bb_pd = 0; + } +#endif + +#ifdef CONFIG_PM_ENABLE + if (s_lp_cntl.no_light_sleep) { + if (s_light_sleep_pm_lock != NULL) { + esp_pm_lock_delete(s_light_sleep_pm_lock); + s_light_sleep_pm_lock = NULL; + } + } + + if (s_pm_lock != NULL) { + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; + s_lp_stat.pm_lock_released = 0; + } + +#endif + + if (s_lp_cntl.wakeup_timer_required) { + if (s_lp_stat.wakeup_timer_started) { + esp_timer_stop(s_btdm_slp_tmr); + } + s_lp_stat.wakeup_timer_started = 0; + esp_timer_delete(s_btdm_slp_tmr); + s_btdm_slp_tmr = NULL; + } + + if (s_lp_cntl.enable) { + btdm_vnd_offload_task_deregister(BTDM_VND_OL_SIG_WAKEUP_TMR); + if (s_wakeup_req_sem != NULL) { + semphr_delete_wrapper(s_wakeup_req_sem); + s_wakeup_req_sem = NULL; + } + } + + if (s_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_XTAL) { +#ifdef CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP + if (s_lp_cntl.main_xtal_pu) { + ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF)); + s_lp_cntl.main_xtal_pu = 0; + } +#endif + btdm_lpclk_select_src(BTDM_LPCLK_SEL_RTC_SLOW); + btdm_lpclk_set_div(0); +#if CONFIG_SW_COEXIST_ENABLE + coex_update_lpclk_interval(); +#endif + } + + btdm_lpcycle_us = 0; + } while (0); + + esp_bt_power_domain_off(); +#if CONFIG_MAC_BB_PD + esp_mac_bb_pd_mem_deinit(); +#endif + esp_phy_modem_deinit(); + + if (osi_funcs_p != NULL) { + free(osi_funcs_p); + osi_funcs_p = NULL; + } + + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; +} + +esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) +{ + esp_err_t ret = ESP_OK; + + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) { + return ESP_ERR_INVALID_STATE; + } + + //As the history reason, mode should be equal to the mode which set in esp_bt_controller_init() + if (mode != btdm_controller_get_mode()) { + ESP_LOGE(BT_LOG_TAG, "invalid mode %d, controller support mode is %d", mode, btdm_controller_get_mode()); + return ESP_ERR_INVALID_ARG; + } + + /* Enable PHY when enabling controller to reduce power dissipation after controller init + * Notice the init order: esp_phy_enable() -> bt_bb_v2_init_cmplx() -> coex_pti_v2() + */ + esp_phy_enable(PHY_MODEM_BT); + s_lp_stat.phy_enabled = 1; + +#if CONFIG_SW_COEXIST_ENABLE + coex_enable(); +#endif + + // enable low power mode + do { +#ifdef CONFIG_PM_ENABLE + if (s_lp_cntl.no_light_sleep) { + esp_pm_lock_acquire(s_light_sleep_pm_lock); + } + esp_pm_lock_acquire(s_pm_lock); + s_lp_stat.pm_lock_released = 0; +#endif + +#if CONFIG_MAC_BB_PD + if (esp_register_mac_bb_pd_callback(btdm_mac_bb_power_down_cb) != 0) { + ret = ESP_ERR_INVALID_ARG; + goto error; + } + + if (esp_register_mac_bb_pu_callback(btdm_mac_bb_power_up_cb) != 0) { + ret = ESP_ERR_INVALID_ARG; + goto error; + } +#endif + + if (s_lp_cntl.enable) { + btdm_controller_enable_sleep(true); + } + } while (0); + + // Disable pll track by default in BLE controller on ESP32-C3 and ESP32-S3 + sdk_config_extend_set_pll_track(false); + + if (btdm_controller_enable(mode) != 0) { + ret = ESP_ERR_INVALID_STATE; + goto error; + } + + coex_pti_v2(); + + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED; + + return ret; + +error: + // disable low power mode + do { +#if CONFIG_MAC_BB_PD + esp_unregister_mac_bb_pd_callback(btdm_mac_bb_power_down_cb); + esp_unregister_mac_bb_pu_callback(btdm_mac_bb_power_up_cb); +#endif + + btdm_controller_enable_sleep(false); +#ifdef CONFIG_PM_ENABLE + if (s_lp_cntl.no_light_sleep) { + esp_pm_lock_release(s_light_sleep_pm_lock); + } + if (s_lp_stat.pm_lock_released == 0) { + esp_pm_lock_release(s_pm_lock); + s_lp_stat.pm_lock_released = 1; + } +#endif + } while (0); + +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + if (s_lp_stat.phy_enabled) { + esp_phy_disable(PHY_MODEM_BT); + s_lp_stat.phy_enabled = 0; + } + return ret; +} + +esp_err_t esp_bt_controller_disable(void) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + async_wakeup_request(BTDM_ASYNC_WAKEUP_SRC_DISA); + while (!btdm_power_state_active()){} + btdm_controller_disable(); + + async_wakeup_request_end(BTDM_ASYNC_WAKEUP_SRC_DISA); + +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + if (s_lp_stat.phy_enabled) { + esp_phy_disable(PHY_MODEM_BT); + s_lp_stat.phy_enabled = 0; + } + + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + + // disable low power mode + do { +#if CONFIG_MAC_BB_PD + esp_unregister_mac_bb_pd_callback(btdm_mac_bb_power_down_cb); + esp_unregister_mac_bb_pu_callback(btdm_mac_bb_power_up_cb); +#endif + +#ifdef CONFIG_PM_ENABLE + if (s_lp_cntl.no_light_sleep) { + esp_pm_lock_release(s_light_sleep_pm_lock); + } + + if (s_lp_stat.pm_lock_released == 0) { + esp_pm_lock_release(s_pm_lock); + s_lp_stat.pm_lock_released = 1; + } else { + assert(0); + } +#endif + } while (0); + + return ESP_OK; +} + +esp_bt_controller_status_t esp_bt_controller_get_status(void) +{ + return btdm_controller_status; +} + +/* extra functions */ +esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_t power_level) +{ + esp_err_t stat = ESP_FAIL; + + switch (power_type) { + case ESP_BLE_PWR_TYPE_ADV: + case ESP_BLE_PWR_TYPE_SCAN: + case ESP_BLE_PWR_TYPE_DEFAULT: + if (ble_txpwr_set(power_type, power_level) == 0) { + stat = ESP_OK; + } + break; + default: + stat = ESP_ERR_NOT_SUPPORTED; + break; + } + + return stat; +} + +esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) +{ + esp_power_level_t lvl; + + switch (power_type) { + case ESP_BLE_PWR_TYPE_ADV: + case ESP_BLE_PWR_TYPE_SCAN: + lvl = (esp_power_level_t)ble_txpwr_get(power_type); + break; + case ESP_BLE_PWR_TYPE_CONN_HDL0: + case ESP_BLE_PWR_TYPE_CONN_HDL1: + case ESP_BLE_PWR_TYPE_CONN_HDL2: + case ESP_BLE_PWR_TYPE_CONN_HDL3: + case ESP_BLE_PWR_TYPE_CONN_HDL4: + case ESP_BLE_PWR_TYPE_CONN_HDL5: + case ESP_BLE_PWR_TYPE_CONN_HDL6: + case ESP_BLE_PWR_TYPE_CONN_HDL7: + case ESP_BLE_PWR_TYPE_CONN_HDL8: + case ESP_BLE_PWR_TYPE_DEFAULT: + lvl = (esp_power_level_t)ble_txpwr_get(ESP_BLE_PWR_TYPE_DEFAULT); + break; + default: + lvl = ESP_PWR_LVL_INVALID; + break; + } + + return lvl; +} + +esp_err_t esp_bt_sleep_enable (void) +{ + esp_err_t status; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) { + btdm_controller_enable_sleep (true); + status = ESP_OK; + } else { + status = ESP_ERR_NOT_SUPPORTED; + } + + return status; +} + +esp_err_t esp_bt_sleep_disable (void) +{ + esp_err_t status; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) { + btdm_controller_enable_sleep (false); + status = ESP_OK; + } else { + status = ESP_ERR_NOT_SUPPORTED; + } + + return status; +} + +bool esp_bt_controller_is_sleeping(void) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED || + btdm_controller_get_sleep_mode() != ESP_BT_SLEEP_MODE_1) { + return false; + } + + return !btdm_power_state_active(); +} + +void esp_bt_controller_wakeup_request(void) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED || + btdm_controller_get_sleep_mode() != ESP_BT_SLEEP_MODE_1) { + return; + } + + btdm_wakeup_request(); + +} + +int IRAM_ATTR esp_bt_h4tl_eif_io_event_notify(int event) +{ + return btdm_hci_tl_io_event_post(event); +} + +uint16_t esp_bt_get_tx_buf_num(void) +{ + return l2c_ble_link_get_tx_buf_num(); +} + +static void coex_wifi_sleep_set_hook(bool sleep) +{ + +} +#endif /* CONFIG_BT_ENABLED */ diff --git a/lib/bt/controller/esp32c6/Kconfig.in b/lib/bt/controller/esp32c6/Kconfig.in new file mode 100644 index 00000000..465d713e --- /dev/null +++ b/lib/bt/controller/esp32c6/Kconfig.in @@ -0,0 +1,564 @@ + +menu "HCI Config" + + choice BT_LE_HCI_INTERFACE + prompt "Select HCI interface" + default BT_LE_HCI_INTERFACE_USE_RAM + + config BT_LE_HCI_INTERFACE_USE_RAM + bool "ram" + help + Use RAM as HCI interface + config BT_LE_HCI_INTERFACE_USE_UART + bool "uart" + help + Use UART as HCI interface + endchoice + + config BT_LE_HCI_UART_PORT + int "HCI UART port" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 1 + help + Set the port number of HCI UART + + config BT_LE_HCI_UART_FLOWCTRL + bool "HCI uart Hardware Flow ctrl" + depends on BT_LE_HCI_INTERFACE_USE_UART + default n + + config BT_LE_HCI_UART_TX_PIN + int "HCI uart Tx gpio" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 19 + + config BT_LE_HCI_UART_RX_PIN + int "HCI uart Rx gpio" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 10 + + config BT_LE_HCI_UART_RTS_PIN + int "HCI uart RTS gpio" + depends on BT_LE_HCI_UART_FLOWCTRL + default 4 + + config BT_LE_HCI_UART_CTS_PIN + int "HCI uart CTS gpio" + depends on BT_LE_HCI_UART_FLOWCTRL + default 5 + + config BT_LE_HCI_UART_BAUD + int "HCI uart baudrate" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 921600 + help + HCI uart baud rate 115200 ~ 1000000 + + choice BT_LE_HCI_UART_PARITY + prompt "select uart parity" + depends on BT_LE_HCI_INTERFACE_USE_UART + default BT_LE_HCI_UART_UART_PARITY_DISABLE + + config BT_LE_HCI_UART_UART_PARITY_DISABLE + bool "PARITY_DISABLE" + help + UART_PARITY_DISABLE + config BT_LE_HCI_UART_UART_PARITY_EVEN + bool "PARITY_EVEN" + help + UART_PARITY_EVEN + config BT_LE_HCI_UART_UART_PARITY_ODD + bool "PARITY_ODD" + help + UART_PARITY_ODD + endchoice + + config BT_LE_HCI_UART_TASK_STACK_SIZE + int "HCI uart task stack size" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 1000 + help + Set the size of uart task stack +endmenu + +config BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT + bool + default y + help + Enable NPL porting for controller. + + +menuconfig BT_LE_50_FEATURE_SUPPORT + bool "Enable BLE 5 feature" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable BLE 5 feature + +config BT_LE_LL_CFG_FEAT_LE_2M_PHY + bool "Enable 2M Phy" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable 2M-PHY + +config BT_LE_LL_CFG_FEAT_LE_CODED_PHY + bool "Enable coded Phy" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable coded-PHY + +config BT_LE_EXT_ADV + bool "Enable extended advertising" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable this option to do extended advertising. Extended advertising + will be supported from BLE 5.0 onwards. + +if BT_LE_EXT_ADV + config BT_LE_MAX_EXT_ADV_INSTANCES + int "Maximum number of extended advertising instances." + range 0 4 + default 1 + depends on BT_LE_EXT_ADV + help + Change this option to set maximum number of extended advertising + instances. Minimum there is always one instance of + advertising. Enter how many more advertising instances you + want. + Each extended advertising instance will take about 0.5k DRAM. + + config BT_LE_EXT_ADV_MAX_SIZE + int "Maximum length of the advertising data." + range 0 1650 + default 1650 + depends on BT_LE_EXT_ADV + help + Defines the length of the extended adv data. The value should not + exceed 1650. + + config BT_LE_ENABLE_PERIODIC_ADV + bool "Enable periodic advertisement." + default y + depends on BT_LE_EXT_ADV + help + Enable this option to start periodic advertisement. + + config BT_LE_PERIODIC_ADV_SYNC_TRANSFER + bool "Enable Transer Sync Events" + depends on BT_LE_ENABLE_PERIODIC_ADV + default y + help + This enables controller transfer periodic sync events to host + +endif + +config BT_LE_MAX_PERIODIC_SYNCS + int "Maximum number of periodic advertising syncs" + depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED + + range 0 8 + default 1 if BT_LE_ENABLE_PERIODIC_ADV + default 0 + help + Set this option to set the upper limit for number of periodic sync + connections. This should be less than maximum connections allowed by + controller. + +config BT_LE_MAX_PERIODIC_ADVERTISER_LIST + int "Maximum number of periodic advertiser list" + depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED + range 1 5 + default 5 + help + Set this option to set the upper limit for number of periodic advertiser list. + +config BT_LE_POWER_CONTROL_ENABLED + bool "Enable controller support for BLE Power Control" + depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED && IDF_TARGET_ESP32C6 + default n + help + Set this option to enable the Power Control feature on controller + +menu "Memory Settings" + depends on !BT_NIMBLE_ENABLED + + config BT_LE_MSYS_1_BLOCK_COUNT + int "MSYS_1 Block Count" + default 12 + help + MSYS is a system level mbuf registry. For prepare write & prepare + responses MBUFs are allocated out of msys_1 pool. For NIMBLE_MESH + enabled cases, this block count is increased by 8 than user defined + count. + + config BT_LE_MSYS_1_BLOCK_SIZE + int "MSYS_1 Block Size" + default 256 + help + Dynamic memory size of block 1 + + config BT_LE_MSYS_2_BLOCK_COUNT + int "MSYS_2 Block Count" + default 24 + help + Dynamic memory count + + config BT_LE_MSYS_2_BLOCK_SIZE + int "MSYS_2 Block Size" + default 320 + help + Dynamic memory size of block 2 + + config BT_LE_MSYS_BUF_FROM_HEAP + bool "Get Msys Mbuf from heap" + default y + depends on BT_LE_MSYS_INIT_IN_CONTROLLER + help + This option sets the source of the shared msys mbuf memory between + the Host and the Controller. Allocate the memory from the heap if + this option is sets, from the mempool otherwise. + + config BT_LE_ACL_BUF_COUNT + int "ACL Buffer count" + default 10 + help + The number of ACL data buffers. + + config BT_LE_ACL_BUF_SIZE + int "ACL Buffer size" + default 517 + help + This is the maximum size of the data portion of HCI ACL data packets. + It does not include the HCI data header (of 4 bytes) + + config BT_LE_HCI_EVT_BUF_SIZE + int "HCI Event Buffer size" + default 257 if BT_LE_EXT_ADV + default 70 + help + This is the size of each HCI event buffer in bytes. In case of + extended advertising, packets can be fragmented. 257 bytes is the + maximum size of a packet. + + config BT_LE_HCI_EVT_HI_BUF_COUNT + int "High Priority HCI Event Buffer count" + default 30 + help + This is the high priority HCI events' buffer size. High-priority + event buffers are for everything except advertising reports. If there + are no free high-priority event buffers then host will try to allocate a + low-priority buffer instead + + config BT_LE_HCI_EVT_LO_BUF_COUNT + int "Low Priority HCI Event Buffer count" + default 8 + help + This is the low priority HCI events' buffer size. Low-priority event + buffers are only used for advertising reports. If there are no free + low-priority event buffers, then an incoming advertising report will + get dropped +endmenu + +config BT_LE_CONTROLLER_TASK_STACK_SIZE + int "Controller task stack size" + default 5120 if BLE_MESH + default 4096 + help + This configures stack size of NimBLE controller task + +menuconfig BT_LE_CONTROLLER_LOG_ENABLED + bool "Controller log enable" + default n + help + Enable controller log + +config BT_LE_CONTROLLER_LOG_CTRL_ENABLED + bool "enable controller log module" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Enable controller log module + +config BT_LE_CONTROLLER_LOG_HCI_ENABLED + bool "enable HCI log module" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Enable hci log module + +config BT_LE_CONTROLLER_LOG_DUMP_ONLY + bool "Controller log dump mode only" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Only operate in dump mode + +config BT_LE_LOG_CTRL_BUF1_SIZE + int "size of the first BLE controller LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 4096 + help + Configure the size of the first BLE controller LOG buffer. + +config BT_LE_LOG_CTRL_BUF2_SIZE + int "size of the second BLE controller LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 1024 + help + Configure the size of the second BLE controller LOG buffer. + +config BT_LE_LOG_HCI_BUF_SIZE + int "size of the BLE HCI LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 4096 + help + Configure the size of the BLE HCI LOG buffer. + +config BT_LE_LL_RESOLV_LIST_SIZE + int "BLE LL Resolving list size" + range 1 5 + default 4 + help + Configure the size of resolving list used in link layer. + +menuconfig BT_LE_SECURITY_ENABLE + bool "Enable BLE SM feature" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable BLE sm feature + +config BT_LE_SM_LEGACY + bool "Security manager legacy pairing" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable security manager legacy pairing + +config BT_LE_SM_SC + bool "Security manager secure connections (4.2)" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable security manager secure connections + +config BT_LE_SM_SC_DEBUG_KEYS + bool "Use predefined public-private key pair" + default n + depends on BT_LE_SECURITY_ENABLE && BT_LE_SM_SC + help + If this option is enabled, SM uses predefined DH key pair as described + in Core Specification, Vol. 3, Part H, 2.3.5.6.1. This allows to + decrypt air traffic easily and thus should only be used for debugging. + +config BT_LE_LL_CFG_FEAT_LE_ENCRYPTION + bool "Enable LE encryption" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable encryption connection + +config BT_LE_CRYPTO_STACK_MBEDTLS + bool "Override TinyCrypt with mbedTLS for crypto computations" + default y + depends on !BT_NIMBLE_ENABLED + select MBEDTLS_ECP_RESTARTABLE + select MBEDTLS_CMAC_C + help + Enable this option to choose mbedTLS instead of TinyCrypt for crypto + computations. + +config BT_LE_WHITELIST_SIZE + int "BLE white list size" + range 1 15 + default 12 + depends on !BT_NIMBLE_ENABLED + + help + BLE list size + +config BT_LE_LL_DUP_SCAN_LIST_COUNT + int "BLE duplicate scan list count" + range 5 100 + default 20 + help + config the max count of duplicate scan list + +config BT_LE_LL_SCA + int "BLE Sleep clock accuracy" + range 0 500 + default 60 + help + Sleep clock accuracy of our device (in ppm) + +config BT_LE_MAX_CONNECTIONS + int "Maximum number of concurrent connections" + depends on !BT_NIMBLE_ENABLED + range 1 70 + default 3 + help + Defines maximum number of concurrent BLE connections. For ESP32, user + is expected to configure BTDM_CTRL_BLE_MAX_CONN from controller menu + along with this option. Similarly for ESP32-C3 or ESP32-S3, user is expected to + configure BT_CTRL_BLE_MAX_ACT from controller menu. + Each connection will take about 1k DRAM. + +choice BT_LE_COEX_PHY_CODED_TX_RX_TLIM + prompt "Coexistence: limit on MAX Tx/Rx time for coded-PHY connection" + default BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + depends on ESP_COEX_SW_COEXIST_ENABLE + help + When using PHY-Coded in BLE connection, limitation on max tx/rx time can be applied to + better avoid dramatic performance deterioration of Wi-Fi. + + config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EN + bool "Force Enable" + help + Always enable the limitation on max tx/rx time for Coded-PHY connection + + config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + bool "Force Disable" + help + Disable the limitation on max tx/rx time for Coded-PHY connection +endchoice + +config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF + int + default 0 if !ESP_COEX_SW_COEXIST_ENABLE + default 1 if BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EN + default 0 if BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + +config BT_LE_SLEEP_ENABLE + bool "Enable BLE sleep" + default n + help + Enable BLE sleep + +choice BT_LE_LP_CLK_SRC + prompt "BLE low power clock source" + default BT_LE_LP_CLK_SRC_MAIN_XTAL + config BT_LE_LP_CLK_SRC_MAIN_XTAL + bool "Use main XTAL as RTC clock source" + help + User main XTAL as RTC clock source. + This option is recommended if external 32.768k XTAL is not available. + Using the external 32.768 kHz XTAL will have lower current consumption + in light sleep compared to using the main XTAL. + + config BT_LE_LP_CLK_SRC_DEFAULT + bool "Use system RTC slow clock source" + help + Use the same slow clock source as system RTC + Using any clock source other than external 32.768 kHz XTAL supports only + legacy ADV and SCAN due to low clock accuracy. + +endchoice + +config BT_LE_USE_ESP_TIMER + bool "Enable Esp Timer for Callout" + depends on !BT_NIMBLE_ENABLED + default y + help + Set this option to use Esp Timer which has higher priority timer + instead of FreeRTOS timer +config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + bool "BLE adv report flow control supported" + default y + help + The function is mainly used to enable flow control for advertising reports. When it is enabled, + advertising reports will be discarded by the controller if the number of unprocessed advertising + reports exceeds the size of BLE adv report flow control. + +config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM + int "BLE adv report flow control number" + depends on BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 50 1000 + default 100 + help + The number of unprocessed advertising report that bluetooth host can save.If you set + `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a small value, this may cause adv packets lost. + If you set `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a large value, bluetooth host may cache a + lot of adv packets and this may cause system memory run out. For example, if you set + it to 50, the maximum memory consumed by host is 35 * 50 bytes. Please set + `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` according to your system free memory and handle adv + packets as fast as possible, otherwise it will cause adv packets lost. + +config BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD + int "BLE adv lost event threshold value" + depends on BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 1 1000 + default 20 + help + When adv report flow control is enabled, The ADV lost event will be generated when the number + of ADV packets lost in the controller reaches this threshold. It is better to set a larger value. + If you set `BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it + may cause adv packets lost more. + +config BT_LE_SCAN_DUPL + bool "BLE Scan Duplicate Options" + default y + help + This select enables parameters setting of BLE scan duplicate. + +choice BT_LE_SCAN_DUPL_TYPE + prompt "Scan Duplicate Type" + default BT_LE_SCAN_DUPL_TYPE_DEVICE + depends on BT_LE_SCAN_DUPL + help + Scan duplicate have three ways. one is "Scan Duplicate By Device Address", This way is to use + advertiser address filtering. The adv packet of the same address is only allowed to be reported once. + Another way is "Scan Duplicate By Device Address And Advertising Data". This way is to use advertising + data and device address filtering. All different adv packets with the same address are allowed to be + reported. The last way is "Scan Duplicate By Advertising Data". This way is to use advertising data + filtering. All same advertising data only allow to be reported once even though they are from + different devices. + + config BT_LE_SCAN_DUPL_TYPE_DEVICE + bool "Scan Duplicate By Device Address" + help + This way is to use advertiser address filtering. The adv packet of the same address is only + allowed to be reported once + + config BT_LE_SCAN_DUPL_TYPE_DATA + bool "Scan Duplicate By Advertising Data" + help + This way is to use advertising data filtering. All same advertising data only allow to be reported + once even though they are from different devices. + + config BT_LE_SCAN_DUPL_TYPE_DATA_DEVICE + bool "Scan Duplicate By Device Address And Advertising Data" + help + This way is to use advertising data and device address filtering. All different adv packets with + the same address are allowed to be reported. +endchoice + +config BT_LE_SCAN_DUPL_TYPE + int + depends on BT_LE_SCAN_DUPL + default 0 if BT_LE_SCAN_DUPL_TYPE_DEVICE + default 1 if BT_LE_SCAN_DUPL_TYPE_DATA + default 2 if BT_LE_SCAN_DUPL_TYPE_DATA_DEVICE + default 0 + +config BT_LE_SCAN_DUPL_CACHE_REFRESH_PERIOD + int "Duplicate scan list refresh period (seconds)" + depends on BT_LE_SCAN_DUPL + range 0 1000 + default 0 + help + If the period value is non-zero, the controller will periodically clear the device information + stored in the scan duuplicate filter. If it is 0, the scan duuplicate filter will not be cleared + until the scanning is disabled. Duplicate advertisements for this period should not be sent to the + Host in advertising report events. + There are two scenarios where the ADV packet will be repeatedly reported: + 1. The duplicate scan cache is full, the controller will delete the oldest device information and + add new device information. + 2. When the refresh period is up, the controller will clear all device information and start filtering + again. + +config BT_LE_MSYS_INIT_IN_CONTROLLER + bool "Msys Mbuf Init in Controller" + default y diff --git a/lib/bt/controller/esp32c6/bt.c b/lib/bt/controller/esp32c6/bt.c new file mode 100644 index 00000000..30fdcd00 --- /dev/null +++ b/lib/bt/controller/esp32c6/bt.c @@ -0,0 +1,1413 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "esp_random.h" +#include "esp_heap_caps.h" +#include "esp_heap_caps_init.h" +#include <esp_mac.h> + +#include "sdkconfig.h" + +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "esp_private/esp_modem_clock.h" + +#ifdef ESP_PLATFORM +#include "esp_log.h" +#endif // ESP_PLATFORM + +#if CONFIG_SW_COEXIST_ENABLE +#include "private/esp_coexist_internal.h" +#endif // CONFIG_SW_COEXIST_ENABLE + +#include "nimble/nimble_npl_os.h" +#include "nimble/ble_hci_trans.h" +#include "os/endian.h" + +#include "esp_bt.h" +#include "esp_intr_alloc.h" +#include "esp_sleep.h" +#include "esp_pm.h" +#include "esp_phy_init.h" +#include "esp_private/periph_ctrl.h" +#include "hci_uart.h" +#include "bt_osi_mem.h" + +#if SOC_PM_RETENTION_HAS_CLOCK_BUG +#include "esp_private/sleep_retention.h" +#endif // SOC_PM_RETENTION_HAS_CLOCK_BUG + +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +#include "esp_private/sleep_modem.h" +#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +#include "hci/hci_hal.h" +#endif // CONFIG_BT_BLUEDROID_ENABLED + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_private/periph_ctrl.h" +#include "esp_sleep.h" + +#include "hal/efuse_hal.h" +#include "soc/rtc.h" +/* Macro definition + ************************************************************************ + */ +#define NIMBLE_PORT_LOG_TAG "BLE_INIT" +#define OSI_COEX_VERSION 0x00010006 +#define OSI_COEX_MAGIC_VALUE 0xFADEBEAD + +#define EXT_FUNC_VERSION 0x20221122 +#define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5 + +#define BT_ASSERT_PRINT ets_printf + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +/* ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data */ +#define ACL_DATA_MBUF_LEADINGSPCAE 4 +#endif // CONFIG_BT_BLUEDROID_ENABLED + +/* Types definition + ************************************************************************ + */ +struct osi_coex_funcs_t { + uint32_t _magic; + uint32_t _version; + 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); +}; + +struct ext_funcs_t { + uint32_t ext_version; + int (*_esp_intr_alloc)(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle); + int (*_esp_intr_free)(void **ret_handle); + void *(* _malloc)(size_t size); + void (*_free)(void *p); + void (*_hal_uart_start_tx)(int); + int (*_hal_uart_init_cbs)(int, hci_uart_tx_char, hci_uart_tx_done, hci_uart_rx_char, void *); + int (*_hal_uart_config)(int, int32_t, uint8_t, uint8_t, uart_parity_t, uart_hw_flowcontrol_t); + int (*_hal_uart_close)(int); + void (*_hal_uart_blocking_tx)(int, uint8_t); + int (*_hal_uart_init)(int, void *); + 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); + void (*_osi_assert)(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2); + uint32_t (* _os_random)(void); + int (* _ecc_gen_key_pair)(uint8_t *public, uint8_t *priv); + int (* _ecc_gen_dh_key)(const uint8_t *remote_pub_key_x, const uint8_t *remote_pub_key_y, + const uint8_t *local_priv_key, uint8_t *dhkey); + void (* _esp_reset_rpa_moudle)(void); + uint32_t magic; +}; + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +typedef void (*interface_func_t) (uint32_t len, const uint8_t*addr, bool end); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +/* External functions or variables + ************************************************************************ + */ +extern int ble_osi_coex_funcs_register(struct osi_coex_funcs_t *coex_funcs); +extern int ble_controller_init(esp_bt_controller_config_t *cfg); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +extern int r_ble_log_init_async(interface_func_t bt_controller_log_interface, bool task_create, uint8_t buffers, uint32_t *bufs_size); +extern int r_ble_log_deinit_async(void); +extern void r_ble_log_async_select_dump_buffers(uint8_t buffers); +extern void r_ble_log_async_output_dump_all(bool output); +extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +extern int ble_controller_deinit(void); +extern int ble_controller_enable(uint8_t mode); +extern int ble_controller_disable(void); +extern int esp_register_ext_funcs (struct ext_funcs_t *); +extern void esp_unregister_ext_funcs (void); +extern int esp_ble_ll_set_public_addr(const uint8_t *addr); +extern int esp_register_npl_funcs (struct npl_funcs_t *p_npl_func); +extern void esp_unregister_npl_funcs (void); +extern void npl_freertos_mempool_deinit(void); +extern uint32_t r_os_cputime_get32(void); +extern uint32_t r_os_cputime_ticks_to_usecs(uint32_t ticks); +extern void r_ble_lll_rfmgmt_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, + void *w_arg, uint32_t us_to_enabled); +extern void r_ble_rtc_wake_up_state_clr(void); +extern int os_msys_init(void); +extern void os_msys_deinit(void); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +extern const sleep_retention_entries_config_t *esp_ble_mac_retention_link_get(uint8_t *size, uint8_t extra); +extern void esp_ble_set_wakeup_overhead(uint32_t overhead); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ +extern void esp_ble_change_rtc_freq(uint32_t freq); +extern int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, + const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey); +extern int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); +extern int ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); +extern int ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); +extern int ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); +extern char *ble_controller_get_compile_version(void); +extern uint32_t _bt_bss_start; +extern uint32_t _bt_bss_end; +extern uint32_t _bt_controller_bss_start; +extern uint32_t _bt_controller_bss_end; +extern uint32_t _bt_data_start; +extern uint32_t _bt_data_end; +extern uint32_t _bt_controller_data_start; +extern uint32_t _bt_controller_data_end; + +/* Local Function Declaration + ********************************************************************* + */ +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 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); +#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static void hci_uart_start_tx_wrapper(int uart_no); +static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, + hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg); +static int hci_uart_config_wrapper(int uart_no, int32_t speed, uint8_t databits, uint8_t stopbits, + uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl); +static int hci_uart_close_wrapper(int uart_no); +static void hci_uart_blocking_tx_wrapper(int port, uint8_t data); +static int hci_uart_init_wrapper(int uart_no, void *cfg); +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, + void *arg, void **ret_handle_in); +static int esp_intr_free_wrapper(void **ret_handle); +static void osi_assert_wrapper(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2); +static uint32_t osi_random_wrapper(void); +static void esp_reset_rpa_moudle(void); +static int esp_ecc_gen_key_pair(uint8_t *pub, uint8_t *priv); +static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +/* Local variable definition + *************************************************************************** + */ +/* Static variable declare */ +static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +/* This variable tells if BLE is running */ +static bool s_ble_active = false; +#ifdef CONFIG_PM_ENABLE +static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock = NULL; +#define BTDM_MIN_TIMER_UNCERTAINTY_US (200) +#endif // CONFIG_PM_ENABLE + +#define BLE_RTC_DELAY_US_LIGHT_SLEEP (2500) +#define BLE_RTC_DELAY_US_MODEM_SLEEP (500) + +static const struct osi_coex_funcs_t s_osi_coex_funcs_ro = { + ._magic = OSI_COEX_MAGIC_VALUE, + ._version = OSI_COEX_VERSION, + ._coex_wifi_sleep_set = NULL, + ._coex_core_ble_conn_dyn_prio_get = NULL, + ._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper, + ._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper, +}; + +struct ext_funcs_t ext_funcs_ro = { + .ext_version = EXT_FUNC_VERSION, + ._esp_intr_alloc = esp_intr_alloc_wrapper, + ._esp_intr_free = esp_intr_free_wrapper, + ._malloc = bt_osi_mem_malloc_internal, + ._free = bt_osi_mem_free, +#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART + ._hal_uart_start_tx = hci_uart_start_tx_wrapper, + ._hal_uart_init_cbs = hci_uart_init_cbs_wrapper, + ._hal_uart_config = hci_uart_config_wrapper, + ._hal_uart_close = hci_uart_close_wrapper, + ._hal_uart_blocking_tx = hci_uart_blocking_tx_wrapper, + ._hal_uart_init = hci_uart_init_wrapper, +#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART + ._task_create = task_create_wrapper, + ._task_delete = task_delete_wrapper, + ._osi_assert = osi_assert_wrapper, + ._os_random = osi_random_wrapper, + ._ecc_gen_key_pair = esp_ecc_gen_key_pair, + ._ecc_gen_dh_key = esp_ecc_gen_dh_key, + ._esp_reset_rpa_moudle = esp_reset_rpa_moudle, + .magic = EXT_FUNC_MAGIC_VALUE, +}; + +static void IRAM_ATTR esp_reset_rpa_moudle(void) +{ + +} + +static void IRAM_ATTR osi_assert_wrapper(const uint32_t ln, const char *fn, + uint32_t param1, uint32_t param2) +{ + BT_ASSERT_PRINT("BLE assert: line %d in function %s, param: 0x%x, 0x%x", ln, fn, param1, param2); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + esp_ble_controller_log_dump_all(true); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + assert(0); +} + +static uint32_t IRAM_ATTR osi_random_wrapper(void) +{ + return esp_random(); +} + +static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_set(type, status); +#endif // CONFIG_SW_COEXIST_ENABLE +} + +static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_clear(type, status); +#endif // CONFIG_SW_COEXIST_ENABLE +} + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +bool esp_vhci_host_check_send_available(void) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return false; + } + return true; +} + +static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space) +{ + struct os_mbuf *om; + int rc; + + om = os_msys_get_pkthdr(0, 0); + if (om == NULL) { + return NULL; + } + + if (om->om_omp->omp_databuf_len < leading_space) { + rc = os_mbuf_free_chain(om); + assert(rc == 0); + return NULL; + } + + om->om_data += leading_space; + + return om; +} + +struct os_mbuf *ble_hs_mbuf_acl_pkt(void) +{ + return ble_hs_mbuf_gen_pkt(4 + 1); +} + +void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return; + } + + if (*(data) == DATA_TYPE_COMMAND) { + struct ble_hci_cmd *cmd = NULL; + cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + assert(cmd); + memcpy((uint8_t *)cmd, data + 1, len - 1); + ble_hci_trans_hs_cmd_tx((uint8_t *)cmd); + } + + if (*(data) == DATA_TYPE_ACL) { + struct os_mbuf *om = os_msys_get_pkthdr(len, ACL_DATA_MBUF_LEADINGSPCAE); + assert(om); + assert(os_mbuf_append(om, &data[1], len - 1) == 0); + ble_hci_trans_hs_acl_tx(om); + } +} + +esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_FAIL; + } + + ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL); + + return ESP_OK; +} +#endif // CONFIG_BT_BLUEDROID_ENABLED + +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 (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, + (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); +} + +static void task_delete_wrapper(void *task_handle) +{ + vTaskDelete(task_handle); +} + +static int esp_ecc_gen_key_pair(uint8_t *pub, uint8_t *priv) +{ + int rc = -1; +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + rc = ble_sm_alg_gen_key_pair(pub, priv); +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + return rc; +} + +static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey) +{ + int rc = -1; +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + rc = ble_sm_alg_gen_dhkey(peer_pub_key_x, peer_pub_key_y, our_priv_key, out_dhkey); +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + return rc; +} + +#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static void hci_uart_start_tx_wrapper(int uart_no) +{ + hci_uart_start_tx(uart_no); +} + +static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, + hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg) +{ + int rc = -1; + rc = hci_uart_init_cbs(uart_no, tx_func, tx_done, rx_func, arg); + return rc; +} + + +static int hci_uart_config_wrapper(int port_num, int32_t baud_rate, uint8_t data_bits, + uint8_t stop_bits, uart_parity_t parity, + uart_hw_flowcontrol_t flow_ctl) +{ + int rc = -1; + rc = hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl); + return rc; +} + +static int hci_uart_close_wrapper(int uart_no) +{ + int rc = -1; + rc = hci_uart_close(uart_no); + return rc; +} + +static void hci_uart_blocking_tx_wrapper(int port, uint8_t data) +{ + //This function is nowhere to use. +} + +static int hci_uart_init_wrapper(int uart_no, void *cfg) +{ + //This function is nowhere to use. + return 0; +} + +#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART + +static int ble_hci_unregistered_hook(void*, void*) +{ + ESP_LOGD(NIMBLE_PORT_LOG_TAG,"%s ble hci rx_evt is not registered.",__func__); + return 0; +} + +static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, + void *arg, void **ret_handle_in) +{ + int rc = esp_intr_alloc(source, flags | ESP_INTR_FLAG_IRAM, handler, + arg, (intr_handle_t *)ret_handle_in); + return rc; +} + +static int esp_intr_free_wrapper(void **ret_handle) +{ + int rc = 0; + rc = esp_intr_free((intr_handle_t) * ret_handle); + *ret_handle = NULL; + return rc; +} + +void esp_bt_rtc_slow_clk_select(uint8_t slow_clk_src) +{ + /* Select slow clock source for BT momdule */ + switch (slow_clk_src) { + case MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using main XTAL as clock source"); + uint32_t chip_version = efuse_hal_chip_revision(); + if (chip_version == 0) { + modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (400 - 1)); + } else{ + modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (5 - 1)); + } + break; + case MODEM_CLOCK_LPCLK_SRC_RC_SLOW: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using 136 kHz RC as clock source, can only run legacy ADV or SCAN due to low clock accuracy!"); + modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (5 - 1)); + break; + case MODEM_CLOCK_LPCLK_SRC_XTAL32K: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using external 32.768 kHz XTAL as clock source"); + modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (1 - 1)); + break; + case MODEM_CLOCK_LPCLK_SRC_RC32K: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using 32 kHz RC as clock source, can only run legacy ADV or SCAN due to low clock accuracy!"); + modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (1 - 1)); + break; + case MODEM_CLOCK_LPCLK_SRC_EXT32K: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using 32 kHz oscillator as clock source, can only run legacy ADV or SCAN due to low clock accuracy!"); + modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (1 - 1)); + break; + default: + } +} + +IRAM_ATTR void controller_sleep_cb(uint32_t enable_tick, void *arg) +{ + if (!s_ble_active) { + return; + } +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + r_ble_rtc_wake_up_state_clr(); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + esp_phy_disable(PHY_MODEM_BT); +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + s_ble_active = false; +} + +IRAM_ATTR void controller_wakeup_cb(void *arg) +{ + if (s_ble_active) { + return; + } +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_acquire(s_pm_lock); + r_ble_rtc_wake_up_state_clr(); +#endif //CONFIG_PM_ENABLE + esp_phy_enable(PHY_MODEM_BT); + s_ble_active = true; +} + +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +static esp_err_t sleep_modem_ble_mac_modem_state_init(uint8_t extra) +{ + uint8_t size; + const sleep_retention_entries_config_t *ble_mac_modem_config = esp_ble_mac_retention_link_get(&size, extra); + esp_err_t err = sleep_retention_entries_create(ble_mac_modem_config, size, REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_BLE_MAC); + if (err == ESP_OK) { + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Modem BLE MAC retention initialization"); + } + return err; +} + +static void sleep_modem_ble_mac_modem_state_deinit(void) +{ + sleep_retention_entries_destroy(SLEEP_RETENTION_MODULE_BLE_MAC); +} + +void sleep_modem_light_sleep_overhead_set(uint32_t overhead) +{ + esp_ble_set_wakeup_overhead(overhead); +} +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + + +esp_err_t controller_sleep_init(void) +{ + esp_err_t rc = 0; + +#ifdef CONFIG_BT_LE_SLEEP_ENABLE + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "BLE modem sleep is enabled"); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + BLE_RTC_DELAY_US_LIGHT_SLEEP); +#else + r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + BLE_RTC_DELAY_US_MODEM_SLEEP); +#endif /* FREERTOS_USE_TICKLESS_IDLE */ +#endif // CONFIG_BT_LE_SLEEP_ENABLE + +#ifdef CONFIG_PM_ENABLE + rc = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "bt", &s_pm_lock); + if (rc != ESP_OK) { + goto error; + } +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + /* Create a new regdma link for BLE related register restoration */ + rc = sleep_modem_ble_mac_modem_state_init(1); + assert(rc == 0); + esp_sleep_enable_bt_wakeup(); + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "Enable light sleep, the wake up source is BLE timer"); + + rc = esp_pm_register_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); + if (rc != ESP_OK) { + goto error; + } + +#if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + sleep_modem_register_mac_bb_module_prepare_callback(sleep_modem_mac_bb_power_down_prepare, + sleep_modem_mac_bb_power_up_prepare); +#endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + return rc; + +error: + +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +#if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + sleep_modem_unregister_mac_bb_module_prepare_callback(sleep_modem_mac_bb_power_down_prepare, + sleep_modem_mac_bb_power_up_prepare); +#endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + esp_sleep_disable_bt_wakeup(); + esp_pm_unregister_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + /*lock should release first and then delete*/ + if (s_pm_lock != NULL) { + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; + } +#endif // CONFIG_PM_ENABLE + + return rc; +} + +void controller_sleep_deinit(void) +{ +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +#if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + sleep_modem_unregister_mac_bb_module_prepare_callback(sleep_modem_mac_bb_power_down_prepare, + sleep_modem_mac_bb_power_up_prepare); +#endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + r_ble_rtc_wake_up_state_clr(); + esp_sleep_disable_bt_wakeup(); + sleep_modem_ble_mac_modem_state_deinit(); + esp_pm_unregister_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ +#ifdef CONFIG_PM_ENABLE + /* lock should be released first */ + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; +#endif //CONFIG_PM_ENABLE +} + +typedef enum { + FILTER_DUPLICATE_PDUTYPE = BIT(0), + FILTER_DUPLICATE_LENGTH = BIT(1), + FILTER_DUPLICATE_ADDRESS = BIT(2), + FILTER_DUPLICATE_ADVDATA = BIT(3), + FILTER_DUPLICATE_DEFAULT = FILTER_DUPLICATE_PDUTYPE | FILTER_DUPLICATE_ADDRESS, + FILTER_DUPLICATE_PDU_ALL = 0xF, + FILTER_DUPLICATE_EXCEPTION_FOR_MESH = BIT(4), + FILTER_DUPLICATE_AD_TYPE = BIT(5), +}disc_duplicate_mode_t; + + +extern void r_filter_duplicate_mode_enable(disc_duplicate_mode_t mode); +extern void r_filter_duplicate_mode_disable(disc_duplicate_mode_t mode); +extern void r_filter_duplicate_set_ring_list_max_num(uint32_t max_num); +extern void r_scan_duplicate_cache_refresh_set_time(uint32_t period_time); + +int +ble_vhci_disc_duplicate_mode_enable(int mode) +{ + // TODO: use vendor hci to update + r_filter_duplicate_mode_enable(mode); + return true; +} + +int +ble_vhci_disc_duplicate_mode_disable(int mode) +{ + // TODO: use vendor hci to update + r_filter_duplicate_mode_disable(mode); + return true; +} + +int ble_vhci_disc_duplicate_set_max_cache_size(int max_cache_size){ + // TODO: use vendor hci to update + r_filter_duplicate_set_ring_list_max_num(max_cache_size); + return true; +} + +int ble_vhci_disc_duplicate_set_period_refresh_time(int refresh_period_time){ + // TODO: use vendor hci to update + r_scan_duplicate_cache_refresh_set_time(refresh_period_time); + return true; +} + +/** + * @brief Config scan duplicate option mode from menuconfig (Adapt to the old configuration method.) + */ +void ble_controller_scan_duplicate_config(void) +{ + uint32_t duplicate_mode = FILTER_DUPLICATE_DEFAULT; + uint32_t cache_size = 100; +#if CONFIG_BT_LE_SCAN_DUPL == true + cache_size = CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT; + if (CONFIG_BT_LE_SCAN_DUPL_TYPE == 0) { + duplicate_mode = FILTER_DUPLICATE_ADDRESS | FILTER_DUPLICATE_PDUTYPE; + } else if (CONFIG_BT_LE_SCAN_DUPL_TYPE == 1) { + duplicate_mode = FILTER_DUPLICATE_ADVDATA; + } else if (CONFIG_BT_LE_SCAN_DUPL_TYPE == 2) { + duplicate_mode = FILTER_DUPLICATE_ADDRESS | FILTER_DUPLICATE_ADVDATA; + } + duplicate_mode |= FILTER_DUPLICATE_EXCEPTION_FOR_MESH; + + ble_vhci_disc_duplicate_set_period_refresh_time(CONFIG_BT_LE_SCAN_DUPL_CACHE_REFRESH_PERIOD); +#endif + + ble_vhci_disc_duplicate_mode_disable(0xFFFFFFFF); + ble_vhci_disc_duplicate_mode_enable(duplicate_mode); + ble_vhci_disc_duplicate_set_max_cache_size(cache_size); +} + +esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) +{ + uint8_t mac[6]; + esp_err_t ret = ESP_OK; + ble_npl_count_info_t npl_info; + uint32_t slow_clk_freq = 0; + + memset(&npl_info, 0, sizeof(ble_npl_count_info_t)); + + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_ERR_INVALID_STATE; + } + + if (!cfg) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "cfg is NULL"); + return ESP_ERR_INVALID_ARG; + } + + ret = esp_register_ext_funcs(&ext_funcs_ro); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "register extend functions failed"); + return ret; + } + + /* Initialize the function pointers for OS porting */ + npl_freertos_funcs_init(); + struct npl_funcs_t *p_npl_funcs = npl_freertos_funcs_get(); + if (!p_npl_funcs) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl functions get failed"); + return ESP_ERR_INVALID_ARG; + } + + ret = esp_register_npl_funcs(p_npl_funcs); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl functions register failed"); + goto free_mem; + } + + ble_get_npl_element_info(cfg, &npl_info); + npl_freertos_set_controller_npl_info(&npl_info); + if (npl_freertos_mempool_init() != 0) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl mempool init failed"); + ret = ESP_ERR_INVALID_ARG; + goto free_mem; + } + +#if CONFIG_BT_NIMBLE_ENABLED + /* ble_npl_eventq_init() needs to use npl functions in rom and + * must be called after esp_bt_controller_init(). + */ + ble_npl_eventq_init(nimble_port_get_dflt_eventq()); +#endif // CONFIG_BT_NIMBLE_ENABLED + /* Enable BT-related clocks */ + modem_clock_module_enable(PERIPH_BT_MODULE); + modem_clock_module_mac_reset(PERIPH_BT_MODULE); + /* Select slow clock source for BT momdule */ +#if CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL); + slow_clk_freq = 100000; +#else +#if CONFIG_RTC_CLK_SRC_INT_RC + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_RC_SLOW); + slow_clk_freq = 30000; +#elif CONFIG_RTC_CLK_SRC_EXT_CRYS + if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_XTAL32K); + slow_clk_freq = 32768; + } else { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock"); + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL); + slow_clk_freq = 100000; + } +#elif CONFIG_RTC_CLK_SRC_INT_RC32K + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_RC32K); + slow_clk_freq = 32000; +#elif CONFIG_RTC_CLK_SRC_EXT_OSC + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_EXT32K); + slow_clk_freq = 32000; +#else + ESP_LOGE(NIMBLE_PORT_LOG_TAG, "Unsupported clock source"); + assert(0); +#endif +#endif /* CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL */ + esp_phy_modem_init(); + + if (ble_osi_coex_funcs_register((struct osi_coex_funcs_t *)&s_osi_coex_funcs_ro) != 0) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "osi coex funcs reg failed"); + ret = ESP_ERR_INVALID_ARG; + goto modem_deint; + } + +#if CONFIG_SW_COEXIST_ENABLE + coex_init(); +#endif // CONFIG_SW_COEXIST_ENABLE + + ret = ble_controller_init(cfg); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_init failed %d", ret); + goto modem_deint; + } + + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + interface_func_t bt_controller_log_interface; + bt_controller_log_interface = esp_bt_controller_log_interface; + uint8_t buffers = 0; +#if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED + buffers |= ESP_BLE_LOG_BUF_CONTROLLER; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED +#if CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED + buffers |= ESP_BLE_LOG_BUF_HCI; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED +#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY + ret = r_ble_log_init_async(bt_controller_log_interface, false, buffers, (uint32_t *)log_bufs_size); +#else + ret = r_ble_log_init_async(bt_controller_log_interface, true, buffers, (uint32_t *)log_bufs_size); +#endif // CONFIG_BT_CONTROLLER_LOG_DUMP + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); + goto controller_init_err; + } +#endif // CONFIG_BT_CONTROLLER_LOG_ENABLED + + esp_ble_change_rtc_freq(slow_clk_freq); + + ble_controller_scan_duplicate_config(); + + ret = os_msys_init(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "msys_init failed %d", ret); + goto free_controller; + } + + ret = controller_sleep_init(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "controller_sleep_init failed %d", ret); + goto free_controller; + } + ESP_ERROR_CHECK(esp_read_mac((uint8_t *)mac, ESP_MAC_BT)); + swap_in_place(mac, 6); + esp_ble_ll_set_public_addr(mac); + + ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + + ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hci_unregistered_hook,NULL, + (ble_hci_trans_rx_acl_fn *)ble_hci_unregistered_hook,NULL); + return ESP_OK; + +free_controller: + controller_sleep_deinit(); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +controller_init_err: + r_ble_log_deinit_async(); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + os_msys_deinit(); + ble_controller_deinit(); +modem_deint: + esp_phy_modem_deinit(); + modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); + modem_clock_module_disable(PERIPH_BT_MODULE); +#if CONFIG_BT_NIMBLE_ENABLED + ble_npl_eventq_deinit(nimble_port_get_dflt_eventq()); +#endif // CONFIG_BT_NIMBLE_ENABLED +free_mem: + npl_freertos_mempool_deinit(); + esp_unregister_npl_funcs(); + npl_freertos_funcs_deinit(); + esp_unregister_ext_funcs(); + return ret; +} + +esp_err_t esp_bt_controller_deinit(void) +{ + if ((ble_controller_status < ESP_BT_CONTROLLER_STATUS_INITED) || + (ble_controller_status >= ESP_BT_CONTROLLER_STATUS_ENABLED)) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + + controller_sleep_deinit(); + + os_msys_deinit(); + + esp_phy_modem_deinit(); + modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); + modem_clock_module_disable(PERIPH_BT_MODULE); + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + r_ble_log_deinit_async(); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + ble_controller_deinit(); + +#if CONFIG_BT_NIMBLE_ENABLED + /* De-initialize default event queue */ + ble_npl_eventq_deinit(nimble_port_get_dflt_eventq()); +#endif // CONFIG_BT_NIMBLE_ENABLED + + esp_unregister_npl_funcs(); + + esp_unregister_ext_funcs(); + + /* De-initialize npl functions */ + npl_freertos_funcs_deinit(); + + npl_freertos_mempool_deinit(); + + ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + + return ESP_OK; +} + +esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) +{ + esp_err_t ret = ESP_OK; + + if (mode != ESP_BT_MODE_BLE) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller mode"); + return ESP_FAIL; + } + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + if (!s_ble_active) { +#if CONFIG_PM_ENABLE + esp_pm_lock_acquire(s_pm_lock); +#endif // CONFIG_PM_ENABLE + esp_phy_enable(PHY_MODEM_BT); + s_ble_active = true; + } + esp_btbb_enable(); +#if CONFIG_SW_COEXIST_ENABLE + coex_enable(); +#endif // CONFIG_SW_COEXIST_ENABLE + + if (ble_controller_enable(mode) != 0) { + ret = ESP_FAIL; + goto error; + } + ble_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED; + return ESP_OK; + +error: +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + esp_btbb_disable(); + if (s_ble_active) { + esp_phy_disable(PHY_MODEM_BT); +#if CONFIG_PM_ENABLE + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + s_ble_active = false; + } + return ret; +} + +esp_err_t esp_bt_controller_disable(void) +{ + if (ble_controller_status < ESP_BT_CONTROLLER_STATUS_ENABLED) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + if (ble_controller_disable() != 0) { + return ESP_FAIL; + } +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + esp_btbb_disable(); + if (s_ble_active) { + esp_phy_disable(PHY_MODEM_BT); +#if CONFIG_PM_ENABLE + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + s_ble_active = false; + } + ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + return ESP_OK; +} + +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +{ + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "%s not implemented, return OK", __func__); + return ESP_OK; +} + +static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) +{ + int ret = heap_caps_add_region(start, end); + + /* heap_caps_add_region() returns ESP_ERR_INVALID_SIZE if the memory region is + * is too small to fit a heap. This cannot be termed as a fatal error and hence + * we replace it by ESP_OK + */ + if (ret == ESP_ERR_INVALID_SIZE) { + return ESP_OK; + } + return ret; +} + +esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) +{ + intptr_t mem_start, mem_end; + + if (mode & ESP_BT_MODE_BLE) { + /* If the addresses of btdm .bss and bt .bss are consecutive, + * they are registered in the system heap as a piece of memory + */ + if(_bt_bss_end == _bt_controller_bss_start) { + mem_start = (intptr_t)&_bt_bss_start; + mem_end = (intptr_t)&_bt_controller_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BSS [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } else { + mem_start = (intptr_t)&_bt_bss_start; + mem_end = (intptr_t)&_bt_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + + mem_start = (intptr_t)&_bt_controller_bss_start; + mem_end = (intptr_t)&_bt_controller_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release Controller BSS [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + /* If the addresses of btdm .data and bt .data are consecutive, + * they are registered in the system heap as a piece of memory + */ + if(_bt_data_end == _bt_controller_data_start) { + mem_start = (intptr_t)&_bt_data_start; + mem_end = (intptr_t)&_bt_controller_data_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release data [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } else { + mem_start = (intptr_t)&_bt_data_start; + mem_end = (intptr_t)&_bt_data_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + + mem_start = (intptr_t)&_bt_controller_data_start; + mem_end = (intptr_t)&_bt_controller_data_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release Controller Data [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + } + + return ESP_OK; +} + + +esp_bt_controller_status_t esp_bt_controller_get_status(void) +{ + return ble_controller_status; +} + +esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_t power_level) +{ + esp_err_t stat = ESP_FAIL; + + switch (power_type) { + case ESP_BLE_PWR_TYPE_DEFAULT: + case ESP_BLE_PWR_TYPE_ADV: + case ESP_BLE_PWR_TYPE_SCAN: + if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + stat = ESP_OK; + } + break; + case ESP_BLE_PWR_TYPE_CONN_HDL0: + case ESP_BLE_PWR_TYPE_CONN_HDL1: + case ESP_BLE_PWR_TYPE_CONN_HDL2: + case ESP_BLE_PWR_TYPE_CONN_HDL3: + case ESP_BLE_PWR_TYPE_CONN_HDL4: + case ESP_BLE_PWR_TYPE_CONN_HDL5: + case ESP_BLE_PWR_TYPE_CONN_HDL6: + case ESP_BLE_PWR_TYPE_CONN_HDL7: + case ESP_BLE_PWR_TYPE_CONN_HDL8: + if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { + stat = ESP_OK; + } + break; + default: + stat = ESP_ERR_NOT_SUPPORTED; + break; + } + + return stat; +} + +esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle, + esp_power_level_t power_level) +{ + esp_err_t stat = ESP_FAIL; + switch (power_type) { + case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: + case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: + case ESP_BLE_ENHANCED_PWR_TYPE_INIT: + if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + stat = ESP_OK; + } + break; + case ESP_BLE_ENHANCED_PWR_TYPE_ADV: + case ESP_BLE_ENHANCED_PWR_TYPE_CONN: + if (ble_txpwr_set(power_type, handle, power_level) == 0) { + stat = ESP_OK; + } + break; + default: + stat = ESP_ERR_NOT_SUPPORTED; + break; + } + + return stat; +} + +esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) +{ + int tx_level = 0; + + switch (power_type) { + case ESP_BLE_PWR_TYPE_ADV: + case ESP_BLE_PWR_TYPE_SCAN: + case ESP_BLE_PWR_TYPE_DEFAULT: + tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + break; + case ESP_BLE_PWR_TYPE_CONN_HDL0: + case ESP_BLE_PWR_TYPE_CONN_HDL1: + case ESP_BLE_PWR_TYPE_CONN_HDL2: + case ESP_BLE_PWR_TYPE_CONN_HDL3: + case ESP_BLE_PWR_TYPE_CONN_HDL4: + case ESP_BLE_PWR_TYPE_CONN_HDL5: + case ESP_BLE_PWR_TYPE_CONN_HDL6: + case ESP_BLE_PWR_TYPE_CONN_HDL7: + case ESP_BLE_PWR_TYPE_CONN_HDL8: + tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); + break; + default: + return ESP_PWR_LVL_INVALID; + } + + if (tx_level < 0) { + return ESP_PWR_LVL_INVALID; + } + + return (esp_power_level_t)tx_level; +} + +esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, + uint16_t handle) +{ + int tx_level = 0; + + switch (power_type) { + case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: + case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: + case ESP_BLE_ENHANCED_PWR_TYPE_INIT: + tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + break; + case ESP_BLE_ENHANCED_PWR_TYPE_ADV: + case ESP_BLE_ENHANCED_PWR_TYPE_CONN: + tx_level = ble_txpwr_get(power_type, handle); + break; + default: + return ESP_PWR_LVL_INVALID; + } + + if (tx_level < 0) { + return ESP_PWR_LVL_INVALID; + } + + return (esp_power_level_t)tx_level; +} + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) +{ + for (int i = 0; i < len; i++) { + esp_rom_printf("%02x ", addr[i]); + } + if (end) { + esp_rom_printf("\n"); + } +} + +void esp_ble_controller_log_dump_all(bool output) +{ + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(5000); + BT_ASSERT_PRINT("\r\n[DUMP_START:"); + r_ble_log_async_output_dump_all(output); + BT_ASSERT_PRINT(":DUMP_END]\r\n"); + portEXIT_CRITICAL_SAFE(&spinlock); +} +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +#if (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC +#define BLE_SM_KEY_ERR 0x17 +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS +#include "mbedtls/aes.h" +#if CONFIG_BT_LE_SM_SC +#include "mbedtls/cipher.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/cmac.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/ecp.h" + +static mbedtls_ecp_keypair keypair; +#endif // CONFIG_BT_LE_SM_SC + +#else +#include "tinycrypt/aes.h" +#include "tinycrypt/constants.h" +#include "tinycrypt/utils.h" + +#if CONFIG_BT_LE_SM_SC +#include "tinycrypt/cmac_mode.h" +#include "tinycrypt/ecc_dh.h" +#endif // CONFIG_BT_LE_SM_SC +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + +/* Based on Core Specification 4.2 Vol 3. Part H 2.3.5.6.1 */ +static const uint8_t ble_sm_alg_dbg_priv_key[32] = { + 0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38, 0x74, 0xc9, 0xb3, 0xe3, + 0xd2, 0x10, 0x3f, 0x50, 0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99, + 0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd +}; + +int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey) +{ + uint8_t dh[32]; + uint8_t pk[64]; + uint8_t priv[32]; + int rc = BLE_SM_KEY_ERR; + + swap_buf(pk, peer_pub_key_x, 32); + swap_buf(&pk[32], peer_pub_key_y, 32); + swap_buf(priv, our_priv_key, 32); + +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + struct mbedtls_ecp_point pt = {0}, Q = {0}; + mbedtls_mpi z = {0}, d = {0}; + mbedtls_ctr_drbg_context ctr_drbg = {0}; + mbedtls_entropy_context entropy = {0}; + + uint8_t pub[65] = {0}; + /* Hardcoded first byte of pub key for MBEDTLS_ECP_PF_UNCOMPRESSED */ + pub[0] = 0x04; + memcpy(&pub[1], pk, 64); + + /* Initialize the required structures here */ + mbedtls_ecp_point_init(&pt); + mbedtls_ecp_point_init(&Q); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_entropy_init(&entropy); + mbedtls_mpi_init(&d); + mbedtls_mpi_init(&z); + + /* Below 3 steps are to validate public key on curve secp256r1 */ + if (mbedtls_ecp_group_load(&keypair.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1) != 0) { + goto exit; + } + + if (mbedtls_ecp_point_read_binary(&keypair.MBEDTLS_PRIVATE(grp), &pt, pub, 65) != 0) { + goto exit; + } + + if (mbedtls_ecp_check_pubkey(&keypair.MBEDTLS_PRIVATE(grp), &pt) != 0) { + goto exit; + } + + /* Set PRNG */ + if ((rc = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0)) != 0) { + goto exit; + } + + /* Prepare point Q from pub key */ + if (mbedtls_ecp_point_read_binary(&keypair.MBEDTLS_PRIVATE(grp), &Q, pub, 65) != 0) { + goto exit; + } + + if (mbedtls_mpi_read_binary(&d, priv, 32) != 0) { + goto exit; + } + + rc = mbedtls_ecdh_compute_shared(&keypair.MBEDTLS_PRIVATE(grp), &z, &Q, &d, + mbedtls_ctr_drbg_random, &ctr_drbg); + if (rc != 0) { + goto exit; + } + + rc = mbedtls_mpi_write_binary(&z, dh, 32); + if (rc != 0) { + goto exit; + } + +exit: + mbedtls_ecp_point_free(&pt); + mbedtls_mpi_free(&z); + mbedtls_mpi_free(&d); + mbedtls_ecp_point_free(&Q); + mbedtls_entropy_free(&entropy); + mbedtls_ctr_drbg_free(&ctr_drbg); + if (rc != 0) { + return BLE_SM_KEY_ERR; + } + +#else + if (uECC_valid_public_key(pk, &curve_secp256r1) < 0) { + return BLE_SM_KEY_ERR; + } + + rc = uECC_shared_secret(pk, priv, dh, &curve_secp256r1); + if (rc == TC_CRYPTO_FAIL) { + return BLE_SM_KEY_ERR; + } +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + + swap_buf(out_dhkey, dh, 32); + return 0; +} + +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS +static int mbedtls_gen_keypair(uint8_t *public_key, uint8_t *private_key) +{ + int rc = BLE_SM_KEY_ERR; + mbedtls_entropy_context entropy = {0}; + mbedtls_ctr_drbg_context ctr_drbg = {0}; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_ecp_keypair_init(&keypair); + + if ((rc = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + NULL, 0)) != 0) { + goto exit; + } + + if ((rc = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, &keypair, + mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { + goto exit; + } + + if ((rc = mbedtls_mpi_write_binary(&keypair.MBEDTLS_PRIVATE(d), private_key, 32)) != 0) { + goto exit; + } + + size_t olen = 0; + uint8_t pub[65] = {0}; + + if ((rc = mbedtls_ecp_point_write_binary(&keypair.MBEDTLS_PRIVATE(grp), &keypair.MBEDTLS_PRIVATE(Q), MBEDTLS_ECP_PF_UNCOMPRESSED, + &olen, pub, 65)) != 0) { + goto exit; + } + + memcpy(public_key, &pub[1], 64); + +exit: + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + if (rc != 0) { + mbedtls_ecp_keypair_free(&keypair); + return BLE_SM_KEY_ERR; + } + + return 0; +} +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + +/** + * pub: 64 bytes + * priv: 32 bytes + */ +int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv) +{ +#if CONFIG_BT_LE_SM_SC_DEBUG_KEYS + swap_buf(pub, ble_sm_alg_dbg_pub_key, 32); + swap_buf(&pub[32], &ble_sm_alg_dbg_pub_key[32], 32); + swap_buf(priv, ble_sm_alg_dbg_priv_key, 32); +#else + uint8_t pk[64]; + + do { +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + if (mbedtls_gen_keypair(pk, priv) != 0) { + return BLE_SM_KEY_ERR; + } +#else + if (uECC_make_key(pk, priv, &curve_secp256r1) != TC_CRYPTO_SUCCESS) { + return BLE_SM_KEY_ERR; + } +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + /* Make sure generated key isn't debug key. */ + } while (memcmp(priv, ble_sm_alg_dbg_priv_key, 32) == 0); + + swap_buf(pub, pk, 32); + swap_buf(&pub[32], &pk[32], 32); + swap_in_place(priv, 32); +#endif // CONFIG_BT_LE_SM_SC_DEBUG_KEYS + return 0; +} + +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC +#endif // (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) + diff --git a/lib/bt/controller/esp32c6/esp_bt_cfg.h b/lib/bt/controller/esp32c6/esp_bt_cfg.h new file mode 100644 index 00000000..9e341e32 --- /dev/null +++ b/lib/bt/controller/esp32c6/esp_bt_cfg.h @@ -0,0 +1,219 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ESP_BT_CFG_H__ +#define __ESP_BT_CFG_H__ + +#include <stdint.h> +#include <stdbool.h> +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_BT_NIMBLE_ENABLED +#include "syscfg/syscfg.h" +#endif + +#define NIMBLE_LL_STACK_SIZE CONFIG_BT_LE_CONTROLLER_TASK_STACK_SIZE + +#if CONFIG_BT_NIMBLE_ENABLED + + #if CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_CODED_PHY + #define BLE_LL_SCAN_PHY_NUMBER_N (2) + #else + #define BLE_LL_SCAN_PHY_NUMBER_N (1) + #endif + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST MYNEWT_VAL(BLE_MAX_PERIODIC_ADVERTISER_LIST) + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS) + #define DEFAULT_BT_LE_MAX_CONNECTIONS MYNEWT_VAL(BLE_MAX_CONNECTIONS) + #define DEFAULT_BT_LE_ACL_BUF_SIZE MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE) + #define DEFAULT_BT_LE_ACL_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE) + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE MYNEWT_VAL(BLE_LL_WHITELIST_SIZE) + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT) + #define DEFAULT_BT_LE_POWER_CONTROL_ENABLED MYNEWT_VAL(BLE_POWER_CONTROL) + #if defined(CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT) + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (1) + #else + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) + #endif +#else + + #if CONFIG_BT_LE_LL_CFG_FEAT_LE_CODED_PHY + #define BLE_LL_SCAN_PHY_NUMBER_N (2) + #else + #define BLE_LL_SCAN_PHY_NUMBER_N (1) + #endif + + #if defined(CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST) + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST (CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST) + #else + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST (5) + #endif + + #if defined(CONFIG_BT_LE_MAX_PERIODIC_SYNCS) + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS (CONFIG_BT_LE_MAX_PERIODIC_SYNCS) + #else + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS (1) + #endif + + #if defined(CONFIG_BT_LE_MAX_CONNECTIONS) + #define DEFAULT_BT_LE_MAX_CONNECTIONS (CONFIG_BT_LE_MAX_CONNECTIONS) + #else + #define DEFAULT_BT_LE_MAX_CONNECTIONS (2) + #endif + + #if defined(CONFIG_BT_LE_ACL_BUF_SIZE) + #define DEFAULT_BT_LE_ACL_BUF_SIZE (CONFIG_BT_LE_ACL_BUF_SIZE) + #else + #define DEFAULT_BT_LE_ACL_BUF_SIZE (255) + #endif + + #if defined(CONFIG_BT_LE_ACL_BUF_COUNT) + #define DEFAULT_BT_LE_ACL_BUF_COUNT (CONFIG_BT_LE_ACL_BUF_COUNT) + #else + #define DEFAULT_BT_LE_ACL_BUF_COUNT (24) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_BUF_SIZE) + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE (CONFIG_BT_LE_HCI_EVT_BUF_SIZE) + #else + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE (70) + #endif + + #if defined(CONFIG_BT_LE_EXT_ADV_MAX_SIZE) + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE (CONFIG_BT_LE_EXT_ADV_MAX_SIZE) + #else + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE (31) + #endif + + #if defined(CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES) + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES (CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES) + #else + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES (1) + #endif + + #if defined(CONFIG_BT_LE_WHITELIST_SIZE) + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE (CONFIG_BT_LE_WHITELIST_SIZE) + #else + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE (12) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT (CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT) + #else + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT (30) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT (CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT) + #else + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT (8) + #endif + + #if defined(CONFIG_BT_LE_POWER_CONTROL_ENABLED) + #define DEFAULT_BT_LE_POWER_CONTROL_ENABLED (CONFIG_BT_LE_POWER_CONTROL_ENABLED) + #else + #define DEFAULT_BT_LE_POWER_CONTROL_ENABLED (0) + #endif + #if defined(CONFIG_BT_LE_50_FEATURE_SUPPORT) + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (1) + #else + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) + #endif +#endif + +#define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF + +#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART +#define HCI_UART_EN CONFIG_BT_LE_HCI_INTERFACE_USE_UART +#else +#define HCI_UART_EN 0 // hci ram mode +#endif + +#ifdef CONFIG_BT_LE_SLEEP_ENABLE +#define NIMBLE_SLEEP_ENABLE CONFIG_BT_LE_SLEEP_ENABLE +#else +#define NIMBLE_SLEEP_ENABLE 0 +#endif + + +#ifdef CONFIG_BT_LE_TX_CCA_ENABLED + #define DEFAULT_BT_LE_TX_CCA_ENABLED (CONFIG_BT_LE_TX_CCA_ENABLED) +#else + #define DEFAULT_BT_LE_TX_CCA_ENABLED (0) +#endif + +#ifdef CONFIG_BT_LE_CCA_RSSI_THRESH + #define DEFAULT_BT_LE_CCA_RSSI_THRESH (CONFIG_BT_LE_CCA_RSSI_THRESH) +#else + #define DEFAULT_BT_LE_CCA_RSSI_THRESH (50) +#endif + +#define DEFAULT_BT_LE_SCAN_RSP_DATA_MAX_LEN_N DEFAULT_BT_LE_EXT_ADV_MAX_SIZE + + +#if HCI_UART_EN + #define DEFAULT_BT_LE_HCI_UART_TX_PIN (CONFIG_BT_LE_HCI_UART_TX_PIN) + #define DEFAULT_BT_LE_HCI_UART_RX_PIN (CONFIG_BT_LE_HCI_UART_RX_PIN) + #define DEFAULT_BT_LE_HCI_UART_PORT (CONFIG_BT_LE_HCI_UART_PORT) + #define DEFAULT_BT_LE_HCI_UART_BAUD (CONFIG_BT_LE_HCI_UART_BAUD) + #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS) + #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1) + #define DEFAULT_BT_LE_HCI_UART_PARITY (0) + #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) +#else + #define DEFAULT_BT_LE_HCI_UART_TX_PIN (0) + #define DEFAULT_BT_LE_HCI_UART_RX_PIN (0) + #define DEFAULT_BT_LE_HCI_UART_PORT (0) + #define DEFAULT_BT_LE_HCI_UART_BAUD (0) + #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0) + #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0) + #define DEFAULT_BT_LE_HCI_UART_PARITY (0) + #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) +#endif + +/* Unchanged configuration */ + +#define BLE_LL_CTRL_PROC_TIMEOUT_MS_N (40000) /* ms */ + +#define BLE_LL_CFG_NUM_HCI_CMD_PKTS_N (1) + +#define BLE_LL_SCHED_ADV_MAX_USECS_N (852) + +#define BLE_LL_SCHED_DIRECT_ADV_MAX_USECS_N (502) + +#define BLE_LL_SCHED_MAX_ADV_PDU_USECS_N (376) + +#define BLE_LL_SUB_VERS_NR_N (0x0000) + +#define BLE_LL_JITTER_USECS_N (16) + +#define BLE_PHY_MAX_PWR_DBM_N (10) + +#define BLE_LL_CONN_DEF_AUTH_PYLD_TMO_N (3000) + +#define RTC_FREQ_N (32768) /* in Hz */ + +#define BLE_LL_TX_PWR_DBM_N (9) + + +#define RUN_BQB_TEST (0) +#define RUN_QA_TEST (0) +#define NIMBLE_DISABLE_SCAN_BACKOFF (0) + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_BT_CFG_H__ */ diff --git a/lib/bt/controller/esp32h2/Kconfig.in b/lib/bt/controller/esp32h2/Kconfig.in new file mode 100644 index 00000000..9e8fabe7 --- /dev/null +++ b/lib/bt/controller/esp32h2/Kconfig.in @@ -0,0 +1,556 @@ + +menu "HCI Config" + + choice BT_LE_HCI_INTERFACE + prompt "Select HCI interface" + default BT_LE_HCI_INTERFACE_USE_RAM + + config BT_LE_HCI_INTERFACE_USE_RAM + bool "ram" + help + Use RAM as HCI interface + config BT_LE_HCI_INTERFACE_USE_UART + bool "uart" + help + Use UART as HCI interface + endchoice + + config BT_LE_HCI_UART_PORT + int "HCI UART port" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 1 + help + Set the port number of HCI UART + + config BT_LE_HCI_UART_FLOWCTRL + bool "HCI uart Hardware Flow ctrl" + depends on BT_LE_HCI_INTERFACE_USE_UART + default n + + config BT_LE_HCI_UART_TX_PIN + int "HCI uart Tx gpio" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 19 + + config BT_LE_HCI_UART_RX_PIN + int "HCI uart Rx gpio" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 10 + + config BT_LE_HCI_UART_RTS_PIN + int "HCI uart RTS gpio" + depends on BT_LE_HCI_UART_FLOWCTRL + default 4 + + config BT_LE_HCI_UART_CTS_PIN + int "HCI uart CTS gpio" + depends on BT_LE_HCI_UART_FLOWCTRL + default 5 + + config BT_LE_HCI_UART_BAUD + int "HCI uart baudrate" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 921600 + help + HCI uart baud rate 115200 ~ 1000000 + + choice BT_LE_HCI_UART_PARITY + prompt "select uart parity" + depends on BT_LE_HCI_INTERFACE_USE_UART + default BT_LE_HCI_UART_UART_PARITY_DISABLE + + config BT_LE_HCI_UART_UART_PARITY_DISABLE + bool "PARITY_DISABLE" + help + UART_PARITY_DISABLE + config BT_LE_HCI_UART_UART_PARITY_EVEN + bool "PARITY_EVEN" + help + UART_PARITY_EVEN + config BT_LE_HCI_UART_UART_PARITY_ODD + bool "PARITY_ODD" + help + UART_PARITY_ODD + endchoice + + config BT_LE_HCI_UART_TASK_STACK_SIZE + int "HCI uart task stack size" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 1000 + help + Set the size of uart task stack +endmenu + +config BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT + bool + default y + help + Enable NPL porting for controller. + + +menuconfig BT_LE_50_FEATURE_SUPPORT + bool "Enable BLE 5 feature" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable BLE 5 feature + +config BT_LE_LL_CFG_FEAT_LE_2M_PHY + bool "Enable 2M Phy" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable 2M-PHY + +config BT_LE_LL_CFG_FEAT_LE_CODED_PHY + bool "Enable coded Phy" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable coded-PHY + +config BT_LE_EXT_ADV + bool "Enable extended advertising" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable this option to do extended advertising. Extended advertising + will be supported from BLE 5.0 onwards. + +if BT_LE_EXT_ADV + config BT_LE_MAX_EXT_ADV_INSTANCES + int "Maximum number of extended advertising instances." + range 0 4 + default 1 + depends on BT_LE_EXT_ADV + help + Change this option to set maximum number of extended advertising + instances. Minimum there is always one instance of + advertising. Enter how many more advertising instances you + want. + Each extended advertising instance will take about 0.5k DRAM. + + config BT_LE_EXT_ADV_MAX_SIZE + int "Maximum length of the advertising data." + range 0 1650 + default 1650 + depends on BT_LE_EXT_ADV + help + Defines the length of the extended adv data. The value should not + exceed 1650. + + config BT_LE_ENABLE_PERIODIC_ADV + bool "Enable periodic advertisement." + default y + depends on BT_LE_EXT_ADV + help + Enable this option to start periodic advertisement. + + config BT_LE_PERIODIC_ADV_SYNC_TRANSFER + bool "Enable Transer Sync Events" + depends on BT_LE_ENABLE_PERIODIC_ADV + default y + help + This enables controller transfer periodic sync events to host + +endif + +config BT_LE_MAX_PERIODIC_SYNCS + int "Maximum number of periodic advertising syncs" + depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED + + range 0 8 + default 1 if BT_LE_ENABLE_PERIODIC_ADV + default 0 + help + Set this option to set the upper limit for number of periodic sync + connections. This should be less than maximum connections allowed by + controller. + +config BT_LE_MAX_PERIODIC_ADVERTISER_LIST + int "Maximum number of periodic advertiser list" + depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED + range 1 5 + default 5 + help + Set this option to set the upper limit for number of periodic advertiser list. + +config BT_LE_POWER_CONTROL_ENABLED + bool "Enable controller support for BLE Power Control" + depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED + default n + help + Set this option to enable the Power Control feature on controller + +menu "Memory Settings" + depends on !BT_NIMBLE_ENABLED + + config BT_LE_MSYS_1_BLOCK_COUNT + int "MSYS_1 Block Count" + default 12 + help + MSYS is a system level mbuf registry. For prepare write & prepare + responses MBUFs are allocated out of msys_1 pool. For NIMBLE_MESH + enabled cases, this block count is increased by 8 than user defined + count. + + config BT_LE_MSYS_1_BLOCK_SIZE + int "MSYS_1 Block Size" + default 256 + help + Dynamic memory size of block 1 + + config BT_LE_MSYS_2_BLOCK_COUNT + int "MSYS_2 Block Count" + default 24 + help + Dynamic memory count + + config BT_LE_MSYS_2_BLOCK_SIZE + int "MSYS_2 Block Size" + default 320 + help + Dynamic memory size of block 2 + + config BT_LE_ACL_BUF_COUNT + int "ACL Buffer count" + default 10 + help + The number of ACL data buffers. + + config BT_LE_ACL_BUF_SIZE + int "ACL Buffer size" + default 517 + help + This is the maximum size of the data portion of HCI ACL data packets. + It does not include the HCI data header (of 4 bytes) + + config BT_LE_HCI_EVT_BUF_SIZE + int "HCI Event Buffer size" + default 257 if BT_LE_EXT_ADV + default 70 + help + This is the size of each HCI event buffer in bytes. In case of + extended advertising, packets can be fragmented. 257 bytes is the + maximum size of a packet. + + config BT_LE_HCI_EVT_HI_BUF_COUNT + int "High Priority HCI Event Buffer count" + default 30 + help + This is the high priority HCI events' buffer size. High-priority + event buffers are for everything except advertising reports. If there + are no free high-priority event buffers then host will try to allocate a + low-priority buffer instead + + config BT_LE_HCI_EVT_LO_BUF_COUNT + int "Low Priority HCI Event Buffer count" + default 8 + help + This is the low priority HCI events' buffer size. Low-priority event + buffers are only used for advertising reports. If there are no free + low-priority event buffers, then an incoming advertising report will + get dropped +endmenu + +config BT_LE_CONTROLLER_TASK_STACK_SIZE + int "Controller task stack size" + default 5120 if BLE_MESH + default 4096 + help + This configures stack size of NimBLE controller task + +menuconfig BT_LE_CONTROLLER_LOG_ENABLED + bool "Controller log enable" + default n + help + Enable controller log + +config BT_LE_CONTROLLER_LOG_CTRL_ENABLED + bool "enable controller log module" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Enable controller log module + +config BT_LE_CONTROLLER_LOG_HCI_ENABLED + bool "enable HCI log module" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Enable hci log module + +config BT_LE_CONTROLLER_LOG_DUMP_ONLY + bool "Controller log dump mode only" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Only operate in dump mode + +config BT_LE_LOG_CTRL_BUF1_SIZE + int "size of the first BLE controller LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 4096 + help + Configure the size of the first BLE controller LOG buffer. + +config BT_LE_LOG_CTRL_BUF2_SIZE + int "size of the second BLE controller LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 1024 + help + Configure the size of the second BLE controller LOG buffer. + +config BT_LE_LOG_HCI_BUF_SIZE + int "size of the BLE HCI LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 4096 + help + Configure the size of the BLE HCI LOG buffer. + +config BT_LE_LL_RESOLV_LIST_SIZE + int "BLE LL Resolving list size" + range 1 5 + default 4 + help + Configure the size of resolving list used in link layer. + +menuconfig BT_LE_SECURITY_ENABLE + bool "Enable BLE SM feature" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable BLE sm feature + +config BT_LE_SM_LEGACY + bool "Security manager legacy pairing" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable security manager legacy pairing + +config BT_LE_SM_SC + bool "Security manager secure connections (4.2)" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable security manager secure connections + +config BT_LE_SM_SC_DEBUG_KEYS + bool "Use predefined public-private key pair" + default n + depends on BT_LE_SECURITY_ENABLE && BT_LE_SM_SC + help + If this option is enabled, SM uses predefined DH key pair as described + in Core Specification, Vol. 3, Part H, 2.3.5.6.1. This allows to + decrypt air traffic easily and thus should only be used for debugging. + +config BT_LE_LL_CFG_FEAT_LE_ENCRYPTION + bool "Enable LE encryption" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable encryption connection + +config BT_LE_CRYPTO_STACK_MBEDTLS + bool "Override TinyCrypt with mbedTLS for crypto computations" + default y + depends on !BT_NIMBLE_ENABLED + select MBEDTLS_ECP_RESTARTABLE + select MBEDTLS_CMAC_C + help + Enable this option to choose mbedTLS instead of TinyCrypt for crypto + computations. + +config BT_LE_WHITELIST_SIZE + int "BLE white list size" + range 1 15 + default 12 + depends on !BT_NIMBLE_ENABLED + + help + BLE list size + +config BT_LE_LL_DUP_SCAN_LIST_COUNT + int "BLE duplicate scan list count" + range 5 100 + default 20 + help + config the max count of duplicate scan list + +config BT_LE_LL_SCA + int "BLE Sleep clock accuracy" + range 0 500 + default 60 + help + Sleep clock accuracy of our device (in ppm) + +config BT_LE_MAX_CONNECTIONS + int "Maximum number of concurrent connections" + depends on !BT_NIMBLE_ENABLED + range 1 35 + default 3 + help + Defines maximum number of concurrent BLE connections. For ESP32, user + is expected to configure BTDM_CTRL_BLE_MAX_CONN from controller menu + along with this option. Similarly for ESP32-C3 or ESP32-S3, user is expected to + configure BT_CTRL_BLE_MAX_ACT from controller menu. + Each connection will take about 1k DRAM. + +choice BT_LE_COEX_PHY_CODED_TX_RX_TLIM + prompt "Coexistence: limit on MAX Tx/Rx time for coded-PHY connection" + default BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + depends on ESP_COEX_SW_COEXIST_ENABLE + help + When using PHY-Coded in BLE connection, limitation on max tx/rx time can be applied to + better avoid dramatic performance deterioration of Wi-Fi. + + config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EN + bool "Force Enable" + help + Always enable the limitation on max tx/rx time for Coded-PHY connection + + config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + bool "Force Disable" + help + Disable the limitation on max tx/rx time for Coded-PHY connection +endchoice + +config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF + int + default 0 if !ESP_COEX_SW_COEXIST_ENABLE + default 1 if BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EN + default 0 if BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + +config BT_LE_SLEEP_ENABLE + bool "Enable BLE sleep" + default n + help + Enable BLE sleep + +choice BT_LE_LP_CLK_SRC + prompt "BLE low power clock source" + default BT_LE_LP_CLK_SRC_MAIN_XTAL + config BT_LE_LP_CLK_SRC_MAIN_XTAL + bool "Use main XTAL as RTC clock source" + help + User main XTAL as RTC clock source. + This option is recommended if external 32.768k XTAL is not available. + Using the external 32.768 kHz XTAL will have lower current consumption + in light sleep compared to using the main XTAL. + + config BT_LE_LP_CLK_SRC_DEFAULT + bool "Use system RTC slow clock source" + help + Use the same slow clock source as system RTC + Using any clock source other than external 32.768 kHz XTAL supports only + legacy ADV and SCAN due to low clock accuracy. + +endchoice + +config BT_LE_USE_ESP_TIMER + bool "Enable Esp Timer for Callout" + depends on !BT_NIMBLE_ENABLED + default y + help + Set this option to use Esp Timer which has higher priority timer + instead of FreeRTOS timer + +config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + bool "BLE adv report flow control supported" + default y + help + The function is mainly used to enable flow control for advertising reports. When it is enabled, + advertising reports will be discarded by the controller if the number of unprocessed advertising + reports exceeds the size of BLE adv report flow control. + +config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM + int "BLE adv report flow control number" + depends on BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 50 1000 + default 100 + help + The number of unprocessed advertising report that bluetooth host can save.If you set + `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a small value, this may cause adv packets lost. + If you set `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a large value, bluetooth host may cache a + lot of adv packets and this may cause system memory run out. For example, if you set + it to 50, the maximum memory consumed by host is 35 * 50 bytes. Please set + `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` according to your system free memory and handle adv + packets as fast as possible, otherwise it will cause adv packets lost. + +config BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD + int "BLE adv lost event threshold value" + depends on BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 1 1000 + default 20 + help + When adv report flow control is enabled, The ADV lost event will be generated when the number + of ADV packets lost in the controller reaches this threshold. It is better to set a larger value. + If you set `BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it + may cause adv packets lost more. + +config BT_LE_SCAN_DUPL + bool "BLE Scan Duplicate Options" + default y + help + This select enables parameters setting of BLE scan duplicate. + +choice BT_LE_SCAN_DUPL_TYPE + prompt "Scan Duplicate Type" + default BT_LE_SCAN_DUPL_TYPE_DEVICE + depends on BT_LE_SCAN_DUPL + help + Scan duplicate have three ways. one is "Scan Duplicate By Device Address", This way is to use + advertiser address filtering. The adv packet of the same address is only allowed to be reported once. + Another way is "Scan Duplicate By Device Address And Advertising Data". This way is to use advertising + data and device address filtering. All different adv packets with the same address are allowed to be + reported. The last way is "Scan Duplicate By Advertising Data". This way is to use advertising data + filtering. All same advertising data only allow to be reported once even though they are from + different devices. + + config BT_LE_SCAN_DUPL_TYPE_DEVICE + bool "Scan Duplicate By Device Address" + help + This way is to use advertiser address filtering. The adv packet of the same address is only + allowed to be reported once + + config BT_LE_SCAN_DUPL_TYPE_DATA + bool "Scan Duplicate By Advertising Data" + help + This way is to use advertising data filtering. All same advertising data only allow to be reported + once even though they are from different devices. + + config BT_LE_SCAN_DUPL_TYPE_DATA_DEVICE + bool "Scan Duplicate By Device Address And Advertising Data" + help + This way is to use advertising data and device address filtering. All different adv packets with + the same address are allowed to be reported. +endchoice + +config BT_LE_SCAN_DUPL_TYPE + int + depends on BT_LE_SCAN_DUPL + default 0 if BT_LE_SCAN_DUPL_TYPE_DEVICE + default 1 if BT_LE_SCAN_DUPL_TYPE_DATA + default 2 if BT_LE_SCAN_DUPL_TYPE_DATA_DEVICE + default 0 + +config BT_LE_SCAN_DUPL_CACHE_REFRESH_PERIOD + int "Duplicate scan list refresh period (seconds)" + depends on BT_LE_SCAN_DUPL + range 0 1000 + default 0 + help + If the period value is non-zero, the controller will periodically clear the device information + stored in the scan duuplicate filter. If it is 0, the scan duuplicate filter will not be cleared + until the scanning is disabled. Duplicate advertisements for this period should not be sent to the + Host in advertising report events. + There are two scenarios where the ADV packet will be repeatedly reported: + 1. The duplicate scan cache is full, the controller will delete the oldest device information and + add new device information. + 2. When the refresh period is up, the controller will clear all device information and start filtering + again. + +config BT_LE_MSYS_INIT_IN_CONTROLLER + bool + default y diff --git a/lib/bt/controller/esp32h2/bt.c b/lib/bt/controller/esp32h2/bt.c new file mode 100644 index 00000000..183799c4 --- /dev/null +++ b/lib/bt/controller/esp32h2/bt.c @@ -0,0 +1,1385 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "esp_random.h" +#include "esp_heap_caps.h" +#include "esp_heap_caps_init.h" +#include "esp_mac.h" + +#include "sdkconfig.h" + +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "esp_private/esp_modem_clock.h" + +#ifdef ESP_PLATFORM +#include "esp_log.h" +#endif // ESP_PLATFORM + +#if CONFIG_SW_COEXIST_ENABLE +#include "private/esp_coexist_internal.h" +#endif // CONFIG_SW_COEXIST_ENABLE + +#include "nimble/nimble_npl_os.h" +#include "nimble/ble_hci_trans.h" +#include "os/endian.h" + +#include "esp_bt.h" +#include "esp_intr_alloc.h" +#include "esp_sleep.h" +#include "esp_pm.h" +#include "esp_phy_init.h" +#include "esp_private/periph_ctrl.h" +#include "hci_uart.h" +#include "bt_osi_mem.h" + +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +#include "esp_private/sleep_modem.h" +#include "esp_private/sleep_retention.h" +#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +#include "hci/hci_hal.h" +#endif // CONFIG_BT_BLUEDROID_ENABLED + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_private/periph_ctrl.h" +#include "esp_sleep.h" +#include "soc/rtc.h" +/* Macro definition + ************************************************************************ + */ +#define NIMBLE_PORT_LOG_TAG "BLE_INIT" +#define OSI_COEX_VERSION 0x00010006 +#define OSI_COEX_MAGIC_VALUE 0xFADEBEAD + +#define EXT_FUNC_VERSION 0x20221122 +#define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5 + +#define BT_ASSERT_PRINT ets_printf + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +/* ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data */ +#define ACL_DATA_MBUF_LEADINGSPCAE 4 +#endif // CONFIG_BT_BLUEDROID_ENABLED + +/* Types definition + ************************************************************************ + */ +struct osi_coex_funcs_t { + uint32_t _magic; + uint32_t _version; + 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); +}; + +struct ext_funcs_t { + uint32_t ext_version; + int (*_esp_intr_alloc)(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle); + int (*_esp_intr_free)(void **ret_handle); + void *(* _malloc)(size_t size); + void (*_free)(void *p); + void (*_hal_uart_start_tx)(int); + int (*_hal_uart_init_cbs)(int, hci_uart_tx_char, hci_uart_tx_done, hci_uart_rx_char, void *); + int (*_hal_uart_config)(int, int32_t, uint8_t, uint8_t, uart_parity_t, uart_hw_flowcontrol_t); + int (*_hal_uart_close)(int); + void (*_hal_uart_blocking_tx)(int, uint8_t); + int (*_hal_uart_init)(int, void *); + 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); + void (*_osi_assert)(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2); + uint32_t (* _os_random)(void); + int (* _ecc_gen_key_pair)(uint8_t *public, uint8_t *priv); + int (* _ecc_gen_dh_key)(const uint8_t *remote_pub_key_x, const uint8_t *remote_pub_key_y, + const uint8_t *local_priv_key, uint8_t *dhkey); + void (* _esp_reset_rpa_moudle)(void); + uint32_t magic; +}; + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +typedef void (*interface_func_t) (uint32_t len, const uint8_t*addr, bool end); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +/* External functions or variables + ************************************************************************ + */ +extern int ble_osi_coex_funcs_register(struct osi_coex_funcs_t *coex_funcs); +extern int ble_controller_init(esp_bt_controller_config_t *cfg); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +extern int r_ble_log_init_async(interface_func_t bt_controller_log_interface, bool task_create, uint8_t buffers, uint32_t *bufs_size); +extern int r_ble_log_deinit_async(void); +extern void r_ble_log_async_select_dump_buffers(uint8_t buffers); +extern void r_ble_log_async_output_dump_all(bool output); +extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +extern int ble_controller_deinit(void); +extern int ble_controller_enable(uint8_t mode); +extern int ble_controller_disable(void); +extern int esp_register_ext_funcs (struct ext_funcs_t *); +extern void esp_unregister_ext_funcs (void); +extern int esp_ble_ll_set_public_addr(const uint8_t *addr); +extern int esp_register_npl_funcs (struct npl_funcs_t *p_npl_func); +extern void esp_unregister_npl_funcs (void); +extern void npl_freertos_mempool_deinit(void); +extern uint32_t r_os_cputime_get32(void); +extern uint32_t r_os_cputime_ticks_to_usecs(uint32_t ticks); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +extern const sleep_retention_entries_config_t *esp_ble_mac_retention_link_get(uint8_t *size, uint8_t extra); +extern void esp_ble_set_wakeup_overhead(uint32_t overhead); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ +extern void esp_ble_change_rtc_freq(uint32_t freq); +extern void r_ble_lll_rfmgmt_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, + void *w_arg, uint32_t us_to_enabled); +extern void r_ble_rtc_wake_up_state_clr(void); +extern int os_msys_init(void); +extern void os_msys_deinit(void); +extern int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, + const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey); +extern int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); +extern int ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); +extern int ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); +extern int ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); +extern char *ble_controller_get_compile_version(void); +extern uint32_t _bt_bss_start; +extern uint32_t _bt_bss_end; +extern uint32_t _bt_controller_bss_start; +extern uint32_t _bt_controller_bss_end; +extern uint32_t _bt_data_start; +extern uint32_t _bt_data_end; +extern uint32_t _bt_controller_data_start; +extern uint32_t _bt_controller_data_end; + +/* Local Function Declaration + ********************************************************************* + */ +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 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); +#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static void hci_uart_start_tx_wrapper(int uart_no); +static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, + hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg); +static int hci_uart_config_wrapper(int uart_no, int32_t speed, uint8_t databits, uint8_t stopbits, + uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl); +static int hci_uart_close_wrapper(int uart_no); +static void hci_uart_blocking_tx_wrapper(int port, uint8_t data); +static int hci_uart_init_wrapper(int uart_no, void *cfg); +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, + void *arg, void **ret_handle_in); +static int esp_intr_free_wrapper(void **ret_handle); +static void osi_assert_wrapper(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2); +static uint32_t osi_random_wrapper(void); +static void esp_reset_rpa_moudle(void); +static int esp_ecc_gen_key_pair(uint8_t *pub, uint8_t *priv); +static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +/* Local variable definition + *************************************************************************** + */ +/* Static variable declare */ +static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +/* This variable tells if BLE is running */ +static bool s_ble_active = false; +#ifdef CONFIG_PM_ENABLE +static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock = NULL; +#define BTDM_MIN_TIMER_UNCERTAINTY_US (200) +#endif // CONFIG_PM_ENABLE + +#define BLE_RTC_DELAY_US_LIGHT_SLEEP (5100) +#define BLE_RTC_DELAY_US_MODEM_SLEEP (1500) + +static const struct osi_coex_funcs_t s_osi_coex_funcs_ro = { + ._magic = OSI_COEX_MAGIC_VALUE, + ._version = OSI_COEX_VERSION, + ._coex_wifi_sleep_set = NULL, + ._coex_core_ble_conn_dyn_prio_get = NULL, + ._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper, + ._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper, +}; + +struct ext_funcs_t ext_funcs_ro = { + .ext_version = EXT_FUNC_VERSION, + ._esp_intr_alloc = esp_intr_alloc_wrapper, + ._esp_intr_free = esp_intr_free_wrapper, + ._malloc = bt_osi_mem_malloc_internal, + ._free = bt_osi_mem_free, +#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART + ._hal_uart_start_tx = hci_uart_start_tx_wrapper, + ._hal_uart_init_cbs = hci_uart_init_cbs_wrapper, + ._hal_uart_config = hci_uart_config_wrapper, + ._hal_uart_close = hci_uart_close_wrapper, + ._hal_uart_blocking_tx = hci_uart_blocking_tx_wrapper, + ._hal_uart_init = hci_uart_init_wrapper, +#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART + ._task_create = task_create_wrapper, + ._task_delete = task_delete_wrapper, + ._osi_assert = osi_assert_wrapper, + ._os_random = osi_random_wrapper, + ._ecc_gen_key_pair = esp_ecc_gen_key_pair, + ._ecc_gen_dh_key = esp_ecc_gen_dh_key, + ._esp_reset_rpa_moudle = esp_reset_rpa_moudle, + .magic = EXT_FUNC_MAGIC_VALUE, +}; + +static void IRAM_ATTR esp_reset_rpa_moudle(void) +{ + +} + +static void IRAM_ATTR osi_assert_wrapper(const uint32_t ln, const char *fn, + uint32_t param1, uint32_t param2) +{ + BT_ASSERT_PRINT("BLE assert: line %d in function %s, param: 0x%x, 0x%x", ln, fn, param1, param2); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + esp_ble_controller_log_dump_all(true); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + assert(0); +} + +static uint32_t IRAM_ATTR osi_random_wrapper(void) +{ + return esp_random(); +} + +static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_set(type, status); +#endif // CONFIG_SW_COEXIST_ENABLE +} + +static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_clear(type, status); +#endif // CONFIG_SW_COEXIST_ENABLE +} + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +bool esp_vhci_host_check_send_available(void) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return false; + } + return true; +} + +static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space) +{ + struct os_mbuf *om; + int rc; + + om = os_msys_get_pkthdr(0, 0); + if (om == NULL) { + return NULL; + } + + if (om->om_omp->omp_databuf_len < leading_space) { + rc = os_mbuf_free_chain(om); + assert(rc == 0); + return NULL; + } + + om->om_data += leading_space; + + return om; +} + +struct os_mbuf *ble_hs_mbuf_acl_pkt(void) +{ + return ble_hs_mbuf_gen_pkt(4 + 1); +} + +void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return; + } + + if (*(data) == DATA_TYPE_COMMAND) { + struct ble_hci_cmd *cmd = NULL; + cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + assert(cmd); + memcpy((uint8_t *)cmd, data + 1, len - 1); + ble_hci_trans_hs_cmd_tx((uint8_t *)cmd); + } + + if (*(data) == DATA_TYPE_ACL) { + struct os_mbuf *om = os_msys_get_pkthdr(len, ACL_DATA_MBUF_LEADINGSPCAE); + assert(om); + assert(os_mbuf_append(om, &data[1], len - 1) == 0); + ble_hci_trans_hs_acl_tx(om); + } +} + +esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_FAIL; + } + + ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL); + + return ESP_OK; +} +#endif // CONFIG_BT_BLUEDROID_ENABLED + +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 (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, + (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); +} + +static void task_delete_wrapper(void *task_handle) +{ + vTaskDelete(task_handle); +} + +static int esp_ecc_gen_key_pair(uint8_t *pub, uint8_t *priv) +{ + int rc = -1; +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + rc = ble_sm_alg_gen_key_pair(pub, priv); +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + return rc; +} + +static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey) +{ + int rc = -1; +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + rc = ble_sm_alg_gen_dhkey(peer_pub_key_x, peer_pub_key_y, our_priv_key, out_dhkey); +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + return rc; +} + +#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static void hci_uart_start_tx_wrapper(int uart_no) +{ + hci_uart_start_tx(uart_no); +} + +static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, + hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg) +{ + int rc = -1; + rc = hci_uart_init_cbs(uart_no, tx_func, tx_done, rx_func, arg); + return rc; +} + + +static int hci_uart_config_wrapper(int port_num, int32_t baud_rate, uint8_t data_bits, + uint8_t stop_bits, uart_parity_t parity, + uart_hw_flowcontrol_t flow_ctl) +{ + int rc = -1; + rc = hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl); + return rc; +} + +static int hci_uart_close_wrapper(int uart_no) +{ + int rc = -1; + rc = hci_uart_close(uart_no); + return rc; +} + +static void hci_uart_blocking_tx_wrapper(int port, uint8_t data) +{ + //This function is nowhere to use. +} + +static int hci_uart_init_wrapper(int uart_no, void *cfg) +{ + //This function is nowhere to use. + return 0; +} + +#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART + +static int ble_hci_unregistered_hook(void*, void*) +{ + ESP_LOGD(NIMBLE_PORT_LOG_TAG,"%s ble hci rx_evt is not registered.",__func__); + return 0; +} + +static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, + void *arg, void **ret_handle_in) +{ + int rc = esp_intr_alloc(source, flags | ESP_INTR_FLAG_IRAM, handler, + arg, (intr_handle_t *)ret_handle_in); + return rc; +} + +static int esp_intr_free_wrapper(void **ret_handle) +{ + int rc = 0; + rc = esp_intr_free((intr_handle_t) * ret_handle); + *ret_handle = NULL; + return rc; +} + +void esp_bt_rtc_slow_clk_select(uint8_t slow_clk_src) +{ + /* Select slow clock source for BT momdule */ + switch (slow_clk_src) { + case MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using main XTAL as clock source"); + modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (320 - 1)); + break; + case MODEM_CLOCK_LPCLK_SRC_RC_SLOW: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using 136 kHz RC as clock source, can only run legacy ADV or SCAN due to low clock accuracy!"); + modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (5 - 1)); + break; + case MODEM_CLOCK_LPCLK_SRC_XTAL32K: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using external 32.768 kHz XTAL as clock source"); + modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (1 - 1)); + break; + case MODEM_CLOCK_LPCLK_SRC_RC32K: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using 32 kHz RC as clock source, can only run legacy ADV or SCAN due to low clock accuracy!"); + modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (1 - 1)); + break; + case MODEM_CLOCK_LPCLK_SRC_EXT32K: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using 32 kHz oscillator as clock source, can only run legacy ADV or SCAN due to low clock accuracy!"); + modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (1 - 1)); + break; + default: + } +} + +IRAM_ATTR void controller_sleep_cb(uint32_t enable_tick, void *arg) +{ + if (!s_ble_active) { + return; + } +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + r_ble_rtc_wake_up_state_clr(); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + esp_phy_disable(PHY_MODEM_BT); +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + s_ble_active = false; +} + +IRAM_ATTR void controller_wakeup_cb(void *arg) +{ + if (s_ble_active) { + return; + } +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_acquire(s_pm_lock); + r_ble_rtc_wake_up_state_clr(); +#endif //CONFIG_PM_ENABLE + esp_phy_enable(PHY_MODEM_BT); + s_ble_active = true; +} + +#ifdef CONFIG_FREERTOS_USE_TICKLESS_IDLE +static esp_err_t sleep_modem_ble_mac_modem_state_init(uint8_t extra) +{ + uint8_t size; + const sleep_retention_entries_config_t *ble_mac_modem_config = esp_ble_mac_retention_link_get(&size, extra); + esp_err_t err = sleep_retention_entries_create(ble_mac_modem_config, size, REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_BLE_MAC); + if (err == ESP_OK) { + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Modem BLE MAC retention initialization"); + } + return err; +} + +static void sleep_modem_ble_mac_modem_state_deinit(void) +{ + sleep_retention_entries_destroy(SLEEP_RETENTION_MODULE_BLE_MAC); +} + +void sleep_modem_light_sleep_overhead_set(uint32_t overhead) +{ + esp_ble_set_wakeup_overhead(overhead); +} +#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE + +esp_err_t controller_sleep_init(void) +{ + esp_err_t rc = 0; + +#ifdef CONFIG_BT_LE_SLEEP_ENABLE + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "BLE modem sleep is enabled"); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + BLE_RTC_DELAY_US_LIGHT_SLEEP); +#else + r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + BLE_RTC_DELAY_US_MODEM_SLEEP); +#endif /* FREERTOS_USE_TICKLESS_IDLE */ +#endif // CONFIG_BT_LE_SLEEP_ENABLE + +#ifdef CONFIG_PM_ENABLE + rc = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "bt", &s_pm_lock); + if (rc != ESP_OK) { + goto error; + } +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + /* Create a new regdma link for BLE related register restoration */ + rc = sleep_modem_ble_mac_modem_state_init(0); + assert(rc == 0); + esp_sleep_enable_bt_wakeup(); + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "Enable light sleep, the wake up source is BLE timer"); + + rc = esp_pm_register_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); + if (rc != ESP_OK) { + goto error; + } +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + return rc; + +error: + +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + esp_sleep_disable_bt_wakeup(); + esp_pm_unregister_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + /*lock should release first and then delete*/ + if (s_pm_lock != NULL) { + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; + } +#endif // CONFIG_PM_ENABLE + + return rc; +} + +void controller_sleep_deinit(void) +{ +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + r_ble_rtc_wake_up_state_clr(); + esp_sleep_disable_bt_wakeup(); + sleep_modem_ble_mac_modem_state_deinit(); + esp_pm_unregister_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ +#ifdef CONFIG_PM_ENABLE + /* lock should be released first */ + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; +#endif //CONFIG_PM_ENABLE +} + +typedef enum { + FILTER_DUPLICATE_PDUTYPE = BIT(0), + FILTER_DUPLICATE_LENGTH = BIT(1), + FILTER_DUPLICATE_ADDRESS = BIT(2), + FILTER_DUPLICATE_ADVDATA = BIT(3), + FILTER_DUPLICATE_DEFAULT = FILTER_DUPLICATE_PDUTYPE | FILTER_DUPLICATE_ADDRESS, + FILTER_DUPLICATE_PDU_ALL = 0xF, + FILTER_DUPLICATE_EXCEPTION_FOR_MESH = BIT(4), + FILTER_DUPLICATE_AD_TYPE = BIT(5), +}disc_duplicate_mode_t; + + +extern void r_filter_duplicate_mode_enable(disc_duplicate_mode_t mode); +extern void r_filter_duplicate_mode_disable(disc_duplicate_mode_t mode); +extern void r_filter_duplicate_set_ring_list_max_num(uint32_t max_num); +extern void r_scan_duplicate_cache_refresh_set_time(uint32_t period_time); + +int +ble_vhci_disc_duplicate_mode_enable(int mode) +{ + // TODO: use vendor hci to update + r_filter_duplicate_mode_enable(mode); + return true; +} + +int +ble_vhci_disc_duplicate_mode_disable(int mode) +{ + // TODO: use vendor hci to update + r_filter_duplicate_mode_disable(mode); + return true; +} + +int ble_vhci_disc_duplicate_set_max_cache_size(int max_cache_size){ + // TODO: use vendor hci to update + r_filter_duplicate_set_ring_list_max_num(max_cache_size); + return true; +} + +int ble_vhci_disc_duplicate_set_period_refresh_time(int refresh_period_time){ + // TODO: use vendor hci to update + r_scan_duplicate_cache_refresh_set_time(refresh_period_time); + return true; +} + +/** + * @brief Config scan duplicate option mode from menuconfig (Adapt to the old configuration method.) + */ +void ble_controller_scan_duplicate_config(void) +{ + uint32_t duplicate_mode = FILTER_DUPLICATE_DEFAULT; + uint32_t cache_size = 100; +#if CONFIG_BT_LE_SCAN_DUPL == true + cache_size = CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT; + if (CONFIG_BT_LE_SCAN_DUPL_TYPE == 0) { + duplicate_mode = FILTER_DUPLICATE_ADDRESS | FILTER_DUPLICATE_PDUTYPE; + } else if (CONFIG_BT_LE_SCAN_DUPL_TYPE == 1) { + duplicate_mode = FILTER_DUPLICATE_ADVDATA; + } else if (CONFIG_BT_LE_SCAN_DUPL_TYPE == 2) { + duplicate_mode = FILTER_DUPLICATE_ADDRESS | FILTER_DUPLICATE_ADVDATA; + } + duplicate_mode |= FILTER_DUPLICATE_EXCEPTION_FOR_MESH; + + ble_vhci_disc_duplicate_set_period_refresh_time(CONFIG_BT_LE_SCAN_DUPL_CACHE_REFRESH_PERIOD); +#endif + + ble_vhci_disc_duplicate_mode_disable(0xFFFFFFFF); + ble_vhci_disc_duplicate_mode_enable(duplicate_mode); + ble_vhci_disc_duplicate_set_max_cache_size(cache_size); +} + +esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) +{ + uint8_t mac[6]; + esp_err_t ret = ESP_OK; + ble_npl_count_info_t npl_info; + uint32_t slow_clk_freq = 0; + + memset(&npl_info, 0, sizeof(ble_npl_count_info_t)); + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_ERR_INVALID_STATE; + } + + if (!cfg) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "cfg is NULL"); + return ESP_ERR_INVALID_ARG; + } + + ret = esp_register_ext_funcs(&ext_funcs_ro); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "register extend functions failed"); + return ret; + } + + /* Initialize the function pointers for OS porting */ + npl_freertos_funcs_init(); + struct npl_funcs_t *p_npl_funcs = npl_freertos_funcs_get(); + if (!p_npl_funcs) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl functions get failed"); + return ESP_ERR_INVALID_ARG; + } + + ret = esp_register_npl_funcs(p_npl_funcs); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl functions register failed"); + goto free_mem; + } + + ble_get_npl_element_info(cfg, &npl_info); + npl_freertos_set_controller_npl_info(&npl_info); + if (npl_freertos_mempool_init() != 0) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl mempool init failed"); + ret = ESP_ERR_INVALID_ARG; + goto free_mem; + } + +#if CONFIG_BT_NIMBLE_ENABLED + /* ble_npl_eventq_init() needs to use npl functions in rom and + * must be called after esp_bt_controller_init(). + */ + ble_npl_eventq_init(nimble_port_get_dflt_eventq()); +#endif // CONFIG_BT_NIMBLE_ENABLED + + /* Enable BT-related clocks */ + modem_clock_module_enable(PERIPH_BT_MODULE); + modem_clock_module_mac_reset(PERIPH_BT_MODULE); +#if CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL); + slow_clk_freq = 100000; +#else +#if CONFIG_RTC_CLK_SRC_INT_RC + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_RC_SLOW); + slow_clk_freq = 30000; +#elif CONFIG_RTC_CLK_SRC_EXT_CRYS + if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_XTAL32K); + slow_clk_freq = 32768; + } else { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock"); + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL); + slow_clk_freq = 100000; + } +#elif CONFIG_RTC_CLK_SRC_INT_RC32K + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_RC32K); + slow_clk_freq = 32000; +#elif CONFIG_RTC_CLK_SRC_EXT_OSC + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_EXT32K); + slow_clk_freq = 32000; +#else + ESP_LOGE(NIMBLE_PORT_LOG_TAG, "Unsupported clock source"); + assert(0); +#endif +#endif /* CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL */ + + if (ble_osi_coex_funcs_register((struct osi_coex_funcs_t *)&s_osi_coex_funcs_ro) != 0) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "osi coex funcs reg failed"); + ret = ESP_ERR_INVALID_ARG; + goto modem_deint; + } + +#if CONFIG_SW_COEXIST_ENABLE + coex_init(); +#endif // CONFIG_SW_COEXIST_ENABLE + + ret = ble_controller_init(cfg); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_init failed %d", ret); + goto modem_deint; + } + + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + interface_func_t bt_controller_log_interface; + bt_controller_log_interface = esp_bt_controller_log_interface; + uint8_t buffers = 0; +#if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED + buffers |= ESP_BLE_LOG_BUF_CONTROLLER; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED +#if CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED + buffers |= ESP_BLE_LOG_BUF_HCI; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED +#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY + ret = r_ble_log_init_async(bt_controller_log_interface, false, buffers, (uint32_t *)log_bufs_size); +#else + ret = r_ble_log_init_async(bt_controller_log_interface, true, buffers, (uint32_t *)log_bufs_size); +#endif // CONFIG_BT_CONTROLLER_LOG_DUMP + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); + goto controller_init_err; + } +#endif // CONFIG_BT_CONTROLLER_LOG_ENABLED + + esp_ble_change_rtc_freq(slow_clk_freq); + + ble_controller_scan_duplicate_config(); + + ret = os_msys_init(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "msys_init failed %d", ret); + goto free_controller; + } + + ret = controller_sleep_init(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "controller_sleep_init failed %d", ret); + goto free_controller; + } + + ESP_ERROR_CHECK(esp_read_mac((uint8_t *)mac, ESP_MAC_BT)); + swap_in_place(mac, 6); + esp_ble_ll_set_public_addr(mac); + + ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + + ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hci_unregistered_hook,NULL, + (ble_hci_trans_rx_acl_fn *)ble_hci_unregistered_hook,NULL); + return ESP_OK; + +free_controller: + controller_sleep_deinit(); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +controller_init_err: + r_ble_log_deinit_async(); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + os_msys_deinit(); + ble_controller_deinit(); +modem_deint: + modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); + modem_clock_module_disable(PERIPH_BT_MODULE); +#if CONFIG_BT_NIMBLE_ENABLED + ble_npl_eventq_deinit(nimble_port_get_dflt_eventq()); +#endif // CONFIG_BT_NIMBLE_ENABLED +free_mem: + npl_freertos_mempool_deinit(); + esp_unregister_npl_funcs(); + npl_freertos_funcs_deinit(); + esp_unregister_ext_funcs(); + return ret; +} + +esp_err_t esp_bt_controller_deinit(void) +{ + if ((ble_controller_status < ESP_BT_CONTROLLER_STATUS_INITED) || + (ble_controller_status >= ESP_BT_CONTROLLER_STATUS_ENABLED)) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + + controller_sleep_deinit(); + + os_msys_deinit(); + + modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); + modem_clock_module_disable(PERIPH_BT_MODULE); + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + r_ble_log_deinit_async(); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + ble_controller_deinit(); + +#if CONFIG_BT_NIMBLE_ENABLED + /* De-initialize default event queue */ + ble_npl_eventq_deinit(nimble_port_get_dflt_eventq()); +#endif // CONFIG_BT_NIMBLE_ENABLED + + esp_unregister_npl_funcs(); + + esp_unregister_ext_funcs(); + + /* De-initialize npl functions */ + npl_freertos_funcs_deinit(); + + npl_freertos_mempool_deinit(); + + ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + + return ESP_OK; +} + +esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) +{ + esp_err_t ret = ESP_OK; + + if (mode != ESP_BT_MODE_BLE) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller mode"); + return ESP_FAIL; + } + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + if (!s_ble_active) { +#if CONFIG_PM_ENABLE + esp_pm_lock_acquire(s_pm_lock); +#endif // CONFIG_PM_ENABLE + esp_phy_enable(PHY_MODEM_BT); + s_ble_active = true; + } + esp_btbb_enable(); +#if CONFIG_SW_COEXIST_ENABLE + coex_enable(); +#endif // CONFIG_SW_COEXIST_ENABLE + + if (ble_controller_enable(mode) != 0) { + ret = ESP_FAIL; + goto error; + } + ble_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED; + return ESP_OK; + +error: +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + esp_btbb_disable(); + if (s_ble_active) { + esp_phy_disable(PHY_MODEM_BT); +#if CONFIG_PM_ENABLE + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + s_ble_active = false; + } + return ret; +} + +esp_err_t esp_bt_controller_disable(void) +{ + if (ble_controller_status < ESP_BT_CONTROLLER_STATUS_ENABLED) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + if (ble_controller_disable() != 0) { + return ESP_FAIL; + } +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + esp_btbb_disable(); + if (s_ble_active) { + esp_phy_disable(PHY_MODEM_BT); +#if CONFIG_PM_ENABLE + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + s_ble_active = false; + } + ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + return ESP_OK; +} + +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +{ + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "%s not implemented, return OK", __func__); + return ESP_OK; +} + +static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) +{ + int ret = heap_caps_add_region(start, end); + + /* heap_caps_add_region() returns ESP_ERR_INVALID_SIZE if the memory region is + * is too small to fit a heap. This cannot be termed as a fatal error and hence + * we replace it by ESP_OK + */ + if (ret == ESP_ERR_INVALID_SIZE) { + return ESP_OK; + } + return ret; +} + +esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) +{ + intptr_t mem_start, mem_end; + + if (mode & ESP_BT_MODE_BLE) { + /* If the addresses of btdm .bss and bt .bss are consecutive, + * they are registered in the system heap as a piece of memory + */ + if(_bt_bss_end == _bt_controller_bss_start) { + mem_start = (intptr_t)&_bt_bss_start; + mem_end = (intptr_t)&_bt_controller_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BSS [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } else { + mem_start = (intptr_t)&_bt_bss_start; + mem_end = (intptr_t)&_bt_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + + mem_start = (intptr_t)&_bt_controller_bss_start; + mem_end = (intptr_t)&_bt_controller_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release Controller BSS [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + /* If the addresses of btdm .data and bt .data are consecutive, + * they are registered in the system heap as a piece of memory + */ + if(_bt_data_end == _bt_controller_data_start) { + mem_start = (intptr_t)&_bt_data_start; + mem_end = (intptr_t)&_bt_controller_data_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release data [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } else { + mem_start = (intptr_t)&_bt_data_start; + mem_end = (intptr_t)&_bt_data_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + + mem_start = (intptr_t)&_bt_controller_data_start; + mem_end = (intptr_t)&_bt_controller_data_end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release Controller Data [0x%08x] - [0x%08x], len %d", + mem_start, mem_end, mem_end - mem_start); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + } + } + + return ESP_OK; +} + + +esp_bt_controller_status_t esp_bt_controller_get_status(void) +{ + return ble_controller_status; +} + +esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_t power_level) +{ + esp_err_t stat = ESP_FAIL; + + switch (power_type) { + case ESP_BLE_PWR_TYPE_DEFAULT: + case ESP_BLE_PWR_TYPE_ADV: + case ESP_BLE_PWR_TYPE_SCAN: + if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + stat = ESP_OK; + } + break; + case ESP_BLE_PWR_TYPE_CONN_HDL0: + case ESP_BLE_PWR_TYPE_CONN_HDL1: + case ESP_BLE_PWR_TYPE_CONN_HDL2: + case ESP_BLE_PWR_TYPE_CONN_HDL3: + case ESP_BLE_PWR_TYPE_CONN_HDL4: + case ESP_BLE_PWR_TYPE_CONN_HDL5: + case ESP_BLE_PWR_TYPE_CONN_HDL6: + case ESP_BLE_PWR_TYPE_CONN_HDL7: + case ESP_BLE_PWR_TYPE_CONN_HDL8: + if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { + stat = ESP_OK; + } + break; + default: + stat = ESP_ERR_NOT_SUPPORTED; + break; + } + + return stat; +} + +esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle, + esp_power_level_t power_level) +{ + esp_err_t stat = ESP_FAIL; + switch (power_type) { + case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: + case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: + case ESP_BLE_ENHANCED_PWR_TYPE_INIT: + if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + stat = ESP_OK; + } + break; + case ESP_BLE_ENHANCED_PWR_TYPE_ADV: + case ESP_BLE_ENHANCED_PWR_TYPE_CONN: + if (ble_txpwr_set(power_type, handle, power_level) == 0) { + stat = ESP_OK; + } + break; + default: + stat = ESP_ERR_NOT_SUPPORTED; + break; + } + + return stat; +} + +esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) +{ + int tx_level = 0; + + switch (power_type) { + case ESP_BLE_PWR_TYPE_ADV: + case ESP_BLE_PWR_TYPE_SCAN: + case ESP_BLE_PWR_TYPE_DEFAULT: + tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + break; + case ESP_BLE_PWR_TYPE_CONN_HDL0: + case ESP_BLE_PWR_TYPE_CONN_HDL1: + case ESP_BLE_PWR_TYPE_CONN_HDL2: + case ESP_BLE_PWR_TYPE_CONN_HDL3: + case ESP_BLE_PWR_TYPE_CONN_HDL4: + case ESP_BLE_PWR_TYPE_CONN_HDL5: + case ESP_BLE_PWR_TYPE_CONN_HDL6: + case ESP_BLE_PWR_TYPE_CONN_HDL7: + case ESP_BLE_PWR_TYPE_CONN_HDL8: + tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); + break; + default: + return ESP_PWR_LVL_INVALID; + } + + if (tx_level < 0) { + return ESP_PWR_LVL_INVALID; + } + + return (esp_power_level_t)tx_level; +} + +esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, + uint16_t handle) +{ + int tx_level = 0; + + switch (power_type) { + case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: + case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: + case ESP_BLE_ENHANCED_PWR_TYPE_INIT: + tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + break; + case ESP_BLE_ENHANCED_PWR_TYPE_ADV: + case ESP_BLE_ENHANCED_PWR_TYPE_CONN: + tx_level = ble_txpwr_get(power_type, handle); + break; + default: + return ESP_PWR_LVL_INVALID; + } + + if (tx_level < 0) { + return ESP_PWR_LVL_INVALID; + } + + return (esp_power_level_t)tx_level; +} + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) +{ + for (int i = 0; i < len; i++) { + esp_rom_printf("%02x ", addr[i]); + } + if (end) { + esp_rom_printf("\n"); + } +} + +void esp_ble_controller_log_dump_all(bool output) +{ + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(5000); + BT_ASSERT_PRINT("\r\n[DUMP_START:"); + r_ble_log_async_output_dump_all(output); + BT_ASSERT_PRINT(":DUMP_END]\r\n"); + portEXIT_CRITICAL_SAFE(&spinlock); +} +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +#if (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC +#define BLE_SM_KEY_ERR 0x17 +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS +#include "mbedtls/aes.h" +#if CONFIG_BT_LE_SM_SC +#include "mbedtls/cipher.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/cmac.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/ecp.h" + +static mbedtls_ecp_keypair keypair; +#endif // CONFIG_BT_LE_SM_SC + +#else +#include "tinycrypt/aes.h" +#include "tinycrypt/constants.h" +#include "tinycrypt/utils.h" + +#if CONFIG_BT_LE_SM_SC +#include "tinycrypt/cmac_mode.h" +#include "tinycrypt/ecc_dh.h" +#endif // CONFIG_BT_LE_SM_SC +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + +/* Based on Core Specification 4.2 Vol 3. Part H 2.3.5.6.1 */ +static const uint8_t ble_sm_alg_dbg_priv_key[32] = { + 0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38, 0x74, 0xc9, 0xb3, 0xe3, + 0xd2, 0x10, 0x3f, 0x50, 0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99, + 0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd +}; + +int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey) +{ + uint8_t dh[32]; + uint8_t pk[64]; + uint8_t priv[32]; + int rc = BLE_SM_KEY_ERR; + + swap_buf(pk, peer_pub_key_x, 32); + swap_buf(&pk[32], peer_pub_key_y, 32); + swap_buf(priv, our_priv_key, 32); + +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + struct mbedtls_ecp_point pt = {0}, Q = {0}; + mbedtls_mpi z = {0}, d = {0}; + mbedtls_ctr_drbg_context ctr_drbg = {0}; + mbedtls_entropy_context entropy = {0}; + + uint8_t pub[65] = {0}; + /* Hardcoded first byte of pub key for MBEDTLS_ECP_PF_UNCOMPRESSED */ + pub[0] = 0x04; + memcpy(&pub[1], pk, 64); + + /* Initialize the required structures here */ + mbedtls_ecp_point_init(&pt); + mbedtls_ecp_point_init(&Q); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_entropy_init(&entropy); + mbedtls_mpi_init(&d); + mbedtls_mpi_init(&z); + + /* Below 3 steps are to validate public key on curve secp256r1 */ + if (mbedtls_ecp_group_load(&keypair.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1) != 0) { + goto exit; + } + + if (mbedtls_ecp_point_read_binary(&keypair.MBEDTLS_PRIVATE(grp), &pt, pub, 65) != 0) { + goto exit; + } + + if (mbedtls_ecp_check_pubkey(&keypair.MBEDTLS_PRIVATE(grp), &pt) != 0) { + goto exit; + } + + /* Set PRNG */ + if ((rc = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0)) != 0) { + goto exit; + } + + /* Prepare point Q from pub key */ + if (mbedtls_ecp_point_read_binary(&keypair.MBEDTLS_PRIVATE(grp), &Q, pub, 65) != 0) { + goto exit; + } + + if (mbedtls_mpi_read_binary(&d, priv, 32) != 0) { + goto exit; + } + + rc = mbedtls_ecdh_compute_shared(&keypair.MBEDTLS_PRIVATE(grp), &z, &Q, &d, + mbedtls_ctr_drbg_random, &ctr_drbg); + if (rc != 0) { + goto exit; + } + + rc = mbedtls_mpi_write_binary(&z, dh, 32); + if (rc != 0) { + goto exit; + } + +exit: + mbedtls_ecp_point_free(&pt); + mbedtls_mpi_free(&z); + mbedtls_mpi_free(&d); + mbedtls_ecp_point_free(&Q); + mbedtls_entropy_free(&entropy); + mbedtls_ctr_drbg_free(&ctr_drbg); + if (rc != 0) { + return BLE_SM_KEY_ERR; + } + +#else + if (uECC_valid_public_key(pk, &curve_secp256r1) < 0) { + return BLE_SM_KEY_ERR; + } + + rc = uECC_shared_secret(pk, priv, dh, &curve_secp256r1); + if (rc == TC_CRYPTO_FAIL) { + return BLE_SM_KEY_ERR; + } +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + + swap_buf(out_dhkey, dh, 32); + return 0; +} + +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS +static int mbedtls_gen_keypair(uint8_t *public_key, uint8_t *private_key) +{ + int rc = BLE_SM_KEY_ERR; + mbedtls_entropy_context entropy = {0}; + mbedtls_ctr_drbg_context ctr_drbg = {0}; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_ecp_keypair_init(&keypair); + + if ((rc = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + NULL, 0)) != 0) { + goto exit; + } + + if ((rc = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, &keypair, + mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { + goto exit; + } + + if ((rc = mbedtls_mpi_write_binary(&keypair.MBEDTLS_PRIVATE(d), private_key, 32)) != 0) { + goto exit; + } + + size_t olen = 0; + uint8_t pub[65] = {0}; + + if ((rc = mbedtls_ecp_point_write_binary(&keypair.MBEDTLS_PRIVATE(grp), &keypair.MBEDTLS_PRIVATE(Q), MBEDTLS_ECP_PF_UNCOMPRESSED, + &olen, pub, 65)) != 0) { + goto exit; + } + + memcpy(public_key, &pub[1], 64); + +exit: + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + if (rc != 0) { + mbedtls_ecp_keypair_free(&keypair); + return BLE_SM_KEY_ERR; + } + + return 0; +} +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + +/** + * pub: 64 bytes + * priv: 32 bytes + */ +int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv) +{ +#if CONFIG_BT_LE_SM_SC_DEBUG_KEYS + swap_buf(pub, ble_sm_alg_dbg_pub_key, 32); + swap_buf(&pub[32], &ble_sm_alg_dbg_pub_key[32], 32); + swap_buf(priv, ble_sm_alg_dbg_priv_key, 32); +#else + uint8_t pk[64]; + + do { +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + if (mbedtls_gen_keypair(pk, priv) != 0) { + return BLE_SM_KEY_ERR; + } +#else + if (uECC_make_key(pk, priv, &curve_secp256r1) != TC_CRYPTO_SUCCESS) { + return BLE_SM_KEY_ERR; + } +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + /* Make sure generated key isn't debug key. */ + } while (memcmp(priv, ble_sm_alg_dbg_priv_key, 32) == 0); + + swap_buf(pub, pk, 32); + swap_buf(&pub[32], &pk[32], 32); + swap_in_place(priv, 32); +#endif // CONFIG_BT_LE_SM_SC_DEBUG_KEYS + return 0; +} + +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC +#endif // (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) + diff --git a/lib/bt/controller/esp32h2/esp_bt_cfg.h b/lib/bt/controller/esp32h2/esp_bt_cfg.h new file mode 100644 index 00000000..c0c5801a --- /dev/null +++ b/lib/bt/controller/esp32h2/esp_bt_cfg.h @@ -0,0 +1,220 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ESP_BT_CFG_H__ +#define __ESP_BT_CFG_H__ + +#include <stdint.h> +#include <stdbool.h> +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_BT_NIMBLE_ENABLED +#include "syscfg/syscfg.h" +#endif + +#define NIMBLE_LL_STACK_SIZE CONFIG_BT_LE_CONTROLLER_TASK_STACK_SIZE + +#if CONFIG_BT_NIMBLE_ENABLED + + #if CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_CODED_PHY + #define BLE_LL_SCAN_PHY_NUMBER_N (2) + #else + #define BLE_LL_SCAN_PHY_NUMBER_N (1) + #endif + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST MYNEWT_VAL(BLE_MAX_PERIODIC_ADVERTISER_LIST) + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS) + #define DEFAULT_BT_LE_MAX_CONNECTIONS MYNEWT_VAL(BLE_MAX_CONNECTIONS) + #define DEFAULT_BT_LE_ACL_BUF_SIZE MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE) + #define DEFAULT_BT_LE_ACL_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE) + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE MYNEWT_VAL(BLE_LL_WHITELIST_SIZE) + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT) + #define DEFAULT_BT_LE_POWER_CONTROL_ENABLED MYNEWT_VAL(BLE_POWER_CONTROL) + #if defined(CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT) + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (1) + #else + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) + #endif +#else + + #if CONFIG_BT_LE_LL_CFG_FEAT_LE_CODED_PHY + #define BLE_LL_SCAN_PHY_NUMBER_N (2) + #else + #define BLE_LL_SCAN_PHY_NUMBER_N (1) + #endif + + #if defined(CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST) + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST (CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST) + #else + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST (5) + #endif + + #if defined(CONFIG_BT_LE_MAX_PERIODIC_SYNCS) + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS (CONFIG_BT_LE_MAX_PERIODIC_SYNCS) + #else + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS (1) + #endif + + #if defined(CONFIG_BT_LE_MAX_CONNECTIONS) + #define DEFAULT_BT_LE_MAX_CONNECTIONS (CONFIG_BT_LE_MAX_CONNECTIONS) + #else + #define DEFAULT_BT_LE_MAX_CONNECTIONS (2) + #endif + + #if defined(CONFIG_BT_LE_ACL_BUF_SIZE) + #define DEFAULT_BT_LE_ACL_BUF_SIZE (CONFIG_BT_LE_ACL_BUF_SIZE) + #else + #define DEFAULT_BT_LE_ACL_BUF_SIZE (255) + #endif + + #if defined(CONFIG_BT_LE_ACL_BUF_COUNT) + #define DEFAULT_BT_LE_ACL_BUF_COUNT (CONFIG_BT_LE_ACL_BUF_COUNT) + #else + #define DEFAULT_BT_LE_ACL_BUF_COUNT (24) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_BUF_SIZE) + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE (CONFIG_BT_LE_HCI_EVT_BUF_SIZE) + #else + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE (70) + #endif + + #if defined(CONFIG_BT_LE_EXT_ADV_MAX_SIZE) + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE (CONFIG_BT_LE_EXT_ADV_MAX_SIZE) + #else + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE (31) + #endif + + #if defined(CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES) + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES (CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES) + #else + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES (1) + #endif + + #if defined(CONFIG_BT_LE_WHITELIST_SIZE) + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE (CONFIG_BT_LE_WHITELIST_SIZE) + #else + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE (12) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT (CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT) + #else + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT (30) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT (CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT) + #else + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT (8) + #endif + + #if defined(CONFIG_BT_LE_POWER_CONTROL_ENABLED) + #define DEFAULT_BT_LE_POWER_CONTROL_ENABLED (CONFIG_BT_LE_POWER_CONTROL_ENABLED) + #else + #define DEFAULT_BT_LE_POWER_CONTROL_ENABLED (0) + #endif + + #if defined(CONFIG_BT_LE_50_FEATURE_SUPPORT) + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (1) + #else + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) + #endif +#endif + +#define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF + +#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART +#define HCI_UART_EN CONFIG_BT_LE_HCI_INTERFACE_USE_UART +#else +#define HCI_UART_EN 0 // hci ram mode +#endif + +#ifdef CONFIG_BT_LE_SLEEP_ENABLE +#define NIMBLE_SLEEP_ENABLE CONFIG_BT_LE_SLEEP_ENABLE +#else +#define NIMBLE_SLEEP_ENABLE 0 +#endif + + +#ifdef CONFIG_BT_LE_TX_CCA_ENABLED + #define DEFAULT_BT_LE_TX_CCA_ENABLED (CONFIG_BT_LE_TX_CCA_ENABLED) +#else + #define DEFAULT_BT_LE_TX_CCA_ENABLED (0) +#endif + +#ifdef CONFIG_BT_LE_CCA_RSSI_THRESH + #define DEFAULT_BT_LE_CCA_RSSI_THRESH (CONFIG_BT_LE_CCA_RSSI_THRESH) +#else + #define DEFAULT_BT_LE_CCA_RSSI_THRESH (50) +#endif + +#define DEFAULT_BT_LE_SCAN_RSP_DATA_MAX_LEN_N DEFAULT_BT_LE_EXT_ADV_MAX_SIZE + + +#if HCI_UART_EN + #define DEFAULT_BT_LE_HCI_UART_TX_PIN (CONFIG_BT_LE_HCI_UART_TX_PIN) + #define DEFAULT_BT_LE_HCI_UART_RX_PIN (CONFIG_BT_LE_HCI_UART_RX_PIN) + #define DEFAULT_BT_LE_HCI_UART_PORT (CONFIG_BT_LE_HCI_UART_PORT) + #define DEFAULT_BT_LE_HCI_UART_BAUD (CONFIG_BT_LE_HCI_UART_BAUD) + #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS) + #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1) + #define DEFAULT_BT_LE_HCI_UART_PARITY (0) + #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) +#else + #define DEFAULT_BT_LE_HCI_UART_TX_PIN (0) + #define DEFAULT_BT_LE_HCI_UART_RX_PIN (0) + #define DEFAULT_BT_LE_HCI_UART_PORT (0) + #define DEFAULT_BT_LE_HCI_UART_BAUD (0) + #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0) + #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0) + #define DEFAULT_BT_LE_HCI_UART_PARITY (0) + #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) +#endif + +/* Unchanged configuration */ + +#define BLE_LL_CTRL_PROC_TIMEOUT_MS_N (40000) /* ms */ + +#define BLE_LL_CFG_NUM_HCI_CMD_PKTS_N (1) + +#define BLE_LL_SCHED_ADV_MAX_USECS_N (852) + +#define BLE_LL_SCHED_DIRECT_ADV_MAX_USECS_N (502) + +#define BLE_LL_SCHED_MAX_ADV_PDU_USECS_N (376) + +#define BLE_LL_SUB_VERS_NR_N (0x0000) + +#define BLE_LL_JITTER_USECS_N (16) + +#define BLE_PHY_MAX_PWR_DBM_N (10) + +#define BLE_LL_CONN_DEF_AUTH_PYLD_TMO_N (3000) + +#define RTC_FREQ_N (32768) /* in Hz */ + +#define BLE_LL_TX_PWR_DBM_N (9) + + +#define RUN_BQB_TEST (0) +#define RUN_QA_TEST (0) +#define NIMBLE_DISABLE_SCAN_BACKOFF (0) + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_BT_CFG_H__ */ diff --git a/lib/bt/controller/esp32p4/Kconfig.in b/lib/bt/controller/esp32p4/Kconfig.in new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/lib/bt/controller/esp32p4/Kconfig.in diff --git a/lib/bt/controller/esp32s2/Kconfig.in b/lib/bt/controller/esp32s2/Kconfig.in new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/lib/bt/controller/esp32s2/Kconfig.in diff --git a/lib/bt/controller/esp32s3/Kconfig.in b/lib/bt/controller/esp32s3/Kconfig.in new file mode 100644 index 00000000..7f817135 --- /dev/null +++ b/lib/bt/controller/esp32s3/Kconfig.in @@ -0,0 +1 @@ +source "$IDF_PATH/components/bt/controller/esp32c3/Kconfig.in" diff --git a/lib/bt/controller/lib_esp32/.gitlab-ci.yml b/lib/bt/controller/lib_esp32/.gitlab-ci.yml new file mode 100644 index 00000000..d3b58bac --- /dev/null +++ b/lib/bt/controller/lib_esp32/.gitlab-ci.yml @@ -0,0 +1,30 @@ +stages: + - deploy + +push_master_to_github: + stage: deploy + tags: + - internet + only: + - master + - /^release\/v/ + - /^v\d+\.\d+/ +# when: on_success + image: $CI_DOCKER_REGISTRY/esp32-ci-env + variables: + GIT_DEPTH: 0 + script: + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $GH_PUSH_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + - git remote add github git@github.com:espressif/esp32-bt-lib.git + # Ref: esp-idf tools/ci/push_to_github.sh + - | + if [ -n "${CI_COMMIT_TAG}" ]; then + git push github "${CI_COMMIT_TAG}" + else + git push github "${CI_COMMIT_SHA}:refs/heads/${CI_COMMIT_REF_NAME}" + fi diff --git a/lib/bt/controller/lib_esp32/LICENSE b/lib/bt/controller/lib_esp32/LICENSE new file mode 100755 index 00000000..d6456956 --- /dev/null +++ b/lib/bt/controller/lib_esp32/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/lib/bt/controller/lib_esp32/README.rst b/lib/bt/controller/lib_esp32/README.rst new file mode 100755 index 00000000..c5541990 --- /dev/null +++ b/lib/bt/controller/lib_esp32/README.rst @@ -0,0 +1,10 @@ +ESP32 BT/BLE Stack Libraries +==================== + +This repository contains binary libraries supporting the ESP32 RF subsystems. It is used as a submodule within `Espressif IoT Development Framework`_ (ESP-IDF). + +Files in this repository are Copyright (C) 2015-2016 Espressif Systems. + +These binary libraries are provided under the same license as the parent esp-idf project - the Apache License 2.0 as provided in the file LICENSE. (The license text refers to this as "Object" form.) + +.. _Espressif IoT Development Framework: https://github.com/espressif/esp-idf diff --git a/lib/bt/controller/lib_esp32/esp32/libbtdm_app.a b/lib/bt/controller/lib_esp32/esp32/libbtdm_app.a Binary files differnew file mode 100644 index 00000000..7e859375 --- /dev/null +++ b/lib/bt/controller/lib_esp32/esp32/libbtdm_app.a diff --git a/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/NOTICE b/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/NOTICE new file mode 100644 index 00000000..73decc2c --- /dev/null +++ b/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/NOTICE @@ -0,0 +1,9 @@ +Apache Mynewt NimBLE +Copyright 2015-2021 The Apache Software Foundation +Modifications Copyright 2017-2022 Espressif Systems (Shanghai) CO., LTD. + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +Portions of this software were developed at +Runtime Inc, copyright 2015.
\ No newline at end of file diff --git a/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/README.md b/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/README.md new file mode 100644 index 00000000..607d1dc2 --- /dev/null +++ b/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/README.md @@ -0,0 +1 @@ +This software includes portions of code derived from mynewt-nimble project. See [NOTICE](NOTICE) file for details.
\ No newline at end of file diff --git a/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a b/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a Binary files differnew file mode 100644 index 00000000..3ae32051 --- /dev/null +++ b/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a diff --git a/lib/bt/controller/lib_esp32c3_family/.gitlab-ci.yml b/lib/bt/controller/lib_esp32c3_family/.gitlab-ci.yml new file mode 100644 index 00000000..1c701e57 --- /dev/null +++ b/lib/bt/controller/lib_esp32c3_family/.gitlab-ci.yml @@ -0,0 +1,31 @@ +stages: + - deploy + +push_master_to_github: + stage: deploy + tags: + - internet + only: + - master + - /^release\/v/ +# when: on_success + image: $CI_DOCKER_REGISTRY/esp32-ci-env + variables: + GIT_STRATEGY: clone + GITHUB_PUSH_REFS: refs/remotes/origin/release refs/remotes/origin/master + script: + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $GH_PUSH_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + - git remote add github git@github.com:espressif/esp32c3-bt-lib.git + # What the next line of script does: goes through the list of refs for all branches we push to github, + # generates a snippet of shell which is evaluated. The snippet checks CI_BUILD_REF against the SHA + # (aka objectname) at tip of each branch, and if any SHAs match then it checks out the local branch + # and then pushes that ref to a corresponding github branch + # + # NB: In gitlab 9.x, CI_BUILD_REF was deprecated. New name is CI_COMMIT_REF. If below command suddenly + # generates bash syntax errors, this is probably why. + - eval $(git for-each-ref --shell bash --format 'if [ $CI_BUILD_REF == %(objectname) ]; then git checkout -B %(refname:strip=3); git push --follow-tags github %(refname:strip=3); fi;' $GITHUB_PUSH_REFS) diff --git a/lib/bt/controller/lib_esp32c3_family/LICENSE b/lib/bt/controller/lib_esp32c3_family/LICENSE new file mode 100755 index 00000000..d6456956 --- /dev/null +++ b/lib/bt/controller/lib_esp32c3_family/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/lib/bt/controller/lib_esp32c3_family/README.md b/lib/bt/controller/lib_esp32c3_family/README.md new file mode 100644 index 00000000..36e3ffec --- /dev/null +++ b/lib/bt/controller/lib_esp32c3_family/README.md @@ -0,0 +1,10 @@ +ESP32-C3 and ESP32-S3 BLE Stack Libraries +========================================= + +This repository contains binary libraries supporting the ESP32C3 and ESP32S3 RF subsystems. It is used as a submodule within `Espressif IoT Development Framework`_ (ESP-IDF). + +Files in this repository are Copyright (C) 2021 Espressif Systems. + +These binary libraries are provided under the same license as the parent esp-idf project - the Apache License 2.0 as provided in the file LICENSE. (The license text refers to this as "Object" form.) + +.. _Espressif IoT Development Framework: https://github.com/espressif/esp-idf diff --git a/lib/bt/controller/lib_esp32c3_family/esp32c3/libbtdm_app.a b/lib/bt/controller/lib_esp32c3_family/esp32c3/libbtdm_app.a Binary files differnew file mode 100644 index 00000000..c9774edd --- /dev/null +++ b/lib/bt/controller/lib_esp32c3_family/esp32c3/libbtdm_app.a diff --git a/lib/bt/controller/lib_esp32c3_family/esp32s3/libbtdm_app.a b/lib/bt/controller/lib_esp32c3_family/esp32s3/libbtdm_app.a Binary files differnew file mode 100644 index 00000000..35adfbb0 --- /dev/null +++ b/lib/bt/controller/lib_esp32c3_family/esp32s3/libbtdm_app.a diff --git a/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/NOTICE b/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/NOTICE new file mode 100644 index 00000000..a0cb7d8b --- /dev/null +++ b/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/NOTICE @@ -0,0 +1,9 @@ +Apache Mynewt NimBLE +Copyright 2015-2021 The Apache Software Foundation +Modifications Copyright 2017-2023 Espressif Systems (Shanghai) CO., LTD. + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +Portions of this software were developed at +Runtime Inc, copyright 2015.
\ No newline at end of file diff --git a/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/README.md b/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/README.md new file mode 100644 index 00000000..607d1dc2 --- /dev/null +++ b/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/README.md @@ -0,0 +1 @@ +This software includes portions of code derived from mynewt-nimble project. See [NOTICE](NOTICE) file for details.
\ No newline at end of file diff --git a/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/libble_app.a b/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/libble_app.a Binary files differnew file mode 100644 index 00000000..77fd8fd1 --- /dev/null +++ b/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/libble_app.a diff --git a/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/NOTICE b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/NOTICE new file mode 100644 index 00000000..ed17c42a --- /dev/null +++ b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/NOTICE @@ -0,0 +1,9 @@ +Apache Mynewt NimBLE +Copyright 2015-2022 The Apache Software Foundation +Modifications Copyright 2017-2023 Espressif Systems (Shanghai) CO., LTD. + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +Portions of this software were developed at +Runtime Inc, copyright 2015. diff --git a/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/README.md b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/README.md new file mode 100644 index 00000000..7a64988a --- /dev/null +++ b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/README.md @@ -0,0 +1 @@ +This software includes portions of code derived from mynewt-nimble project. See [NOTICE](NOTICE) file for details. diff --git a/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/beta1/libble_app.a b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/beta1/libble_app.a Binary files differnew file mode 100644 index 00000000..200dff9b --- /dev/null +++ b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/beta1/libble_app.a diff --git a/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/beta2/libble_app.a b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/beta2/libble_app.a Binary files differnew file mode 100644 index 00000000..28ac5c45 --- /dev/null +++ b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/beta2/libble_app.a diff --git a/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/libble_app.a b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/libble_app.a Binary files differnew file mode 100644 index 00000000..03761e55 --- /dev/null +++ b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/libble_app.a |
