feat(ble): added ble support for esp32h4 eco1

This commit is contained in:
ShenWeilong
2026-03-30 21:21:16 +08:00
parent 099d7ee8ce
commit 6e359ad99e
151 changed files with 12582 additions and 846 deletions
+1
View File
@@ -166,6 +166,7 @@
- "components/heap/tlsf"
- "components/bt/controller/lib_esp32c6/esp32c6-bt-lib"
- "components/bt/controller/lib_esp32c5/esp32c5-bt-lib"
- "components/bt/controller/lib_esp32h4/esp32h4-bt-lib"
- "components/bt/esp_ble_mesh/lib/lib"
- ".gitmodules"
+5
View File
@@ -116,6 +116,11 @@
url = ../../espressif/esp32h2-bt-lib.git
shallow = true
[submodule "components/bt/controller/lib_esp32h4/esp32h4-bt-lib"]
path = components/bt/controller/lib_esp32h4/esp32h4-bt-lib
url = ../../espressif/esp32h4-bt-lib.git
shallow = true
[submodule "components/bt/controller/lib_esp32c2/esp32c2-bt-lib"]
path = components/bt/controller/lib_esp32c2/esp32c2-bt-lib
url = ../../espressif/esp32c2-bt-lib.git
+42 -3
View File
@@ -105,9 +105,15 @@ if(CONFIG_BT_ENABLED)
list(APPEND priv_include_dirs
common/btc/include
common/include
)
if(NOT CONFIG_BT_DUAL_MODE_ARCH)
list(APPEND priv_include_dirs
porting/mem/
porting/include
)
endif()
list(APPEND include_dirs ${common_include_dirs})
list(APPEND srcs "common/btc/core/btc_alarm.c"
@@ -672,7 +678,22 @@ if(CONFIG_BT_ENABLED)
endif()
endif()
if(CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT)
if(CONFIG_BT_DUAL_MODE_ARCH)
add_subdirectory(porting_btdm)
list(APPEND srcs
${porting_btdm_srcs}
)
if(CONFIG_BT_NIMBLE_ENABLED)
list(APPEND srcs
"host/nimble/nimble/nimble/transport/esp_ipc_btdm/src/hci_esp_ipc.c"
)
endif()
list(APPEND include_dirs
${porting_btdm_include_dirs}
)
elseif(CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT)
list(APPEND srcs
"porting/npl/freertos/src/npl_os_freertos.c"
"porting/mem/os_msys_init.c"
@@ -867,9 +888,21 @@ if(CONFIG_BT_ENABLED)
list(APPEND srcs
"host/nimble/nimble/porting/nimble/src/nimble_port.c"
"host/nimble/nimble/porting/npl/freertos/src/nimble_port_freertos.c"
"host/nimble/port/src/nvs_port.c"
"host/nimble/port/src/esp_nimble_mem.c"
)
if(CONFIG_BT_DUAL_MODE_ARCH)
list(APPEND srcs
"host/nimble/nimble/porting/npl/esp-idf/src/nimble_port_freertos.c"
)
list(APPEND include_dirs
"host/nimble/nimble/porting/npl/esp-idf/include"
)
else()
list(APPEND srcs
"host/nimble/nimble/porting/npl/freertos/src/nimble_port_freertos.c"
)
endif()
list(APPEND include_dirs
host/nimble/nimble/porting/nimble/include
@@ -884,7 +917,7 @@ if(CONFIG_BT_ENABLED)
)
endif()
if(NOT CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT)
if((NOT CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT) AND (NOT CONFIG_BT_DUAL_MODE_ARCH))
list(APPEND srcs
"host/nimble/nimble/porting/nimble/src/endian.c"
"porting/mem/os_mempool.c"
@@ -1087,6 +1120,12 @@ if(CONFIG_BT_ENABLED)
endif()
endif()
target_link_libraries(${COMPONENT_LIB} PRIVATE libble_app)
if(CONFIG_BT_DUAL_MODE_ARCH)
add_prebuilt_library(libbtdm_common
"controller/lib_${target_name}/${target_name}-bt-lib/libbtdm_common.a")
target_link_libraries(${COMPONENT_LIB} PRIVATE libbtdm_common)
endif()
endif()
set_source_files_properties(
@@ -0,0 +1,739 @@
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 Transfer 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
menuconfig BT_LE_ISO_SUPPORT
bool "Enable BLE ISO feature"
default n
help
Support BLE 5.2 ISO feature
config BT_LE_ISO_FRA_UNSEG
bool "Enable Unsegmented mode for Framed PDU"
depends on BT_LE_ISO_SUPPORT
help
Enable this to support the Framed Unsegmented mode.
config BT_LE_ISO_NSFC_EN
bool "Enable Non-standard Flow Control (NSFC) mode"
depends on BT_LE_ISO_SUPPORT
default y
help
Enable this to support ISO non-standard flow control.
Note:
If non-standard flow control mode is used, no Number of
Completed Packets event will be posted from Controller.
Instead before transmitting an ISO packet, Host needs to
invoke an API provided by Controller to make sure that
the ISO packet could be accommodated by Controller.
config BT_LE_ISO_NSFC_NUM
int "Maximum number of ISO packets for NSFC mode"
depends on BT_LE_ISO_SUPPORT && BT_LE_ISO_NSFC_EN
range 1 255
default 12
help
Maximum number of ISO packets could be accommodated by
Controller while using non-standard flow control mode.
config BT_LE_ISO_BUF_COUNT
int "Number of allocated ISO buffers"
depends on BT_LE_ISO_SUPPORT
range 1 255
default 12
help
Number of ISO buffers allocated in Controller.
config BT_LE_ISO_BUF_SIZE
int "Size of each allocated ISO buffer"
depends on BT_LE_ISO_SUPPORT
range 1 65535
default 251
help
Size of each allocated ISO buffer in Controller.
And the allocated ISO buffers will be used to hold
ISO Data PDUs for transmission.
Currently a larger value is meaningless, which only
increase memory consumption.
config BT_LE_ISO_BIG
int "Maximum number of BIGs"
depends on BT_LE_ISO_SUPPORT
range 1 2
default 1
help
Maximum number of BIGs.
config BT_LE_ISO_BIS
int "Maximum number of BISes"
depends on BT_LE_ISO_SUPPORT
range 1 6
default 2
help
Maximum number of BISes.
config BT_LE_ISO_BIS_PER_BIG
int "Maximum number of BISes per BIG"
depends on BT_LE_ISO_SUPPORT
range 1 BT_LE_ISO_BIS
default BT_LE_ISO_BIS
help
Maximum number of BISes per BIG.
config BT_LE_ISO_CIG
int "Maximum number of CIGs"
depends on BT_LE_ISO_SUPPORT
range 1 2
default 1
help
Maximum number of CIGs.
config BT_LE_ISO_CIS
int "Maximum number of CISes"
depends on BT_LE_ISO_SUPPORT
range 1 6
default 2
help
Maximum number of CISes.
config BT_LE_ISO_CIS_PER_CIG
int "Maximum number of CISes per CIG"
depends on BT_LE_ISO_SUPPORT
range 1 BT_LE_ISO_CIS
default BT_LE_ISO_CIS
help
Maximum number of CISes per CIG.
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
menu "Controller debug features"
menuconfig BT_LE_CONTROLLER_LOG_ENABLED
bool "Controller log enable"
default n
help
Enable controller log
config BT_LE_CONTROLLER_LOG_MODE_BLE_LOG_V2
bool "Utilize BLE Log v2 for controller log"
depends on BLE_LOG_ENABLED
default y
help
Utilize BLE Log v2 for controller log
if !BT_LE_CONTROLLER_LOG_MODE_BLE_LOG_V2
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_CONTROLLER_LOG_SPI_OUT_ENABLED
bool "Output ble controller logs to SPI bus (Experimental)"
depends on BT_LE_CONTROLLER_LOG_ENABLED
depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY
select BT_BLE_LOG_SPI_OUT_ENABLED
default n
help
Output ble controller logs to SPI bus
config BT_LE_CONTROLLER_LOG_UHCI_OUT_ENABLED
bool "Output ble controller logs via UART DMA (Experimental)"
depends on BT_LE_CONTROLLER_LOG_ENABLED
depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY
depends on !BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
select BT_BLE_LOG_UHCI_OUT_ENABLED
default y
help
Output ble controller logs via UART DMA
config BT_LE_CONTROLLER_LOG_STORAGE_ENABLE
bool "Store ble controller logs to flash(Experimental)"
depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY
depends on BT_LE_CONTROLLER_LOG_ENABLED
default n
help
Store ble controller logs to flash memory.
config BT_LE_CONTROLLER_LOG_PARTITION_SIZE
int "size of ble controller log partition(Multiples of 4K)"
depends on BT_LE_CONTROLLER_LOG_STORAGE_ENABLE
default 65536
help
The size of ble controller log partition shall be a multiples of 4K.
The name of log partition shall be "bt_ctrl_log".
The partition type shall be ESP_PARTITION_TYPE_DATA.
The partition sub_type shall be ESP_PARTITION_SUBTYPE_ANY.
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.
endif
config BT_LE_CONTROLLER_LOG_WRAP_PANIC_HANDLER_ENABLE
bool "Enable wrap panic handler"
depends on BT_LE_CONTROLLER_LOG_ENABLED
default n
help
Wrap esp_panic_handler to get controller logs when PC pointer exception crashes.
config BT_LE_CONTROLLER_LOG_TASK_WDT_USER_HANDLER_ENABLE
bool "Enable esp_task_wdt_isr_user_handler implementation"
depends on BT_LE_CONTROLLER_LOG_ENABLED
default n
help
Implement esp_task_wdt_isr_user_handler to get controller logs when task wdt issue is triggered.
config BT_LE_CONTROLLER_LOG_OUTPUT_LEVEL
int "The output level of controller log"
depends on BT_LE_CONTROLLER_LOG_ENABLED
range 0 5
default 1
help
The output level of controller log.
config BT_LE_CONTROLLER_LOG_MOD_OUTPUT_SWITCH
hex "The switch of module log output"
depends on BT_LE_CONTROLLER_LOG_ENABLED
range 0 0xFFFFFFFF
default 0xFFFFFFFF
help
The switch of module log output, this is an unsigned 32-bit hexadecimal value.
config BT_LE_ERROR_SIM_ENABLED
bool "Enable controller features for internal testing"
default n
config BT_LE_ASSERT_WHEN_ABNORMAL_DISCONN_ENABLED
bool "When ACL disconnects abnormally, assertion processing is performed(Experimental)"
default n
config BT_LE_DEBUG_REMAIN_SCENE_ENABLED
bool "Remain scene with GDB to capture relevant status info(Experimental)"
default n
help
Retain scene with GDB to capture info, requires disabling WDT (CONFIG_ESP_INT_WDT, CONFIG_ESP_TASK_WDT_EN).
config BT_LE_PTR_CHECK_ENABLED
bool "Enable boundary check for internal memory"
default n
config BT_LE_MEM_CHECK_ENABLED
bool "Enable memory allocation check"
default n
help
Used in internal tests only. Enable the memory allocation check.
endmenu
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 n
depends on !BT_NIMBLE_ENABLED
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 70
default 3
help
Defines maximum number of concurrent BLE connections.
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
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 1 if BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EN
default 0 if BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS
choice BT_LE_LP_CLK_SRC
prompt "BLE low power clock source"
default BT_LE_LP_CLK_SRC_MAIN_XTAL
depends on BT_CTRL_SLEEP_ENABLE
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_SIZE
int "Maximum number of devices in scan duplicate filter"
depends on BT_LE_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_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
config BT_LE_TX_CCA_ENABLED
bool "Enable TX CCA feature"
default n
help
Enable CCA feature to cancel sending the packet if the signal power is stronger than CCA threshold.
config BT_LE_CCA_RSSI_THRESH
int "CCA RSSI threshold value"
depends on BT_LE_TX_CCA_ENABLED
range 20 100
default 20
help
Power threshold of CCA in unit of -1 dBm.
choice BT_LE_DFT_TX_POWER_LEVEL_DBM
prompt "BLE default Tx power level(dBm)"
default BT_LE_DFT_TX_POWER_LEVEL_P9
help
Specify default Tx power level(dBm).
config BT_LE_DFT_TX_POWER_LEVEL_N15
bool "-15dBm"
config BT_LE_DFT_TX_POWER_LEVEL_N12
bool "-12dBm"
config BT_LE_DFT_TX_POWER_LEVEL_N9
bool "-9dBm"
config BT_LE_DFT_TX_POWER_LEVEL_N6
bool "-6dBm"
config BT_LE_DFT_TX_POWER_LEVEL_N3
bool "-3dBm"
config BT_LE_DFT_TX_POWER_LEVEL_N0
bool "0dBm"
config BT_LE_DFT_TX_POWER_LEVEL_P3
bool "+3dBm"
config BT_LE_DFT_TX_POWER_LEVEL_P6
bool "+6dBm"
config BT_LE_DFT_TX_POWER_LEVEL_P9
bool "+9dBm"
config BT_LE_DFT_TX_POWER_LEVEL_P12
bool "+12dBm"
config BT_LE_DFT_TX_POWER_LEVEL_P15
bool "+15dBm"
config BT_LE_DFT_TX_POWER_LEVEL_P18
bool "+18dBm"
config BT_LE_DFT_TX_POWER_LEVEL_P20
bool "+20dBm"
endchoice
config BT_LE_DFT_TX_POWER_LEVEL_DBM_EFF
int
default -15 if BT_LE_DFT_TX_POWER_LEVEL_N15
default -12 if BT_LE_DFT_TX_POWER_LEVEL_N12
default -9 if BT_LE_DFT_TX_POWER_LEVEL_N9
default -6 if BT_LE_DFT_TX_POWER_LEVEL_N6
default -3 if BT_LE_DFT_TX_POWER_LEVEL_N3
default 0 if BT_LE_DFT_TX_POWER_LEVEL_N0
default 3 if BT_LE_DFT_TX_POWER_LEVEL_P3
default 6 if BT_LE_DFT_TX_POWER_LEVEL_P6
default 9 if BT_LE_DFT_TX_POWER_LEVEL_P9
default 12 if BT_LE_DFT_TX_POWER_LEVEL_P12
default 15 if BT_LE_DFT_TX_POWER_LEVEL_P15
default 18 if BT_LE_DFT_TX_POWER_LEVEL_P18
default 20 if BT_LE_DFT_TX_POWER_LEVEL_P20
default 0
config BT_LE_ERROR_SIM_ENABLED
bool "Enable controller features for internal testing"
default n
+191
View File
@@ -0,0 +1,191 @@
choice
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"
depends on SOC_BLE_SUPPORTED
config BTDM_CTRL_MODE_BR_EDR_ONLY
bool "BR/EDR Only"
depends on SOC_BT_CLASSIC_SUPPORTED
config BTDM_CTRL_MODE_BTDM
bool "Bluetooth Dual Mode"
depends on SOC_BLE_SUPPORTED && SOC_BT_CLASSIC_SUPPORTED
endchoice
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_CHOICE_0
bool "Core 0 (PRO CPU)"
config BT_CTRL_PINNED_TO_CORE_CHOICE_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_CHOICE_0
default 1 if BT_CTRL_PINNED_TO_CORE_CHOICE_1
default 0
config BT_CTRL_TASK_STACK_SIZE
int "Controller task stack size"
default 5120 if BLE_MESH
default 4096
help
This configures stack size of NimBLE controller task
config BT_CTRL_SLEEP_ENABLE
bool "Enable Bluetooth Controller sleep"
default n
help
Enable Bluetooth Controller sleep
menu "Bluetooth controller HCI"
config BT_CTRL_HCI_CMD_NUM
int "HCI CMD buffer number"
range 1 255
default 5
choice BT_CTRL_HCI_INTERFACE
prompt "HCI mode"
default BT_CTRL_HCI_INTERFACE_USE_RAM
config BT_CTRL_HCI_INTERFACE_USE_RAM
bool "VHCI"
help
Use RAM as HCI interface
config BT_CTRL_HCI_INTERFACE_USE_UART
bool "UART(H4)"
help
Use UART as HCI interface
endchoice
choice BT_CTRL_UART_HCI_MODE_CHOICE
prompt "UART HCI mode"
depends on BT_CTRL_HCI_INTERFACE_USE_UART
default BT_CTRL_UART_HCI_NO_DMA_MODE
help
Specify UART HCI mode: DMA or No DMA
config BT_CTRL_UART_HCI_DMA_MODE
bool "UHCI(UART with DMA)(EXPERIMENTAL)"
help
UART HCI Mode with DMA functionality.
config BT_CTRL_UART_HCI_NO_DMA_MODE
bool "UART(NO DMA)"
help
UART HCI Mode without DMA functionality.
endchoice
config BT_CTRL_HCI_UART_PORT
int "HCI UART port"
depends on BT_CTRL_HCI_INTERFACE_USE_UART
default 1
help
Set the port number of HCI UART
config BT_CTRL_HCI_UART_FLOWCTRL
bool "HCI uart Hardware Flow ctrl"
depends on BT_CTRL_HCI_INTERFACE_USE_UART
default n
config BT_CTRL_HCI_UART_TX_PIN
int "HCI uart Tx gpio"
depends on BT_CTRL_HCI_INTERFACE_USE_UART
default 19
config BT_CTRL_HCI_UART_RX_PIN
int "HCI uart Rx gpio"
depends on BT_CTRL_HCI_INTERFACE_USE_UART
default 10
config BT_CTRL_HCI_UART_RTS_PIN
int "HCI uart RTS gpio"
depends on BT_CTRL_HCI_UART_FLOWCTRL
default 4
config BT_CTRL_HCI_UART_CTS_PIN
int "HCI uart CTS gpio"
depends on BT_CTRL_HCI_UART_FLOWCTRL
default 5
config BT_CTRL_HCI_UART_BAUD
int "HCI uart baudrate"
depends on BT_CTRL_HCI_INTERFACE_USE_UART
default 921600
help
HCI uart baud rate 115200 ~ 1000000
choice BT_CTRL_HCI_UART_PARITY
prompt "select uart parity"
depends on BT_CTRL_HCI_INTERFACE_USE_UART
default BT_CTRL_HCI_UART_UART_PARITY_DISABLE
config BT_CTRL_HCI_UART_UART_PARITY_DISABLE
bool "PARITY_DISABLE"
help
UART_PARITY_DISABLE
config BT_CTRL_HCI_UART_UART_PARITY_EVEN
bool "PARITY_EVEN"
help
UART_PARITY_EVEN
config BT_CTRL_HCI_UART_UART_PARITY_ODD
bool "PARITY_ODD"
help
UART_PARITY_ODD
endchoice
config BT_CTRL_HCI_UART_RX_BUFFER_SIZE
int "The size of rx ring buffer memory"
depends on BT_CTRL_UART_HCI_NO_DMA_MODE
default 512
help
The size of rx ring buffer memory
config BT_CTRL_HCI_UART_TX_BUFFER_SIZE
int "The size of tx ring buffer memory"
depends on BT_CTRL_UART_HCI_NO_DMA_MODE
default 256
help
The size of tx ring buffer memory
config BT_CTRL_HCI_TRANS_TASK_STACK_SIZE
int "HCI transport task stack size"
depends on !BT_CTRL_HCI_INTERFACE_USE_RAM
default 1024
help
This configures stack size of hci transport task
config BT_CTRL_HCI_TRANS_RX_MEM_NUM
int "The amount of rx memory received at the same time"
depends on BT_CTRL_UART_HCI_DMA_MODE
default 3
help
The amount of rx memory received at the same time
config BT_CTRL_HCI_LLDESCS_POOL_NUM
int "The amount of lldecs memory for driver dma mode"
depends on BT_CTRL_UART_HCI_DMA_MODE
default 20
help
The amount of lldecs memory for driver dma mode
endmenu
menu "BLE Controller Settings"
depends on BTDM_CTRL_MODE_BLE_ONLY || BTDM_CTRL_MODE_BTDM
source "$IDF_PATH/components/bt/controller/$IDF_TARGET/Kconfig.ble.in"
endmenu
config BT_DUAL_MODE_ARCH
bool
default y
File diff suppressed because it is too large Load Diff
+335
View File
@@ -0,0 +1,335 @@
/*
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_err.h"
#include "esp_log.h"
#include "sdkconfig.h"
/* From ESP Bluetooth */
#include "esp_bt.h"
#include "esp_hci_transport.h"
#include "ble_priv.h"
#include "btdm_coex.h"
#include "btdm_lp.h"
#include "btdm_log.h"
#include "btdm_external.h"
/*
***************************************************************************************************
* Local Defined Macros
***************************************************************************************************
*/
#define BTDM_LOG_TAG "BTDM_INIT"
#if UC_BT_CTRL_HCI_INTERFACE_USE_RAM
#define BT_HCI_TRANSPORT_MODE HCI_TRANSPORT_VHCI
#elif UC_BT_CTRL_HCI_INTERFACE_USE_UART
#define BT_HCI_TRANSPORT_MODE HCI_TRANSPORT_UART_NO_DMA
#if UC_BT_CTRL_UART_HCI_DMA_MODE
#define BT_HCI_TRANSPORT_MODE HCI_TRANSPORT_UART_UHCI
#endif // UC_BT_CTRL_UART_HCI_DMA_MODE
#endif // UC_BT_CTRL_HCI_INTERFACE_USE_RAM
/*
***************************************************************************************************
* External Functions
***************************************************************************************************
*/
extern const char *r_btdm_get_compile_version(void);
extern int r_btdm_hci_fc_env_init();
extern void r_btdm_hci_fc_env_deinit(void);
extern int r_btdm_hci_fc_enable(void);
extern void r_btdm_hci_fc_disable(void);
extern int r_btdm_task_init(esp_btdm_controller_config_t *cfg);
extern void r_btdm_task_deinit(void);
extern int r_btdm_task_enable(void);
extern void r_btdm_task_disable(void);
extern void r_btdm_task_shutdown(void);
/*
***************************************************************************************************
* Local Variables
***************************************************************************************************
*/
esp_bt_controller_status_t s_btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
/*
***************************************************************************************************
* Static Function Definitions
***************************************************************************************************
*/
static void
bt_shutdown(void)
{
if (s_btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return;
}
r_btdm_task_shutdown();
btdm_lp_shutdown();
}
/*
***************************************************************************************************
* Public Function Definitions
***************************************************************************************************
*/
esp_err_t
esp_bt_mem_release(esp_bt_mode_t mode)
{
ESP_LOGW(BTDM_LOG_TAG, "esp_bt_mem_release not implement yet!");
return ESP_OK;
}
esp_err_t
esp_bt_controller_mem_release(esp_bt_mode_t mode)
{
ESP_LOGW(BTDM_LOG_TAG, "esp_bt_controller_mem_release not implement yet!");
return ESP_OK;
}
esp_err_t
esp_bt_controller_init(esp_bt_controller_config_t *cfg)
{
int ret;
// TODO: Delete workaround
btdm_osal_elem_num_t elem = {
.evt_count = 3 + 100,
.evtq_count = 1 + 2,
.co_count = 0 + 10,
.sem_count = 0,
.mutex_count = 1,
};
ESP_LOGI(BTDM_LOG_TAG, "BTDM version [%s]", r_btdm_get_compile_version());
if (cfg->btdm.bluetooth_mode == ESP_BT_MODE_IDLE) {
ESP_LOGE(BTDM_LOG_TAG, "bluetooth_mode in cfg is IDLE");
return ESP_ERR_INVALID_ARG;
}
if (s_btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) {
return ESP_ERR_INVALID_STATE;
}
s_btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
ret = ESP_FAIL;
#if UC_BT_CTRL_BLE_IS_ENABLE
ble_osal_elem_calc(cfg, &elem);
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
bredr_osal_elem_calc(cfg, &elem);
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
ret = btdm_osal_elem_mempool_init(&elem);
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "btdm_osal_elem_mempool_init failed: %d", ret);
goto init_failed;
}
ret = btdm_log_init();
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "btdm_log_init failed: %d", ret);
goto init_failed;
}
ret = btdm_external_init();
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "btdm_external_init failed: %d", ret);
goto init_failed;
}
ret = btdm_coex_init();
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "btdm_coex_init failed: %d", ret);
goto init_failed;
}
btdm_lp_enable_clock(&cfg->btdm);
ret = r_btdm_task_init(&cfg->btdm);
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "r_btdm_task_init failed: %d", ret);
goto init_failed;
}
ret = btdm_lp_init();
if (ret != ESP_OK) {
ESP_LOGE(BTDM_LOG_TAG, "btdm_lp_init failed %d", ret);
goto init_failed;
}
#if UC_BT_CTRL_CONN_FC_ENABLE
ret = r_btdm_hci_fc_env_init();
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "r_btdm_hci_fc_env_init failed: %d", ret);
goto init_failed;
}
#endif // UC_BT_CTRL_CONN_FC_ENABLE
#if UC_BT_CTRL_BLE_IS_ENABLE
ret = ble_stack_init(cfg);
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "ble_stack_init failed: %d", ret);
goto init_failed;
}
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
ret = bredr_stack_init(cfg);
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "bredr_stack_init failed: %d", ret);
goto init_failed;
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
ret = hci_transport_init(BT_HCI_TRANSPORT_MODE);
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "hci_transport_init failed %d", ret);
goto init_failed;
}
ESP_LOGI(BTDM_LOG_TAG, "BTDM controller init OK");
return ESP_OK;
init_failed:
esp_bt_controller_deinit();
return ESP_FAIL;
}
esp_err_t
esp_bt_controller_deinit(void)
{
if (s_btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) {
return ESP_ERR_INVALID_STATE;
}
s_btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
hci_transport_deinit();
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
bredr_stack_deinit();
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
#if UC_BT_CTRL_BLE_IS_ENABLE
ble_stack_deinit();
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#if UC_BT_CTRL_CONN_FC_ENABLE
r_btdm_hci_fc_env_deinit();
#endif // UC_BT_CTRL_CONN_FC_ENABLE
btdm_lp_deinit();
r_btdm_task_deinit();
btdm_lp_disable_clock();
btdm_coex_deinit();
btdm_log_deinit();
btdm_external_deinit();
btdm_osal_elem_mempool_deinit();
return ESP_OK;
}
esp_err_t
esp_bt_controller_enable(esp_bt_mode_t mode)
{
int ret;
if (s_btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) {
return ESP_ERR_INVALID_STATE;
}
s_btdm_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED;
btdm_lp_reset(true);
ret = btdm_coex_enable();
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "btdm_coex_enable failed %d", ret);
goto enable_failed;
}
#if UC_BT_CTRL_BLE_IS_ENABLE
ret = ble_stack_enable();
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "ble_stack_enable failed %d", ret);
goto enable_failed;
}
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
ret = bredr_stack_enable();
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "bredr_stack_enable failed %d", ret);
goto enable_failed;
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
#if UC_BT_CTRL_CONN_FC_ENABLE
ret = r_btdm_hci_fc_enable();
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "r_btdm_hci_fc_enable failed %d", ret);
goto enable_failed;
}
#endif // UC_BT_CTRL_CONN_FC_ENABLE
ret = r_btdm_task_enable();
if (ret) {
ESP_LOGE(BTDM_LOG_TAG, "r_btdm_task_enable failed %d", ret);
goto enable_failed;
}
ret = esp_register_shutdown_handler(bt_shutdown);
if (ret) {
ESP_LOGW(BTDM_LOG_TAG, "Register shutdown handler failed, ret = 0x%x", ret);
}
return ESP_OK;
enable_failed:
esp_bt_controller_disable();
return ESP_FAIL;
}
esp_err_t
esp_bt_controller_disable(void)
{
if (s_btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
s_btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
esp_unregister_shutdown_handler(bt_shutdown);
r_btdm_task_disable();
#if UC_BT_CTRL_CONN_FC_ENABLE
r_btdm_hci_fc_disable();
#endif // UC_BT_CTRL_CONN_FC_ENABLE
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
bredr_stack_disable();
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
#if UC_BT_CTRL_BLE_IS_ENABLE
ble_stack_disable();
#endif // UC_BT_CTRL_BLE_IS_ENABLE
btdm_coex_disable();
btdm_lp_reset(false);
return ESP_OK;
}
esp_bt_controller_status_t
esp_bt_controller_get_status(void)
{
return s_btdm_controller_status;
}
@@ -24,9 +24,7 @@
#include "common/bt_target.h"
#include "osi/pkt_queue.h"
#include "stack/bt_types.h"
#if ((BT_CONTROLLER_INCLUDED == TRUE) && SOC_ESP_NIMBLE_CONTROLLER)
#include "os/os_mbuf.h"
#endif
typedef enum {
DATA_TYPE_COMMAND = 1,
DATA_TYPE_ACL = 2,
@@ -87,11 +85,6 @@ typedef struct hci_hal_t {
// Gets the correct hal implementation, as compiled for.
const hci_hal_t *hci_hal_h4_get_interface(void);
#if ((BT_CONTROLLER_INCLUDED == TRUE) && SOC_ESP_NIMBLE_CONTROLLER)
int ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg);
int ble_hs_rx_data(struct os_mbuf *om, void *arg);
#endif
#endif /* _HCI_HAL_H */
+1 -1
View File
@@ -569,7 +569,7 @@ menu "Memory Settings"
config BT_NIMBLE_MEMPOOL_RUNTIME_ALLOC
bool "Support on-demand runtime memory allocation for mempool"
depends on BT_NIMBLE_ENABLED && BT_NIMBLE_STATIC_TO_DYNAMIC
depends on BT_NIMBLE_ENABLED && BT_NIMBLE_STATIC_TO_DYNAMIC && !BT_DUAL_MODE_ARCH
default n
help
When this option is enabled, mempool does not require pre-allocating memory.
@@ -13,9 +13,95 @@
extern "C" {
#endif
// #pragma message "This file should be replaced with bt_osi_mem.h, used here for compatibility"
void *bt_osi_mem_malloc(size_t size);
void *bt_osi_mem_calloc(size_t n, size_t size);
void bt_osi_mem_free(void *ptr);
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
size_t bt_osi_mem_used_size_get(void);
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
#if CONFIG_BT_NIMBLE_MEM_DEBUG
/**
* @brief Initialize NimBLE memory debug module
*/
void nimble_mem_dbg_init(void);
/**
* @brief Record memory allocation information
*
* @param p Pointer to allocated memory
* @param size Size of allocation
* @param func Function name where allocation occurred
* @param line Line number where allocation occurred
*/
void nimble_mem_dbg_record(void *p, int size, const char *func, int line);
/**
* @brief Clean up memory allocation record
*
* @param p Pointer to memory being freed
* @param func Function name where free occurred
* @param line Line number where free occurred
*/
void nimble_mem_dbg_clean(void *p, const char *func, int line);
/**
* @brief Display all memory debug information
*/
void nimble_mem_dbg_show(void);
/**
* @brief Get maximum memory size used
*
* @return Maximum memory size in bytes
*/
uint32_t nimble_mem_dbg_get_max_size(void);
/**
* @brief Get current memory size in use
*
* @return Current memory size in bytes
*/
uint32_t nimble_mem_dbg_get_current_size(void);
/**
* @brief Start tracking memory usage for a specific section
*
* @param index Section index (0 to NIMBLE_MEM_DBG_MAX_SECTION_NUM-1)
*/
void nimble_mem_dbg_set_section_start(uint8_t index);
/**
* @brief Stop tracking memory usage for a specific section
*
* @param index Section index (0 to NIMBLE_MEM_DBG_MAX_SECTION_NUM-1)
*/
void nimble_mem_dbg_set_section_end(uint8_t index);
/**
* @brief Get maximum memory size used in a specific section
*
* @param index Section index (0 to NIMBLE_MEM_DBG_MAX_SECTION_NUM-1)
* @return Maximum memory size in bytes for this section
*/
uint32_t nimble_mem_dbg_get_max_size_section(uint8_t index);
/**
* @brief Reallocate memory with debug tracking
*
* @param ptr Pointer to memory to reallocate
* @param new_size New size of allocation
* @param func Function name where realloc occurred
* @param line Line number where realloc occurred
* @return Pointer to reallocated memory
*/
void *nimble_mem_dbg_realloc(void *ptr, size_t new_size, const char *func, int line);
#endif // CONFIG_BT_NIMBLE_MEM_DEBUG
#include "bt_osi_mem.h"
#if CONFIG_BT_NIMBLE_MEM_DEBUG
@@ -0,0 +1,339 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_attr.h"
#include "esp_heap_caps.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include <assert.h>
static uint8_t log_count;
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
static size_t host_mem_used_size = 0;
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
#if CONFIG_BT_NIMBLE_MEM_DEBUG
#define NIMBLE_MEM_DBG_INFO_MAX 1024*3
typedef struct {
void *p;
int size;
const char *func;
int line;
} nimble_mem_dbg_info_t;
static uint32_t nimble_mem_dbg_count = 0;
static nimble_mem_dbg_info_t nimble_mem_dbg_info[NIMBLE_MEM_DBG_INFO_MAX];
static uint32_t nimble_mem_dbg_current_size = 0;
static uint32_t nimble_mem_dbg_max_size = 0;
#define NIMBLE_MEM_DBG_MAX_SECTION_NUM 5
typedef struct {
bool used;
uint32_t max_size;
} nimble_mem_dbg_max_size_section_t;
static nimble_mem_dbg_max_size_section_t nimble_mem_dbg_max_size_section[NIMBLE_MEM_DBG_MAX_SECTION_NUM];
void nimble_mem_dbg_init(void)
{
int i;
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
nimble_mem_dbg_info[i].p = NULL;
nimble_mem_dbg_info[i].size = 0;
nimble_mem_dbg_info[i].func = NULL;
nimble_mem_dbg_info[i].line = 0;
}
nimble_mem_dbg_count = 0;
nimble_mem_dbg_current_size = 0;
nimble_mem_dbg_max_size = 0;
for (i = 0; i < NIMBLE_MEM_DBG_MAX_SECTION_NUM; i++){
nimble_mem_dbg_max_size_section[i].used = false;
nimble_mem_dbg_max_size_section[i].max_size = 0;
}
}
void nimble_mem_dbg_record(void *p, int size, const char *func, int line)
{
int i;
if (!p || size == 0) {
ESP_LOGE("BT_NIMBLE_MEM", "%s invalid !!\n", __func__);
return;
}
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
if (nimble_mem_dbg_info[i].p == NULL) {
nimble_mem_dbg_info[i].p = p;
nimble_mem_dbg_info[i].size = size;
nimble_mem_dbg_info[i].func = func;
nimble_mem_dbg_info[i].line = line;
nimble_mem_dbg_count++;
break;
}
}
if (i >= NIMBLE_MEM_DBG_INFO_MAX) {
ESP_LOGE("BT_NIMBLE_MEM", "%s full %s %d !!\n", __func__, func, line);
}
nimble_mem_dbg_current_size += size;
if(nimble_mem_dbg_max_size < nimble_mem_dbg_current_size) {
nimble_mem_dbg_max_size = nimble_mem_dbg_current_size;
}
for (i = 0; i < NIMBLE_MEM_DBG_MAX_SECTION_NUM; i++){
if (nimble_mem_dbg_max_size_section[i].used) {
if(nimble_mem_dbg_max_size_section[i].max_size < nimble_mem_dbg_current_size) {
nimble_mem_dbg_max_size_section[i].max_size = nimble_mem_dbg_current_size;
}
}
}
}
void nimble_mem_dbg_clean(void *p, const char *func, int line)
{
int i;
if (!p) {
ESP_LOGE("BT_NIMBLE_MEM", "%s %d free->%p invalid\n", func, line, p);
return;
}
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
if (nimble_mem_dbg_info[i].p == p) {
nimble_mem_dbg_current_size -= nimble_mem_dbg_info[i].size;
nimble_mem_dbg_info[i].p = NULL;
nimble_mem_dbg_info[i].size = 0;
nimble_mem_dbg_info[i].func = NULL;
nimble_mem_dbg_info[i].line = 0;
nimble_mem_dbg_count--;
break;
}
}
if (i >= NIMBLE_MEM_DBG_INFO_MAX) {
ESP_LOGE("BT_NIMBLE_MEM", "%s full %s %d !!\n", __func__, func, line);
}
}
void nimble_mem_dbg_show(void)
{
int i;
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
if (nimble_mem_dbg_info[i].p || nimble_mem_dbg_info[i].size != 0 ) {
ESP_LOGE("BT_NIMBLE_MEM", "--> p %p, s %d, f %s, l %d\n",
nimble_mem_dbg_info[i].p, nimble_mem_dbg_info[i].size,
nimble_mem_dbg_info[i].func, nimble_mem_dbg_info[i].line);
}
}
ESP_LOGE("BT_NIMBLE_MEM", "--> count %ld\n", nimble_mem_dbg_count);
ESP_LOGE("BT_NIMBLE_MEM", "--> size %ldB\n--> max size %ldB\n",
nimble_mem_dbg_current_size, nimble_mem_dbg_max_size);
}
uint32_t nimble_mem_dbg_get_max_size(void)
{
return nimble_mem_dbg_max_size;
}
uint32_t nimble_mem_dbg_get_current_size(void)
{
return nimble_mem_dbg_current_size;
}
void nimble_mem_dbg_set_section_start(uint8_t index)
{
if (index >= NIMBLE_MEM_DBG_MAX_SECTION_NUM) {
ESP_LOGE("BT_NIMBLE_MEM", "Then range of index should be between 0 and %d, current index is %d.\n",
NIMBLE_MEM_DBG_MAX_SECTION_NUM - 1, index);
return;
}
if (nimble_mem_dbg_max_size_section[index].used) {
ESP_LOGW("BT_NIMBLE_MEM", "This index(%d) has been started, restart it.\n", index);
}
nimble_mem_dbg_max_size_section[index].used = true;
nimble_mem_dbg_max_size_section[index].max_size = nimble_mem_dbg_current_size;
}
void nimble_mem_dbg_set_section_end(uint8_t index)
{
if (index >= NIMBLE_MEM_DBG_MAX_SECTION_NUM) {
ESP_LOGE("BT_NIMBLE_MEM", "Then range of index should be between 0 and %d, current index is %d.\n",
NIMBLE_MEM_DBG_MAX_SECTION_NUM - 1, index);
return;
}
if (!nimble_mem_dbg_max_size_section[index].used) {
ESP_LOGE("BT_NIMBLE_MEM", "This index(%d) has not been started.\n", index);
return;
}
nimble_mem_dbg_max_size_section[index].used = false;
}
uint32_t nimble_mem_dbg_get_max_size_section(uint8_t index)
{
if (index >= NIMBLE_MEM_DBG_MAX_SECTION_NUM){
ESP_LOGE("BT_NIMBLE_MEM", "Then range of index should be between 0 and %d, current index is %d.\n",
NIMBLE_MEM_DBG_MAX_SECTION_NUM - 1, index);
return 0;
}
return nimble_mem_dbg_max_size_section[index].max_size;
}
void *nimble_mem_dbg_realloc(void *ptr, size_t new_size, const char *func, int line)
{
size_t old_size = 0;
int i;
void *new_ptr = realloc(ptr, new_size);
if (new_ptr == NULL && new_size > 0) {
// realloc failed, keep old ptr record
return NULL;
}
// Find and clean old record if ptr is not NULL
if (ptr != NULL) {
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
if (nimble_mem_dbg_info[i].p == ptr) {
old_size = nimble_mem_dbg_info[i].size;
nimble_mem_dbg_current_size -= old_size;
nimble_mem_dbg_info[i].p = NULL;
nimble_mem_dbg_info[i].size = 0;
nimble_mem_dbg_info[i].func = NULL;
nimble_mem_dbg_info[i].line = 0;
nimble_mem_dbg_count--;
break;
}
}
}
// Record the new allocation if new_size > 0
if (new_ptr != NULL && new_size > 0) {
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
if (nimble_mem_dbg_info[i].p == NULL) {
nimble_mem_dbg_info[i].p = new_ptr;
nimble_mem_dbg_info[i].size = new_size;
nimble_mem_dbg_info[i].func = func;
nimble_mem_dbg_info[i].line = line;
nimble_mem_dbg_count++;
break;
}
}
if (i >= NIMBLE_MEM_DBG_INFO_MAX) {
ESP_LOGE("BT_NIMBLE_MEM", "%s full %s %d !!\n", __func__, func, line);
}
nimble_mem_dbg_current_size += new_size;
if (nimble_mem_dbg_max_size < nimble_mem_dbg_current_size) {
nimble_mem_dbg_max_size = nimble_mem_dbg_current_size;
}
for (i = 0; i < NIMBLE_MEM_DBG_MAX_SECTION_NUM; i++) {
if (nimble_mem_dbg_max_size_section[i].used &&
nimble_mem_dbg_max_size_section[i].max_size < nimble_mem_dbg_current_size) {
nimble_mem_dbg_max_size_section[i].max_size = nimble_mem_dbg_current_size;
}
}
}
return new_ptr;
}
#endif // CONFIG_BT_NIMBLE_MEM_DEBUG
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
IRAM_ATTR
#endif
void *bt_osi_mem_malloc(size_t size)
{
void *mem = NULL;
#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL
mem = heap_caps_malloc(size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
mem = heap_caps_malloc(size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT
mem = heap_caps_malloc_prefer(size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#else
mem = malloc(size);
#endif
if (!mem) {
log_count ++;
if ((log_count % 100) == 0) {
ESP_EARLY_LOGI("ESP_LOG_INFO","malloc failed (size %zu)",size);
log_count = 0;
}
assert(mem != NULL);
}
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
if(mem) {
host_mem_used_size += heap_caps_get_allocated_size(mem);
}
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
return mem;
}
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
IRAM_ATTR
#endif
void *bt_osi_mem_calloc(size_t n, size_t size)
{
void *mem = NULL;
#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL
mem = heap_caps_calloc(n, size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
mem = heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT
mem = heap_caps_calloc_prefer(n, size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#else
mem = calloc(n, size);
#endif
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
if(mem) {
host_mem_used_size += heap_caps_get_allocated_size(mem);
}
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
return mem;
}
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
IRAM_ATTR
#endif
void bt_osi_mem_free(void *ptr)
{
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
if (ptr) {
size_t alloc_size = heap_caps_get_allocated_size(ptr);
// assert(host_mem_used_size >= alloc_size);
host_mem_used_size -= alloc_size;
}
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
if (ptr) {
heap_caps_free(ptr);
}
}
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
size_t
bt_osi_mem_used_size_get(void)
{
return host_mem_used_size;
}
#if CONFIG_BT_NIMBLE_ENABLED
uint32_t esp_host_used_heap_size_get(void)
{
return bt_osi_mem_used_size_get();
}
#endif // CONFIG_BT_NIMBLE_ENABLED
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
+380 -129
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -12,23 +12,75 @@
#include "esp_err.h"
#include "sdkconfig.h"
#include "esp_task.h"
#include "esp_assert.h"
#include "nimble/nimble_npl.h"
#include "esp_bt_cfg.h"
#include "btdm_user_cfg.h"
#if CONFIG_BTDM_CTRL_MODE_BLE_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM
// #include "nimble/nimble_npl.h"
#include "ble_user_cfg.h"
#endif /* CONFIG_BTDM_CTRL_MODE_BLE_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM */
#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART
#include "driver/uart.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_BT_HCI_TL_MAGIC_VALUE 0xfadebead
#define ESP_BT_HCI_TL_VERSION 0x00010000
/**
* @brief Bluetooth audio data transport path
*/
typedef enum {
ESP_SCO_DATA_PATH_HCI = 0, /*!< data over HCI transport */
ESP_SCO_DATA_PATH_PCM = 1, /*!< data over PCM interface */
} esp_sco_data_path_t;
/**
* @brief Type of controller HCI transport layer
*/
typedef enum {
ESP_BT_CTRL_HCI_TL_UART = 0, /*!< HCI UART h4 transport layer */
ESP_BT_CTRL_HCI_TL_VHCI = 1, /*!< VHCI interface */
} esp_bt_ctrl_hci_tl_t;
#define ESP_BT_HCI_TL_STATUS_OK (0) /*!< HCI_TL Tx/Rx operation status OK */
/**
* @brief callback function for HCI Transport Layer send/receive operations
*/
typedef void (* esp_bt_hci_tl_callback_t) (void *arg, uint8_t status);
#if CONFIG_BT_CTRL_HCI_MODE_CHOICE_VHCI
#define CFG_HCI_TL_TYPE 1
#else
#define CFG_HCI_TL_TYPE 0
#endif
/**
* @brief Controller HCI transport layer function structure
* This structure shall be registered when HCI transport layer is UART
*/
typedef struct {
uint32_t _magic; /* Magic number */
uint32_t _version; /* version number of the defined structure */
uint32_t _reserved; /* reserved for future use */
int (* _open)(void); /* hci tl open */
void (* _close)(void); /* hci tl close */
void (* _finish_transfers)(void); /* hci tl finish transfers */
void (* _recv)(uint8_t *buf, uint32_t len, esp_bt_hci_tl_callback_t callback, void* arg); /* hci tl recv */
void (* _send)(uint8_t *buf, uint32_t len, esp_bt_hci_tl_callback_t callback, void* arg); /* hci tl send */
bool (* _flow_off)(void); /* hci tl flow off */
void (* _flow_on)(void); /* hci tl flow on */
} esp_bt_hci_tl_t;
/**
* @brief Bluetooth mode for controller enable/disable
*/
typedef enum {
ESP_BT_MODE_IDLE = 0x00, /*!< Bluetooth is not running */
ESP_BT_MODE_BLE = 0x01, /*!< Run BLE mode */
@@ -37,9 +89,8 @@ typedef enum {
} esp_bt_mode_t;
/**
* @brief Bluetooth controller enable/disable/initialised/de-initialised status
* @brief Bluetooth controller enable/disable/initialised/de-initialised status.
*/
typedef enum {
ESP_BT_CONTROLLER_STATUS_IDLE = 0, /*!< Controller is in idle state */
ESP_BT_CONTROLLER_STATUS_INITED, /*!< Controller is in initialising state */
@@ -77,25 +128,31 @@ typedef enum {
* @brief Bluetooth TX power level(index), it's just a index corresponding to power(dbm).
*/
typedef enum {
ESP_PWR_LVL_N27 = 0, /*!< Corresponding to -27dbm */
ESP_PWR_LVL_N24 = 1, /*!< Corresponding to -24dbm */
ESP_PWR_LVL_N21 = 2, /*!< Corresponding to -21dbm */
ESP_PWR_LVL_N18 = 3, /*!< Corresponding to -18dbm */
ESP_PWR_LVL_N15 = 4, /*!< Corresponding to -15dbm */
ESP_PWR_LVL_N12 = 5, /*!< Corresponding to -12dbm */
ESP_PWR_LVL_N9 = 6, /*!< Corresponding to -9dbm */
ESP_PWR_LVL_N6 = 7, /*!< Corresponding to -6dbm */
ESP_PWR_LVL_N3 = 8, /*!< Corresponding to -3dbm */
ESP_PWR_LVL_N0 = 9, /*!< Corresponding to 0dbm */
ESP_PWR_LVL_P3 = 10, /*!< Corresponding to +3dbm */
ESP_PWR_LVL_P6 = 11, /*!< Corresponding to +6dbm */
ESP_PWR_LVL_P9 = 12, /*!< Corresponding to +9dbm */
ESP_PWR_LVL_P12 = 13, /*!< Corresponding to +12dbm */
ESP_PWR_LVL_P15 = 14, /*!< Corresponding to +15dbm */
ESP_PWR_LVL_P18 = 15, /*!< Corresponding to +18dbm */
ESP_PWR_LVL_INVALID = 0xFF, /*!< Indicates an invalid value */
ESP_PWR_LVL_N24 = 0, /*!< Corresponding to -24dbm */
ESP_PWR_LVL_N21 = 1, /*!< Corresponding to -21dbm */
ESP_PWR_LVL_N18 = 2, /*!< Corresponding to -18dbm */
ESP_PWR_LVL_N15 = 3, /*!< Corresponding to -15dbm */
ESP_PWR_LVL_N12 = 4, /*!< Corresponding to -12dbm */
ESP_PWR_LVL_N9 = 5, /*!< Corresponding to -9dbm */
ESP_PWR_LVL_N6 = 6, /*!< Corresponding to -6dbm */
ESP_PWR_LVL_N3 = 7, /*!< Corresponding to -3dbm */
ESP_PWR_LVL_N0 = 8, /*!< Corresponding to 0dbm */
ESP_PWR_LVL_P3 = 9, /*!< Corresponding to +3dbm */
ESP_PWR_LVL_P6 = 10, /*!< Corresponding to +6dbm */
ESP_PWR_LVL_P9 = 11, /*!< Corresponding to +9dbm */
ESP_PWR_LVL_P12 = 12, /*!< Corresponding to +12dbm */
ESP_PWR_LVL_P15 = 13, /*!< Corresponding to +15dbm */
ESP_PWR_LVL_P16 = 14, /*!< Corresponding to +16dbm */
ESP_PWR_LVL_P17 = 15, /*!< Corresponding to +17dbm */
ESP_PWR_LVL_P18 = 16, /*!< Corresponding to +18dbm */
ESP_PWR_LVL_P19 = 17, /*!< Corresponding to +19dbm */
ESP_PWR_LVL_P20 = 18, /*!< Corresponding to +20dbm */
ESP_PWR_LVL_INVALID = 0xFF, /*!< Indicates an invalid value */
} esp_power_level_t;
/**
* @brief The enhanced type of which tx power, could set Advertising/Connection/Default and etc.
*/
typedef enum {
ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT = 0,
ESP_BLE_ENHANCED_PWR_TYPE_ADV,
@@ -105,11 +162,22 @@ typedef enum {
ESP_BLE_ENHANCED_PWR_TYPE_MAX,
} esp_ble_enhanced_power_type_t;
/**
* @brief Address type and address value.
*/
typedef struct {
uint8_t type;
uint8_t val[6];
uint8_t type; /*!< Type of the Bluetooth address (public, random, etc.) */
uint8_t val[6]; /*!< Array containing the 6-byte Bluetooth address value */
} esp_ble_addr_t;
/**
* @brief Select buffers
*/
typedef enum {
ESP_BLE_LOG_BUF_HCI = 0x02,
ESP_BLE_LOG_BUF_CONTROLLER = 0x05,
} esp_ble_log_buf_t;
/**
* @brief Set BLE TX power
* Connection Tx power should only be set after connection created.
@@ -127,7 +195,6 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_
*/
esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type);
/**
* @brief ENHANCED API for Setting BLE TX power
* Connection Tx power should only be set after connection created.
@@ -147,119 +214,250 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type
*/
esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle);
#define CONFIG_VERSION 0x20220824
#define CONFIG_MAGIC 0x5A5AA5A5
#define BLE_CONFIG_VERSION 0x20241029
#define BLE_CONFIG_MAGIC 0x5A5AA5A5
#define BTDM_CONFIG_VERSION 0x20260127
#define BTDM_CONFIG_MAGIC_VALUE 0x5a5aa5a5
/* Types definition
************************************************************************
*/
typedef struct {
uint32_t version;
uint16_t task_stack_size; /*!< Size of Bluetooth controller task stack */
uint8_t task_prio; /*!< Priority of the Bluetooth controller task */
uint8_t task_run_cpu; /*!< CPU number on which the Bluetooth controller task runs */
uint8_t hci_cmd_num; /*!< HCI command buffer number */
uint8_t hci_conn_num; /*!< HCI level connection number */
uint8_t sleep_en;
uint8_t version_num;
uint8_t bluetooth_mode; /*!< Controller mode: BR/EDR, BLE or Dual Mode */
uint32_t magic;
}esp_btdm_controller_config_t;
/**
* @brief Controller config options, depend on config mask.
* Config mask indicate which functions enabled, this means
* some options or parameters of some functions enabled by config mask.
*/
typedef struct {
uint32_t config_version;
uint16_t ble_ll_resolv_list_size;
uint16_t ble_hci_evt_hi_buf_count;
uint16_t ble_hci_evt_lo_buf_count;
uint8_t ble_ll_sync_list_cnt;
uint8_t ble_ll_sync_cnt;
uint16_t ble_ll_rsp_dup_list_count;
uint16_t ble_ll_adv_dup_list_count;
uint8_t ble_ll_tx_pwr_dbm;
uint64_t rtc_freq;
uint16_t ble_ll_sca;
uint8_t ble_ll_scan_phy_number;
uint16_t ble_ll_conn_def_auth_pyld_tmo;
uint8_t ble_ll_jitter_usecs;
uint16_t ble_ll_sched_max_adv_pdu_usecs;
uint16_t ble_ll_sched_direct_adv_max_usecs;
uint16_t ble_ll_sched_adv_max_usecs;
uint16_t ble_scan_rsp_data_max_len;
uint8_t ble_ll_cfg_num_hci_cmd_pkts;
uint32_t ble_ll_ctrl_proc_timeout_ms;
uint16_t nimble_max_connections;
uint8_t ble_whitelist_size;
uint16_t ble_acl_buf_size;
uint16_t ble_acl_buf_count;
uint16_t ble_hci_evt_buf_size;
uint16_t ble_multi_adv_instances;
uint16_t ble_ext_adv_max_size;
uint16_t controller_task_stack_size;
uint8_t controller_task_prio;
uint8_t controller_run_cpu;
uint8_t enable_qa_test;
uint8_t enable_bqb_test;
uint8_t enable_uart_hci;
uint8_t ble_hci_uart_port;
uint32_t ble_hci_uart_baud;
uint8_t ble_hci_uart_data_bits;
uint8_t ble_hci_uart_stop_bits;
uint8_t ble_hci_uart_flow_ctrl;
uint8_t ble_hci_uart_uart_parity;
uint8_t enable_tx_cca;
uint8_t cca_rssi_thresh;
uint8_t sleep_en;
uint8_t coex_phy_coded_tx_rx_time_limit;
uint8_t dis_scan_backoff;
uint8_t ble_scan_classify_filter_enable;
uint8_t cca_drop_mode;
int8_t cca_low_tx_pwr;
uint8_t main_xtal_freq;
uint32_t config_magic;
struct {
uint32_t config_version; /*!< Version number of the defined structure */
uint16_t ble_ll_resolv_list_size; /*!< Size of the resolvable private address list */
uint16_t ble_hci_evt_hi_buf_count; /*!< Count of high buffers for HCI events */
uint16_t ble_hci_evt_lo_buf_count; /*!< Count of low buffers for HCI events */
uint8_t ble_ll_sync_list_cnt; /*!< Number of synchronization lists */
uint8_t ble_ll_sync_cnt; /*!< Number of synchronizations */
uint16_t ble_ll_rsp_dup_list_count; /*!< Count of duplicated lists for scan response packets */
uint16_t ble_ll_adv_dup_list_count; /*!< Count of duplicated lists for advertising packets */
uint8_t ble_ll_tx_pwr_dbm; /*!< Tx power (transmit power) in dBm */
uint64_t rtc_freq; /*!< Frequency of RTC (Real-Time Clock) */
uint16_t ble_ll_sca; /*!< Sleep Clock Accuracy (SCA) parameter */
uint8_t ble_ll_scan_phy_number; /*!< Number of PHYs supported for scanning */
uint16_t ble_ll_conn_def_auth_pyld_tmo; /*!< Connection default authentication payload timeout */
uint8_t ble_ll_jitter_usecs; /*!< Jitter time in microseconds */
uint16_t ble_ll_sched_max_adv_pdu_usecs; /*!< Maximum time in microseconds for advertising PDU scheduling */
uint16_t ble_ll_sched_direct_adv_max_usecs; /*!< Maximum time in microseconds for directed advertising scheduling */
uint16_t ble_ll_sched_adv_max_usecs; /*!< Maximum time in microseconds for advertising scheduling */
uint16_t ble_scan_rsp_data_max_len; /*!< Maximum length of scan response data */
uint8_t ble_ll_cfg_num_hci_cmd_pkts; /*!< Number of HCI command packets that can be queued */
uint32_t ble_ll_ctrl_proc_timeout_ms; /*!< Control processing timeout in milliseconds */
uint16_t nimble_max_connections; /*!< Maximum number of connections supported */
uint8_t ble_whitelist_size; /*!< Size of the white list */
uint16_t ble_acl_buf_size; /*!< Buffer size of ACL (Asynchronous Connection-Less) data */
uint16_t ble_acl_buf_count; /*!< Buffer count of ACL data */
uint16_t ble_hci_evt_buf_size; /*!< Buffer size for HCI event data */
uint16_t ble_multi_adv_instances; /*!< Number of advertising instances */
uint16_t ble_ext_adv_max_size; /*!< Maximum size of extended advertising data */
uint16_t controller_task_stack_size; /*!< Size of Bluetooth controller task stack, to be removed */
uint8_t controller_task_prio; /*!< Priority of the Bluetooth task, to be removed */
uint8_t controller_run_cpu; /*!< CPU number on which the Bluetooth controller task runs, to be removed */
uint8_t enable_qa_test; /*!< Enable for QA test */
uint8_t enable_bqb_test; /*!< Enable for BQB test */
uint8_t enable_tx_cca; /*!< Enable Clear Channel Assessment (CCA) when transmitting */
uint8_t cca_rssi_thresh; /*!< RSSI threshold for CCA */
uint8_t sleep_en; /*!< Enable sleep functionality */
uint8_t coex_phy_coded_tx_rx_time_limit; /*!< Coexistence PHY coded TX and RX time limit */
uint8_t dis_scan_backoff; /*!< Disable scan backoff */
uint8_t ble_scan_classify_filter_enable; /*!< Enable classification filter for BLE scan */
uint8_t cca_drop_mode; /*!< CCA drop mode */
int8_t cca_low_tx_pwr; /*!< Low TX power setting for CCA */
uint8_t main_xtal_freq; /*!< Main crystal frequency */
uint8_t ignore_wl_for_direct_adv; /*!< Ignore the white list for directed advertising */
uint8_t enable_pcl; /*!< Enable power control */
uint8_t csa2_select;
uint8_t enable_csr;
int8_t backoff_rssi;
bool iso_enabled;
bool iso_bqb_test;
bool iso_fra_unseg;
bool iso_nsfc_en;
uint8_t iso_nsfc_num;
uint8_t iso_buf_count;
uint16_t iso_buf_size;
uint8_t iso_big_count;
uint16_t iso_bis_count;
uint8_t iso_bis_per_big;
uint8_t iso_cig_count;
uint16_t iso_cis_count;
uint8_t iso_cis_per_cig;
uint32_t config_magic; /*!< Configuration magic value */
} ble; /* Bluetooth LE controller configuration options */
esp_btdm_controller_config_t btdm; /*!< BTDM controller common configuration options */ /*!< BTDM controller common configuration options */
} esp_bt_controller_config_t;
#if defined(CONFIG_BTDM_CTRL_MODE_BLE_ONLY)
#define BTDM_CONTROLLER_MODE_EFF ESP_BT_MODE_BLE
#elif defined(CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY)
#define BTDM_CONTROLLER_MODE_EFF ESP_BT_MODE_CLASSIC_BT
#else
#define BTDM_CONTROLLER_MODE_EFF ESP_BT_MODE_BTDM
#endif
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() { \
.config_version = CONFIG_VERSION, \
.ble_ll_resolv_list_size = CONFIG_BT_LE_LL_RESOLV_LIST_SIZE, \
.ble_hci_evt_hi_buf_count = DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT, \
.ble_hci_evt_lo_buf_count = DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT, \
.ble_ll_sync_list_cnt = DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST, \
.ble_ll_sync_cnt = DEFAULT_BT_LE_MAX_PERIODIC_SYNCS, \
.ble_ll_rsp_dup_list_count = CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT, \
.ble_ll_adv_dup_list_count = CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT, \
.ble_ll_tx_pwr_dbm = BLE_LL_TX_PWR_DBM_N, \
.rtc_freq = RTC_FREQ_N, \
.ble_ll_sca = CONFIG_BT_LE_LL_SCA, \
.ble_ll_scan_phy_number = BLE_LL_SCAN_PHY_NUMBER_N, \
.ble_ll_conn_def_auth_pyld_tmo = BLE_LL_CONN_DEF_AUTH_PYLD_TMO_N, \
.ble_ll_jitter_usecs = BLE_LL_JITTER_USECS_N, \
.ble_ll_sched_max_adv_pdu_usecs = BLE_LL_SCHED_MAX_ADV_PDU_USECS_N, \
.ble_ll_sched_direct_adv_max_usecs = BLE_LL_SCHED_DIRECT_ADV_MAX_USECS_N, \
.ble_ll_sched_adv_max_usecs = BLE_LL_SCHED_ADV_MAX_USECS_N, \
.ble_scan_rsp_data_max_len = DEFAULT_BT_LE_SCAN_RSP_DATA_MAX_LEN_N, \
.ble_ll_cfg_num_hci_cmd_pkts = BLE_LL_CFG_NUM_HCI_CMD_PKTS_N, \
.ble_ll_ctrl_proc_timeout_ms = BLE_LL_CTRL_PROC_TIMEOUT_MS_N, \
.nimble_max_connections = DEFAULT_BT_LE_MAX_CONNECTIONS, \
.ble_whitelist_size = DEFAULT_BT_NIMBLE_WHITELIST_SIZE, \
.ble_acl_buf_size = DEFAULT_BT_LE_ACL_BUF_SIZE, \
.ble_acl_buf_count = DEFAULT_BT_LE_ACL_BUF_COUNT, \
.ble_hci_evt_buf_size = DEFAULT_BT_LE_HCI_EVT_BUF_SIZE, \
.ble_multi_adv_instances = DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES, \
.ble_ext_adv_max_size = DEFAULT_BT_LE_EXT_ADV_MAX_SIZE, \
.controller_task_stack_size = NIMBLE_LL_STACK_SIZE, \
.controller_task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.controller_run_cpu = 0, \
.enable_qa_test = RUN_QA_TEST, \
.enable_bqb_test = RUN_BQB_TEST, \
.enable_uart_hci = HCI_UART_EN, \
.ble_hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, \
.ble_hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, \
.ble_hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS, \
.ble_hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, \
.ble_hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, \
.ble_hci_uart_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, \
.enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED, \
.cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH, \
.cca_drop_mode = 0, \
.cca_low_tx_pwr = 0, \
.sleep_en = NIMBLE_SLEEP_ENABLE, \
.coex_phy_coded_tx_rx_time_limit = DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF, \
.ble_scan_classify_filter_enable = 0, \
.main_xtal_freq = CONFIG_XTAL_FREQ, \
.config_magic = CONFIG_MAGIC, \
#if defined(CONFIG_BT_CTRL_BR_EDR_TEST_MODE_EN)
#define BT_CTRL_BR_EDR_TEST_MODE_EN 1
#else
#define BT_CTRL_BR_EDR_TEST_MODE_EN 0
#endif
#ifndef CONFIG_BT_CTRL_BR_EDR_DTM_EN_EFF
#define CONFIG_BT_CTRL_BR_EDR_DTM_EN_EFF false
#endif
#if defined(CONFIG_BT_CTRL_BR_EDR_TX_CCA_ENABLED)
#define BT_CTRL_BR_EDR_TX_CCA_ENABLED (CONFIG_BT_CTRL_BR_EDR_TX_CCA_ENABLED)
#else
#define BT_CTRL_BR_EDR_TX_CCA_ENABLED (0)
#endif
#if defined(CONFIG_BT_CTRL_BR_EDR_CCA_RSSI_THRESH)
#define BT_CTRL_BR_EDR_CCA_RSSI_THRESH (CONFIG_BT_CTRL_BR_EDR_CCA_RSSI_THRESH)
#else
#define BT_CTRL_BR_EDR_CCA_RSSI_THRESH (50)
#endif
#if defined(CONFIG_BT_LE_ISO_SUPPORT)
#define DEFAULT_BT_LE_ISO_ENABLED 1
#if defined(CONFIG_BT_LE_ISO_FRA_UNSEG)
#define DEFAULT_BT_LE_ISO_FRA_UNSEG CONFIG_BT_LE_ISO_FRA_UNSEG
#else
#define DEFAULT_BT_LE_ISO_FRA_UNSEG (0)
#endif
#if defined(CONFIG_BT_LE_ISO_NSFC_EN)
#define DEFAULT_BT_LE_ISO_NSFC_EN CONFIG_BT_LE_ISO_NSFC_EN
#define DEFAULT_BT_LE_ISO_NSFC_NUM CONFIG_BT_LE_ISO_NSFC_NUM
#else
#define DEFAULT_BT_LE_ISO_NSFC_EN (0)
#define DEFAULT_BT_LE_ISO_NSFC_NUM (0)
#endif
#define DEFAULT_BT_LE_ISO_BUF_COUNT CONFIG_BT_LE_ISO_BUF_COUNT
#define DEFAULT_BT_LE_ISO_BUF_SIZE CONFIG_BT_LE_ISO_BUF_SIZE
#define DEFAULT_BT_LE_ISO_BIG CONFIG_BT_LE_ISO_BIG
#define DEFAULT_BT_LE_ISO_BIS CONFIG_BT_LE_ISO_BIS
#define DEFAULT_BT_LE_ISO_BIS_PER_BIG CONFIG_BT_LE_ISO_BIS_PER_BIG
#define DEFAULT_BT_LE_ISO_CIG CONFIG_BT_LE_ISO_CIG
#define DEFAULT_BT_LE_ISO_CIS CONFIG_BT_LE_ISO_CIS
#define DEFAULT_BT_LE_ISO_CIS_PER_CIG CONFIG_BT_LE_ISO_CIS_PER_CIG
#else
#define DEFAULT_BT_LE_ISO_ENABLED 0
#define DEFAULT_BT_LE_ISO_FRA_UNSEG 0
#define DEFAULT_BT_LE_ISO_NSFC_EN 0
#define DEFAULT_BT_LE_ISO_NSFC_NUM 0
#define DEFAULT_BT_LE_ISO_BUF_COUNT 0
#define DEFAULT_BT_LE_ISO_BUF_SIZE 0
#define DEFAULT_BT_LE_ISO_BIG 0
#define DEFAULT_BT_LE_ISO_BIS 0
#define DEFAULT_BT_LE_ISO_BIS_PER_BIG 0
#define DEFAULT_BT_LE_ISO_CIG 0
#define DEFAULT_BT_LE_ISO_CIS 0
#define DEFAULT_BT_LE_ISO_CIS_PER_CIG 0
#endif
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() { \
.ble = { \
.config_version = BLE_CONFIG_VERSION, \
.ble_ll_resolv_list_size = CONFIG_BT_LE_LL_RESOLV_LIST_SIZE, \
.ble_hci_evt_hi_buf_count = DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT, \
.ble_hci_evt_lo_buf_count = DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT, \
.ble_ll_sync_list_cnt = DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST, \
.ble_ll_sync_cnt = DEFAULT_BT_LE_MAX_PERIODIC_SYNCS, \
.ble_ll_rsp_dup_list_count = CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT, \
.ble_ll_adv_dup_list_count = CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT, \
.ble_ll_tx_pwr_dbm = 0, \
.rtc_freq = 32000, \
.ble_ll_sca = CONFIG_BT_LE_LL_SCA, \
.ble_ll_scan_phy_number = BLE_LL_SCAN_PHY_NUMBER_N, \
.ble_ll_conn_def_auth_pyld_tmo = BLE_LL_CONN_DEF_AUTH_PYLD_TMO_N, \
.ble_ll_jitter_usecs = BLE_LL_JITTER_USECS_N, \
.ble_ll_sched_max_adv_pdu_usecs = BLE_LL_SCHED_MAX_ADV_PDU_USECS_N, \
.ble_ll_sched_direct_adv_max_usecs = BLE_LL_SCHED_DIRECT_ADV_MAX_USECS_N, \
.ble_ll_sched_adv_max_usecs = BLE_LL_SCHED_ADV_MAX_USECS_N, \
.ble_scan_rsp_data_max_len = DEFAULT_BT_LE_SCAN_RSP_DATA_MAX_LEN_N, \
.ble_ll_cfg_num_hci_cmd_pkts = BLE_LL_CFG_NUM_HCI_CMD_PKTS_N, \
.ble_ll_ctrl_proc_timeout_ms = BLE_LL_CTRL_PROC_TIMEOUT_MS_N, \
.nimble_max_connections = DEFAULT_BT_LE_MAX_CONNECTIONS, \
.ble_whitelist_size = DEFAULT_BT_NIMBLE_WHITELIST_SIZE, \
.ble_acl_buf_size = DEFAULT_BT_LE_ACL_BUF_SIZE, \
.ble_acl_buf_count = DEFAULT_BT_LE_ACL_BUF_COUNT, \
.ble_hci_evt_buf_size = DEFAULT_BT_LE_HCI_EVT_BUF_SIZE, \
.ble_multi_adv_instances = DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES, \
.ble_ext_adv_max_size = DEFAULT_BT_LE_EXT_ADV_MAX_SIZE, \
.controller_task_stack_size = UC_BT_CTRL_TASK_STACK_SIZE, \
.controller_task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.controller_run_cpu = 0, \
.enable_qa_test = RUN_QA_TEST, \
.enable_bqb_test = RUN_BQB_TEST, \
.enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED, \
.cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH, \
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
.coex_phy_coded_tx_rx_time_limit = DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF, \
.dis_scan_backoff = NIMBLE_DISABLE_SCAN_BACKOFF, \
.ble_scan_classify_filter_enable = 1, \
.main_xtal_freq = CONFIG_XTAL_FREQ, \
.ignore_wl_for_direct_adv = 0, \
.enable_pcl = 0, \
.csa2_select = 1, \
.enable_csr = 0, \
.backoff_rssi = -100, \
.iso_enabled = DEFAULT_BT_LE_ISO_ENABLED, \
.iso_bqb_test = false, \
.iso_fra_unseg = DEFAULT_BT_LE_ISO_FRA_UNSEG, \
.iso_nsfc_en = DEFAULT_BT_LE_ISO_NSFC_EN, \
.iso_nsfc_num = DEFAULT_BT_LE_ISO_NSFC_NUM, \
.iso_buf_count = DEFAULT_BT_LE_ISO_BUF_COUNT, \
.iso_buf_size = DEFAULT_BT_LE_ISO_BUF_SIZE, \
.iso_big_count = DEFAULT_BT_LE_ISO_BIG, \
.iso_bis_count = DEFAULT_BT_LE_ISO_BIS, \
.iso_bis_per_big = DEFAULT_BT_LE_ISO_BIS_PER_BIG, \
.iso_cig_count = DEFAULT_BT_LE_ISO_CIG, \
.iso_cis_count = DEFAULT_BT_LE_ISO_CIS, \
.iso_cis_per_cig = DEFAULT_BT_LE_ISO_CIS_PER_CIG, \
.config_magic = BLE_CONFIG_MAGIC, \
}, \
.btdm = { \
.version = BTDM_CONFIG_VERSION, \
.task_stack_size = UC_BT_CTRL_TASK_STACK_SIZE, \
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
.hci_conn_num = DEFAULT_BT_LE_MAX_CONNECTIONS + DEFAULT_BT_LE_ISO_CIS + DEFAULT_BT_LE_ISO_BIS, \
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
.version_num = 0, \
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
.magic = BTDM_CONFIG_MAGIC_VALUE, \
}, \
}
/**
* @brief Initialize BT controller to allocate task and other resource.
* This function should be called only once, before any other BT functions are called.
* @param cfg: Initial configuration of BT controller. Different from previous version, there's a mode and some
* connection configuration in "cfg" to configure controller work mode and allocate the resource which is needed.
* @return ESP_OK - success, other - failed
*/
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg);
/**
@@ -267,11 +465,53 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg);
* @return status value
*/
esp_bt_controller_status_t esp_bt_controller_get_status(void);
/**
* @brief Get BLE TX power
* Connection Tx power should only be get after connection created.
* @param power_type : The type of which tx power, could set Advertising/Connection/Default and etc
* @return >= 0 - Power level, < 0 - Invalid
*/
esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type);
/**
* @brief De-initialize BT controller to free resource and delete task.
* You should stop advertising and scanning, as well as
* disconnect all existing connections before de-initializing BT controller.
*
* This function should be called only once, after any other BT functions are called.
* This function is not whole completed, esp_bt_controller_init cannot called after this function.
* @return ESP_OK - success, other - failed
*/
esp_err_t esp_bt_controller_deinit(void);
/**
* @brief Enable BT controller.
* Due to a known issue, you cannot call esp_bt_controller_enable() a second time
* to change the controller mode dynamically. To change controller mode, call
* esp_bt_controller_disable() and then call esp_bt_controller_enable() with the new mode.
* @param mode : the mode(BLE/BT/BTDM) to enable. For compatible of API, retain this argument. This mode must be
* equal as the mode in "cfg" of esp_bt_controller_init().
* @return ESP_OK - success, other - failed
*/
esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode);
/**
* @brief Disable BT controller
* @return ESP_OK - success, other - failed
*/
esp_err_t esp_bt_controller_disable(void);
/**
* @brief Get BT controller is initialised/de-initialised/enabled/disabled
* @return status value
*/
esp_bt_controller_status_t esp_bt_controller_get_status(void);
/** @brief esp_vhci_host_callback
* used for vhci call host function to notify what host need to do
*/
typedef struct esp_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*/
@@ -359,9 +599,20 @@ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode);
*/
esp_err_t esp_bt_mem_release(esp_bt_mode_t mode);
/* Returns random static address or -1 if not present */
/**
* @brief Returns random static address or -1 if not present.
* @return ESP_OK - success, other - failed
*/
extern int esp_ble_hw_get_static_addr(esp_ble_addr_t *addr);
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
/**
* @brief dump all log information cached in buffers.
* @param output : true for log dump, false will take no effect
*/
void esp_ble_controller_log_dump_all(bool output);
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,360 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
// @brief HCI VS Commands for Espressif's Bluetooth Host
//
// @note The following vendor-specific HCI commands are exclusively for Espressif's Bluetooth Host (ESP-Bluedroid Host or ESP-NimBLE Host).
// If you are using a non-ESP host or HCI UART, these commands will remain disabled unless the initialization function is explicitly called from the application.
// Note, these init functions as well as these additional HCI VS commands are intended for Espressif's Bluetooth Host use only.
// Application developers **should not** call the init functions in their applications.
//
/**
* @brief Config scanning duplicate exceptional list (OCF: 0x0108)
*
* @note The init function is `advFilter_stack_eanbleDupExcListCmd(true)`
*/
#define ESP_BT_VS_CONFIG_DUP_EXC_LIST_OCF (0x0108)
/**
* @brief Update exception list cmd parameters
*/
struct bt_hci_vs_update_exc_list {
uint8_t subcode; /*!< Add, remove or clear exception list */
uint32_t type; /*!< device type */
uint8_t device_info[6]; /*!< device information */
};
/**
* @brief Enable/disable advertising report flow control (OCF: 0x0109)
*
* @note The init function is `scan_stack_enableAdvFlowCtrlVsCmd(true)`
*/
#define ESP_BT_VS_SET_ADV_REPORT_FLOW_CTRL_OCF (0x0109)
/**
* @brief Init ADV flow control cmd parameters
*/
struct bt_hci_vs_init_adv_flow_ctrl {
uint8_t enable; /*!< Enable ADV flow control */
uint16_t num; /*!< ADV buffer maximum value */
uint16_t adv_lost_threshold; /*!< ADV lost event triggered threshold */
};
/**
* @brief Update the number of advertising report in ADV flow control (OCF: 0x010A)
*
* @note The init function is `scan_stack_enableAdvFlowCtrlVsCmd(true)`
*/
#define ESP_BT_VS_UPD_ADV_REPORT_FLOW_CTRL_NUM_OCF (0x010a)
/**
* @brief Update ADV flow control cmd parameters
*/
struct bt_hci_vs_update_adv_flow_ctrl {
uint16_t num; /*!< The number of ADV report processed */
};
/**
* @brief Clear legacy advertising (same as HCI_LE_Clear_Advertising_Sets) (OCF: 0x010C)
*
* @note The init function is `adv_stack_enableClearLegacyAdvVsCmd(true)`
*/
#define ESP_BT_VS_CLR_LEGACY_ADV_OCF (0x010c)
/**
* @brief Clear legacy ADV cmd parameters
*/
struct bt_hci_vs_ble_clr_legacy_adv {
// no parameters
};
/**
* @brief Set parameters of duplicate list (OCF: 0x010D)
*
* @note The init function is `advFilter_stack_eanbleDupExcListCmd(true)`
*/
#define ESP_BT_VS_SET_DUP_LIST_PARAMS_OCF (0x010d)
/**
* @brief Set duplicate list cmd parameters
*/
struct bt_hci_vs_ble_set_dup_params {
uint8_t dup_mode; /*!< Duplicate mode */
uint8_t dup_ad_type; /*!< Duplicate data type */
uint16_t ring_list_max_num; /*!< Duplicate list size */
};
/**
* @brief Enable/disable duplicate and exception list (OCF: 0x010E)
*
* @note The init function is `advFilter_stack_eanbleDupExcListCmd(true)`
*/
#define ESP_BT_VS_ENABLE_DUP_EXC_LIST_OCF (0x010e)
/**
* @brief Enable duplicate and exception list cmd parameters
*/
struct bt_hci_vs_ble_enable_dup_exc {
uint8_t enable; /*!< Enable or disable */
uint8_t ring_list_reset; /*!< Reset list */
};
/**
* @brief Enable optimization of multiple connections (OCF: 0x010F)
*
* @note The init function is `arr_stack_enableMultiConnVsCmd(true)`
*/
#define ESP_BT_VS_ENABLE_ARRANGEMENT_OCF (0x010f)
/**
* @brief Multiple connections optimization cmd parameters
*/
struct bt_hci_vs_ble_enable_arrangement {
uint32_t common_factor; /*!< The greatest common factor of connection interval */
uint8_t enable; /*!< Enable or disable */
};
/**
* @brief Set scheduling length for a certain role (OCF: 0x0110)
*
* @note The init function is `arr_stack_enableMultiConnVsCmd(true)`
*/
#define ESP_BT_VS_SET_SCHED_ROLE_LEN_OCF (0x0110)
/**
* @brief Scheduling length cmd parameters
*/
struct bt_hci_vs_ble_set_sched_role_len {
uint8_t role; /*!< BLE role; 0: central; 1: peripheral */
uint32_t len; /*!< Length is us */
};
/**
* @brief Set RSSI threshold for automatic power control (OCF: 0x0111)
*
* @note The init function is `pcl_stack_enableSetRssiThreshVsCmd(true)`
*/
#define ESP_BT_VS_SET_PCL_RSSI_THRESH_OCF (0x0111)
/**
* @brief PCL RSSI threshold cmd parameters
*/
struct bt_hci_vs_ble_set_pcl_rssi_thresh {
uint16_t conn_handle; /*!< Connection handle */
uint8_t rssi_thresh_min_1M; /*!< Lower limit for 1M */
uint8_t rssi_thresh_max_1M; /*!< Upper limit for 1M */
uint8_t rssi_thresh_min_2M; /*!< Lower limit for 2M */
uint8_t rssi_thresh_max_2M; /*!< Upper limit for 2M */
uint8_t rssi_thresh_min_s2coded; /*!< Lower limit for s2 coded */
uint8_t rssi_thresh_max_s2coded; /*!< Upper limit for s2 coded */
uint8_t rssi_thresh_min_s8coded; /*!< Lower limit for s8 coded */
uint8_t rssi_thresh_max_s8coded; /*!< Upper limit for s8 coded */
};
/**
* @brief Enable/disable channel selection algorithm #2 (OCF: 0x0112)
*
* @note The init function is `chanSel_stack_enableSetCsaVsCmd(true)`
*/
#define ESP_BT_VS_ENABLE_CSA2_OCF (0x0112)
/**
* @brief Enable/disable channel selection algorithm #2 cmd parameters
*/
struct bt_hci_vs_ble_csa_enable {
uint8_t csa2_select; /*!< Select CSA2 */
};
/**
* @brief Set parameters of controller logs (OCF: 0x0114)
*
* @note The init function is `log_stack_enableLogsRelatedVsCmd(true)`
*/
#define ESP_BT_VS_SET_LOG_PARAMS_OCF (0x0114)
/**
* @brief Controller logs cmd parameters
*/
struct bt_hci_vs_ble_log_params {
uint8_t type; /*!< Operation type */
uint32_t output_enable; /*!< Enable/disable output */
uint8_t buffer_optoin /*!< Select log buffers */
};
/**
* @brief Set BLE vendor events mask (OCF: 0x0116)
*
* @note The init function is `hci_stack_enableSetVsEvtMaskVsCmd(true)`
*/
#define ESP_BT_VS_SET_LE_VENDOR_EVTS_MASK_OCF (0x0116)
/**
* @brief Set BLE vendor events mask cmd parameters
*/
struct bt_hci_vs_ble_set_vs_evts_mask {
uint32_t evt_masks; /*!< BLE vendor events Mask */
};
/**
* @brief Set peer sleep clock accuracy to a constant value (OCF: 0x0118)
*
* @note The init function is `winWiden_stack_enableSetConstPeerScaVsCmd(true)`
*/
#define ESP_BT_VS_SET_CONST_PEER_SCA_OCF (0x0118)
/**
* @brief Peer constant SCA cmd parameters
*/
struct bt_hci_vs_ble_set_const_peer_sca {
uint16_t peer_sca; /*!< Peer SCA */
};
// @brief HCI VS Events for Espressif's Bluetooth Host
//
// @note The following HCI VS events are exclusively for Espressif's Bluetooth Host (ESP-Bluedroid Host or ESP-NimBLE Host).
// If you are using a non-ESP host or HCI UART, these events will remain disabled unless the initialization function is explicitly called from the application.
// Note, these init functions as well as these additional HCI VS events are intended for Espressif's Bluetooth Host use only.
// Application developers **should not** call the init functions in their applications.
//
/**
* @brief BLE Scan/Connect Request, Aux Connect Response received event (EVTCODE: 0xFF, SUBCODE: 0xC0)
*
* @note The init function is `adv_stack_enableScanReqRxdVsEvent(true)`
*/
#define ESP_BT_VS_LE_CONN_SCAN_REQ_RXED_EVT_SUBCODE (0xC0)
/**
* @brief BLE Scan/Connect Request, Aux Connect Response received event parameters
*/
struct bt_hci_vs_le_conn_scan_req_rxed_evt {
uint8_t evt_type; /*!< Event type; 0: SCAN_REQ; 1: CONN_IND */
uint8_t handle; /*!< Advertisement handle */
uint8_t peer_addr_type; /*!< Peer address type */
uint8_t peer_addr[6]; /*!< Peer address */
};
/**
* @brief BLE Channel Map Update Completion event (EVTCODE: 0xFF, SUBCODE: 0xC1)
*
* @note The init function is `conn_stack_enableChanMapUpdCompVsEvent(true)`
*/
#define ESP_BT_VS_LE_CHAN_UPDATE_COMP_EVT_SUBCODE (0xC1)
/**
* @brief BLE Channel Map Update Completion event parameters
*/
struct bt_hci_vs_le_chan_update_comp_evt {
uint8_t status; /*!< Controller error code */
uint16_t handle; /*!< Connection handle */
uint8_t ch_map[5]; /*!< Updated channel map */
};
/**
* @brief BLE Wakeup From Sleep event (EVTCODE: 0xFF, SUBCODE: 0xC3)
*
* @note The init function is `sleep_stack_enableWakeupVsEvent(true)`
*/
#define ESP_BT_VS_LE_SLEEP_WAKEUP_EVT_SUBCODE (0xC3)
/**
* @brief BLE wakeup event parameters
*/
struct bt_hci_vs_le_sleep_wakeup_evt {
// no parameters
};
/**
* @brief BLE advertising report lost event for flow control (EVTCODE: 0x3E, SUBCODE: 0xF0)
*
* @note The init function is `scan_stack_enableAdvFlowCtrlVsCmd(true)`
*/
#define ESP_BT_VS_LE_ADV_LOST_EVT_SUBCODE (0xF0)
/**
* @brief ADV lost event parameters
*/
struct bt_hci_vs_le_adv_lost_evt {
uint32_t nb_lost; /*!< The number of ADV report discarded */
};
//
// @brief HCI VS Commands for Espressif's Internal-Use Debugging
//
// @note The following HCI VS debugging commands are implemented in Bluetooth controller pre-compiled libraries.
// These commands are not linked into the application binary, unless the function `esp_ble_internalTestFeaturesEnable(true)`is called from the application.
// They are intended for Espressif's internal use only. Application developers **should not** call `esp_ble_internalTestFeaturesEnable(true)` in their applications.
//
#define ESP_BT_VS_CFG_TEST_RELATED_OCF (0x0113)
#define ESP_BT_VS_CFG_TEST_ENABLE_SUBCMD (0X00)
#define ESP_BT_VS_CFG_TEST_ENABLE_ADV_DELAY_SUBCMD (0X01)
#define ESP_BT_VS_CFG_TEST_SET_PREF_CODED_SUBCMD (0X02)
#define ESP_BT_VS_CFG_TEST_SET_DEFAULT_PRIV_MODE_SUBCMD (0X03)
#define ESP_BT_VS_CFG_TEST_SET_SCAN_FOREVER_SUBCMD (0X04)
#define ESP_BT_VS_CFG_TEST_SET_EXPECTED_PEER_SUBCMD (0X05)
#define ESP_BT_VS_CFG_TEST_GET_ADV_TXED_CNT_SUBCMD (0X06)
#define ESP_BT_VS_CFG_TEST_GET_SCAN_RXED_CNT_SUBCMD (0X07)
#define ESP_BT_VS_CFG_TEST_SET_TXPWR_LVL_SUBCMD (0X08)
#define ESP_BT_VS_CFG_TEST_GET_TXPWR_LVL_SUBCMD (0X09)
#define ESP_BT_VS_CFG_TEST_SET_TXPWR_LVL_ENH_SUBCMD (0X0a)
#define ESP_BT_VS_CFG_TEST_GET_TXPWR_LVL_ENH_SUBCMD (0X0b)
#define ESP_BT_VS_CFG_TEST_IGNORE_WL_FOR_DIR_ADV_SUBCMD (0X0c)
#define ESP_BT_VS_CFG_TEST_GET_ADV_RXED_RSSI_SUBCMD (0X0d)
#define ESP_BT_VS_CFG_TEST_ENABLE_CCA_SUBCMD (0X0e)
#define ESP_BT_VS_CFG_TEST_SET_CCA_WIN_SUBCMD (0X0f)
#define ESP_BT_VS_CFG_TEST_READ_CCA_DATA_SUBCM (0X10)
#define ESP_BT_VS_CFG_TEST_CLEAR_RAND_ADDR_SUBCMD (0X11)
#define ESP_BT_VS_CFG_TEST_GET_MAX_TXPWR_SUBCMD (0X12)
#define ESP_BT_VS_CFG_TEST_GET_TXPWR_RANGE_SUBCMD (0X13)
#define ESP_BT_VS_CFG_TEST_SET_SCAN_AA_SUBCMD (0X14)
#define ESP_BT_VS_CFG_TEST_SET_ADV_AA_SUBCMD (0X15)
#define ESP_BT_VS_CFG_TEST_SET_SCAN_CHAN_SUBCMD (0X16)
#define ESP_BT_VS_CFG_TEST_SKIP_LIGHT_SLEEP_CHECK_SUBCMD (0X17)
#define ESP_BT_VS_CFG_TEST_SET_WAKEUP_OVERHEAD_SUBCMD (0X18)
#define ESP_BT_VS_CFG_TEST_GET_ADV_MIN_ITVL_SUBCMD (0X19)
#define ESP_BT_VS_CFG_TEST_GET_CTRL_STATUS_SUBCMD (0X1a)
#define ESP_BT_VS_CFG_TEST_SET_CONN_PHY_TXPWR_SUBCMD (0X1b)
#define ESP_BT_VS_CFG_TEST_GET_CONN_PHY_TXPWR_SUBCMD (0X1c)
#define ESP_BT_VS_CFG_TEST_GET_RXBUF_EMPTY_CNT_SUBCMD (0X1d)
#define ESP_BT_VS_CFG_TEST_RESTART_SUBCMD (0X1e)
#define ESP_BT_VS_CFG_TEST_ENABLE_RECODE_RX_STATE_SUBCMD (0X1f)
#define ESP_BT_VS_CFG_TEST_GET_RECODE_CNT_SUBCMD (0X20)
#define ESP_BT_VS_CFG_TEST_CLR_RECODE_CNT_SUBCMD (0X21)
#define ESP_BT_VS_CFG_TEST_GET_CTRL_COMPILE_VER_SUBCMD (0X24)
#define ESP_BT_VS_CFG_TEST_SET_AUX_ADV_OFFSET_SUBCMD (0X25)
#define ESP_BT_VS_CFG_TEST_INIT_FLEXIBLE_MODE_SUBCMD (0X26)
#define ESP_BT_VS_CFG_TEST_ENABLE_FLEXIBLE_MODE_SUBCMD (0X27)
#define ESP_BT_VS_CFG_TEST_SET_FLEXIBLE_CONN_ERR_SUBCMD (0X28)
#define ESP_BT_VS_CFG_TEST_SET_FLEXIBLE_ADV_ERR_SUBCMD (0X29)
#define ESP_BT_VS_CFG_TEST_SET_FLEXIBLE_SCAN_ERR_SUBCMD (0X2a)
#define ESP_BT_VS_CFG_TEST_GET_TXED_CRCERR_SUBCMD (0X2c)
#define ESP_BT_VS_CFG_TEST_GET_BACKOFF_UPLIMIT_SUBCMD (0X2d)
#define ESP_BT_VS_CFG_TEST_GET_RXED_ADV_ADI_SUBCMD (0X2f)
#define ESP_BT_VS_CFG_TEST_SET_SCH_RAND_MODE_SUBCMD (0X30)
#define ESP_BT_VS_CFG_TEST_SET_RX_SENS_THRESH_SUBCMD (0X31)
#define ESP_BT_VS_CFG_TEST_CHECK_MSYS_BUF_SUBCMD (0X32)
#define ESP_BT_VS_CFG_TEST_UPDATE_BLE_TIMER_SUBCMD (0X33)
#define ESP_BT_VS_CFG_TEST_UPDATE_BLE_RTC_SUBCMD (0X34)
#define ESP_BT_VS_CFG_TEST_SET_LOCKED_MEM_NUM_SUBCMD (0X35)
#define ESP_BT_VS_CFG_TEST_ALLOW_MEM_ALLOC_SUBCMD (0X36)
#define ESP_BT_VS_CFG_TEST_SET_SCH_RAND_INFO_PTR_SUBCMD (0X37)
#define ESP_BT_VS_CFG_TEST_SET_DIAG_IO_SUBCMD (0X38)
#define ESP_BT_VS_CFG_TEST_SET_AGC_MAX_GAIN_SUBCMD (0X39)
#define ESP_BT_VS_CFG_TEST_ENABLE_CHAN_ASSESS_SUBCMD (0X40)
#define ESP_BT_VS_CFG_TEST_SET_BACKOFF_UPLIMIT_SUBCMD (0X41)
#define ESP_BT_VS_CFG_TEST_SET_CONN_TOP_PRIO_RESV_THRESH_SUBCMD (0X42)
#define ESP_BT_VS_CFG_TEST_SET_TEST_EVT_MSK_SUBCMD (0X43)
#define ESP_BT_VS_CFG_TEST_GET_WAKEUP_TIMEOUT_SUBCMD (0X45)
#define ESP_BT_VS_CFG_TEST_RELATED_SUBCMD_MAX (0Xff)
//
// @brief HCI VS Events for Espressif's Internal-Use Debugging
//
// @note The following HCI VS debugging events are implemented in Bluetooth controller pre-compiled libraries.
// These events are not linked into the application binary, unless the function `esp_ble_internalTestFeaturesEnable(true)`is called from the application.
// Application developers **should not** call `esp_ble_internalTestFeaturesEnable(true)` in their applications.
//
#define ESP_BT_VS_LE_RUNNING_STATUS_EVT_SUBCODE (0xC3)
#ifdef __cplusplus
}
#endif
+2 -84
View File
@@ -10,101 +10,19 @@
#include "esp_attr.h"
#include "esp_heap_caps.h"
void *bt_osi_mem_malloc(size_t size);
void *bt_osi_mem_calloc(size_t n, size_t size);
void *bt_osi_mem_malloc_internal(size_t size);
void *bt_osi_mem_calloc_internal(size_t n, size_t size);
void bt_osi_mem_free(void *ptr);
void bt_osi_mem_free_internal(void *ptr);
#if CONFIG_BT_LE_MEM_CHECK_ENABLED
void bt_osi_mem_count_limit_set(uint16_t count_limit);
#endif // CONFIG_BT_LE_MEM_CHECK_ENABLED
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
size_t bt_osi_mem_internal_used_size_get(void);
// TODO: Remove it. bt_osi_mem_used_size_get has been defined in esp_nimble_mem.h.
size_t bt_osi_mem_used_size_get(void);
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
#if CONFIG_BT_NIMBLE_MEM_DEBUG
/**
* @brief Initialize NimBLE memory debug module
*/
void nimble_mem_dbg_init(void);
/**
* @brief Record memory allocation information
*
* @param p Pointer to allocated memory
* @param size Size of allocation
* @param func Function name where allocation occurred
* @param line Line number where allocation occurred
*/
void nimble_mem_dbg_record(void *p, int size, const char *func, int line);
/**
* @brief Clean up memory allocation record
*
* @param p Pointer to memory being freed
* @param func Function name where free occurred
* @param line Line number where free occurred
*/
void nimble_mem_dbg_clean(void *p, const char *func, int line);
/**
* @brief Display all memory debug information
*/
void nimble_mem_dbg_show(void);
/**
* @brief Get maximum memory size used
*
* @return Maximum memory size in bytes
*/
uint32_t nimble_mem_dbg_get_max_size(void);
/**
* @brief Get current memory size in use
*
* @return Current memory size in bytes
*/
uint32_t nimble_mem_dbg_get_current_size(void);
/**
* @brief Start tracking memory usage for a specific section
*
* @param index Section index (0 to NIMBLE_MEM_DBG_MAX_SECTION_NUM-1)
*/
void nimble_mem_dbg_set_section_start(uint8_t index);
/**
* @brief Stop tracking memory usage for a specific section
*
* @param index Section index (0 to NIMBLE_MEM_DBG_MAX_SECTION_NUM-1)
*/
void nimble_mem_dbg_set_section_end(uint8_t index);
/**
* @brief Get maximum memory size used in a specific section
*
* @param index Section index (0 to NIMBLE_MEM_DBG_MAX_SECTION_NUM-1)
* @return Maximum memory size in bytes for this section
*/
uint32_t nimble_mem_dbg_get_max_size_section(uint8_t index);
/**
* @brief Reallocate memory with debug tracking
*
* @param ptr Pointer to memory to reallocate
* @param new_size New size of allocation
* @param func Function name where realloc occurred
* @param line Line number where realloc occurred
* @return Pointer to reallocated memory
*/
void *nimble_mem_dbg_realloc(void *ptr, size_t new_size, const char *func, int line);
#endif // CONFIG_BT_NIMBLE_MEM_DEBUG
+8 -335
View File
@@ -10,311 +10,17 @@
#include "esp_log.h"
#include <assert.h>
static uint8_t log_count;
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
static size_t controller_mem_used_size = 0;
static size_t host_mem_used_size = 0;
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
#if CONFIG_BT_LE_MEM_CHECK_ENABLED
static uint16_t mem_count_limit = 0;
static uint16_t curr_mem_count;
#endif // CONFIG_BT_LE_MEM_CHECK_ENABLED
#if CONFIG_BT_NIMBLE_MEM_DEBUG
#define NIMBLE_MEM_DBG_INFO_MAX 1024*3
typedef struct {
void *p;
int size;
const char *func;
int line;
} nimble_mem_dbg_info_t;
static uint32_t nimble_mem_dbg_count = 0;
static nimble_mem_dbg_info_t nimble_mem_dbg_info[NIMBLE_MEM_DBG_INFO_MAX];
static uint32_t nimble_mem_dbg_current_size = 0;
static uint32_t nimble_mem_dbg_max_size = 0;
#define NIMBLE_MEM_DBG_MAX_SECTION_NUM 5
typedef struct {
bool used;
uint32_t max_size;
} nimble_mem_dbg_max_size_section_t;
static nimble_mem_dbg_max_size_section_t nimble_mem_dbg_max_size_section[NIMBLE_MEM_DBG_MAX_SECTION_NUM];
void nimble_mem_dbg_init(void)
{
int i;
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
nimble_mem_dbg_info[i].p = NULL;
nimble_mem_dbg_info[i].size = 0;
nimble_mem_dbg_info[i].func = NULL;
nimble_mem_dbg_info[i].line = 0;
}
nimble_mem_dbg_count = 0;
nimble_mem_dbg_current_size = 0;
nimble_mem_dbg_max_size = 0;
for (i = 0; i < NIMBLE_MEM_DBG_MAX_SECTION_NUM; i++){
nimble_mem_dbg_max_size_section[i].used = false;
nimble_mem_dbg_max_size_section[i].max_size = 0;
}
}
void nimble_mem_dbg_record(void *p, int size, const char *func, int line)
{
int i;
if (!p || size == 0) {
ESP_LOGE("BT_NIMBLE_MEM", "%s invalid !!\n", __func__);
return;
}
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
if (nimble_mem_dbg_info[i].p == NULL) {
nimble_mem_dbg_info[i].p = p;
nimble_mem_dbg_info[i].size = size;
nimble_mem_dbg_info[i].func = func;
nimble_mem_dbg_info[i].line = line;
nimble_mem_dbg_count++;
break;
}
}
if (i >= NIMBLE_MEM_DBG_INFO_MAX) {
ESP_LOGE("BT_NIMBLE_MEM", "%s full %s %d !!\n", __func__, func, line);
}
nimble_mem_dbg_current_size += size;
if(nimble_mem_dbg_max_size < nimble_mem_dbg_current_size) {
nimble_mem_dbg_max_size = nimble_mem_dbg_current_size;
}
for (i = 0; i < NIMBLE_MEM_DBG_MAX_SECTION_NUM; i++){
if (nimble_mem_dbg_max_size_section[i].used) {
if(nimble_mem_dbg_max_size_section[i].max_size < nimble_mem_dbg_current_size) {
nimble_mem_dbg_max_size_section[i].max_size = nimble_mem_dbg_current_size;
}
}
}
}
void nimble_mem_dbg_clean(void *p, const char *func, int line)
{
int i;
if (!p) {
ESP_LOGE("BT_NIMBLE_MEM", "%s %d free->%p invalid\n", func, line, p);
return;
}
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
if (nimble_mem_dbg_info[i].p == p) {
nimble_mem_dbg_current_size -= nimble_mem_dbg_info[i].size;
nimble_mem_dbg_info[i].p = NULL;
nimble_mem_dbg_info[i].size = 0;
nimble_mem_dbg_info[i].func = NULL;
nimble_mem_dbg_info[i].line = 0;
nimble_mem_dbg_count--;
break;
}
}
if (i >= NIMBLE_MEM_DBG_INFO_MAX) {
ESP_LOGE("BT_NIMBLE_MEM", "%s full %s %d !!\n", __func__, func, line);
}
}
void nimble_mem_dbg_show(void)
{
int i;
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
if (nimble_mem_dbg_info[i].p || nimble_mem_dbg_info[i].size != 0 ) {
ESP_LOGE("BT_NIMBLE_MEM", "--> p %p, s %d, f %s, l %d\n",
nimble_mem_dbg_info[i].p, nimble_mem_dbg_info[i].size,
nimble_mem_dbg_info[i].func, nimble_mem_dbg_info[i].line);
}
}
ESP_LOGE("BT_NIMBLE_MEM", "--> count %ld\n", nimble_mem_dbg_count);
ESP_LOGE("BT_NIMBLE_MEM", "--> size %ldB\n--> max size %ldB\n",
nimble_mem_dbg_current_size, nimble_mem_dbg_max_size);
}
uint32_t nimble_mem_dbg_get_max_size(void)
{
return nimble_mem_dbg_max_size;
}
uint32_t nimble_mem_dbg_get_current_size(void)
{
return nimble_mem_dbg_current_size;
}
void nimble_mem_dbg_set_section_start(uint8_t index)
{
if (index >= NIMBLE_MEM_DBG_MAX_SECTION_NUM) {
ESP_LOGE("BT_NIMBLE_MEM", "Then range of index should be between 0 and %d, current index is %d.\n",
NIMBLE_MEM_DBG_MAX_SECTION_NUM - 1, index);
return;
}
if (nimble_mem_dbg_max_size_section[index].used) {
ESP_LOGW("BT_NIMBLE_MEM", "This index(%d) has been started, restart it.\n", index);
}
nimble_mem_dbg_max_size_section[index].used = true;
nimble_mem_dbg_max_size_section[index].max_size = nimble_mem_dbg_current_size;
}
void nimble_mem_dbg_set_section_end(uint8_t index)
{
if (index >= NIMBLE_MEM_DBG_MAX_SECTION_NUM) {
ESP_LOGE("BT_NIMBLE_MEM", "Then range of index should be between 0 and %d, current index is %d.\n",
NIMBLE_MEM_DBG_MAX_SECTION_NUM - 1, index);
return;
}
if (!nimble_mem_dbg_max_size_section[index].used) {
ESP_LOGE("BT_NIMBLE_MEM", "This index(%d) has not been started.\n", index);
return;
}
nimble_mem_dbg_max_size_section[index].used = false;
}
uint32_t nimble_mem_dbg_get_max_size_section(uint8_t index)
{
if (index >= NIMBLE_MEM_DBG_MAX_SECTION_NUM){
ESP_LOGE("BT_NIMBLE_MEM", "Then range of index should be between 0 and %d, current index is %d.\n",
NIMBLE_MEM_DBG_MAX_SECTION_NUM - 1, index);
return 0;
}
return nimble_mem_dbg_max_size_section[index].max_size;
}
void *nimble_mem_dbg_realloc(void *ptr, size_t new_size, const char *func, int line)
{
size_t old_size = 0;
int i;
void *new_ptr = realloc(ptr, new_size);
if (new_ptr == NULL && new_size > 0) {
// realloc failed, keep old ptr record
return NULL;
}
// Find and clean old record if ptr is not NULL
if (ptr != NULL) {
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
if (nimble_mem_dbg_info[i].p == ptr) {
old_size = nimble_mem_dbg_info[i].size;
nimble_mem_dbg_current_size -= old_size;
nimble_mem_dbg_info[i].p = NULL;
nimble_mem_dbg_info[i].size = 0;
nimble_mem_dbg_info[i].func = NULL;
nimble_mem_dbg_info[i].line = 0;
nimble_mem_dbg_count--;
break;
}
}
}
// Record the new allocation if new_size > 0
if (new_ptr != NULL && new_size > 0) {
for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) {
if (nimble_mem_dbg_info[i].p == NULL) {
nimble_mem_dbg_info[i].p = new_ptr;
nimble_mem_dbg_info[i].size = new_size;
nimble_mem_dbg_info[i].func = func;
nimble_mem_dbg_info[i].line = line;
nimble_mem_dbg_count++;
break;
}
}
if (i >= NIMBLE_MEM_DBG_INFO_MAX) {
ESP_LOGE("BT_NIMBLE_MEM", "%s full %s %d !!\n", __func__, func, line);
}
nimble_mem_dbg_current_size += new_size;
if (nimble_mem_dbg_max_size < nimble_mem_dbg_current_size) {
nimble_mem_dbg_max_size = nimble_mem_dbg_current_size;
}
for (i = 0; i < NIMBLE_MEM_DBG_MAX_SECTION_NUM; i++) {
if (nimble_mem_dbg_max_size_section[i].used &&
nimble_mem_dbg_max_size_section[i].max_size < nimble_mem_dbg_current_size) {
nimble_mem_dbg_max_size_section[i].max_size = nimble_mem_dbg_current_size;
}
}
}
return new_ptr;
}
#endif // CONFIG_BT_NIMBLE_MEM_DEBUG
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
IRAM_ATTR
#endif
void *bt_osi_mem_malloc(size_t size)
{
void *mem = NULL;
#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL
mem = heap_caps_malloc(size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
mem = heap_caps_malloc(size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT
mem = heap_caps_malloc_prefer(size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#else
mem = malloc(size);
#endif
if (!mem) {
log_count ++;
if ((log_count % 100) == 0) {
ESP_EARLY_LOGI("ESP_LOG_INFO","malloc failed (size %zu)",size);
log_count = 0;
}
assert(mem != NULL);
}
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
if(mem) {
host_mem_used_size += heap_caps_get_allocated_size(mem);
}
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
return mem;
}
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
IRAM_ATTR
#endif
void *bt_osi_mem_calloc(size_t n, size_t size)
{
void *mem = NULL;
#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL
mem = heap_caps_calloc(n, size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
mem = heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT
mem = heap_caps_calloc_prefer(n, size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#else
mem = calloc(n, size);
#endif
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
if(mem) {
host_mem_used_size += heap_caps_get_allocated_size(mem);
}
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
return mem;
}
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
IRAM_ATTR
#endif
void *bt_osi_mem_malloc_internal(size_t size)
void *
bt_osi_mem_malloc_internal(size_t size)
{
void *mem_ptr;
#if CONFIG_BT_LE_MEM_CHECK_ENABLED
@@ -334,10 +40,9 @@ void *bt_osi_mem_malloc_internal(size_t size)
return mem_ptr;
}
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
IRAM_ATTR
#endif
void *bt_osi_mem_calloc_internal(size_t n, size_t size)
void *
bt_osi_mem_calloc_internal(size_t n, size_t size)
{
void *mem_ptr;
#if CONFIG_BT_LE_MEM_CHECK_ENABLED
@@ -357,10 +62,8 @@ void *bt_osi_mem_calloc_internal(size_t n, size_t size)
return mem_ptr;
}
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
IRAM_ATTR
#endif
void bt_osi_mem_free_internal(void *ptr)
void
bt_osi_mem_free_internal(void *ptr)
{
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
if (ptr) {
@@ -374,23 +77,6 @@ void bt_osi_mem_free_internal(void *ptr)
}
}
#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE
IRAM_ATTR
#endif
void bt_osi_mem_free(void *ptr)
{
#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
if (ptr) {
size_t alloc_size = heap_caps_get_allocated_size(ptr);
// assert(host_mem_used_size >= alloc_size);
host_mem_used_size -= alloc_size;
}
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
if (ptr) {
heap_caps_free(ptr);
}
}
#if CONFIG_BT_LE_MEM_CHECK_ENABLED
void bt_osi_mem_count_limit_set(uint16_t count_limit)
{
@@ -406,21 +92,8 @@ bt_osi_mem_internal_used_size_get(void)
return controller_mem_used_size;
}
size_t
bt_osi_mem_used_size_get(void)
{
return host_mem_used_size;
}
uint32_t esp_ble_controller_used_heap_size_get(void)
{
return bt_osi_mem_internal_used_size_get();
}
#if CONFIG_BT_NIMBLE_ENABLED
uint32_t esp_host_used_heap_size_get(void)
{
return bt_osi_mem_used_size_get();
}
#endif // CONFIG_BT_NIMBLE_ENABLED
#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED
+56
View File
@@ -0,0 +1,56 @@
set(porting_btdm_srcs "")
set(porting_btdm_include_dirs "")
# btdm_common
file(GLOB_RECURSE BTDM_COMMON_SRCS "controller/btdm_common/src/*.c")
list(APPEND porting_btdm_srcs ${BTDM_COMMON_SRCS})
list(APPEND porting_btdm_include_dirs "${CMAKE_CURRENT_SOURCE_DIR}/controller/btdm_common/include")
# ble
if(CONFIG_BTDM_CTRL_MODE_BLE_ONLY OR CONFIG_BTDM_CTRL_MODE_BTDM)
file(GLOB_RECURSE BLE_SRCS "controller/ble/src/*.c")
list(APPEND porting_btdm_srcs ${BLE_SRCS})
list(APPEND porting_btdm_include_dirs "${CMAKE_CURRENT_SOURCE_DIR}/controller/ble/include")
endif()
# bredr
if(CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY OR CONFIG_BTDM_CTRL_MODE_BTDM)
file(GLOB_RECURSE BREDR_SRCS "controller/bredr/src/*.c")
list(APPEND porting_btdm_srcs ${BREDR_SRCS})
list(APPEND porting_btdm_include_dirs "${CMAKE_CURRENT_SOURCE_DIR}/controller/bredr/include")
endif()
# transport
file(GLOB_RECURSE TRANSPORT_SRCS "transport/src/*.c")
list(APPEND porting_btdm_srcs ${TRANSPORT_SRCS})
list(APPEND porting_btdm_include_dirs "${CMAKE_CURRENT_SOURCE_DIR}/transport/include")
if(CONFIG_BT_CTRL_HCI_INTERFACE_USE_RAM)
if(CONFIG_BT_NIMBLE_ENABLED)
list(APPEND porting_btdm_srcs
"${CMAKE_CURRENT_SOURCE_DIR}/transport/driver/vhci/hci_driver_nimble.c"
)
else()
list(APPEND porting_btdm_srcs
"${CMAKE_CURRENT_SOURCE_DIR}/transport/driver/vhci/hci_driver_standard.c"
)
endif()
elseif(CONFIG_BT_CTRL_HCI_INTERFACE_USE_UART)
list(APPEND porting_btdm_srcs
"${CMAKE_CURRENT_SOURCE_DIR}/transport/driver/common/hci_driver_util.c"
"${CMAKE_CURRENT_SOURCE_DIR}/transport/driver/common/hci_driver_h4.c"
"${CMAKE_CURRENT_SOURCE_DIR}/transport/driver/common/hci_driver_mem.c"
"${CMAKE_CURRENT_SOURCE_DIR}/transport/driver/uart/hci_driver_uart_config.c"
)
if(CONFIG_BT_CTRL_UART_HCI_NO_DMA_MODE)
list(APPEND porting_btdm_srcs
"${CMAKE_CURRENT_SOURCE_DIR}/transport/driver/uart/hci_driver_uart.c"
)
else()
list(APPEND porting_btdm_srcs
"${CMAKE_CURRENT_SOURCE_DIR}/transport/driver/uart/hci_driver_uart_dma.c"
)
endif()
endif()
set(porting_btdm_srcs ${porting_btdm_srcs} PARENT_SCOPE)
set(porting_btdm_include_dirs ${porting_btdm_include_dirs} PARENT_SCOPE)
@@ -0,0 +1,721 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _BLE_MBUF_H
#define _BLE_MBUF_H
#include "btdm_mempool.h"
#include "queue.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* A mbuf pool from which to allocate mbufs. This contains a pointer to the os
* mempool to allocate mbufs out of, the total number of elements in the pool,
* and the amount of "user" data in a non-packet header mbuf. The total pool
* size, in bytes, should be:
* ble_mbuf_count * (omp_databuf_len + sizeof(struct ble_mbuf))
*/
struct ble_mbuf_pool {
/**
* Total length of the databuf in each mbuf. This is the size of the
* mempool block, minus the mbuf header
*/
uint16_t omp_databuf_len;
/**
* The memory pool which to allocate mbufs out of
*/
struct btdm_mempool *omp_pool;
STAILQ_ENTRY(ble_mbuf_pool) omp_next;
};
/**
* A packet header structure that precedes the mbuf packet headers.
*/
struct ble_mbuf_pkthdr {
/**
* Overall length of the packet.
*/
uint16_t omp_len;
/**
* Flags
*/
uint16_t omp_flags;
STAILQ_ENTRY(ble_mbuf_pkthdr) omp_next;
};
/**
* Chained memory buffer.
*/
struct ble_mbuf {
/**
* Current pointer to data in the structure
*/
uint8_t *om_data;
/**
* Flags associated with this buffer, see BLE_MBUF_F_* definitions
*/
uint8_t om_flags;
/**
* Length of packet header
*/
uint8_t om_pkthdr_len;
/**
* Length of data in this buffer
*/
uint16_t om_len;
/**
* The mbuf pool this mbuf was allocated out of
*/
struct ble_mbuf_pool *om_omp;
SLIST_ENTRY(ble_mbuf) om_next;
/**
* Pointer to the beginning of the data, after this buffer
*/
uint8_t om_databuf[0];
};
/*
* Checks whether a given mbuf is a packet header mbuf
*
* @param __om The mbuf to check
*/
#define BLE_MBUF_IS_PKTHDR(__om) ((__om)->om_pkthdr_len >= sizeof(struct ble_mbuf_pkthdr))
/** Get a packet header pointer given an mbuf pointer */
#define BLE_MBUF_PKTHDR(__om) \
((struct ble_mbuf_pkthdr *)(uintptr_t)(void *)((uint8_t *)&(__om)->om_data + \
sizeof(struct ble_mbuf)))
/** Given a mbuf packet header pointer, return a pointer to the mbuf */
#define BLE_MBUF_PKTHDR_TO_MBUF(__hdr) \
(struct ble_mbuf *)(uintptr_t)((uint8_t *)(__hdr) - sizeof(struct ble_mbuf))
/**
* Gets the length of an entire mbuf chain. The specified mbuf must have a
* packet header.
*/
#define BLE_MBUF_PKTLEN(__om) (BLE_MBUF_PKTHDR(__om)->omp_len)
/**
* Access the data of a mbuf, and cast it to type
*
* @param __om The mbuf to access, and cast
* @param __type The type to cast it to
*/
#define BLE_MBUF_DATA(__om, __type) (__type)((__om)->om_data)
/**
* Access the "user header" in the head of an mbuf chain.
*
* @param om Pointer to the head of an mbuf chain.
*/
#define BLE_MBUF_USRHDR(om) \
(void *)((uint8_t *)om + sizeof(struct ble_mbuf) + sizeof(struct ble_mbuf_pkthdr))
/**
* Retrieves the length of the user header in an mbuf.
*
* @param om Pointer to the mbuf to query.
*/
#define BLE_MBUF_USRHDR_LEN(om) ((om)->om_pkthdr_len - sizeof(struct ble_mbuf_pkthdr))
/*
* Called by BLE_MBUF_LEADINGSPACE() macro
*/
static inline uint16_t
_ble_mbuf_leadingspace(struct ble_mbuf *om)
{
extern uint16_t r_os_mbuf_leadingspace(struct ble_mbuf * om);
return r_os_mbuf_leadingspace(om);
}
/**
* Returns the leading space (space at the beginning) of the mbuf.
* Works on both packet header, and regular mbufs, as it accounts
* for the additional space allocated to the packet header.
*
* @param __omp Is the mbuf pool (which contains packet header length.)
* @param __om Is the mbuf in that pool to get the leadingspace for
*
* @return Amount of leading space available in the mbuf
*/
#define BLE_MBUF_LEADINGSPACE(__om) _ble_mbuf_leadingspace(__om)
/** @cond INTERNAL_HIDDEN */
/* Called by BLE_MBUF_TRAILINGSPACE() macro. */
static inline uint16_t
_ble_mbuf_trailingspace(struct ble_mbuf *om)
{
extern uint16_t r_os_mbuf_trailingspace(struct ble_mbuf * om);
return r_os_mbuf_trailingspace(om);
}
/** @endcond */
/**
* Returns the trailing space (space at the end) of the mbuf.
* Works on both packet header and regular mbufs.
*
* @param __omp The mbuf pool for this mbuf
* @param __om Is the mbuf in that pool to get trailing space for
*
* @return The amount of trailing space available in the mbuf
*/
#define BLE_MBUF_TRAILINGSPACE(__om) _ble_mbuf_trailingspace(__om)
/**
* MSYS is a system level mbuf registry. Allows the system to share
* packet buffers amongst the various networking stacks that can be running
* simultaeneously.
*
* Mbuf pools are created in the system initialization code, and then when
* a mbuf is allocated out of msys, it will try and find the best fit based
* upon estimated mbuf size.
*
* os_msys_register() registers a mbuf pool with MSYS, and allows MSYS to
* allocate mbufs out of it.
*
* @param new_pool The pool to register with MSYS
*
* @return 0 on success, non-zero on failure
*/
static inline int
ble_msys_register(struct ble_mbuf_pool *mp)
{
extern int r_os_msys_register(struct ble_mbuf_pool * mp);
return r_os_msys_register(mp);
}
/**
* Allocate a mbuf from msys. Based upon the data size requested,
* os_msys_get() will choose the mbuf pool that has the best fit.
*
* @param dsize The estimated size of the data being stored in the mbuf
* @param leadingspace The amount of leadingspace to allocate in the mbuf
*
* @return A freshly allocated mbuf on success, NULL on failure.
*/
static inline struct ble_mbuf *
ble_msys_get(uint16_t dsize, uint16_t leadingspace)
{
extern struct ble_mbuf *r_os_msys_get(uint16_t dsize, uint16_t leadingspace);
return r_os_msys_get(dsize, leadingspace);
}
/**
* De-registers all mbuf pools from msys.
*/
static inline void
ble_msys_reset(void)
{
extern void r_os_msys_reset(void);
r_os_msys_reset();
}
/**
* Allocate a packet header structure from the MSYS pool. See
* os_msys_register() for a description of MSYS.
*
* @param dsize The estimated size of the data being stored in the mbuf
* @param user_hdr_len The length to allocate for the packet header structure
*
* @return A freshly allocated mbuf on success, NULL on failure.
*/
static inline struct ble_mbuf *
ble_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len)
{
extern struct ble_mbuf *r_os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len);
return r_os_msys_get_pkthdr(dsize, user_hdr_len);
}
/**
* Count the number of blocks in all the mbuf pools that are allocated.
*
* @return total number of blocks allocated in Msys
*/
static inline int
ble_msys_count(void)
{
extern int r_os_msys_count(void);
return r_os_msys_count();
}
/**
* Return the number of free blocks in Msys
*
* @return Number of free blocks available in Msys
*/
static inline int
ble_msys_num_free(void)
{
extern int r_os_msys_num_free(void);
return r_os_msys_num_free();
}
/**
* Initialize a pool of mbufs.
*
* @param omp The mbuf pool to initialize
* @param mp The memory pool that will hold this mbuf pool
* @param buf_len The length of the buffer itself.
* @param nbufs The number of buffers in the pool
*
* @return 0 on success, error code on failure.
*/
static inline int
ble_mbuf_pool_init(struct ble_mbuf_pool *omp, struct btdm_mempool *mp, uint16_t buf_len,
uint16_t nbufs)
{
extern int r_os_mbuf_pool_init(struct ble_mbuf_pool *, struct btdm_mempool * mp, uint16_t,
uint16_t);
return r_os_mbuf_pool_init(omp, mp, buf_len, nbufs);
}
/**
* Get an mbuf from the mbuf pool. The mbuf is allocated, and initialized
* prior to being returned.
*
* @param omp The mbuf pool to return the packet from
* @param leadingspace The amount of leadingspace to put before the data
* section by default.
*
* @return An initialized mbuf on success, and NULL on failure.
*/
static inline struct ble_mbuf *
ble_mbuf_get(struct ble_mbuf_pool *omp, uint16_t leadingspace)
{
extern struct ble_mbuf *r_os_mbuf_get(struct ble_mbuf_pool * omp, uint16_t leadingspace);
return r_os_mbuf_get(omp, leadingspace);
}
/**
* Allocate a new packet header mbuf out of the os_mbuf_pool.
*
* @param omp The mbuf pool to allocate out of
* @param user_pkthdr_len The packet header length to reserve for the caller.
*
* @return A freshly allocated mbuf on success, NULL on failure.
*/
static inline struct ble_mbuf *
ble_mbuf_get_pkthdr(struct ble_mbuf_pool *omp, uint8_t user_pkthdr_len)
{
extern struct ble_mbuf *r_os_mbuf_get_pkthdr(struct ble_mbuf_pool * omp,
uint8_t user_pkthdr_len);
return r_os_mbuf_get_pkthdr(omp, user_pkthdr_len);
}
/**
* Duplicate a chain of mbufs. Return the start of the duplicated chain.
*
* @param omp The mbuf pool to duplicate out of
* @param om The mbuf chain to duplicate
*
* @return A pointer to the new chain of mbufs
*/
static inline struct ble_mbuf *
ble_mbuf_dup(struct ble_mbuf *m)
{
extern struct ble_mbuf *r_os_mbuf_dup(struct ble_mbuf * m);
return r_os_mbuf_dup(m);
}
/**
* Locates the specified absolute offset within an mbuf chain. The offset
* can be one past than the total length of the chain, but no greater.
*
* @param om The start of the mbuf chain to seek within.
* @param off The absolute address to find.
* @param out_off On success, this points to the relative offset
* within the returned mbuf.
*
* @return The mbuf containing the specified offset on
* success.
* NULL if the specified offset is out of bounds.
*/
static inline struct ble_mbuf *
ble_mbuf_off(const struct ble_mbuf *om, int off, uint16_t *out_off)
{
extern struct ble_mbuf *r_os_mbuf_off(const struct ble_mbuf *om, int off, uint16_t *out_off);
return r_os_mbuf_off(om, off, out_off);
}
/*
* Copy data from an mbuf chain starting "off" bytes from the beginning,
* continuing for "len" bytes, into the indicated buffer.
*
* @param m The mbuf chain to copy from
* @param off The offset into the mbuf chain to begin copying from
* @param len The length of the data to copy
* @param dst The destination buffer to copy into
*
* @return 0 on success;
* -1 if the mbuf does not contain enough data.
*/
static inline int
ble_mbuf_copydata(const struct ble_mbuf *m, int off, int len, void *dst)
{
extern int r_os_mbuf_copydata(const struct ble_mbuf *m, int off, int len, void *dst);
return r_os_mbuf_copydata(m, off, len, dst);
}
/**
* @brief Calculates the length of an mbuf chain.
*
* Calculates the length of an mbuf chain. If the mbuf contains a packet
* header, you should use `OS_MBUF_PKTLEN()` as a more efficient alternative to
* this function.
*
* @param om The mbuf to measure.
*
* @return The length, in bytes, of the provided mbuf
* chain.
*/
static inline uint16_t
ble_mbuf_len(const struct ble_mbuf *om)
{
extern uint16_t r_os_mbuf_len(const struct ble_mbuf *om);
return r_os_mbuf_len(om);
}
/**
* Append data onto a mbuf
*
* @param om The mbuf to append the data onto
* @param data The data to append onto the mbuf
* @param len The length of the data to append
*
* @return 0 on success, and an error code on failure
*/
static inline int
ble_mbuf_append(struct ble_mbuf *m, const void *data, uint16_t len)
{
extern int r_os_mbuf_append(struct ble_mbuf * m, const void *, uint16_t);
return r_os_mbuf_append(m, data, len);
}
/**
* Reads data from one mbuf and appends it to another. On error, the specified
* data range may be partially appended. Neither mbuf is required to contain
* an mbuf packet header.
*
* @param dst The mbuf to append to.
* @param src The mbuf to copy data from.
* @param src_off The absolute offset within the source mbuf
* chain to read from.
* @param len The number of bytes to append.
*
* @return 0 on success;
* OS_EINVAL if the specified range extends beyond
* the end of the source mbuf chain.
*/
static inline int
ble_mbuf_appendfrom(struct ble_mbuf *dst, const struct ble_mbuf *src, uint16_t src_off,
uint16_t len)
{
extern int r_os_mbuf_appendfrom(struct ble_mbuf * dst, const struct ble_mbuf *src,
uint16_t src_off, uint16_t len);
return r_os_mbuf_appendfrom(dst, src, src_off, len);
}
/**
* Release a mbuf back to the pool
*
* @param mb The Mbuf to release back to the pool
*
* @return 0 on success, -1 on failure
*/
static inline int
ble_mbuf_free(struct ble_mbuf *mb)
{
extern int r_os_mbuf_free(struct ble_mbuf * mb);
return r_os_mbuf_free(mb);
}
/**
* Free a chain of mbufs
*
* @param om The starting mbuf of the chain to free back into the pool
*
* @return 0 on success, -1 on failure
*/
static inline int
ble_mbuf_free_chain(struct ble_mbuf *om)
{
extern int r_os_mbuf_free_chain(struct ble_mbuf * om);
return r_os_mbuf_free_chain(om);
}
/**
* Adjust the length of a mbuf, trimming either from the head or the tail
* of the mbuf.
*
* @param mp The mbuf chain to adjust
* @param req_len The length to trim from the mbuf. If positive, trims
* from the head of the mbuf, if negative, trims from the
* tail of the mbuf.
*/
static inline void
ble_mbuf_adj(struct ble_mbuf *mp, int req_len)
{
extern void r_os_mbuf_adj(struct ble_mbuf * mp, int req_len);
r_os_mbuf_adj(mp, req_len);
}
/**
* Performs a memory compare of the specified region of an mbuf chain against a
* flat buffer.
*
* @param om The start of the mbuf chain to compare.
* @param off The offset within the mbuf chain to start the
* comparison.
* @param data The flat buffer to compare.
* @param len The length of the flat buffer.
*
* @return 0 if both memory regions are identical;
* A memcmp return code if there is a mismatch;
* INT_MAX if the mbuf is too short.
*/
static inline int
ble_mbuf_cmpf(const struct ble_mbuf *om, int off, const void *data, int len)
{
extern int r_os_mbuf_cmpf(const struct ble_mbuf *om, int off, const void *data, int len);
return r_os_mbuf_cmpf(om, off, data, len);
}
/**
* Compares the contents of two mbuf chains. The ranges of the two chains to
* be compared are specified via the two offset parameters and the len
* parameter. Neither mbuf chain is required to contain a packet header.
*
* @param om1 The first mbuf chain to compare.
* @param offset1 The absolute offset within om1 at which to
* start the comparison.
* @param om2 The second mbuf chain to compare.
* @param offset2 The absolute offset within om2 at which to
* start the comparison.
* @param len The number of bytes to compare.
*
* @return 0 if both mbuf segments are identical;
* A memcmp() return code if the segment contents
* differ;
* INT_MAX if a specified range extends beyond the
* end of its corresponding mbuf chain.
*/
static inline int
ble_mbuf_cmpm(const struct ble_mbuf *om1, uint16_t offset1, const struct ble_mbuf *om2,
uint16_t offset2, uint16_t len)
{
extern int r_os_mbuf_cmpm(const struct ble_mbuf *om1, uint16_t offset1,
const struct ble_mbuf *om2, uint16_t offset2, uint16_t len);
return r_os_mbuf_cmpm(om1, offset1, om2, offset2, len);
}
/**
* Increases the length of an mbuf chain by adding data to the front. If there
* is insufficient room in the leading mbuf, additional mbufs are allocated and
* prepended as necessary. If this function fails to allocate an mbuf, the
* entire chain is freed.
*
* The specified mbuf chain does not need to contain a packet header.
*
* @param omp The mbuf pool to allocate from.
* @param om The head of the mbuf chain.
* @param len The number of bytes to prepend.
*
* @return The new head of the chain on success;
* NULL on failure.
*/
static inline struct ble_mbuf *
ble_mbuf_prepend(struct ble_mbuf *om, int len)
{
extern struct ble_mbuf *r_os_mbuf_prepend(struct ble_mbuf * om, int len);
return r_os_mbuf_prepend(om, len);
}
/**
* Prepends a chunk of empty data to the specified mbuf chain and ensures the
* chunk is contiguous. If either operation fails, the specified mbuf chain is
* freed and NULL is returned.
*
* @param om The mbuf chain to prepend to.
* @param len The number of bytes to prepend and pullup.
*
* @return The modified mbuf on success;
* NULL on failure (and the mbuf chain is freed).
*/
static inline struct ble_mbuf *
ble_mbuf_prepend_pullup(struct ble_mbuf *om, uint16_t len)
{
extern struct ble_mbuf *r_os_mbuf_prepend_pullup(struct ble_mbuf * om, uint16_t len);
return r_os_mbuf_prepend_pullup(om, len);
}
/**
* Copies the contents of a flat buffer into an mbuf chain, starting at the
* specified destination offset. If the mbuf is too small for the source data,
* it is extended as necessary. If the destination mbuf contains a packet
* header, the header length is updated.
*
* @param om The mbuf chain to copy into.
* @param off The offset within the chain to copy to.
* @param src The source buffer to copy from.
* @param len The number of bytes to copy.
*
* @return 0 on success; nonzero on failure.
*/
static inline int
ble_mbuf_copyinto(struct ble_mbuf *om, int off, const void *src, int len)
{
extern int r_os_mbuf_copyinto(struct ble_mbuf * om, int off, const void *src, int len);
return r_os_mbuf_copyinto(om, off, src, len);
}
/**
* Attaches a second mbuf chain onto the end of the first. If the first chain
* contains a packet header, the header's length is updated. If the second
* chain has a packet header, its header is cleared.
*
* @param first The mbuf chain being attached to.
* @param second The mbuf chain that gets attached.
*/
static inline void
ble_mbuf_concat(struct ble_mbuf *first, struct ble_mbuf *second)
{
extern void r_os_mbuf_concat(struct ble_mbuf * first, struct ble_mbuf * second);
r_os_mbuf_concat(first, second);
}
/**
* Increases the length of an mbuf chain by the specified amount. If there is
* not sufficient room in the last buffer, a new buffer is allocated and
* appended to the chain. It is an error to request more data than can fit in
* a single buffer.
*
* @param om The head of the chain to extend.
* @param len The number of bytes to extend by.
*
* @return A pointer to the new data on success;
* NULL on failure.
*/
static inline void *
ble_mbuf_extend(struct ble_mbuf *om, uint16_t len)
{
extern void *r_os_mbuf_extend(struct ble_mbuf * om, uint16_t len);
return r_os_mbuf_extend(om, len);
}
/**
* Rearrange a mbuf chain so that len bytes are contiguous,
* and in the data area of an mbuf (so that OS_MBUF_DATA() will
* work on a structure of size len.) Returns the resulting
* mbuf chain on success, free's it and returns NULL on failure.
*
* If there is room, it will add up to "max_protohdr - len"
* extra bytes to the contiguous region, in an attempt to avoid being
* called next time.
*
* @param om The mbuf chain to make contiguous
* @param len The number of bytes in the chain to make contiguous
*
* @return The contiguous mbuf chain on success, NULL on failure.
*/
static inline struct ble_mbuf *
ble_mbuf_pullup(struct ble_mbuf *om, uint16_t len)
{
extern struct ble_mbuf *r_os_mbuf_pullup(struct ble_mbuf * om, uint16_t len);
return r_os_mbuf_pullup(om, len);
}
/**
* Removes and frees empty mbufs from the front of a chain. If the chain
* contains a packet header, it is preserved.
*
* @param om The mbuf chain to trim.
*
* @return The head of the trimmed mbuf chain.
*/
static inline struct ble_mbuf *
ble_mbuf_trim_front(struct ble_mbuf *om)
{
extern struct ble_mbuf *r_os_mbuf_trim_front(struct ble_mbuf * om);
return r_os_mbuf_trim_front(om);
}
/**
* Increases the length of an mbuf chain by inserting a gap at the specified
* offset. The contents of the gap are indeterminate. If the mbuf chain
* contains a packet header, its total length is increased accordingly.
*
* This function never frees the provided mbuf chain.
*
* @param om The mbuf chain to widen.
* @param off The offset at which to insert the gap.
* @param len The size of the gap to insert.
*
* @return 0 on success; SYS_[...] error code on failure.
*/
static inline int
ble_mbuf_widen(struct ble_mbuf *om, uint16_t off, uint16_t len)
{
extern int r_os_mbuf_widen(struct ble_mbuf * om, uint16_t off, uint16_t len);
return r_os_mbuf_widen(om, off, len);
}
/**
* Creates a single chained mbuf from m1 and m2 utilizing all
* the available buffer space in all mbufs in the resulting
* chain. In other words, ensures there is no leading space in
* any mbuf in the resulting chain and trailing space only in
* the last mbuf in the chain. Mbufs from either chain may be
* freed if not needed. No mbufs are allocated. Note that mbufs
* from m2 are added to the end of m1. If m1 has a packet
* header, it is retained and length updated. If m2 has a packet
* header it is discarded. If m1 is NULL, NULL is returned and
* m2 is left untouched.
*
* @param m1 Pointer to first mbuf chain to pack
* @param m2 Pointer to second mbuf chain to pack
*
* @return struct os_mbuf* Pointer to resulting mbuf chain
*/
static inline struct ble_mbuf *
ble_mbuf_pack_chains(struct ble_mbuf *m1, struct ble_mbuf *m2)
{
extern struct ble_mbuf *r_os_mbuf_pack_chains(struct ble_mbuf * m1, struct ble_mbuf * m2);
return r_os_mbuf_pack_chains(m1, m2);
}
#ifdef __cplusplus
}
#endif
#endif /* _BLE_MBUF_H */
@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BLE_MSYS_H_
#define _BLE_MSYS_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
int ble_msys_init(void);
void ble_msys_deinit(void);
#ifdef __cplusplus
}
#endif
#endif /* _BLE_MSYS_H_ */
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ESP_BLE_PRIV_H_
#define _ESP_BLE_PRIV_H_
#include "btdm_osal.h"
int ble_stack_init(esp_bt_controller_config_t *cfg);
void ble_stack_deinit(void);
int ble_stack_enable(void);
void ble_stack_disable(void);
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
esp_err_t sleep_modem_ble_mac_modem_state_init(void);
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
void ble_osal_elem_calc(esp_bt_controller_config_t *cfg, btdm_osal_elem_num_t *elem);
#endif // _ESP_BLE_PRIV_H_
@@ -1,16 +1,14 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_BT_CFG_H__
#define __ESP_BT_CFG_H__
#ifndef __BLE_USER_CFG_H__
#define __BLE_USER_CFG_H__
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
@@ -20,8 +18,6 @@ extern "C" {
#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
@@ -29,7 +25,6 @@ extern "C" {
#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)
@@ -41,7 +36,8 @@ extern "C" {
#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_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF
#define DEFAULT_BT_LE_POWER_CONTROL_ENABLED MYNEWT_VAL(BLE_POWER_CONTROL)
#else
#if CONFIG_BT_LE_LL_CFG_FEAT_LE_CODED_PHY
@@ -116,35 +112,15 @@ extern "C" {
#define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT (8)
#endif
#if defined (CONFIG_BT_LE_HCI_UART_FLOWCTRL)
#define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (CONFIG_BT_LE_HCI_UART_FLOWCTRL)
#if DEFAULT_BT_LE_HCI_UART_FLOW_CTRL
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (CONFIG_BT_LE_HCI_UART_CTS_PIN)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (CONFIG_BT_LE_HCI_UART_RTS_PIN)
#else
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1)
#endif
#define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF
#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_HCI_UART_FLOW_CTRL (0)
#define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1)
#define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1)
#define DEFAULT_BT_LE_POWER_CONTROL_ENABLED (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
@@ -162,24 +138,6 @@ extern "C" {
#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)
#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)
#endif
/* Unchanged configuration */
#define BLE_LL_CTRL_PROC_TIMEOUT_MS_N (40000) /* ms */
@@ -200,26 +158,21 @@ extern "C" {
#define BLE_LL_CONN_DEF_AUTH_PYLD_TMO_N (3000)
#if CONFIG_RTC_CLK_SRC_EXT_CRYS
#define RTC_FREQ_N (32768) /* in Hz */
#define BLE_LL_TX_PWR_DBM_N (9)
#ifdef CONFIG_BT_LE_BQB_TEST_EN
#define RUN_BQB_TEST (CONFIG_BT_LE_BQB_TEST_EN)
#else
#define RTC_FREQ_N (32000) /* in Hz */
#if CONFIG_RTC_CLK_SRC_EXT_OSC || CONFIG_RTC_CLK_SRC_INT_RC32K
#pragma message "RTC clock source may not available"
#endif
#endif
#define BLE_LL_TX_PWR_DBM_N (0)
#define RUN_BQB_TEST (0)
#endif // CONFIG_BT_LE_BQB_TEST_EN
#define RUN_QA_TEST (0)
#define NIMBLE_DISABLE_SCAN_BACKOFF (0)
#ifdef __cplusplus
}
#endif
#endif /* __ESP_BT_CFG_H__ */
#endif /* __BLE_USER_CFG_H__ */
@@ -0,0 +1,425 @@
/*
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* @addtogroup OSKernel
* @{
* @defgroup OSMempool Memory Pools
* @{
*/
#ifndef _OS_MEMPOOL_H_
#define _OS_MEMPOOL_H_
#include <stdbool.h>
#include "os/os.h"
#include "os/queue.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* A memory block structure. This simply contains a pointer to the free list
* chain and is only used when the block is on the free list. When the block
* has been removed from the free list the entire memory block is usable by the
* caller.
*/
struct os_memblock {
SLIST_ENTRY(os_memblock) mb_next;
};
/* XXX: Change this structure so that we keep the first address in the pool? */
/* XXX: add memory debug structure and associated code */
/* XXX: Change how I coded the SLIST_HEAD here. It should be named:
SLIST_HEAD(,os_memblock) mp_head; */
/**
* Memory pool
*/
struct os_mempool {
/** Size of the memory blocks, in bytes. */
uint32_t mp_block_size;
/** The number of memory blocks. */
uint16_t mp_num_blocks;
/** The number of free blocks left */
uint16_t mp_num_free;
/** The lowest number of free blocks seen */
uint16_t mp_min_free;
/** Bitmap of OS_MEMPOOL_F_[...] values. */
uint8_t mp_flags;
/** Address of memory buffer used by pool */
uint32_t mp_membuf_addr;
STAILQ_ENTRY(os_mempool) mp_list;
SLIST_HEAD(,os_memblock);
/** Name for memory block */
const char *name;
/** The number of allocated blocks. */
uint32_t mp_alloc_blocks;
};
/**
* Indicates an extended mempool. Address can be safely cast to
* (struct os_mempool_ext *).
*/
#define OS_MEMPOOL_F_EXT 0x01
/* Flag to indicate runtime allocation mode */
#define OS_MEMPOOL_F_RUNTIME 0x02
/* Flag to indicate reuse block for runtime allocation mode */
#define OS_MEMPOOL_F_REUSED 0x04
struct os_mempool_ext;
/**
* Block put callback function. If configured, this callback gets executed
* whenever a block is freed to the corresponding extended mempool. Note: The
* os_memblock_put() function calls this callback instead of freeing the block
* itself. Therefore, it is the callback's responsibility to free the block
* via a call to os_memblock_put_from_cb().
*
* @param ome The extended mempool that a block is being
* freed back to.
* @param data The block being freed.
* @param arg Optional argument configured along with the
* callback.
*
* @return Indicates whether the block was successfully
* freed. A non-zero value should only be
* returned if the block was not successfully
* released back to its pool.
*/
typedef os_error_t os_mempool_put_fn(struct os_mempool_ext *ome, void *data,
void *arg);
struct os_mempool_ext {
struct os_mempool mpe_mp;
/* Callback that is executed immediately when a block is freed. */
os_mempool_put_fn *mpe_put_cb;
void *mpe_put_arg;
};
#define OS_MEMPOOL_INFO_NAME_LEN (32)
/**
* Information describing a memory pool, used to return OS information
* to the management layer.
*/
struct os_mempool_info {
/** Size of the memory blocks in the pool */
int omi_block_size;
/** Number of memory blocks in the pool */
int omi_num_blocks;
/** Number of free memory blocks */
int omi_num_free;
/** Minimum number of free memory blocks ever */
int omi_min_free;
/** Name of the memory pool */
char omi_name[OS_MEMPOOL_INFO_NAME_LEN];
};
/**
* Get information about the next system memory pool.
*
* @param mempool The current memory pool, or NULL if starting iteration.
* @param info A pointer to the structure to return memory pool information
* into.
*
* @return The next memory pool in the list to get information about, or NULL
* when at the last memory pool.
*/
struct os_mempool *os_mempool_info_get_next(struct os_mempool *,
struct os_mempool_info *);
/*
* To calculate size of the memory buffer needed for the pool. NOTE: This size
* is NOT in bytes! The size is the number of os_membuf_t elements required for
* the memory pool.
*/
#if MYNEWT_VAL(OS_MEMPOOL_GUARD)
/*
* Leave extra 4 bytes of guard area at the end.
*/
#define OS_MEMPOOL_BLOCK_SZ(sz) ((sz) + sizeof(os_membuf_t))
#else
#define OS_MEMPOOL_BLOCK_SZ(sz) (sz)
#endif
#if (OS_ALIGNMENT == 4)
typedef uint32_t os_membuf_t;
#elif (OS_ALIGNMENT == 8)
typedef uint64_t os_membuf_t;
#elif (OS_ALIGNMENT == 16)
typedef __uint128_t os_membuf_t;
#else
#error "Unhandled `OS_ALIGNMENT` for `os_membuf_t`"
#endif /* OS_ALIGNMENT == * */
#define OS_MEMPOOL_SIZE(n,blksize) ((((blksize) + ((OS_ALIGNMENT)-1)) / (OS_ALIGNMENT)) * (n))
/** Calculates the number of bytes required to initialize a memory pool. */
#define OS_MEMPOOL_BYTES(n,blksize) \
(sizeof (os_membuf_t) * OS_MEMPOOL_SIZE((n), (blksize)))
#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED
/**
* Initialize a memory pool.
*
* @param mp Pointer to a pointer to a mempool
* @param blocks The number of blocks in the pool
* @param blocks_size The size of the block, in bytes.
* @param membuf Pointer to memory to contain blocks.
* @param name Name of the pool.
*
* @return os_error_t
*/
os_error_t r_os_mempool_init(struct os_mempool *mp, uint16_t blocks,
uint32_t block_size, void *membuf, const char *name);
#define os_mempool_init r_os_mempool_init
/**
* Initializes an extended memory pool. Extended attributes (e.g., callbacks)
* are not specified when this function is called; they are assigned manually
* after initialization.
*
* @param mpe The extended memory pool to initialize.
* @param blocks The number of blocks in the pool.
* @param block_size The size of each block, in bytes.
* @param membuf Pointer to memory to contain blocks.
* @param name Name of the pool.
*
* @return os_error_t
*/
os_error_t r_os_mempool_ext_init(struct os_mempool_ext *mpe, uint16_t blocks,
uint32_t block_size, void *membuf, const char *name);
#define os_mempool_ext_init r_os_mempool_ext_init
/**
* Removes the specified mempool from the list of initialized mempools.
*
* @param mp The mempool to unregister.
*
* @return 0 on success;
* OS_INVALID_PARM if the mempool is not
* registered.
*/
// os_error_t r_os_mempool_unregister(struct os_mempool *mp);
#define os_mempool_unregister(mp)
/**
* Clears a memory pool.
*
* @param mp The mempool to clear.
*
* @return os_error_t
*/
os_error_t r_os_mempool_clear(struct os_mempool *mp);
#define os_mempool_clear r_os_mempool_clear
/**
* Performs an integrity check of the specified mempool. This function
* attempts to detect memory corruption in the specified memory pool.
*
* @param mp The mempool to check.
*
* @return true if the memory pool passes the integrity
* check;
* false if the memory pool is corrupt.
*/
bool r_os_mempool_is_sane(const struct os_mempool *mp);
#define os_mempool_is_sane r_os_mempool_is_sane
/**
* Checks if a memory block was allocated from the specified mempool.
*
* @param mp The mempool to check as parent.
* @param block_addr The memory block to check as child.
*
* @return 0 if the block does not belong to the mempool;
* 1 if the block does belong to the mempool.
*/
int r_os_memblock_from(const struct os_mempool *mp, const void *block_addr);
#define os_memblock_from r_os_memblock_from
/**
* Get a memory block from a memory pool
*
* @param mp Pointer to the memory pool
*
* @return void* Pointer to block if available; NULL otherwise
*/
void *r_os_memblock_get(struct os_mempool *mp);
#define os_memblock_get r_os_memblock_get
/**
* Puts the memory block back into the pool, ignoring the put callback, if any.
* This function should only be called from a put callback to free a block
* without causing infinite recursion.
*
* @param mp Pointer to memory pool
* @param block_addr Pointer to memory block
*
* @return os_error_t
*/
os_error_t r_os_memblock_put_from_cb(struct os_mempool *mp, void *block_addr);
#define os_memblock_put_from_cb r_os_memblock_put_from_cb
/**
* Puts the memory block back into the pool
*
* @param mp Pointer to memory pool
* @param block_addr Pointer to memory block
*
* @return os_error_t
*/
os_error_t r_os_memblock_put(struct os_mempool *mp, void *block_addr);
#define os_memblock_put r_os_memblock_put
#else
/**
* Initialize a memory pool.
*
* @param mp Pointer to a pointer to a mempool
* @param blocks The number of blocks in the pool
* @param blocks_size The size of the block, in bytes.
* @param membuf Pointer to memory to contain blocks.
* @param name Name of the pool.
*
* @return os_error_t
*/
os_error_t os_mempool_init(struct os_mempool *mp, uint16_t blocks,
uint32_t block_size, void *membuf, const char *name);
/**
* Initializes an extended memory pool. Extended attributes (e.g., callbacks)
* are not specified when this function is called; they are assigned manually
* after initialization.
*
* @param mpe The extended memory pool to initialize.
* @param blocks The number of blocks in the pool.
* @param block_size The size of each block, in bytes.
* @param membuf Pointer to memory to contain blocks.
* @param name Name of the pool.
*
* @return os_error_t
*/
os_error_t os_mempool_ext_init(struct os_mempool_ext *mpe, uint16_t blocks,
uint32_t block_size, void *membuf, const char *name);
/**
* Removes the specified mempool from the list of initialized mempools.
*
* @param mp The mempool to unregister.
*
* @return 0 on success;
* OS_INVALID_PARM if the mempool is not
* registered.
*/
os_error_t os_mempool_unregister(struct os_mempool *mp);
/**
* Clears a memory pool.
*
* @param mp The mempool to clear.
*
* @return os_error_t
*/
os_error_t os_mempool_clear(struct os_mempool *mp);
/**
* Clears an extended memory pool.
*
* @param mpe The extended memory pool to clear.
*
* @return os_error_t
*/
os_error_t os_mempool_ext_clear(struct os_mempool_ext *mpe);
/**
* Performs an integrity check of the specified mempool. This function
* attempts to detect memory corruption in the specified memory pool.
*
* @param mp The mempool to check.
*
* @return true if the memory pool passes the integrity
* check;
* false if the memory pool is corrupt.
*/
bool os_mempool_is_sane(const struct os_mempool *mp);
/**
* Checks if a memory block was allocated from the specified mempool.
*
* @param mp The mempool to check as parent.
* @param block_addr The memory block to check as child.
*
* @return 0 if the block does not belong to the mempool;
* 1 if the block does belong to the mempool.
*/
int os_memblock_from(const struct os_mempool *mp, const void *block_addr);
/**
* Get a memory block from a memory pool
*
* @param mp Pointer to the memory pool
*
* @return void* Pointer to block if available; NULL otherwise
*/
void *os_memblock_get(struct os_mempool *mp);
/**
* Puts the memory block back into the pool, ignoring the put callback, if any.
* This function should only be called from a put callback to free a block
* without causing infinite recursion.
*
* @param mp Pointer to memory pool
* @param block_addr Pointer to memory block
*
* @return os_error_t
*/
os_error_t os_memblock_put_from_cb(struct os_mempool *mp, void *block_addr);
/**
* Puts the memory block back into the pool
*
* @param mp Pointer to memory pool
* @param block_addr Pointer to memory block
*
* @return os_error_t
*/
os_error_t os_memblock_put(struct os_mempool *mp, void *block_addr);
#endif
#ifdef __cplusplus
}
#endif
#endif /* _OS_MEMPOOL_H_ */
/**
* @} OSMempool
* @} OSKernel
*/
@@ -0,0 +1,78 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_err.h"
#include "queue.h"
#include "sdkconfig.h"
#if CONFIG_BT_NIMBLE_ENABLED
#include "syscfg/syscfg.h"
#endif
/*
***************************************************************************************************
* Local Defined Macros
***************************************************************************************************
*/
#define BLE_MSYS_ALIGN(__n, __a) \
((((__n) & ((__a) - 1)) == 0) ? (__n) : ((__n) + ((__a) - ((__n) & ((__a) - 1)))))
#if CONFIG_BT_NIMBLE_ENABLED
#define BLE_MSYS_1_BLOCK_COUNT MYNEWT_VAL(MSYS_1_BLOCK_COUNT)
#define BLE_MSYS_1_BLOCK_SIZE MYNEWT_VAL(MSYS_1_BLOCK_SIZE)
#define BLE_MSYS_2_BLOCK_COUNT MYNEWT_VAL(MSYS_2_BLOCK_COUNT)
#define BLE_MSYS_2_BLOCK_SIZE MYNEWT_VAL(MSYS_2_BLOCK_SIZE)
#define BLE_MSYS_BLOCK_FROM_HEAP CONFIG_BT_NIMBLE_MSYS_BUF_FROM_HEAP
#else
#define BLE_MSYS_1_BLOCK_COUNT CONFIG_BT_LE_MSYS_1_BLOCK_COUNT
#define BLE_MSYS_1_BLOCK_SIZE CONFIG_BT_LE_MSYS_1_BLOCK_SIZE
#define BLE_MSYS_2_BLOCK_COUNT CONFIG_BT_LE_MSYS_2_BLOCK_COUNT
#define BLE_MSYS_2_BLOCK_SIZE CONFIG_BT_LE_MSYS_2_BLOCK_SIZE
#define BLE_MSYS_BLOCK_FROM_HEAP CONFIG_BT_LE_MSYS_BUF_FROM_HEAP
#endif /* CONFIG_BT_NIMBLE_ENABLED */
#if BLE_MSYS_1_BLOCK_COUNT > 0
#define SYSINIT_MSYS_1_MEMBLOCK_SIZE BLE_MSYS_ALIGN(BLE_MSYS_1_BLOCK_SIZE, 4)
#define SYSINIT_MSYS_1_MEMPOOL_SIZE \
OS_MEMPOOL_SIZE(BLE_MSYS_1_BLOCK_COUNT, SYSINIT_MSYS_1_MEMBLOCK_SIZE)
#else
#error "BLE_MSYS_1_BLOCK_COUNT should be larger than 0!"
#endif /* BLE_MSYS_1_BLOCK_COUNT > 0 */
#if BLE_MSYS_2_BLOCK_COUNT > 0
#define SYSINIT_MSYS_2_MEMBLOCK_SIZE BLE_MSYS_ALIGN(BLE_MSYS_2_BLOCK_SIZE, 4)
#define SYSINIT_MSYS_2_MEMPOOL_SIZE \
OS_MEMPOOL_SIZE(BLE_MSYS_2_BLOCK_COUNT, SYSINIT_MSYS_2_MEMBLOCK_SIZE)
#else
#error #error "BLE_MSYS_2_BLOCK_COUNT should be larger than 0!"
#endif /* BLE_MSYS_2_BLOCK_COUNT > 0 */
/*
***************************************************************************************************
* External Functions
***************************************************************************************************
*/
extern int r_esp_ble_msys_init(uint16_t msys_size1, uint16_t msys_size2, uint16_t msys_cnt1,
uint16_t msys_cnt2, uint8_t from_heap);
extern void r_esp_ble_msys_deinit(void);
/*
***************************************************************************************************
* BLE MSYS Initialization
***************************************************************************************************
*/
int
ble_msys_init(void)
{
return r_esp_ble_msys_init(SYSINIT_MSYS_1_MEMBLOCK_SIZE, SYSINIT_MSYS_2_MEMBLOCK_SIZE,
BLE_MSYS_1_BLOCK_COUNT, BLE_MSYS_2_BLOCK_COUNT,
BLE_MSYS_BLOCK_FROM_HEAP);
}
void
ble_msys_deinit(void)
{
r_esp_ble_msys_deinit();
}
@@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BTDM_COEX_H_
#define _BTDM_COEX_H_
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
esp_err_t btdm_coex_init(void);
void btdm_coex_deinit(void);
esp_err_t btdm_coex_enable(void);
void btdm_coex_disable(void);
#ifdef __cplusplus
}
#endif
#endif /* _BTDM_COEX_H_ */
@@ -0,0 +1,146 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BTDM_ENDIAN_H_
#define _BTDM_ENDIAN_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
static inline void
btdm_put_le16(void *buf, uint16_t x)
{
extern void r_btdm_put_le16(void *buf, uint16_t x);
r_btdm_put_le16(buf, x);
}
static inline void
btdm_put_le24(void *buf, uint32_t x)
{
extern void r_btdm_put_le24(void *buf, uint32_t x);
r_btdm_put_le24(buf, x);
}
static inline void
btdm_put_le32(void *buf, uint32_t x)
{
extern void r_btdm_put_le32(void *buf, uint32_t x);
r_btdm_put_le32(buf, x);
}
static inline void
btdm_put_le64(void *buf, uint64_t x)
{
extern void r_btdm_put_le64(void *buf, uint64_t x);
r_btdm_put_le64(buf, x);
}
static inline uint16_t
btdm_get_le16(const void *buf)
{
extern uint16_t r_btdm_get_le16(const void *buf);
return r_btdm_get_le16(buf);
}
static inline uint32_t
btdm_get_le24(const void *buf)
{
extern uint32_t r_btdm_get_le24(const void *buf);
return r_btdm_get_le24(buf);
}
static inline uint32_t
btdm_get_le32(const void *buf)
{
extern uint32_t r_btdm_get_le32(const void *buf);
return r_btdm_get_le32(buf);
}
static inline uint64_t
btdm_get_le64(const void *buf)
{
extern uint64_t r_btdm_get_le64(const void *buf);
return r_btdm_get_le64(buf);
}
static inline void
btdm_put_be16(void *buf, uint16_t x)
{
extern void r_btdm_put_be16(void *buf, uint16_t x);
r_btdm_put_be16(buf, x);
}
static inline void
btdm_put_be24(void *buf, uint32_t x)
{
extern void r_btdm_put_be24(void *buf, uint32_t x);
r_btdm_put_be24(buf, x);
}
static inline void
btdm_put_be32(void *buf, uint32_t x)
{
extern void r_btdm_put_be32(void *buf, uint32_t x);
r_btdm_put_be32(buf, x);
}
static inline void
btdm_put_be64(void *buf, uint64_t x)
{
extern void r_btdm_put_be64(void *buf, uint64_t x);
r_btdm_put_be64(buf, x);
}
static inline uint16_t
btdm_get_be16(const void *buf)
{
extern uint16_t r_btdm_get_be16(const void *buf);
return r_btdm_get_be16(buf);
}
static inline uint32_t
btdm_get_be24(const void *buf)
{
extern uint32_t r_btdm_get_be24(const void *buf);
return r_btdm_get_be24(buf);
}
static inline uint32_t
btdm_get_be32(const void *buf)
{
extern uint32_t r_btdm_get_be32(const void *buf);
return r_btdm_get_be32(buf);
}
static inline uint64_t
btdm_get_be64(const void *buf)
{
extern uint64_t r_btdm_get_be64(const void *buf);
return r_btdm_get_be64(buf);
}
static inline void
btdm_swap_in_place(void *buf, int len)
{
extern void r_btdm_swap_in_place(void *buf, int len);
r_btdm_swap_in_place(buf, len);
}
static inline void
btdm_swap_buf(uint8_t *dst, const uint8_t *src, int len)
{
extern void r_btdm_swap_buf(uint8_t *dst, const uint8_t *src, int len);
r_btdm_swap_buf(dst, src, len);
}
#ifdef __cplusplus
}
#endif
#endif /* _BTDM_ENDIAN_H_ */
@@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BTDM_EXTERNAL_H_
#define _BTDM_EXTERNAL_H_
#include <stdbool.h>
#include <stdint.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BTDM_EXTERNAL_WR_FUNC(f) wr_ ## f
#define btdm_external_bb_get_tx_pwr_table BTDM_EXTERNAL_WR_FUNC(btdm_external_bb_get_tx_pwr_table)
/*
* Function declarations for BTDM EXTERNAL
*/
const int8_t *wr_btdm_external_bb_get_tx_pwr_table(uint8_t *length);
int btdm_external_init(void);
void btdm_external_deinit(void);
#ifdef __cplusplus
}
#endif
#endif /* _BTDM_EXTERNAL_H_ */
@@ -0,0 +1,13 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BTDM_LOG_H_
#define _BTDM_LOG_H_
int btdm_log_init(void);
void btdm_log_deinit(void);
#endif
@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BTDM_LP_H_
#define _BTDM_LP_H_
void btdm_lp_enable_clock(esp_btdm_controller_config_t *cfg);
void btdm_lp_disable_clock(void);
int btdm_lp_init(void);
void btdm_lp_deinit(void);
void btdm_lp_reset(bool enable_stage);
void btdm_lp_shutdown(void);
#endif
@@ -0,0 +1,244 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _BTDM_MEMPOOL_H_
#define _BTDM_MEMPOOL_H_
#include "btdm_osal.h"
#include "queue.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* A memory block structure. This simply contains a pointer to the free list
* chain and is only used when the block is on the free list. When the block
* has been removed from the free list the entire memory block is usable by the
* caller.
*/
struct btdm_memblock {
SLIST_ENTRY(btdm_memblock) mb_next;
};
/* XXX: Change this structure so that we keep the first address in the pool? */
/* XXX: add memory debug structure and associated code */
/* XXX: Change how I coded the SLIST_HEAD here. It should be named:
SLIST_HEAD(,btdm_memblock) mp_head; */
/**
* Memory pool
*/
struct btdm_mempool {
/** Size of the memory blocks, in bytes. */
uint32_t mp_block_size;
/** The number of memory blocks. */
uint16_t mp_num_blocks;
/** The number of free blocks left */
uint16_t mp_num_free;
/** The lowest number of free blocks seen */
uint16_t mp_min_free;
/** Bitmap of OS_MEMPOOL_F_[...] values. */
uint8_t mp_flags;
/** Address of memory buffer used by pool */
uint32_t mp_membuf_addr;
STAILQ_ENTRY(btdm_mempool) mp_list;
SLIST_HEAD(, btdm_memblock);
/** Name for memory block */
const char *name;
};
/**
* Indicates an extended mempool. Address can be safely cast to
* (struct btdm_mempool_ext *).
*/
#define BTDM_MEMPOOL_F_EXT 0x01
#define BTDM_ALIGNMENT 4
#define BTDM_MEMPOOL_SIZE(n, blksize) \
((((blksize) + ((BTDM_ALIGNMENT) - 1)) / (BTDM_ALIGNMENT)) * (n))
#if (BTDM_ALIGNMENT == 4)
typedef uint32_t btdm_membuf_t;
#elif (BTDM_ALIGNMENT == 8)
typedef uint64_t btdm_membuf_t;
#elif (BTDM_ALIGNMENT == 16)
typedef __uint128_t btdm_membuf_t;
#else
#error "Unhandled `BTDM_ALIGNMENT` for `btdm_membuf_t`"
#endif /* BTDM_ALIGNMENT == * */
/**
* Initialize a memory pool.
*
* @param mp Pointer to a pointer to a mempool
* @param blocks The number of blocks in the pool
* @param blocks_size The size of the block, in bytes.
* @param membuf Pointer to memory to contain blocks.
* @param name Name of the pool.
*
* @return btdm_osal_error_t
*/
static inline btdm_osal_error_t
btdm_mempool_init(struct btdm_mempool *mp, uint16_t blocks, uint32_t block_size, void *membuf,
const char *name)
{
extern btdm_osal_error_t r_btdm_os_mempool_init(struct btdm_mempool * mp, uint16_t blocks,
uint32_t block_size, void *membuf,
const char *name);
return r_btdm_os_mempool_init(mp, blocks, block_size, membuf, name);
}
#if 0
/**
* Initializes an extended memory pool. Extended attributes (e.g., callbacks)
* are not specified when this function is called; they are assigned manually
* after initialization.
*
* @param mpe The extended memory pool to initialize.
* @param blocks The number of blocks in the pool.
* @param block_size The size of each block, in bytes.
* @param membuf Pointer to memory to contain blocks.
* @param name Name of the pool.
*
* @return btdm_osal_error_t
*/
static inline btdm_osal_error_t
btdm_mempool_ext_init(struct btdm_mempool_ext *mpe, uint16_t blocks, uint32_t block_size,
void *membuf, const char *name)
{
extern btdm_osal_error_t r_btdm_os_mempool_ext_init(struct btdm_mempool_ext * mpe,
uint16_t blocks, uint32_t block_size,
void *membuf, const char *name);
return r_btdm_os_mempool_ext_init(mpe, blocks, block_size, membuf, name);
}
#endif
/**
* Clears a memory pool.
*
* @param mp The mempool to clear.
*
* @return btdm_osal_error_t
*/
static inline btdm_osal_error_t
btdm_mempool_clear(struct btdm_mempool *mp)
{
extern btdm_osal_error_t r_btdm_os_mempool_clear(struct btdm_mempool * mp);
return r_btdm_os_mempool_clear(mp);
}
/**
* Performs an integrity check of the specified mempool. This function
* attempts to detect memory corruption in the specified memory pool.
*
* @param mp The mempool to check.
*
* @return true if the memory pool passes the integrity
* check;
* false if the memory pool is corrupt.
*/
static inline bool
btdm_mempool_is_sane(const struct btdm_mempool *mp)
{
extern bool r_btdm_os_mempool_is_sane(const struct btdm_mempool *mp);
return r_btdm_os_mempool_is_sane(mp);
}
/**
* Checks if a memory block was allocated from the specified mempool.
*
* @param mp The mempool to check as parent.
* @param block_addr The memory block to check as child.
*
* @return 0 if the block does not belong to the mempool;
* 1 if the block does belong to the mempool.
*/
static inline int
btdm_memblock_from(const struct btdm_mempool *mp, const void *block_addr)
{
extern int r_btdm_os_memblock_from(const struct btdm_mempool *mp, const void *block_addr);
return r_btdm_os_memblock_from(mp, block_addr);
}
/**
* Get a memory block from a memory pool
*
* @param mp Pointer to the memory pool
*
* @return void* Pointer to block if available; NULL otherwise
*/
static inline void *
btdm_memblock_get(struct btdm_mempool *mp)
{
extern void *r_btdm_os_memblock_get(struct btdm_mempool * mp);
return r_btdm_os_memblock_get(mp);
}
/**
* Puts the memory block back into the pool, ignoring the put callback, if any.
* This function should only be called from a put callback to free a block
* without causing infinite recursion.
*
* @param mp Pointer to memory pool
* @param block_addr Pointer to memory block
*
* @return btdm_osal_error_t
*/
static inline btdm_osal_error_t
btdm_mempool_put_from_cb(struct btdm_mempool *mp, void *block_addr)
{
extern btdm_osal_error_t r_btdm_os_memblock_put_from_cb(struct btdm_mempool * mp,
void *block_addr);
return r_btdm_os_memblock_put_from_cb(mp, block_addr);
}
/**
* Puts the memory block back into the pool
*
* @param mp Pointer to memory pool
* @param block_addr Pointer to memory block
*
* @return btdm_osal_error_t
*/
static inline btdm_osal_error_t
btdm_memblock_put(struct btdm_mempool *mp, void *block_addr)
{
extern btdm_osal_error_t r_btdm_os_memblock_put(struct btdm_mempool * mp, void *block_addr);
return r_btdm_os_memblock_put(mp, block_addr);
}
static inline uint16_t
btdm_memblock_free_num_get(struct btdm_mempool *mp)
{
extern uint16_t r_btdm_os_memblock_num_free(struct btdm_mempool * mp);
return r_btdm_os_memblock_num_free(mp);
}
#ifdef __cplusplus
}
#endif
#endif /* _BTDM_MEMPOOL_H_ */
@@ -0,0 +1,221 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BTDM_OSAL_H_
#define _BTDM_OSAL_H_
#include "sdkconfig.h"
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
enum btdm_osal_error {
BTDM_OSAL_OK = 0,
BTDM_OSAL_ENOMEM = 1,
BTDM_OSAL_EINVAL = 2,
BTDM_OSAL_INVALID_PARM = 3,
BTDM_OSAL_MEM_NOT_ALIGNED = 4,
BTDM_OSAL_BAD_MUTEX = 5,
BTDM_OSAL_TIMEOUT = 6,
BTDM_OSAL_ERR_IN_ISR = 7, /* Function cannot be called from ISR */
BTDM_OSAL_ERR_PRIV = 8, /* Privileged access error */
BTDM_OSAL_NOT_STARTED = 9, /* OS must be started to call this function, but isn't */
BTDM_OSAL_ENOENT = 10, /* No such thing */
BTDM_OSAL_EBUSY = 11, /* Resource busy */
BTDM_OSAL_ERROR = 12, /* Generic Error */
};
enum btdm_osal_malloc_flag {
BTDM_OSAL_MALLOC_F_INTERNAL = 0,
BTDM_OSAL_MALLOC_F_NORMAL,
};
typedef enum btdm_osal_malloc_flag btdm_osal_malloc_flag_t;
typedef struct {
uint16_t evt_count;
uint16_t evtq_count;
uint16_t co_count;
uint16_t sem_count;
uint16_t mutex_count;
} btdm_osal_elem_num_t;
struct btdm_osal_event {
void *event;
};
struct btdm_osal_eventq {
void *eventq;
};
struct btdm_osal_callout {
void *co;
};
struct btdm_osal_mutex {
void *mutex;
};
struct btdm_osal_sem {
void *sem;
};
/*
* Type definitions for BTDM OSAL
*/
typedef uint32_t btdm_osal_time_t;
typedef int btdm_osal_error_t;
typedef void btdm_osal_event_fn(struct btdm_osal_event *ev);
typedef void btdm_osal_task_fn(void *arg);
typedef void btdm_osal_intr_fn(void *arg);
typedef void *btdm_osal_task_handle_t;
typedef void *btdm_osal_intr_handle_t;
/*
* Function declarations for BTDM OSAL
*/
void wr_btdm_osal_eventq_init(struct btdm_osal_eventq *evq);
void wr_btdm_osal_eventq_deinit(struct btdm_osal_eventq *evq);
struct btdm_osal_event *wr_btdm_osal_eventq_get(struct btdm_osal_eventq *evq, btdm_osal_time_t tmo);
void wr_btdm_osal_eventq_put(struct btdm_osal_eventq *evq, struct btdm_osal_event *ev);
void wr_btdm_osal_eventq_put_to_front(struct btdm_osal_eventq *evq, struct btdm_osal_event *ev);
void wr_btdm_osal_eventq_remove(struct btdm_osal_eventq *evq, struct btdm_osal_event *ev);
bool wr_btdm_osal_eventq_is_empty(struct btdm_osal_eventq *evq);
void wr_btdm_osal_event_run(struct btdm_osal_event *ev);
void wr_btdm_osal_event_init(struct btdm_osal_event *ev, btdm_osal_event_fn *fn, void *arg);
void wr_btdm_osal_event_deinit(struct btdm_osal_event *ev);
void wr_btdm_osal_event_reset(struct btdm_osal_event *ev);
bool wr_btdm_osal_event_is_queued(struct btdm_osal_event *ev);
void *wr_btdm_osal_event_get_arg(struct btdm_osal_event *ev);
void wr_btdm_osal_event_set_arg(struct btdm_osal_event *ev, void *arg);
btdm_osal_error_t wr_btdm_osal_mutex_init(struct btdm_osal_mutex *mu);
btdm_osal_error_t wr_btdm_osal_mutex_deinit(struct btdm_osal_mutex *mu);
btdm_osal_error_t wr_btdm_osal_mutex_pend(struct btdm_osal_mutex *mu, btdm_osal_time_t timeout);
btdm_osal_error_t wr_btdm_osal_mutex_release(struct btdm_osal_mutex *mu);
btdm_osal_error_t wr_btdm_osal_sem_init(struct btdm_osal_sem *sem, uint16_t tokens);
btdm_osal_error_t wr_btdm_osal_sem_deinit(struct btdm_osal_sem *sem);
btdm_osal_error_t wr_btdm_osal_sem_pend(struct btdm_osal_sem *sem, btdm_osal_time_t timeout);
btdm_osal_error_t wr_btdm_osal_sem_release(struct btdm_osal_sem *sem);
uint16_t wr_btdm_osal_sem_get_count(struct btdm_osal_sem *sem);
int wr_btdm_osal_callout_init(struct btdm_osal_callout *co, struct btdm_osal_eventq *evq,
btdm_osal_event_fn *ev_cb, void *ev_arg);
void wr_btdm_osal_callout_deinit(struct btdm_osal_callout *co);
btdm_osal_error_t wr_btdm_osal_callout_reset(struct btdm_osal_callout *co, btdm_osal_time_t ticks);
void wr_btdm_osal_callout_mem_reset(struct btdm_osal_callout *co);
void wr_btdm_osal_callout_stop(struct btdm_osal_callout *co);
bool wr_btdm_osal_callout_is_active(struct btdm_osal_callout *co);
btdm_osal_time_t wr_btdm_osal_callout_get_ticks(struct btdm_osal_callout *co);
btdm_osal_time_t wr_btdm_osal_callout_remaining_ticks(struct btdm_osal_callout *co,
btdm_osal_time_t time);
void wr_btdm_osal_callout_set_arg(struct btdm_osal_callout *co, void *arg);
btdm_osal_time_t wr_btdm_osal_time_get(void);
btdm_osal_error_t wr_btdm_osal_time_ms_to_ticks(uint32_t ms, btdm_osal_time_t *out_ticks);
btdm_osal_error_t wr_btdm_osal_time_ticks_to_ms(btdm_osal_time_t ticks, uint32_t *out_ms);
btdm_osal_time_t wr_btdm_osal_time_ms_to_ticks32(uint32_t ms);
uint32_t wr_btdm_osal_time_ticks_to_ms32(btdm_osal_time_t ticks);
uint32_t wr_btdm_osal_hw_enter_critical(void);
void wr_btdm_osal_hw_exit_critical(uint32_t ctx);
uint8_t wr_btdm_osal_hw_is_in_critical(void);
uint32_t wr_btdm_osal_get_time_forever(void);
int wr_btdm_osal_task_create(btdm_osal_task_fn *fn, const char *name, uint32_t stack_size,
void *arg, uint32_t priority, btdm_osal_task_handle_t *task_handle,
uint32_t core_id);
void wr_btdm_osal_task_delete(btdm_osal_task_handle_t task_handle);
int wr_btdm_osal_intr_alloc(int src, int flags, btdm_osal_intr_fn *fn, void *arg,
btdm_osal_intr_handle_t *intr_handle);
int wr_btdm_osal_intr_free(btdm_osal_intr_handle_t intr_handle);
void *wr_btdm_osal_malloc(uint32_t size, btdm_osal_malloc_flag_t flags);
void wr_btdm_osal_free(void *ptr);
#if !CONFIG_BTDM_CTRL_MULTI_LINK_ENABLED
void *wr_btdm_osal_mmgmt_block_malloc(uint32_t size);
void wr_btdm_osal_mmgmt_block_free(void *ptr);
void wr_btdm_osal_mmgmt_block_copy(void *dst, const void *src, uint16_t size);
#endif /* !CONFIG_BTDM_CTRL_MULTI_LINK_ENABLED */
// void * wr_btdm_osal_ets_delay_us(uint32_t us);
int wr_btdm_osal_read_efuse_mac(uint8_t *mac);
void wr_btdm_osal_srand(uint32_t seed);
int wr_btdm_osal_rand(void);
int btdm_osal_elem_mempool_init(btdm_osal_elem_num_t *elem_num);
void btdm_osal_elem_mempool_deinit(void);
#define BTDM_OSAL_WR_FUNC(f) wr_ ## f
#define btdm_osal_eventq_init BTDM_OSAL_WR_FUNC(btdm_osal_eventq_init)
#define btdm_osal_eventq_deinit BTDM_OSAL_WR_FUNC(btdm_osal_eventq_deinit)
#define btdm_osal_eventq_get BTDM_OSAL_WR_FUNC(btdm_osal_eventq_get)
#define btdm_osal_eventq_put BTDM_OSAL_WR_FUNC(btdm_osal_eventq_put)
#define btdm_osal_eventq_put_to_front BTDM_OSAL_WR_FUNC(btdm_osal_eventq_put_to_front)
#define btdm_osal_eventq_remove BTDM_OSAL_WR_FUNC(btdm_osal_eventq_remove)
#define btdm_osal_eventq_is_empty BTDM_OSAL_WR_FUNC(btdm_osal_eventq_is_empty)
#define btdm_osal_event_run BTDM_OSAL_WR_FUNC(btdm_osal_event_run)
#define btdm_osal_event_init BTDM_OSAL_WR_FUNC(btdm_osal_event_init)
#define btdm_osal_event_deinit BTDM_OSAL_WR_FUNC(btdm_osal_event_deinit)
#define btdm_osal_event_reset BTDM_OSAL_WR_FUNC(btdm_osal_event_reset)
#define btdm_osal_event_is_queued BTDM_OSAL_WR_FUNC(btdm_osal_event_is_queued)
#define btdm_osal_event_get_arg BTDM_OSAL_WR_FUNC(btdm_osal_event_get_arg)
#define btdm_osal_event_set_arg BTDM_OSAL_WR_FUNC(btdm_osal_event_set_arg)
#define btdm_osal_mutex_init BTDM_OSAL_WR_FUNC(btdm_osal_mutex_init)
#define btdm_osal_mutex_deinit BTDM_OSAL_WR_FUNC(btdm_osal_mutex_deinit)
#define btdm_osal_mutex_pend BTDM_OSAL_WR_FUNC(btdm_osal_mutex_pend)
#define btdm_osal_mutex_release BTDM_OSAL_WR_FUNC(btdm_osal_mutex_release)
#define btdm_osal_sem_init BTDM_OSAL_WR_FUNC(btdm_osal_sem_init)
#define btdm_osal_sem_deinit BTDM_OSAL_WR_FUNC(btdm_osal_sem_deinit)
#define btdm_osal_sem_pend BTDM_OSAL_WR_FUNC(btdm_osal_sem_pend)
#define btdm_osal_sem_release BTDM_OSAL_WR_FUNC(btdm_osal_sem_release)
#define btdm_osal_sem_get_count BTDM_OSAL_WR_FUNC(btdm_osal_sem_get_count)
#define btdm_osal_callout_init BTDM_OSAL_WR_FUNC(btdm_osal_callout_init)
#define btdm_osal_callout_deinit BTDM_OSAL_WR_FUNC(btdm_osal_callout_deinit)
#define btdm_osal_callout_reset BTDM_OSAL_WR_FUNC(btdm_osal_callout_reset)
#define btdm_osal_callout_mem_reset BTDM_OSAL_WR_FUNC(btdm_osal_callout_mem_reset)
#define btdm_osal_callout_stop BTDM_OSAL_WR_FUNC(btdm_osal_callout_stop)
#define btdm_osal_callout_is_active BTDM_OSAL_WR_FUNC(btdm_osal_callout_is_active)
#define btdm_osal_callout_get_ticks BTDM_OSAL_WR_FUNC(btdm_osal_callout_get_ticks)
#define btdm_osal_callout_remaining_ticks BTDM_OSAL_WR_FUNC(btdm_osal_callout_remaining_ticks)
#define btdm_osal_callout_set_arg BTDM_OSAL_WR_FUNC(btdm_osal_callout_set_arg)
#define btdm_osal_time_get BTDM_OSAL_WR_FUNC(btdm_osal_time_get)
#define btdm_osal_time_ms_to_ticks BTDM_OSAL_WR_FUNC(btdm_osal_time_ms_to_ticks)
#define btdm_osal_time_ticks_to_ms BTDM_OSAL_WR_FUNC(btdm_osal_time_ticks_to_ms)
#define btdm_osal_time_ms_to_ticks32 BTDM_OSAL_WR_FUNC(btdm_osal_time_ms_to_ticks32)
#define btdm_osal_time_ticks_to_ms32 BTDM_OSAL_WR_FUNC(btdm_osal_time_ticks_to_ms32)
#define btdm_osal_hw_enter_critical BTDM_OSAL_WR_FUNC(btdm_osal_hw_enter_critical)
#define btdm_osal_hw_exit_critical BTDM_OSAL_WR_FUNC(btdm_osal_hw_exit_critical)
#define btdm_osal_hw_is_in_critical BTDM_OSAL_WR_FUNC(btdm_osal_hw_is_in_critical)
#define btdm_osal_get_time_forever BTDM_OSAL_WR_FUNC(btdm_osal_get_time_forever)
#define btdm_osal_task_create BTDM_OSAL_WR_FUNC(btdm_osal_task_create)
#define btdm_osal_task_delete BTDM_OSAL_WR_FUNC(btdm_osal_task_delete)
#define btdm_osal_intr_alloc BTDM_OSAL_WR_FUNC(btdm_osal_intr_alloc)
#define btdm_osal_intr_free BTDM_OSAL_WR_FUNC(btdm_osal_intr_free)
#define btdm_osal_malloc BTDM_OSAL_WR_FUNC(btdm_osal_malloc)
#define btdm_osal_free BTDM_OSAL_WR_FUNC(btdm_osal_free)
#define btdm_osal_mmgmt_block_malloc BTDM_OSAL_WR_FUNC(btdm_osal_mmgmt_block_malloc)
#define btdm_osal_mmgmt_block_free BTDM_OSAL_WR_FUNC(btdm_osal_mmgmt_block_free)
#define btdm_osal_mmgmt_block_copy BTDM_OSAL_WR_FUNC(btdm_osal_mmgmt_block_copy)
#define btdm_osal_ets_delay_us BTDM_OSAL_WR_FUNC(btdm_osal_ets_delay_us)
#define btdm_osal_read_efuse_mac BTDM_OSAL_WR_FUNC(btdm_osal_read_efuse_mac)
#define btdm_osal_rand BTDM_OSAL_WR_FUNC(btdm_osal_rand)
#ifdef __cplusplus
}
#endif
#endif /* _BTDM_OSAL_H_ */
@@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BTDM_OSAL_FREERTOS_H_
#define _BTDM_OSAL_FREERTOS_H_
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "sdkconfig.h"
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "btdm_osal.h"
#ifdef __cplusplus
extern "C" {
#endif
#if ((defined(CONFIG_BT_NIMBLE_USE_ESP_TIMER) && CONFIG_BT_NIMBLE_USE_ESP_TIMER) || \
(defined(CONFIG_BT_LE_USE_ESP_TIMER) && CONFIG_BT_LE_USE_ESP_TIMER))
/* Use esp timer instead of FreeRTOS timer to implement the callout. */
#define BTDM_OSAL_USE_ESP_TIMER (1)
#else
#define BTDM_OSAL_USE_ESP_TIMER (0)
#endif
struct btdm_osal_event_freertos {
bool queued;
void (*fn)(struct btdm_osal_event *ev);
void *arg;
};
struct btdm_osal_eventq_freertos {
QueueHandle_t q;
};
struct btdm_osal_callout_freertos {
#if BTDM_OSAL_USE_ESP_TIMER
esp_timer_handle_t handle;
#else
TimerHandle_t handle;
#endif
struct btdm_osal_eventq *evq;
struct btdm_osal_event ev;
};
struct btdm_osal_mutex_freertos {
SemaphoreHandle_t handle;
};
struct btdm_osal_sem_freertos {
SemaphoreHandle_t handle;
};
typedef void btdm_osal_event_fn_freertos(struct btdm_osal_event_freertos *ev);
#ifdef __cplusplus
}
#endif
#endif /* _BTDM_OSAL_FREERTOS_H_ */
@@ -0,0 +1,114 @@
/*
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_BTDM_CFG_H__
#define __ESP_BTDM_CFG_H__
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_BT_CTRL_SLEEP_ENABLE
#define UC_BT_CTRL_SLEEP_ENABLE CONFIG_BT_CTRL_SLEEP_ENABLE
#else
#define UC_BT_CTRL_SLEEP_ENABLE (0)
#endif
#define UC_BT_CTRL_TASK_STACK_SIZE CONFIG_BT_CTRL_TASK_STACK_SIZE
#ifdef CONFIG_BT_CTRL_HCI_INTERFACE_USE_UART
#define UC_HCI_UART_EN CONFIG_BT_CTRL_HCI_INTERFACE_USE_UART
#else
#define UC_HCI_UART_EN 0 // hci ram mode
#endif
#if UC_HCI_UART_EN
#define UC_BT_CTRL_HCI_UART_TX_PIN (CONFIG_BT_CTRL_HCI_UART_TX_PIN)
#define UC_BT_CTRL_HCI_UART_RX_PIN (CONFIG_BT_CTRL_HCI_UART_RX_PIN)
#define UC_BT_CTRL_HCI_UART_PORT (CONFIG_BT_CTRL_HCI_UART_PORT)
#define UC_BT_CTRL_HCI_UART_BAUD (CONFIG_BT_CTRL_HCI_UART_BAUD)
#define UC_BT_CTRL_HCI_UART_DATA_BITS (UART_DATA_8_BITS)
#define UC_BT_CTRL_HCI_UART_STOP_BITS (UART_STOP_BITS_1)
#define UC_BT_CTRL_HCI_UART_PARITY (0)
#define UC_BT_CTRL_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE)
#else
#define UC_BT_CTRL_HCI_UART_TX_PIN (0)
#define UC_BT_CTRL_HCI_UART_RX_PIN (0)
#define UC_BT_CTRL_HCI_UART_PORT (0)
#define UC_BT_CTRL_HCI_UART_BAUD (0)
#define UC_BT_CTRL_HCI_UART_DATA_BITS (0)
#define UC_BT_CTRL_HCI_UART_STOP_BITS (0)
#define UC_BT_CTRL_HCI_UART_PARITY (0)
#define UC_BT_CTRL_HCI_UART_TASK_STACK_SIZE (0)
#endif
#if (CONFIG_BT_CTRL_HCI_UART_FLOWCTRL)
#define UC_BT_CTRL_HCI_UART_FLOW_CTRL (CONFIG_BT_CTRL_HCI_UART_FLOWCTRL)
#if UC_BT_CTRL_HCI_UART_FLOW_CTRL
#define UC_BT_CTRL_HCI_UART_CTS_PIN (CONFIG_BT_CTRL_HCI_UART_CTS_PIN)
#define UC_BT_CTRL_HCI_UART_RTS_PIN (CONFIG_BT_CTRL_HCI_UART_RTS_PIN)
#else
#define UC_BT_CTRL_HCI_UART_CTS_PIN (-1)
#define UC_BT_CTRL_HCI_UART_RTS_PIN (-1)
#endif
#else
#define UC_BT_CTRL_HCI_UART_FLOW_CTRL (0)
#define UC_BT_CTRL_HCI_UART_CTS_PIN (-1)
#define UC_BT_CTRL_HCI_UART_RTS_PIN (-1)
#endif
#if (CONFIG_BT_CTRL_HCI_INTERFACE_USE_RAM)
#define UC_BT_CTRL_HCI_INTERFACE_USE_RAM (1)
#else
#define UC_BT_CTRL_HCI_INTERFACE_USE_RAM (0)
#endif
#if (CONFIG_BT_CTRL_HCI_INTERFACE_USE_UART)
#define UC_BT_CTRL_HCI_INTERFACE_USE_UART (1)
#else
#define UC_BT_CTRL_HCI_INTERFACE_USE_UART (0)
#endif
#if (UC_BT_CTRL_HCI_INTERFACE_USE_UART)
#if (CONFIG_BT_CTRL_UART_HCI_DMA_MODE)
#define UC_BT_CTRL_UART_HCI_DMA_MODE (1)
#define UC_BT_CTRL_UART_HCI_NO_DMA_MODE (0)
#else
#define UC_BT_CTRL_UART_HCI_DMA_MODE (0)
#define UC_BT_CTRL_UART_HCI_NO_DMA_MODE (1)
#endif
#endif
#if (!UC_BT_CTRL_HCI_INTERFACE_USE_RAM)
#define UC_BT_CTRL_HCI_TRANS_TASK_STACK_SIZE (CONFIG_BT_CTRL_HCI_TRANS_TASK_STACK_SIZE)
#endif
#if (UC_BT_CTRL_UART_HCI_NO_DMA_MODE)
#define UC_BT_CTRL_HCI_UART_RX_BUFFER_SIZE (CONFIG_BT_CTRL_HCI_UART_RX_BUFFER_SIZE)
#define UC_BT_CTRL_HCI_UART_TX_BUFFER_SIZE (CONFIG_BT_CTRL_HCI_UART_TX_BUFFER_SIZE)
#endif
#if (UC_BT_CTRL_UART_HCI_DMA_MODE)
#define UC_BT_CTRL_HCI_TRANS_RX_MEM_NUM (CONFIG_BT_CTRL_HCI_TRANS_RX_MEM_NUM)
#define UC_BT_CTRL_HCI_LLDESCS_POOL_NUM (CONFIG_BT_CTRL_HCI_LLDESCS_POOL_NUM)
#endif
#define UC_BT_CTRL_BR_EDR_IS_ENABLE (CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM)
#define UC_BT_CTRL_BLE_IS_ENABLE (CONFIG_BTDM_CTRL_MODE_BLE_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM)
//TODO
#define UC_BT_CTRL_CONN_FC_ENABLE (1)
#ifdef __cplusplus
}
#endif
#endif /* __ESP_BTDM_CFG_H__ */
@@ -0,0 +1,210 @@
/*
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _QUEUE_H_
#define _QUEUE_H_
/* The common BSD linked list queue macros are already defined here for ESP-IDF */
#include <sys/queue.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* This file defines circular queues. The other types of data structures:
* singly-linked lists, singly-linked tail queues, lists and tail queues
* are used from sys/queue.h
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A singly-linked tail queue is headed by a pair of pointers, one to the
* head of the list and the other to the tail of the list. The elements are
* singly linked for minimum space and pointer manipulation overhead at the
* expense of O(n) removal for arbitrary elements. New elements can be added
* to the list after an existing element, at the head of the list, or at the
* end of the list. Elements being removed from the head of the tail queue
* should use the explicit macro for this purpose for optimum efficiency.
* A singly-linked tail queue may only be traversed in the forward direction.
* Singly-linked tail queues are ideal for applications with large datasets
* and few or no removals or for implementing a FIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*
*
* SLIST LIST STAILQ TAILQ CIRCLEQ
* _HEAD + + + + +
* _HEAD_INITIALIZER + + + + +
* _ENTRY + + + + +
* _INIT + + + + +
* _EMPTY + + + + +
* _FIRST + + + + +
* _NEXT + + + + +
* _PREV - - - + +
* _LAST - - + + +
* _FOREACH + + + + +
* _FOREACH_REVERSE - - - + +
* _INSERT_HEAD + + + + +
* _INSERT_BEFORE - + - + +
* _INSERT_AFTER + + + + +
* _INSERT_TAIL - - + + +
* _REMOVE_HEAD + - + - -
* _REMOVE + + + + +
*
*/
/*
* Circular queue declarations.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ (void *)&(head), (void *)&(head) }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue functions.
*/
#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_FOREACH(var, head, field) \
for ((var) = CIRCLEQ_FIRST((head)); \
(var) != (void *)(head) || ((var) = NULL); \
(var) = CIRCLEQ_NEXT((var), field))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for ((var) = CIRCLEQ_LAST((head)); \
(var) != (void *)(head) || ((var) = NULL); \
(var) = CIRCLEQ_PREV((var), field))
#define CIRCLEQ_INIT(head) do { \
CIRCLEQ_FIRST((head)) = (void *)(head); \
CIRCLEQ_LAST((head)) = (void *)(head); \
} while (0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field); \
CIRCLEQ_PREV((elm), field) = (listelm); \
if (CIRCLEQ_NEXT((listelm), field) == (void *)(head)) \
CIRCLEQ_LAST((head)) = (elm); \
else \
CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\
CIRCLEQ_NEXT((listelm), field) = (elm); \
} while (0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
CIRCLEQ_NEXT((elm), field) = (listelm); \
CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field); \
if (CIRCLEQ_PREV((listelm), field) == (void *)(head)) \
CIRCLEQ_FIRST((head)) = (elm); \
else \
CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\
CIRCLEQ_PREV((listelm), field) = (elm); \
} while (0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head)); \
CIRCLEQ_PREV((elm), field) = (void *)(head); \
if (CIRCLEQ_LAST((head)) == (void *)(head)) \
CIRCLEQ_LAST((head)) = (elm); \
else \
CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm); \
CIRCLEQ_FIRST((head)) = (elm); \
} while (0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
CIRCLEQ_NEXT((elm), field) = (void *)(head); \
CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head)); \
if (CIRCLEQ_FIRST((head)) == (void *)(head)) \
CIRCLEQ_FIRST((head)) = (elm); \
else \
CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm); \
CIRCLEQ_LAST((head)) = (elm); \
} while (0)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
if (CIRCLEQ_NEXT((elm), field) == (void *)(head)) \
CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field); \
else \
CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) = \
CIRCLEQ_PREV((elm), field); \
if (CIRCLEQ_PREV((elm), field) == (void *)(head)) \
CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field); \
else \
CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) = \
CIRCLEQ_NEXT((elm), field); \
} while (0)
#ifdef __cplusplus
}
#endif
#endif /* !_SYS_QUEUE_H_ */
@@ -0,0 +1,234 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include "sdkconfig.h"
#include "btdm_coex.h"
#if CONFIG_SW_COEXIST_ENABLE
#include "private/esp_coexist_internal.h"
#endif
extern esp_err_t coex_iso_start(void *coex_iso_info);
extern esp_err_t coex_iso_stop(uint16_t handle);
extern uint16_t coex_protect_frame_thres_get(void);
extern void coex_start_int_handle(uint16_t handle, uint32_t duration);
extern void coex_end_int_handle(uint16_t handle, uint32_t duration);
extern void coex_ble_idle_time_inform(uint32_t start_offset, uint32_t duration);
extern uint8_t coex_t_ifs_pti_selection_get(void);
extern void coex_ble_channel_map_set(uint8_t *channel_map);
extern esp_err_t coex_register_ble_cb(uint8_t type, void *func);
extern void bt_rf_coex_log_func_register(void *cb);
/*
***************************************************************************************************
* BTDM COEX Adapter Types
***************************************************************************************************
*/
typedef void (*coex_schm_cb_t)(uint32_t __event);
typedef void (*coex_wifi_channel_change_btdm_cb_t)(uint8_t primary, uint8_t secondary);
typedef void (*coex_funcs_ble_cb_t)(void);
/*
***************************************************************************************************
* BTDM COEX Adapter Functions
***************************************************************************************************
*/
void
wr_btdm_coex_schm_status_bit_set(uint32_t type, uint32_t status)
{
#if CONFIG_SW_COEXIST_ENABLE
coex_schm_status_bit_set(type, status);
#endif // CONFIG_SW_COEXIST_ENABLE
}
void
wr_btdm_coex_schm_status_bit_clear(uint32_t type, uint32_t status)
{
#if CONFIG_SW_COEXIST_ENABLE
coex_schm_status_bit_clear(type, status);
#endif // CONFIG_SW_COEXIST_ENABLE
}
int
wr_btdm_coex_schm_register_btdm_callback(coex_schm_cb_t callback)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_schm_register_callback(COEX_SCHM_CALLBACK_TYPE_BT, callback);
#else
return 0;
#endif
}
uint32_t
wr_btdm_coex_schm_interval_get(void)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_schm_interval_get();
#else
return 0;
#endif
}
uint8_t
wr_btdm_coex_schm_curr_period_get(void)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_schm_curr_period_get();
#else
return 1;
#endif
}
void *
wr_btdm_coex_schm_curr_phase_get(void)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_schm_curr_phase_get();
#else
return NULL;
#endif
}
int
wr_btdm_coex_register_wifi_channel_change_callback(coex_wifi_channel_change_btdm_cb_t callback)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_register_wifi_channel_change_callback(callback);
#else
return -1;
#endif
}
int
wr_btdm_coex_wifi_channel_get(uint8_t *primary, uint8_t *secondary)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_wifi_channel_get(primary, secondary);
#else
return -1;
#endif
}
int
wr_btdm_coex_version_get(unsigned *major, unsigned *minor, unsigned *path)
{
#if CONFIG_SW_COEXIST_ENABLE
// TODO: enable it after update submodule coexist
#if 0
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;
#endif
return 0;
#endif
return -1;
}
int
wr_btdm_coex_iso_start(void *coex_iso_info)
{
#if CONFIG_SW_COEXIST_ENABLE && CONFIG_BT_LE_ISO_SUPPORT
return coex_iso_start(coex_iso_info);
#else
return ESP_OK;
#endif /* CONFIG_SW_COEXIST_ENABLE */
}
int
wr_btdm_coex_iso_stop(uint16_t handle)
{
#if CONFIG_SW_COEXIST_ENABLE && CONFIG_BT_LE_ISO_SUPPORT
return coex_iso_stop(handle);
#else
return ESP_OK;
#endif /* CONFIG_SW_COEXIST_ENABLE */
}
uint16_t
wr_btdm_coex_iso_protect_frame_thres_get(void)
{
#if CONFIG_SW_COEXIST_ENABLE && CONFIG_BT_LE_ISO_SUPPORT
return coex_protect_frame_thres_get();
#else
return 0;
#endif /* CONFIG_SW_COEXIST_ENABLE */
}
void
wr_btdm_coex_iso_start_int_handle(uint16_t handle, uint32_t duration)
{
#if CONFIG_SW_COEXIST_ENABLE && CONFIG_BT_LE_ISO_SUPPORT
coex_start_int_handle(handle, duration);
#endif /* CONFIG_SW_COEXIST_ENABLE */
}
void
wr_btdm_coex_iso_end_int_handle(uint16_t handle, uint32_t duration)
{
#if CONFIG_SW_COEXIST_ENABLE && CONFIG_BT_LE_ISO_SUPPORT
coex_end_int_handle(handle, duration);
#endif /* CONFIG_SW_COEXIST_ENABLE */
}
void
wr_btdm_coex_ble_idle_time_inform(uint32_t start_offset, uint32_t duration)
{
#if CONFIG_SW_COEXIST_ENABLE
coex_ble_idle_time_inform(start_offset, duration);
#endif /* CONFIG_SW_COEXIST_ENABLE */
}
int
wr_btdm_coex_register_ble_cb(uint32_t type, coex_funcs_ble_cb_t func)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_register_ble_cb(type, func);
#else
return ESP_OK;
#endif /* CONFIG_SW_COEXIST_ENABLE */
}
/*
***************************************************************************************************
* BTDM COEX Initialization
***************************************************************************************************
*/
esp_err_t
btdm_coex_init(void)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_init();
#else
return ESP_OK;
#endif
}
void
btdm_coex_deinit(void)
{
}
esp_err_t
btdm_coex_enable(void)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_enable();
#else
return ESP_OK;
#endif
}
void
btdm_coex_disable(void)
{
#if CONFIG_SW_COEXIST_ENABLE
coex_disable();
#endif
}
@@ -0,0 +1,35 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include <stdio.h>
#include "btdm_external.h"
extern const int8_t *bt_bb_get_tx_pwr_table(uint8_t *length);
const int8_t *
wr_btdm_external_bb_get_tx_pwr_table(uint8_t *length)
{
assert(length != NULL);
return bt_bb_get_tx_pwr_table(length);
}
/*
***************************************************************************************************
* BTDM External Function Initialization
***************************************************************************************************
*/
int
btdm_external_init(void)
{
return 0;
}
void
btdm_external_deinit(void)
{
}
@@ -0,0 +1,129 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "assert.h"
#include "esp_attr.h"
#include "esp_rom_sys.h"
/*
***************************************************************************************************
* External Functions
***************************************************************************************************
*/
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
void r_btdm_sched_list_details_dump(void);
void r_ble_phy_hw_state_dump(uint8_t);
void esp_ble_controller_log_dump_all(bool);
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
/*
***************************************************************************************************
* Public Function Definitions
***************************************************************************************************
*/
void IRAM_ATTR
wr_btdm_log_set_flags(uint8_t p0)
{
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
extern void r_ble_log_set_buf_index_flag(uint32_t p0);
r_ble_log_set_buf_index_flag(p0);
#endif // BT_LE_CONTROLLER_LOG_ENABLED
}
void IRAM_ATTR
wr_btdm_log_reset_flags(uint8_t p0)
{
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
extern void r_ble_log_reset_buf_index_flag(uint32_t p0);
r_ble_log_reset_buf_index_flag(p0);
#endif // BT_LE_CONTROLLER_LOG_ENABLED
}
void IRAM_ATTR
wr_btdm_log_internal_x0(uint32_t p0)
{
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
extern void r_ble_log_internal_x0(uint32_t p0);
r_ble_log_internal_x0(p0);
#endif // BT_LE_CONTROLLER_LOG_ENABLED
}
void IRAM_ATTR
wr_btdm_log_internal_x1(uint32_t p0, uint32_t p1)
{
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
extern void r_ble_log_internal_x1(uint32_t p0, uint32_t p1);
r_ble_log_internal_x1(p0, p1);
#endif // BT_LE_CONTROLLER_LOG_ENABLED
}
void IRAM_ATTR
wr_btdm_log_internal_x2(uint32_t p0, uint32_t p1, uint32_t p2)
{
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
extern void r_ble_log_internal_x2(uint32_t p0, uint32_t p1, uint32_t p2);
r_ble_log_internal_x2(p0, p1, p2);
#endif // BT_LE_CONTROLLER_LOG_ENABLED
}
void IRAM_ATTR
wr_btdm_log_internal_x3(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3)
{
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
extern void r_ble_log_internal_x3(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3);
r_ble_log_internal_x3(p0, p1, p2, p3);
#endif // BT_LE_CONTROLLER_LOG_ENABLED
}
void IRAM_ATTR
wr_btdm_log_internal_hex(uint32_t p0, uint32_t p1, uint32_t p2)
{
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
extern void r_ble_log_internal_hex(uint32_t p0, uint32_t p1, uint32_t p2);
r_ble_log_internal_hex(p0, p1, p2);
#endif // BT_LE_CONTROLLER_LOG_ENABLED
}
void IRAM_ATTR
wr_btdm_log_raw_export(uint16_t p0, uint32_t p1, uint32_t p2)
{
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
extern void r_ble_log_raw_export(uint16_t p0, uint32_t p1, uint32_t p2);
r_ble_log_raw_export(p0, p1, p2);
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
}
void IRAM_ATTR
wr_btdm_assert(const char *file, int line, int p0, int p1, uint8_t type)
{
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
r_ble_phy_hw_state_dump(false);
r_btdm_sched_list_details_dump();
esp_ble_controller_log_dump_all(true);
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
esp_rom_printf("assert %s,%d, param:0x%x,0x%x\n", file, line, p0, p1);
assert(0);
}
/*
***************************************************************************************************
* BTDM LOG Initialization
***************************************************************************************************
*/
int
btdm_log_init(void)
{
return 0;
}
void
btdm_log_deinit(void)
{
}
@@ -0,0 +1,358 @@
/*
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_err.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "esp_bt.h"
/* From Modem and Phy */
#include "esp_phy_init.h"
#include "esp_private/esp_modem_clock.h"
#include "esp_private/esp_clk_tree_common.h"
#ifdef CONFIG_PM_ENABLE
#include "esp_pm.h"
#endif
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
#include "esp_private/pm_impl.h"
#include "esp_private/sleep_modem.h"
#include "esp_private/sleep_retention.h"
#endif
/*
***************************************************************************************************
* Local Defined Macros
***************************************************************************************************
*/
#define BTDM_LOG_TAG "BTDM_SLEEP"
#define BTDM_RTC_DELAY_US_LIGHT_SLEEP (2000)
#define BTDM_RTC_DELAY_US_MODEM_SLEEP (1500)
/*
***************************************************************************************************
* External Functions
***************************************************************************************************
*/
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
extern bool r_btdm_sleep_should_skip_light_sleep_check(void);
extern const sleep_retention_entries_config_t *r_btdm_mac_retention_link_get(uint8_t *size);
extern void r_btdm_sleep_wake_up_overhead_set(uint32_t overhead);
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
extern esp_err_t sleep_modem_bredr_mac_modem_state_init(void);
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
#if UC_BT_CTRL_BLE_IS_ENABLE
extern esp_err_t sleep_modem_ble_mac_modem_state_init(void);
#endif // UC_BT_CTRL_BLE_IS_ENABLEs
#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */
extern void r_btdm_sleep_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, void *w_arg,
uint32_t us_to_enabled);
/*
***************************************************************************************************
* Local Variables
***************************************************************************************************
*/
static bool s_bt_active = false;
static DRAM_ATTR modem_clock_lpclk_src_t s_bt_lpclk_src = MODEM_CLOCK_LPCLK_SRC_INVALID;
#ifdef CONFIG_PM_ENABLE
static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock = NULL;
#endif // CONFIG_PM_ENABLE
// static modem_clock_lpclk_src_t s_bt_lpclk_src = MODEM_CLOCK_LPCLK_SRC_INVALID;
static uint32_t s_bt_lpclk_freq = 100000;
/*
***************************************************************************************************
* Static Function Definitions
***************************************************************************************************
*/
static void
btdm_lp_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(BTDM_LOG_TAG, "Using main XTAL as clock source");
modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (CONFIG_XTAL_FREQ * 1000000 / s_bt_lpclk_freq - 1));
break;
case MODEM_CLOCK_LPCLK_SRC_RC_SLOW:
ESP_LOGW(BTDM_LOG_TAG, "Using 136 kHz RC as clock source, use with caution as it may not maintain ACL or Sync process 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(BTDM_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(BTDM_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(BTDM_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:
}
}
static void
btdm_lp_timer_clk_init(esp_btdm_controller_config_t *cfg)
{
if (s_bt_lpclk_src == MODEM_CLOCK_LPCLK_SRC_INVALID) {
#if CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL
s_bt_lpclk_src = MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL;
#else
#if CONFIG_RTC_CLK_SRC_INT_RC
s_bt_lpclk_src = MODEM_CLOCK_LPCLK_SRC_RC_SLOW;
#elif CONFIG_RTC_CLK_SRC_EXT_CRYS
uint32_t clk_freq = 0;
if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
if (!esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_XTAL32K, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &clk_freq)) {
if (clk_freq > 32700 && clk_freq < 33800) {
s_bt_lpclk_src = MODEM_CLOCK_LPCLK_SRC_XTAL32K;
} else {
ESP_LOGW(BTDM_LOG_TAG, "32.768kHz XTAL detection error, switch to main XTAL as Bluetooth sleep clock");
s_bt_lpclk_src = MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL;
}
} else {
ESP_LOGW(BTDM_LOG_TAG, "32.768kHz XTAL detection error, switch to main XTAL as Bluetooth sleep clock");
s_bt_lpclk_src = MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL;
}
} else {
ESP_LOGW(BTDM_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock");
s_bt_lpclk_src = MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL;
}
#elif CONFIG_RTC_CLK_SRC_INT_RC32K
s_bt_lpclk_src = MODEM_CLOCK_LPCLK_SRC_RC32K;
#elif CONFIG_RTC_CLK_SRC_EXT_OSC
s_bt_lpclk_src = MODEM_CLOCK_LPCLK_SRC_EXT32K;
#else
ESP_LOGE(BTDM_LOG_TAG, "Unsupported clock source");
assert(0);
#endif
#endif /* CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL */
}
// if (s_bt_lpclk_src == MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL) {
// cfg->rtc_freq = s_bt_lpclk_freq;
// } else if (s_bt_lpclk_src == MODEM_CLOCK_LPCLK_SRC_XTAL32K) {
// cfg->rtc_freq = 32768;
// } else if (s_bt_lpclk_src == MODEM_CLOCK_LPCLK_SRC_RC_SLOW) {
// cfg->rtc_freq = esp_clk_tree_lp_slow_get_freq_hz(ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED) / 5;
// //TODO
// // cfg->ble_ll_sca = 3000;
// } else if (s_bt_lpclk_src == MODEM_CLOCK_LPCLK_SRC_RC32K) {
// cfg->rtc_freq = 32000;
// } else if (s_bt_lpclk_src == MODEM_CLOCK_LPCLK_SRC_EXT32K) {
// cfg->rtc_freq = 32000;
// }
btdm_lp_rtc_slow_clk_select(s_bt_lpclk_src);
}
static void
btdm_lp_timer_clk_deinit(void)
{
modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE);
}
void
btdm_lp_sleep_cb(uint32_t enable_tick, void *arg)
{
if (!s_bt_active) {
return;
}
esp_phy_disable(PHY_MODEM_BT);
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_release(s_pm_lock);
#endif // CONFIG_PM_ENABLE
s_bt_active = false;
}
void
btdm_lp_wake_up_cb(void *arg)
{
if (s_bt_active) {
return;
}
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_acquire(s_pm_lock);
#endif // CONFIG_PM_ENABLE
esp_phy_enable(PHY_MODEM_BT);
s_bt_active = true;
}
#ifdef CONFIG_FREERTOS_USE_TICKLESS_IDLE
static esp_err_t
btdm_lp_modem_retention_create(void)
{
uint8_t size = 0;
const sleep_retention_entries_config_t *btdm_mac_modem_config =
r_btdm_mac_retention_link_get(&size);
esp_err_t err = sleep_retention_entries_create(btdm_mac_modem_config, size, REGDMA_LINK_PRI_5,
SLEEP_RETENTION_MODULE_BLE_MAC);
if (err == ESP_OK) {
ESP_LOGI(BTDM_LOG_TAG, "Modem BTDM MAC retention initialization");
}
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
sleep_modem_bredr_mac_modem_state_init();
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
#if UC_BT_CTRL_BLE_IS_ENABLE
sleep_modem_ble_mac_modem_state_init();
#endif // UC_BT_CTRL_BLE_IS_ENABLE
return err;
}
static esp_err_t
btdm_lp_modem_state_init(void)
{
sleep_retention_module_init_param_t init_param = {
.cbs = {.create = {.handle = (void *)btdm_lp_modem_retention_create, .arg = NULL}},
.depends = RETENTION_MODULE_BITMAP_INIT(BT_BB)};
esp_err_t err = sleep_retention_module_init(SLEEP_RETENTION_MODULE_BLE_MAC, &init_param);
if (err == ESP_OK) {
err = sleep_retention_module_allocate(SLEEP_RETENTION_MODULE_BLE_MAC);
}
return err;
}
static void
btdm_lp_modem_state_deinit(void)
{
esp_err_t err = sleep_retention_module_free(SLEEP_RETENTION_MODULE_BLE_MAC);
if (err == ESP_OK) {
err = sleep_retention_module_deinit(SLEEP_RETENTION_MODULE_BLE_MAC);
assert(err == ESP_OK);
}
}
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
/*
***************************************************************************************************
* Public Function Definitions
***************************************************************************************************
*/
#include "modem/modem_syscon_reg.h"
void
btdm_lp_enable_clock(esp_btdm_controller_config_t *cfg)
{
modem_clock_module_enable(PERIPH_BT_MODULE);
modem_clock_module_mac_reset(PERIPH_BT_MODULE);
// TODO: set the clock ion modem_clock_module_enable
REG_WRITE(MODEM_SYSCON_CLK_CONF_POWER_ST_REG, 0XFFFFFFFF);
// btdm_lp_timer_clk_init(cfg);
}
void
btdm_lp_disable_clock(void)
{
btdm_lp_timer_clk_deinit();
modem_clock_module_disable(PERIPH_BT_MODULE);
}
int
btdm_lp_init(void)
{
#if UC_BT_CTRL_SLEEP_ENABLE
ESP_LOGI(BTDM_LOG_TAG, "Bluetooth modem sleep is enabled");
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
r_btdm_sleep_set_sleep_cb(btdm_lp_sleep_cb, btdm_lp_wake_up_cb, 0, 0,
BTDM_RTC_DELAY_US_LIGHT_SLEEP);
#else
r_btdm_sleep_set_sleep_cb(btdm_lp_sleep_cb, btdm_lp_wake_up_cb, 0, 0,
BTDM_RTC_DELAY_US_MODEM_SLEEP);
#endif /* FREERTOS_USE_TICKLESS_IDLE */
#endif // UC_BT_CTRL_SLEEP_ENABLE
#ifdef CONFIG_PM_ENABLE
esp_err_t rc = 0;
rc = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "bt", &s_pm_lock);
if (rc != ESP_OK) {
return -1;
}
#if UC_BT_CTRL_SLEEP_ENABLE && CONFIG_FREERTOS_USE_TICKLESS_IDLE
/* Create a new regdma link for BLE related register restoration */
rc = btdm_lp_modem_state_init();
assert(rc == 0);
esp_sleep_enable_bt_wakeup();
ESP_LOGW(BTDM_LOG_TAG, "Enable light sleep, the wake up source is BLE timer");
rc = esp_pm_register_inform_out_light_sleep_overhead_callback(r_btdm_sleep_wake_up_overhead_set);
if (rc != ESP_OK) {
return -2;
}
// rc = esp_pm_register_skip_light_sleep_callback(r_btdm_sleep_should_skip_light_sleep_check);
if (rc != ESP_OK) {
return -3;
}
#endif /* UC_BT_CTRL_SLEEP_ENABLE && CONFIG_FREERTOS_USE_TICKLESS_IDLE */
#endif /* CONFIG_PM_ENABLE */
return 0;
}
void
btdm_lp_deinit(void)
{
#if UC_BT_CTRL_SLEEP_ENABLE && CONFIG_FREERTOS_USE_TICKLESS_IDLE
// esp_pm_unregister_skip_light_sleep_callback(r_btdm_sleep_should_skip_light_sleep_check);
esp_pm_unregister_inform_out_light_sleep_overhead_callback(r_btdm_sleep_wake_up_overhead_set);
esp_sleep_disable_bt_wakeup();
btdm_lp_modem_state_deinit();
#endif /* UC_BT_CTRL_SLEEP_ENABLE && CONFIG_FREERTOS_USE_TICKLESS_IDLE */
#ifdef CONFIG_PM_ENABLE
/* lock should be released first */
if (s_pm_lock) {
esp_pm_lock_delete(s_pm_lock);
s_pm_lock = NULL;
}
#endif // CONFIG_PM_ENABLE
}
void
btdm_lp_reset(bool enable_stage)
{
// TODO: For enable_stage, need to disable the phy by default.
if (enable_stage) {
assert(!s_bt_active);
#if CONFIG_PM_ENABLE
esp_pm_lock_acquire(s_pm_lock);
#endif // CONFIG_PM_ENABLE
esp_phy_enable(PHY_MODEM_BT);
esp_btbb_enable();
s_bt_active = true;
} else {
if (s_bt_active) {
esp_btbb_disable();
esp_phy_disable(PHY_MODEM_BT);
#if CONFIG_PM_ENABLE
esp_pm_lock_release(s_pm_lock);
#endif // CONFIG_PM_ENABLE
s_bt_active = false;
}
}
}
void
btdm_lp_shutdown(void)
{
modem_clock_module_mac_reset(PERIPH_BT_MODULE);
if (s_bt_active) {
// esp_phy_disable(PHY_MODEM_BT);
s_bt_active = false;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,489 @@
/*
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "esp_hci_internal.h"
#include "common/hci_driver_h4.h"
#include "common/hci_driver_util.h"
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
#define HCI_H4_SM_W4_PKT_TYPE 0
#define HCI_H4_SM_W4_HEADER 1
#define HCI_H4_SM_W4_PAYLOAD 2
#define HCI_H4_SM_COMPLETED 3
struct hci_h4_input_buffer {
const uint8_t *buf;
uint16_t len;
};
static int
hci_h4_frame_start(struct hci_h4_sm *rxs, uint8_t pkt_type)
{
rxs->pkt_type = pkt_type;
rxs->len = 0;
rxs->exp_len = 0;
switch (rxs->pkt_type) {
case HCI_H4_CMD:
case HCI_H4_SYNC:
rxs->min_len = 3;
break;
case HCI_H4_ACL:
case HCI_H4_ISO:
rxs->min_len = 4;
break;
#if (!CONFIG_BT_CONTROLLER_ENABLED)
case HCI_H4_EVT:
rxs->min_len = 2;
break;
#endif // (!CONFIG_BT_CONTROLLER_ENABLED)
default:
/* !TODO: Sync loss. Need to wait for reset. */
return -1;
}
return 0;
}
static int
hci_h4_ib_consume(struct hci_h4_input_buffer *ib, uint16_t len)
{
HCI_TRANS_ASSERT((ib->len >= len), ib->len, len);
ib->buf += len;
ib->len -= len;
return len;
}
static int
hci_h4_ib_pull_min_len(struct hci_h4_sm *rxs,
struct hci_h4_input_buffer *ib)
{
uint16_t len;
len = min(ib->len, rxs->min_len - rxs->len);
memcpy(&rxs->hdr[rxs->len], ib->buf, len);
rxs->len += len;
hci_h4_ib_consume(ib, len);
return rxs->len != rxs->min_len;
}
static int
hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
{
int rc;
uint16_t conn_handle = 0;
rc = hci_h4_ib_pull_min_len(h4sm, ib);
if (rc) {
/* need more data */
return 1;
}
switch (h4sm->pkt_type) {
case HCI_H4_CMD:
HCI_TRANS_ASSERT(h4sm->allocs && h4sm->allocs->cmd, 0, 0);
h4sm->pkt = h4sm->allocs->cmd();
if (!h4sm->pkt) {
return -1;
}
memcpy(h4sm->pkt->data, h4sm->hdr, h4sm->len);
h4sm->exp_len = h4sm->hdr[2] + 3;
break;
case HCI_H4_ACL:
conn_handle = btdm_get_le16(&h4sm->hdr[0]) & HCI_INTERNAL_CONN_MASK;
#if UC_BT_CTRL_BLE_IS_ENABLE
if (HCI_INTERNAL_CONN_IS_BLE(conn_handle)) {
assert(h4sm->allocs && h4sm->allocs->acl);
h4sm->om = h4sm->allocs->acl();
if (!h4sm->om) {
return -1;
}
ble_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len);
h4sm->exp_len = btdm_get_le16(&h4sm->hdr[2]) + 4;
break;
}
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
if (HCI_INTERNAL_CONN_IS_BREDR(conn_handle)) {
assert(h4sm->allocs && h4sm->allocs->bredr_acl);
h4sm->exp_len = btdm_get_le16(&h4sm->hdr[2]) + 4;
h4sm->pkt = h4sm->allocs->bredr_acl(conn_handle);
if (!h4sm->pkt) {
return -1;
}
memcpy(h4sm->pkt->data, h4sm->hdr, h4sm->len);
break;
}
case HCI_H4_SYNC:
conn_handle = btdm_get_le16(&h4sm->hdr[0]) & HCI_INTERNAL_CONN_MASK;
assert(h4sm->allocs && h4sm->allocs->sync);
h4sm->exp_len = h4sm->hdr[2] + 3;
h4sm->pkt = h4sm->allocs->sync(conn_handle);
if (!h4sm->pkt) {
return -1;
}
memcpy(h4sm->pkt->data, h4sm->hdr, h4sm->len);
break;
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
#if !CONFIG_BT_CONTROLLER_ENABLED
case HCI_H4_EVT:
if (h4sm->hdr[0] == BLE_HCI_EVCODE_LE_META) {
/* For LE Meta event we need 3 bytes to parse header */
h4sm->min_len = 3;
rc = hci_h4_ib_pull_min_len(h4sm, ib);
if (rc) {
/* need more data */
return 1;
}
}
HCI_TRANS_ASSERT(h4sm->allocs && h4sm->allocs->evt, 0, 0);
/* We can drop legacy advertising events if there's no free buffer in
* discardable pool.
*/
if (h4sm->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) {
h4sm->buf = h4sm->allocs->evt(1);
} else {
h4sm->buf = h4sm->allocs->evt(0);
if (!h4sm->buf) {
return -1;
}
}
if (h4sm->buf) {
memcpy(h4sm->buf, h4sm->hdr, h4sm->len);
}
h4sm->exp_len = h4sm->hdr[1] + 2;
break;
#endif // !CONFIG_BT_CONTROLLER_ENABLED
#if CONFIG_BT_LE_ISO_SUPPORT
case HCI_H4_ISO:
assert(h4sm->allocs && h4sm->allocs->iso);
h4sm->exp_len = (btdm_get_le16(&h4sm->hdr[2]) & 0x7fff) + 4;
h4sm->buf = h4sm->allocs->iso(h4sm->exp_len);
if (!h4sm->buf) {
return -1;
}
memcpy(h4sm->buf, h4sm->hdr, h4sm->len);
break;
#endif // CONFIG_BT_LE_ISO_SUPPORT
default:
assert(0);
break;
}
return 0;
}
static int
hci_h4_sm_w4_payload(struct hci_h4_sm *h4sm,
struct hci_h4_input_buffer *ib)
{
uint16_t len;
len = min(ib->len, h4sm->exp_len - h4sm->len);
switch (h4sm->pkt_type) {
case HCI_H4_CMD:
case HCI_H4_SYNC:
if (h4sm->pkt) {
memcpy(&h4sm->pkt->data[h4sm->len], ib->buf, len);
}
break;
case HCI_H4_EVT:
case HCI_H4_ISO:
if (h4sm->buf) {
memcpy(&h4sm->buf[h4sm->len], ib->buf, len);
}
break;
case HCI_H4_ACL:
HCI_TRANS_ASSERT(h4sm->om, h4sm->pkt_type, len);
uint16_t conn_handle = btdm_get_le16(&h4sm->hdr[0]) & HCI_INTERNAL_CONN_MASK;
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
if (HCI_INTERNAL_CONN_IS_BREDR(conn_handle)) {
memcpy(&h4sm->pkt->data[h4sm->len], ib->buf, len);
break;
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
#if UC_BT_CTRL_BLE_IS_ENABLE
if (HCI_INTERNAL_CONN_IS_BLE(conn_handle)) {
uint16_t mbuf_len = BLE_MBUF_PKTLEN(h4sm->om);
int rc = ble_mbuf_append(h4sm->om, ib->buf, len);
if (rc) {
/* Some data may already be appended so need to adjust h4sm only by
* the size of appended data.
*/
len = BLE_MBUF_PKTLEN(h4sm->om) - mbuf_len;
h4sm->len += len;
hci_h4_ib_consume(ib, len);
return -1;
}
}
break;
#endif // UC_BT_CTRL_BLE_IS_ENABLE
default:
assert(0);
break;
}
h4sm->len += len;
hci_h4_ib_consume(ib, len);
/* return 1 if need more data */
return h4sm->len != h4sm->exp_len;
}
static void
hci_h4_sm_completed(struct hci_h4_sm *h4sm)
{
int rc;
uint8_t data_source = 0xFF;
HCI_TRANS_ASSERT(h4sm->frame_cb, 0, 0);
switch (h4sm->pkt_type) {
#if CONFIG_BT_CONTROLLER_ENABLED
case HCI_H4_ACL:
uint16_t conn_handle = btdm_get_le16(&h4sm->hdr[0]) & HCI_INTERNAL_CONN_MASK;
#if UC_BT_CTRL_BLE_IS_ENABLE
if (HCI_INTERNAL_CONN_IS_BLE(conn_handle)) {
if (h4sm->om) {
rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->om, h4sm->len, HCI_DRIVER_LE_ACL);
HCI_TRANS_ASSERT(rc == 0, rc, 0);
h4sm->om = NULL;
}
}
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
if (HCI_INTERNAL_CONN_IS_BREDR(conn_handle)) {
if (h4sm->buf) {
rc = h4sm->frame_cb(h4sm->pkt_type, (void *)h4sm->buf, h4sm->len, HCI_DRIVER_BREDR_ACL);
HCI_TRANS_ASSERT(rc == 0, rc, 0);
h4sm->buf = NULL;
}
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
break;
case HCI_H4_CMD:
case HCI_H4_SYNC:
case HCI_H4_ISO:
if (h4sm->buf) {
switch(h4sm->pkt_type) {
case HCI_H4_CMD:
data_source = HCI_DRIVER_CMD;
break;
case HCI_H4_SYNC:
data_source = HCI_DRIVER_BREDR_SYNC;
break;
case HCI_H4_ISO:
data_source = HCI_DRIVER_LE_ISO;
break;
}
rc = h4sm->frame_cb(h4sm->pkt_type, (void *)h4sm->buf, h4sm->len, data_source);
HCI_TRANS_ASSERT(rc == 0, rc, 0);
h4sm->buf = NULL;
}
break;
#else
case HCI_H4_CMD:
case HCI_H4_EVT:
if (h4sm->buf) {
assert(h4sm->frame_cb);
rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->buf);
if (rc != 0) {
ble_transport_free(h4sm->buf);
}
h4sm->buf = NULL;
}
break;
case HCI_H4_ACL:
case HCI_H4_ISO:
if (h4sm->om) {
assert(h4sm->frame_cb);
rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->om);
if (rc != 0) {
os_mbuf_free_chain(h4sm->om);
}
h4sm->om = NULL;
}
break;
#endif // CONFIG_BT_CONTROLLER_ENABLED
default:
assert(0);
break;
}
}
static int
hci_h4_sm_free_buf(struct hci_h4_sm *h4sm)
{
switch (h4sm->pkt_type) {
case HCI_H4_CMD:
if (h4sm->buf) {
h4sm->frees->cmd(h4sm->buf);
h4sm->buf = NULL;
}
break;
#if (!CONFIG_BT_CONTROLLER_ENABLED)
case HCI_H4_EVT:
if (h4sm->buf) {
h4sm->frees->evt(h4sm->buf);
h4sm->buf = NULL;
}
break;
#endif // (!CONFIG_BT_CONTROLLER_ENABLED)
case HCI_H4_ACL:
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
uint16_t conn_handle = btdm_get_le16(&h4sm->hdr[0]) & HCI_INTERNAL_CONN_MASK;
if (HCI_INTERNAL_CONN_IS_BLE(conn_handle)) {
if (h4sm->om) {
h4sm->frees->acl(h4sm->om);
h4sm->om = NULL;
}
} else {
if (h4sm->pkt) {
h4sm->frees->bredr_acl(h4sm->pkt);
h4sm->pkt = NULL;
}
}
#else
if (h4sm->om) {
h4sm->frees->acl(h4sm->om);
h4sm->om = NULL;
}
#endif
break;
case HCI_H4_ISO:
if (h4sm->buf) {
h4sm->frees->iso(h4sm->buf);
h4sm->buf = NULL;
}
break;
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
case HCI_H4_SYNC:
if (h4sm->pkt) {
h4sm->frees->sync(h4sm->pkt);
h4sm->pkt = NULL;
}
break;
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
default:
break;
}
return 0;
}
int
hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len)
{
struct hci_h4_input_buffer ib = {
.buf = buf,
.len = len,
};
int rc = 0;
while (ib.len && (rc >= 0)) {
rc = 0;
switch (h4sm->state) {
case HCI_H4_SM_W4_PKT_TYPE:
if (hci_h4_frame_start(h4sm, ib.buf[0]) < 0) {
return -1;
}
hci_h4_ib_consume(&ib, 1);
h4sm->state = HCI_H4_SM_W4_HEADER;
/* no break */
case HCI_H4_SM_W4_HEADER:
rc = hci_h4_sm_w4_header(h4sm, &ib);
assert(rc >= 0);
if (rc) {
break;
}
h4sm->state = HCI_H4_SM_W4_PAYLOAD;
/* no break */
case HCI_H4_SM_W4_PAYLOAD:
rc = hci_h4_sm_w4_payload(h4sm, &ib);
assert(rc >= 0);
if (rc) {
break;
}
h4sm->state = HCI_H4_SM_COMPLETED;
/* no break */
case HCI_H4_SM_COMPLETED:
hci_h4_sm_completed(h4sm);
h4sm->state = HCI_H4_SM_W4_PKT_TYPE;
break;
default:
return -1;
}
}
/* Calculate consumed bytes
*
* Note: we should always consume some bytes unless there is an oom error.
* It's also possible that we have an oom error but already consumed some
* data, in such case just return success and error will be returned on next
* pass.
*/
len = len - ib.len;
if (len == 0) {
HCI_TRANS_ASSERT((rc < 0), rc, ib.len);
return -1;
}
return len;
}
void
hci_h4_sm_init(struct hci_h4_sm *h4sm, const struct hci_h4_allocators *allocs, const struct hci_h4_frees *frees,
hci_h4_frame_cb *frame_cb)
{
memset(h4sm, 0, sizeof(*h4sm));
h4sm->allocs = allocs;
h4sm->frees = frees;
h4sm->frame_cb = frame_cb;
}
@@ -0,0 +1,121 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_hci_internal.h"
#include "common/hci_driver_mem.h"
#include "common/hci_driver_h4.h"
hci_driver_packet_t *
hci_driver_mem_cmd_alloc(void)
{
return btdm_hci_trans_buf_alloc(HCI_H4_CMD, 0);
}
void *
hci_driver_mem_evt_alloc(int discardable)
{
/* The controller shouldn't invoke this. */
assert(0);
return NULL;
}
struct ble_mbuf *
hci_driver_mem_acl_alloc(void)
{
return ble_msys_get_pkthdr(0, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE);
}
struct ble_mbuf *
hci_driver_mem_acl_len_alloc(uint32_t len)
{
return ble_msys_get_pkthdr(len, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE);
}
void *
hci_driver_mem_iso_alloc(uint32_t len)
{
return malloc(len);
}
void
hci_driver_mem_iso_free(void *ptr)
{
free(ptr);
}
struct ble_mbuf *
hci_driver_mem_iso_len_alloc(uint32_t len)
{
return ble_msys_get_pkthdr(len, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE);
}
void
hci_driver_mem_cmd_free(void * ptr)
{
hci_driver_packet_t *pkt = (hci_driver_packet_t *) ptr;
btdm_hci_trans_buf_free(pkt);
}
void
hci_driver_mem_evt_free(void *ptr)
{
hci_driver_packet_t *pkt = (hci_driver_packet_t *) ptr;
btdm_hci_trans_buf_free(pkt);
}
#if UC_BTDM_CTRL_BR_EDR_IS_ENABLE
hci_driver_packet_t *
hci_driver_mem_bredr_acl_alloc(uint16_t handle)
{
return btdm_hci_trans_buf_alloc(HCI_H4_ACL, handle);
}
void
hci_driver_mem_bredr_acl_free(void *ptr)
{
hci_driver_packet_t *pkt = (hci_driver_packet_t *) ptr;
bredr_hci_trans_acl_tx_done(pkt);
bredr_hci_trans_acl_free(pkt);
}
hci_driver_packet_t *
hci_driver_mem_sync_alloc(uint16_t handle)
{
return btdm_hci_trans_buf_alloc(HCI_H4_SYNC, handle);
}
void
hci_driver_mem_sync_free(void *ptr)
{
hci_driver_packet_t *pkt = (hci_driver_packet_t *) ptr;
bredr_hci_trans_sync_tx_done(pkt);
bredr_hci_trans_sync_free(pkt);
}
#endif // UC_BTDM_CTRL_BR_EDR_IS_ENABLE
const struct hci_h4_allocators s_hci_driver_mem_alloc = {
.cmd = hci_driver_mem_cmd_alloc,
.evt = hci_driver_mem_evt_alloc,
.acl = hci_driver_mem_acl_alloc,
.iso = hci_driver_mem_iso_alloc,
#if UC_BTDM_CTRL_BR_EDR_IS_ENABLE
.sync = hci_driver_mem_sync_alloc,
.bredr_acl = hci_driver_mem_bredr_acl_alloc,
#endif // UC_BTDM_CTRL_BR_EDR_IS_ENABLE
};
const struct hci_h4_frees s_hci_driver_mem_free = {
.cmd = hci_driver_mem_cmd_free,
.evt = hci_driver_mem_evt_free,
.acl = ble_mbuf_free_chain,
.iso = hci_driver_mem_iso_free,
.le_evt = r_ble_hci_trans_buf_free,
#if UC_BTDM_CTRL_BR_EDR_IS_ENABLE
.sync = hci_driver_mem_sync_free,
.bredr_acl = hci_driver_mem_bredr_acl_free,
#endif // UC_BTDM_CTRL_BR_EDR_IS_ENABLE
};
@@ -0,0 +1,356 @@
/*
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "esp_hci_driver.h"
#include "esp_hci_internal.h"
#include "common/hci_driver_util.h"
#define TAG "HCI_UTIL"
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
#define HCI_DRIVER_UTIL_BREDR_HCI_EVT_TX_POOL_NUM 4
#define HCI_DRIVER_UTIL_BREDR_TX_POOL_NUM \
(CONFIG_BT_CTRL_BR_EDR_ACLU_RX_BUF_NB_EFF + CONFIG_BT_CTRL_BR_EDR_SYNC_RX_BUF_NB_EFF + HCI_DRIVER_UTIL_BREDR_HCI_EVT_TX_POOL_NUM)
#else
#define HCI_DRIVER_UTIL_BREDR_TX_POOL_NUM 0
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
#if UC_BT_CTRL_BLE_IS_ENABLE
#define HCI_DRIVER_UTIL_BLE_TX_POOL_NUM \
(CONFIG_BT_LE_ACL_BUF_COUNT + CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT + CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT)
#else
#define HCI_DRIVER_UTIL_BLE_TX_POOL_NUM 0
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#define HCI_DRIVER_UTIL_TX_POOL_NUM \
(HCI_DRIVER_UTIL_BLE_TX_POOL_NUM + HCI_DRIVER_UTIL_BREDR_TX_POOL_NUM)
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
/**
* @brief Structure representing HCI TX data.
*/
typedef struct hci_driver_util_tx_entry {
hci_driver_data_type_t data_type; ///< Type of the HCI TX data.
uint8_t data_source; ///< Source of the HCI TX data.
uint32_t length; ///< Length of the TX data.
union {
hci_driver_packet_t *pkt;
uint8_t *data; ///< Length of the TX ISO data.
};
STAILQ_ENTRY(hci_driver_util_tx_entry) next; ///< Next element in the linked list.
} hci_driver_util_tx_entry_t;
/* The list for hci_driver_util_tx_entry */
STAILQ_HEAD(hci_driver_util_tx_list, hci_driver_util_tx_entry);
typedef struct {
struct hci_driver_util_tx_list tx_head;
struct hci_driver_util_tx_entry *cur_tx_entry;
uint32_t cur_tx_off;
struct btdm_mempool *tx_entry_pool;
uint8_t *tx_entry_mem;
} hci_driver_util_env_t;
static hci_driver_util_env_t s_hci_driver_util_env;
static void
hci_driver_util_memory_deinit(void)
{
if (s_hci_driver_util_env.tx_entry_pool) {
free(s_hci_driver_util_env.tx_entry_pool);
s_hci_driver_util_env.tx_entry_pool = NULL;
}
if (s_hci_driver_util_env.tx_entry_mem) {
free(s_hci_driver_util_env.tx_entry_mem);
s_hci_driver_util_env.tx_entry_mem = NULL;
}
}
static int
hci_driver_util_memory_init(void)
{
int rc;
s_hci_driver_util_env.tx_entry_pool = (struct btdm_mempool *)malloc(sizeof(struct btdm_mempool));
if (!s_hci_driver_util_env.tx_entry_pool) {
ESP_LOGE(TAG, "No memory for tx pool");
goto init_err;
}
s_hci_driver_util_env.tx_entry_mem = malloc(BTDM_MEMPOOL_SIZE(HCI_DRIVER_UTIL_TX_POOL_NUM,
sizeof(hci_driver_util_tx_entry_t)) * sizeof(btdm_membuf_t));
if (!s_hci_driver_util_env.tx_entry_mem) {
ESP_LOGE(TAG, "No memory for tx pool buffer");
goto init_err;
}
rc = btdm_mempool_init(s_hci_driver_util_env.tx_entry_pool, HCI_DRIVER_UTIL_TX_POOL_NUM,
sizeof(hci_driver_util_tx_entry_t), s_hci_driver_util_env.tx_entry_mem,
"hci_tx_entry_pool");
if (rc) {
ESP_LOGE(TAG, "Failed to initialize tx pool");
goto init_err;
}
return 0;
init_err:
hci_driver_util_memory_deinit();
return -1;
}
int
hci_driver_util_tx_list_enqueue(hci_driver_data_type_t type, uint8_t *data, uint32_t len, hci_driver_data_source_t data_source)
{
hci_driver_util_tx_entry_t *tx_entry;
hci_driver_packet_t *pkt;
uint8_t event_code = 0;
tx_entry = btdm_memblock_get(s_hci_driver_util_env.tx_entry_pool);
if (tx_entry == NULL) {
return -1;
}
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
pkt = (hci_driver_packet_t *)data;
switch (data_source) {
case HCI_DRIVER_BREDR_ACL:
bredr_hci_trans_acl_tx_done(pkt);
break;
case HCI_DRIVER_BREDR_SYNC:
bredr_hci_trans_sync_tx_done(pkt);
break;
case HCI_DRIVER_BREDR_EVT:
bredr_hci_trans_evt_tx_done(pkt);
break;
default:
break;
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
tx_entry->data_type = type;
tx_entry->data = data;
tx_entry->length = len;
tx_entry->data_source = data_source;
if (data_source == HCI_DRIVER_BTDM_EVT) {
pkt = (hci_driver_packet_t *)data;
event_code = pkt->data[0];
} else if (data_source == HCI_DRIVER_LE_EVT){
event_code = data[0];
}
/* If the txbuf is command status event or command complete event, we should send firstly.
* The tx list maybe used in the controller task and hci task. Therefore, enter critical area.
*/
if ((data_source == HCI_DRIVER_LE_EVT || data_source == HCI_DRIVER_BTDM_EVT) &&
((event_code == 0x0E) || (event_code == 0x0F))) {
btdm_osal_hw_enter_critical();
STAILQ_INSERT_HEAD(&s_hci_driver_util_env.tx_head, tx_entry, next);
btdm_osal_hw_exit_critical(0);
} else {
btdm_osal_hw_enter_critical();
STAILQ_INSERT_TAIL(&s_hci_driver_util_env.tx_head, tx_entry, next);
btdm_osal_hw_exit_critical(0);
}
return 0;
}
uint32_t
hci_driver_util_tx_list_dequeue(uint32_t max_tx_len, void **tx_data, bool *last_frame)
{
uint32_t tx_len;
uint32_t data_len;
hci_driver_util_tx_entry_t *tx_entry;
hci_driver_packet_t *pkt = NULL;
struct ble_mbuf *om = NULL;
uint16_t out_off;
/* Check if there is any remaining data that hasn't been sent completely. If it has been completed,
* free the corresponding memory. Therefore, the HCI TX entry needs to be sent one by one; multiple
* entries cannot be sent together.
*/
tx_len = 0;
tx_entry = s_hci_driver_util_env.cur_tx_entry;
if (tx_entry) {
pkt = tx_entry->pkt;
data_len = tx_entry->length;
if (tx_entry->data_type == HCI_DRIVER_TYPE_ACL) {
if (s_hci_driver_util_env.cur_tx_off >= data_len) {
if (tx_entry->data_source == HCI_DRIVER_LE_ACL) {
om = (struct ble_mbuf *)tx_entry->data;
ble_mbuf_free_chain(om);
}
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
else {
bredr_hci_trans_acl_free(pkt);
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
} else {
if (tx_entry->data_source == HCI_DRIVER_LE_ACL) {
om = (struct ble_mbuf *)tx_entry->data;
om = ble_mbuf_off(om, s_hci_driver_util_env.cur_tx_off, &out_off);
tx_len = min(max_tx_len, om->om_len - out_off);
*tx_data = (void *)&om->om_data[out_off];
} else {
tx_len = min(max_tx_len, data_len - s_hci_driver_util_env.cur_tx_off);
*tx_data = &pkt->data[s_hci_driver_util_env.cur_tx_off];
}
}
} else if (tx_entry->data_type == HCI_DRIVER_TYPE_EVT) {
if (s_hci_driver_util_env.cur_tx_off >= data_len) {
if (tx_entry->data_source == HCI_DRIVER_LE_EVT) {
r_ble_hci_trans_buf_free(tx_entry->data);
}
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
else if (tx_entry->data_source == HCI_DRIVER_BREDR_EVT) {
bredr_hci_trans_evt_free(pkt);
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
else {
btdm_hci_trans_buf_free(pkt);
}
} else {
tx_len = min(max_tx_len, data_len - s_hci_driver_util_env.cur_tx_off);
if (tx_entry->data_source == HCI_DRIVER_LE_EVT) {
*tx_data = &tx_entry->data[s_hci_driver_util_env.cur_tx_off];
} else {
*tx_data = &pkt->data[s_hci_driver_util_env.cur_tx_off];
}
}
} else if (tx_entry->data_type == HCI_DRIVER_TYPE_ISO) {
if (s_hci_driver_util_env.cur_tx_off >= data_len) {
free(tx_entry->data);
} else {
tx_len = min(max_tx_len, data_len - s_hci_driver_util_env.cur_tx_off);
*tx_data = &tx_entry->data[s_hci_driver_util_env.cur_tx_off];
}
}
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
else if (tx_entry->data_type == HCI_DRIVER_TYPE_SYNC) {
if (s_hci_driver_util_env.cur_tx_off >= data_len) {
bredr_hci_trans_sync_free(pkt);
} else {
tx_len = min(max_tx_len, data_len - s_hci_driver_util_env.cur_tx_off);
*tx_data = &pkt->data[s_hci_driver_util_env.cur_tx_off];
}
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
else {
HCI_TRANS_ASSERT(0, tx_entry->data_type, data_len);
}
/* If this is the last frame, inform the invoker not to call this API until the current data
* has been completely sent.
*/
if (tx_len) {
s_hci_driver_util_env.cur_tx_off += tx_len;
if (s_hci_driver_util_env.cur_tx_off >= data_len) {
*last_frame = true;
} else {
*last_frame = false;
}
} else {
btdm_memblock_put(s_hci_driver_util_env.tx_entry_pool, (void *)tx_entry);
s_hci_driver_util_env.cur_tx_entry = NULL;
}
}
/* Find a new entry. */
if (!tx_len && !STAILQ_EMPTY(&s_hci_driver_util_env.tx_head)) {
btdm_osal_hw_enter_critical();
tx_entry = STAILQ_FIRST(&s_hci_driver_util_env.tx_head);
STAILQ_REMOVE_HEAD(&s_hci_driver_util_env.tx_head, next);
btdm_osal_hw_exit_critical(0);
*tx_data = &tx_entry->data_type;
s_hci_driver_util_env.cur_tx_entry = tx_entry;
s_hci_driver_util_env.cur_tx_off = 0;
tx_len = 1;
*last_frame = false;
}
return tx_len;
}
int
hci_driver_util_init(void)
{
memset(&s_hci_driver_util_env, 0, sizeof(hci_driver_util_env_t));
if (hci_driver_util_memory_init()) {
return -1;
}
STAILQ_INIT(&s_hci_driver_util_env.tx_head);
return 0;
}
void
hci_driver_util_deinit(void)
{
hci_driver_util_tx_entry_t *tx_entry;
hci_driver_util_tx_entry_t *next_entry;
/* Free all of controller buffers which haven't been sent yet. The whole mempool will be freed.
* Therefore, it's unnecessary to put the tx_entry into mempool.
*/
tx_entry = STAILQ_FIRST(&s_hci_driver_util_env.tx_head);
while (tx_entry) {
next_entry = STAILQ_NEXT(tx_entry, next);
if (tx_entry->data_type == HCI_DRIVER_TYPE_EVT) {
if (tx_entry->data_source == HCI_DRIVER_LE_EVT) {
r_ble_hci_trans_buf_free(tx_entry->data);
}
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
else if (tx_entry->data_source == HCI_DRIVER_BREDR_EVT) {
bredr_hci_trans_evt_tx_done((hci_driver_packet_t *)tx_entry->data);
bredr_hci_trans_evt_free((hci_driver_packet_t *)tx_entry->data);
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
else {
btdm_hci_trans_buf_free((hci_driver_packet_t *)tx_entry->data);
}
} else if (tx_entry->data_type == HCI_DRIVER_TYPE_ACL) {
if (tx_entry->data_source == HCI_DRIVER_LE_ACL) {
ble_mbuf_free_chain((struct ble_mbuf *)tx_entry->data);
}
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
else {
bredr_hci_trans_acl_tx_done((hci_driver_packet_t *)tx_entry->data);
bredr_hci_trans_acl_free((hci_driver_packet_t *)tx_entry->data);
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
} else if (tx_entry->data_type == HCI_DRIVER_TYPE_ISO) {
free(tx_entry->data);
}
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
else {
// SCO data
bredr_hci_trans_sync_tx_done((hci_driver_packet_t *)tx_entry->pkt);
bredr_hci_trans_sync_free((hci_driver_packet_t *)tx_entry->pkt);
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
tx_entry = next_entry;
}
hci_driver_util_memory_deinit();
memset(&s_hci_driver_util_env, 0, sizeof(hci_driver_util_env_t));
}
void
hci_driver_util_assert_check(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2)
{
ESP_LOGE(TAG, "hci driver assert: line %d in function %s, param: 0x%x, 0x%x", ln, fn, param1, param2);
assert(0);
}
@@ -0,0 +1,274 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "esp_hci_transport.h"
#include "esp_hci_internal.h"
#include "common/hci_driver_h4.h"
#include "common/hci_driver_util.h"
#include "common/hci_driver_mem.h"
#include "hci_driver_uart.h"
static const char *TAG = "hci_uart";
#define CONFIG_BT_LE_HCI_RX_PROC_DATA_LEN (1024)
typedef struct {
TaskHandle_t tx_task_handler;
TaskHandle_t rx_task_handler;
hci_driver_uart_params_config_t *hci_uart_params;
SemaphoreHandle_t tx_sem;
QueueHandle_t rx_event_queue;
uint8_t *rx_data;
struct hci_h4_sm *h4_sm;
hci_driver_forward_fn *forward_cb;
} hci_driver_uart_env_t;
static hci_driver_uart_env_t s_hci_driver_uart_env;
static struct hci_h4_sm s_hci_driver_uart_h4_sm;
static uint8_t s_hci_driver_uart_rx_data[CONFIG_BT_LE_HCI_RX_PROC_DATA_LEN];
static int
hci_driver_uart_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir)
{
int rc;
uint8_t data_source;
data_source = 0;
/* By now, this layer is only used by controller. */
ESP_LOGD(TAG, "uart tx len:%d\n", length);
if (dir == HCI_DRIVER_DIR_BTDMC2H) {
if (data_type == HCI_DRIVER_TYPE_EVT) {
data_source = HCI_DRIVER_BTDM_EVT;
}
} else if (dir == HCI_DRIVER_DIR_LEC2H) {
if (data_type == HCI_DRIVER_TYPE_ACL) {
data_source = HCI_DRIVER_LE_ACL;
} else if (data_type == HCI_DRIVER_TYPE_EVT) {
data_source = HCI_DRIVER_LE_EVT;
} else if (data_type == HCI_DRIVER_TYPE_ISO) {
data_source = HCI_DRIVER_LE_ISO;
}
}
#if UC_BTDM_CTRL_BR_EDR_IS_ENABLE
else if (dir == HCI_DRIVER_DIR_BREDRC2H) {
if (data_type == HCI_DRIVER_TYPE_ACL) {
data_source = HCI_DRIVER_BREDR_ACL;
} else if (data_type == HCI_DRIVER_TYPE_SYNC) {
data_source = HCI_DRIVER_BREDR_SYNC;
} else if (data_type == HCI_DRIVER_TYPE_EVT) {
data_source = HCI_DRIVER_BREDR_EVT;
}
}
#endif // UC_BTDM_CTRL_BR_EDR_IS_ENABLE
else {
assert(0);
}
rc = hci_driver_util_tx_list_enqueue(data_type, data, length, data_source);
if (rc < 0) {
ESP_LOGE(TAG, "tx data enqueue failed!\n");
return rc;
}
xSemaphoreGive(s_hci_driver_uart_env.tx_sem);
return rc;
}
static int
hci_driver_uart_h4_frame_cb(uint8_t pkt_type, void *data, int pkt_len, uint8_t data_source)
{
hci_driver_forward_fn *forward_cb = s_hci_driver_uart_env.forward_cb;
if (!forward_cb) {
ESP_LOGE(TAG, "rx cb is NULL\n");
return -1;
}
ESP_LOGD(TAG, "h4 frame\n");
return forward_cb(pkt_type, data, pkt_len, HCI_DRIVER_DIR_H2C, data_source);
}
static void
hci_driver_uart_tx_task(void *p)
{
void *data;
bool last_frame;
uint32_t tx_len;
uart_port_t port;
port = s_hci_driver_uart_env.hci_uart_params->hci_uart_port;
while (true) {
xSemaphoreTake(s_hci_driver_uart_env.tx_sem, portMAX_DELAY);
while (true) {
tx_len = hci_driver_util_tx_list_dequeue(0xffffff, &data, &last_frame);
if (tx_len == 0) {
break;
}
ESP_LOGD(TAG, "uart tx");
ESP_LOG_BUFFER_HEXDUMP(TAG, data, tx_len, ESP_LOG_DEBUG);
uart_write_bytes(port, data, tx_len);
}
}
}
static void
hci_driver_uart_rx_task(void *p)
{
void *data;
int read_len;
int ret;
uart_port_t port;
uart_event_t uart_event;
port = s_hci_driver_uart_env.hci_uart_params->hci_uart_port;
while (true) {
xQueueReceive(s_hci_driver_uart_env.rx_event_queue, &uart_event, portMAX_DELAY);
data = s_hci_driver_uart_env.rx_data;
while (true) {
read_len = uart_read_bytes(port, data, CONFIG_BT_LE_HCI_RX_PROC_DATA_LEN, 0);
if (read_len == 0) {
break;
}
ESP_LOGD(TAG, "uart rx read_len:%d\n", read_len);
ESP_LOG_BUFFER_HEXDUMP(TAG, data, read_len, ESP_LOG_DEBUG);
ret = hci_h4_sm_rx(s_hci_driver_uart_env.h4_sm, data, read_len);
if (ret < 0) {
ESP_LOGE(TAG, "parse rx data error! sm_state:%d\n", s_hci_driver_uart_env.h4_sm->state);
r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR);
}
}
}
}
static int
hci_driver_uart_task_create(void)
{
/* !TODO: Set the core id by menuconfig */
xTaskCreatePinnedToCore(hci_driver_uart_tx_task, "hci_driver_uart_tx_task",
UC_BTDM_CTRL_HCI_TRANS_TASK_STACK_SIZE, NULL,
ESP_TASK_BT_CONTROLLER_PRIO, &s_hci_driver_uart_env.tx_task_handler,
0);
assert(s_hci_driver_uart_env.tx_task_handler);
xTaskCreatePinnedToCore(hci_driver_uart_rx_task, "hci_driver_uart_rx_task",
UC_BTDM_CTRL_HCI_TRANS_TASK_STACK_SIZE, NULL,
ESP_TASK_BT_CONTROLLER_PRIO, &s_hci_driver_uart_env.rx_task_handler,
0);
assert(s_hci_driver_uart_env.rx_task_handler);
ESP_LOGI(TAG, "hci transport task create successfully, prio:%d, stack size: %ld",
ESP_TASK_BT_CONTROLLER_PRIO, UC_BTDM_CTRL_HCI_TRANS_TASK_STACK_SIZE);
return 0;
}
static void
hci_driver_uart_task_delete(void)
{
if (s_hci_driver_uart_env.tx_task_handler) {
vTaskDelete(s_hci_driver_uart_env.tx_task_handler);
s_hci_driver_uart_env.tx_task_handler = NULL;
}
if (s_hci_driver_uart_env.rx_task_handler) {
vTaskDelete(s_hci_driver_uart_env.rx_task_handler);
s_hci_driver_uart_env.rx_task_handler = NULL;
}
}
static void
hci_driver_uart_deinit(void)
{
hci_driver_uart_task_delete();
ESP_ERROR_CHECK(uart_driver_delete(s_hci_driver_uart_env.hci_uart_params->hci_uart_port));
if (s_hci_driver_uart_env.tx_sem) {
vSemaphoreDelete(s_hci_driver_uart_env.tx_sem);
}
hci_driver_util_deinit();
memset(&s_hci_driver_uart_env, 0, sizeof(hci_driver_uart_env_t));
}
static int
hci_driver_uart_init(hci_driver_forward_fn *cb)
{
int rc;
memset(&s_hci_driver_uart_env, 0, sizeof(hci_driver_uart_env_t));
s_hci_driver_uart_env.h4_sm = &s_hci_driver_uart_h4_sm;
hci_h4_sm_init(s_hci_driver_uart_env.h4_sm, &s_hci_driver_mem_alloc, &s_hci_driver_mem_free, hci_driver_uart_h4_frame_cb);
rc = hci_driver_util_init();
if (rc) {
goto error;
}
s_hci_driver_uart_env.tx_sem = xSemaphoreCreateBinary();
if (!s_hci_driver_uart_env.tx_sem) {
goto error;
}
s_hci_driver_uart_env.rx_data = s_hci_driver_uart_rx_data;
s_hci_driver_uart_env.forward_cb = cb;
s_hci_driver_uart_env.hci_uart_params = hci_driver_uart_config_param_get();
hci_driver_uart_config(s_hci_driver_uart_env.hci_uart_params);
/* Currently, the queue size is set to 1. It will be considered as semaphore. */
ESP_ERROR_CHECK(uart_driver_install(s_hci_driver_uart_env.hci_uart_params->hci_uart_port,
UC_BTDM_CTRL_HCI_UART_RX_BUFFER_SIZE,
UC_BTDM_CTRL_HCI_UART_TX_BUFFER_SIZE,
1, &s_hci_driver_uart_env.rx_event_queue,
0));
rc = hci_driver_uart_task_create();
if (rc) {
goto error;
}
return 0;
error:
hci_driver_uart_deinit();
return rc;
}
int
hci_driver_uart_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin)
{
int rc;
hci_driver_uart_task_delete();
hci_driver_uart_pin_update(tx_pin, rx_pin, cts_pin, rts_pin);
/* Currently, the queue size is set to 1. It will be considered as semaphore. */
ESP_ERROR_CHECK(uart_driver_install(s_hci_driver_uart_env.hci_uart_params->hci_uart_port,
UC_BTDM_CTRL_HCI_UART_RX_BUFFER_SIZE,
UC_BTDM_CTRL_HCI_UART_TX_BUFFER_SIZE,
1, &s_hci_driver_uart_env.rx_event_queue,
0));
rc = hci_driver_uart_task_create();
if (rc) {
hci_driver_uart_task_delete();
return -2;
}
return 0;
}
hci_driver_ops_t hci_driver_uart_ops = {
.hci_driver_tx = hci_driver_uart_tx,
.hci_driver_init = hci_driver_uart_init,
.hci_driver_deinit = hci_driver_uart_deinit,
};
@@ -0,0 +1,86 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
#include "driver/uart.h"
#include "esp_bt.h"
#include "esp_hci_transport.h"
/**
* @brief UART configuration parameters for the HCI driver
*/
typedef struct hci_driver_uart_params_config
{
uint8_t hci_uart_port; /*!< Port of UART for HCI */
uint8_t hci_uart_data_bits; /*!< Data bits of UART for HCI */
uint8_t hci_uart_stop_bits; /*!< Stop bits of UART for HCI */
uint8_t hci_uart_flow_ctrl; /*!< Flow control of UART for HCI */
uint8_t hci_uart_parity; /*!< UART parity */
uint8_t hci_uart_driver_mode; /*!< UART driver mode */
uint32_t hci_uart_baud; /*!< Baudrate of UART for HCI */
int hci_uart_tx_pin; /*!< Tx Pin number of UART for HCI */
int hci_uart_rx_pin; /*!< Rx Pin number of UART for HCI */
int hci_uart_rts_pin; /*!< RTS Pin number of UART for HCI */
int hci_uart_cts_pin; /*!< CTS Pin number of UART for HCI */
} hci_driver_uart_params_config_t;
#define BT_HCI_DRIVER_UART_CONFIG_DEFAULT() { \
.hci_uart_port = UC_BTDM_CTRL_HCI_UART_PORT, \
.hci_uart_baud = UC_BTDM_CTRL_HCI_UART_BAUD, \
.hci_uart_tx_pin = UC_BTDM_CTRL_HCI_UART_TX_PIN , \
.hci_uart_rx_pin = UC_BTDM_CTRL_HCI_UART_RX_PIN, \
.hci_uart_cts_pin = UC_BTDM_CTRL_HCI_UART_CTS_PIN, \
.hci_uart_rts_pin = UC_BTDM_CTRL_HCI_UART_RTS_PIN, \
.hci_uart_data_bits = UC_BTDM_CTRL_HCI_UART_DATA_BITS, \
.hci_uart_stop_bits = UC_BTDM_CTRL_HCI_UART_STOP_BITS, \
.hci_uart_flow_ctrl = UC_BTDM_CTRL_HCI_UART_FLOW_CTRL, \
.hci_uart_parity = UC_BTDM_CTRL_HCI_UART_PARITY, \
}
/**
* @brief Configures the HCI driver UART parameters.
* This function sets up the UART interface according to the specified configuration parameters.
*
* @param uart_config A pointer to a structure containing the UART configuration parameters.
* The structure should include details such as baud rate, parity, stop bits, and flow control.
* Ensure that the uart_config structure is correctly initialized before calling this function.
*
* @return int Returns 0 on success, or a non-zero error code on failure.
*
* @note This function should be called before any UART communication is initiated.
*/
int hci_driver_uart_config(hci_driver_uart_params_config_t *uart_config);
/**
* @brief Update the UART pin configuration for the HCI driver.
*
* This function updates the TX, RX, CTS, and RTS pin assignments for the HCI driver operating over UART.
* It allows dynamic reconfiguration of UART pins as needed.
*
* @param tx_pin The GPIO number assigned to the UART TX pin.
* @param rx_pin The GPIO number assigned to the UART RX pin.
* @param cts_pin The GPIO number assigned to the UART CTS pin.
* @param rts_pin The GPIO number assigned to the UART RTS pin.
*
* @return 0 on success, or a negative error code on failure.
*/
int hci_driver_uart_pin_update(int tx_pin, int rx_pin, int cts_pin, int rts_pin);
/**
* @brief Retrieves the current UART configuration parameters for the HCI driver.
*
* @return hci_driver_uart_params_config_t* Pointer to the structure with UART configuration parameters.
*/
hci_driver_uart_params_config_t * hci_driver_uart_config_param_get(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "driver/uart.h"
#include "hci_driver_uart.h"
#include "esp_private/esp_gpio_reserve.h"
static const char *TAG = "hci_uart_config";
static uart_config_t s_uart_cfg;
static hci_driver_uart_params_config_t s_hci_driver_uart_params = BT_HCI_DRIVER_UART_CONFIG_DEFAULT();
int hci_driver_uart_config(hci_driver_uart_params_config_t *uart_config)
{
uart_config_t *uart_cfg;
uart_cfg = &s_uart_cfg;
uart_cfg->baud_rate = uart_config->hci_uart_baud;
uart_cfg->data_bits = uart_config->hci_uart_data_bits;
uart_cfg->stop_bits = uart_config->hci_uart_stop_bits;
uart_cfg->parity = uart_config->hci_uart_parity;
uart_cfg->flow_ctrl = uart_config->hci_uart_flow_ctrl;
uart_cfg->source_clk= UART_SCLK_DEFAULT;
uart_cfg->rx_flow_ctrl_thresh = UART_HW_FIFO_LEN(uart_config->hci_uart_port) - 1;
ESP_LOGI(TAG,"set uart pin tx:%d, rx:%d.\n", uart_config->hci_uart_tx_pin, uart_config->hci_uart_rx_pin);
ESP_LOGI(TAG,"set rts:%d, cts:%d.\n", uart_config->hci_uart_rts_pin, uart_config->hci_uart_cts_pin);
ESP_LOGI(TAG,"set baud_rate:%d.\n", uart_config->hci_uart_baud);
ESP_LOGI(TAG,"set flow_ctrl:%d.\n", uart_config->hci_uart_flow_ctrl);
ESP_ERROR_CHECK(uart_driver_delete(uart_config->hci_uart_port));
ESP_ERROR_CHECK(uart_param_config(uart_config->hci_uart_port, uart_cfg));
ESP_ERROR_CHECK(uart_set_pin(uart_config->hci_uart_port, uart_config->hci_uart_tx_pin, uart_config->hci_uart_rx_pin,
uart_config->hci_uart_rts_pin, uart_config->hci_uart_cts_pin));
return 0;
}
int
hci_driver_uart_pin_update(int tx_pin, int rx_pin, int cts_pin, int rts_pin)
{
hci_driver_uart_params_config_t *uart_param = &s_hci_driver_uart_params;
/* Fixed warning that the gpio is not usable, may be used by others */
esp_gpio_revoke(BIT64(uart_param->hci_uart_tx_pin));
esp_gpio_revoke(BIT64(uart_param->hci_uart_rx_pin));
if (uart_param->hci_uart_cts_pin != -1) {
esp_gpio_revoke(BIT64(uart_param->hci_uart_cts_pin));
}
if (uart_param->hci_uart_rts_pin != -1) {
esp_gpio_revoke(BIT64(uart_param->hci_uart_rts_pin));
}
uart_param->hci_uart_tx_pin = tx_pin;
uart_param->hci_uart_rx_pin = rx_pin;
uart_param->hci_uart_rts_pin = rts_pin;
uart_param->hci_uart_cts_pin = cts_pin;
return hci_driver_uart_config(uart_param);
}
hci_driver_uart_params_config_t *
hci_driver_uart_config_param_get(void)
{
return &s_hci_driver_uart_params;
}
@@ -0,0 +1,714 @@
/*
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "esp_hci_transport.h"
#include "esp_hci_internal.h"
#include "common/hci_driver_h4.h"
#include "common/hci_driver_util.h"
#include "common/hci_driver_mem.h"
#include "hci_driver_uart.h"
#include "ble_hci_trans.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/gdma.h"
#include "hal/uhci_ll.h"
/*
* UART DMA Desc struct
*
* --------------------------------------------------------------
* | own | EoF | sub_sof | 5'b0 | length [11:0] | size [11:0] |
* --------------------------------------------------------------
* | buf_ptr [31:0] |
* --------------------------------------------------------------
* | next_desc_ptr [31:0] |
* --------------------------------------------------------------
*/
/* this bitfield is start from the LSB!!! */
typedef struct uhci_lldesc_s {
volatile uint32_t size : 12,
length: 12,
offset: 5, /* h/w reserved 5bit, s/w use it as offset in buffer */
sosf : 1, /* start of sub-frame */
eof : 1, /* end of frame */
owner : 1; /* hw or sw */
volatile const uint8_t *buf; /* point to buffer data */
union {
volatile uint32_t empty;
STAILQ_ENTRY(uhci_lldesc_s) qe; /* pointing to the next desc */
};
} uhci_lldesc_t;
/**
* @brief Enumeration of HCI transport transmission states.
*/
typedef enum {
HCI_TRANS_TX_IDLE, ///< HCI Transport TX is in idle state.
HCI_TRANS_TX_START, ///< HCI Transport TX is starting transmission.
HCI_TRANS_TX_END, ///< HCI Transport TX has completed transmission.
} hci_trans_tx_state_t;
typedef struct {
TaskHandle_t task_handler;
hci_driver_uart_params_config_t *hci_uart_params;
SemaphoreHandle_t process_sem;
struct hci_h4_sm *h4_sm;
hci_driver_forward_fn *forward_cb;
struct os_mempool *hci_rx_data_pool; /*!< Init a memory pool for rx_data cache */
uint8_t *hci_rx_data_buffer;
struct os_mempool *hci_rxinfo_pool; /*!< Init a memory pool for rxinfo cache */
os_membuf_t *hci_rxinfo_buffer;
volatile bool rxinfo_mem_exhausted; /*!< Indicate rxinfo memory does not exist */
volatile bool is_continue_rx; /*!< Continue to rx */
volatile hci_trans_tx_state_t hci_tx_state; /*!< HCI Tx State */
struct os_mempool lldesc_mem_pool;/*!< Init a memory pool for uhci_lldesc_t */
uhci_lldesc_t *lldesc_mem;
} hci_driver_uart_dma_env_t;
#define ESP_BT_HCI_TL_STATUS_OK (0) /*!< HCI_TL Tx/Rx operation status OK */
/* The number of lldescs pool */
#define HCI_LLDESCS_POOL_NUM (UC_BT_CTRL_HCI_LLDESCS_POOL_NUM)
/* Default block size for HCI RX data */
#define HCI_RX_DATA_POOL_NUM (UC_BT_CTRL_HCI_TRANS_RX_MEM_NUM)
#define HCI_RX_INFO_POOL_NUM (UC_BT_CTRL_HCI_TRANS_RX_MEM_NUM + 1)
#if UC_BT_CTRL_BLE_IS_ENABLE
#define HCI_RX_DATA_BLOCK_SIZE (DEFAULT_BT_LE_ACL_BUF_SIZE + BLE_HCI_TRANS_CMD_SZ)
#else
#define HCI_RX_DATA_BLOCK_SIZE (1024)
#endif
/**
* @brief callback function for HCI Transport Layer send/receive operations
*/
typedef void (* esp_bt_hci_tl_callback_t) (void *arg, uint8_t status);
struct uart_txrxchannel {
esp_bt_hci_tl_callback_t callback;
void *arg;
uhci_lldesc_t *link_head;
};
struct uart_env_tag {
struct uart_txrxchannel tx;
struct uart_txrxchannel rx;
};
typedef struct hci_message {
void *ptr; ///< Pointer to the message data.
uint32_t length; ///< Length of the message data.
STAILQ_ENTRY(hci_message) next; ///< Next element in the linked list.
} hci_message_t;
static void hci_driver_uart_dma_recv_async(uint8_t *buf, uint32_t size, esp_bt_hci_tl_callback_t callback, void *arg);
int hci_driver_uart_dma_rx_start(uint8_t *rx_data, uint32_t length);
int hci_driver_uart_dma_tx_start(esp_bt_hci_tl_callback_t callback, void *arg);
static const char *TAG = "uart_dma";
static hci_driver_uart_dma_env_t s_hci_driver_uart_dma_env;
static struct hci_h4_sm s_hci_driver_uart_h4_sm;
/* The list for hci_rx_data */
STAILQ_HEAD(g_hci_rxinfo_list, hci_message);
DRAM_ATTR struct g_hci_rxinfo_list g_hci_rxinfo_head;
static DRAM_ATTR struct uart_env_tag uart_env;
static volatile uhci_dev_t *s_uhci_hw = &UHCI0;
static DRAM_ATTR gdma_channel_handle_t s_rx_channel;
static DRAM_ATTR gdma_channel_handle_t s_tx_channel;
static int hci_driver_uart_dma_memory_deinit(void)
{
if (s_hci_driver_uart_dma_env.hci_rxinfo_buffer) {
free(s_hci_driver_uart_dma_env.hci_rxinfo_buffer);
s_hci_driver_uart_dma_env.hci_rxinfo_buffer = NULL;
}
if (s_hci_driver_uart_dma_env.hci_rxinfo_pool) {
free(s_hci_driver_uart_dma_env.hci_rxinfo_pool);
s_hci_driver_uart_dma_env.hci_rxinfo_pool = NULL;
}
if (s_hci_driver_uart_dma_env.hci_rx_data_buffer) {
free(s_hci_driver_uart_dma_env.hci_rx_data_buffer);
s_hci_driver_uart_dma_env.hci_rx_data_buffer = NULL;
}
if (s_hci_driver_uart_dma_env.hci_rx_data_pool) {
free(s_hci_driver_uart_dma_env.hci_rx_data_pool);
s_hci_driver_uart_dma_env.hci_rx_data_pool = NULL;
}
if (s_hci_driver_uart_dma_env.lldesc_mem) {
free(s_hci_driver_uart_dma_env.lldesc_mem);
s_hci_driver_uart_dma_env.lldesc_mem = NULL;
}
return 0;
}
static int hci_driver_uart_dma_memory_init(void)
{
int rc = 0;
s_hci_driver_uart_dma_env.lldesc_mem = malloc(OS_MEMPOOL_SIZE(HCI_LLDESCS_POOL_NUM,
sizeof (uhci_lldesc_t)) * sizeof(os_membuf_t));
if (!s_hci_driver_uart_dma_env.lldesc_mem) {
return -1;
}
rc = os_mempool_init(&s_hci_driver_uart_dma_env.lldesc_mem_pool, HCI_LLDESCS_POOL_NUM,
sizeof (uhci_lldesc_t), s_hci_driver_uart_dma_env.lldesc_mem, "hci_lldesc_pool");
if (rc) {
goto init_err;
}
s_hci_driver_uart_dma_env.hci_rx_data_pool = (struct os_mempool *)malloc(sizeof(struct os_mempool));
if (!s_hci_driver_uart_dma_env.hci_rx_data_pool) {
goto init_err;
}
memset(s_hci_driver_uart_dma_env.hci_rx_data_pool, 0, sizeof(struct os_mempool));
s_hci_driver_uart_dma_env.hci_rx_data_buffer = malloc(OS_MEMPOOL_SIZE(HCI_RX_DATA_POOL_NUM,
HCI_RX_DATA_BLOCK_SIZE) * sizeof(os_membuf_t));
if (!s_hci_driver_uart_dma_env.hci_rx_data_buffer) {
goto init_err;
}
memset(s_hci_driver_uart_dma_env.hci_rx_data_buffer, 0, OS_MEMPOOL_SIZE(HCI_RX_DATA_POOL_NUM,
HCI_RX_DATA_BLOCK_SIZE) * sizeof(os_membuf_t));
rc = os_mempool_init(s_hci_driver_uart_dma_env.hci_rx_data_pool, HCI_RX_DATA_POOL_NUM,
HCI_RX_DATA_BLOCK_SIZE, s_hci_driver_uart_dma_env.hci_rx_data_buffer,
"hci_rx_data_pool");
if (rc) {
goto init_err;
}
/* Malloc hci rxinfo pool */
s_hci_driver_uart_dma_env.hci_rxinfo_pool = (struct os_mempool *)malloc(sizeof(struct os_mempool));
if (!s_hci_driver_uart_dma_env.hci_rxinfo_pool) {
goto init_err;
}
memset(s_hci_driver_uart_dma_env.hci_rxinfo_pool, 0, sizeof(struct os_mempool));
s_hci_driver_uart_dma_env.hci_rxinfo_buffer = malloc(OS_MEMPOOL_SIZE(HCI_RX_INFO_POOL_NUM,
sizeof(hci_message_t)) * sizeof(os_membuf_t));
if (!s_hci_driver_uart_dma_env.hci_rxinfo_buffer) {
goto init_err;
}
memset(s_hci_driver_uart_dma_env.hci_rxinfo_buffer, 0, OS_MEMPOOL_SIZE(HCI_RX_INFO_POOL_NUM,
sizeof(hci_message_t)) * sizeof(os_membuf_t));
rc = os_mempool_init(s_hci_driver_uart_dma_env.hci_rxinfo_pool, HCI_RX_INFO_POOL_NUM,
sizeof(hci_message_t), s_hci_driver_uart_dma_env.hci_rxinfo_buffer,
"hci_rxinfo_pool");
if (rc) {
goto init_err;
}
return rc;
init_err:
hci_driver_uart_dma_memory_deinit();
return rc;
}
static IRAM_ATTR bool hci_uart_tl_rx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{
esp_bt_hci_tl_callback_t callback = uart_env.rx.callback;
void *arg = uart_env.rx.arg;
assert(dma_chan == s_rx_channel);
assert(uart_env.rx.callback != NULL);
// clear callback pointer
uart_env.rx.callback = NULL;
uart_env.rx.arg = NULL;
// call handler
callback(arg, ESP_BT_HCI_TL_STATUS_OK);
return true;
}
static IRAM_ATTR bool hci_uart_tl_tx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{
esp_bt_hci_tl_callback_t callback = uart_env.tx.callback;
assert(dma_chan == s_tx_channel);
assert(uart_env.tx.callback != NULL);
// clear callback pointer
uart_env.tx.callback = NULL;
// call handler
callback(uart_env.tx.arg, ESP_BT_HCI_TL_STATUS_OK);
uart_env.tx.arg = NULL;
return true;
}
uint8_t * IRAM_ATTR hci_driver_uart_dma_rxdata_memory_get(void)
{
uint8_t *rx_data;
rx_data = os_memblock_get(s_hci_driver_uart_dma_env.hci_rx_data_pool);
return rx_data;
}
hci_message_t * IRAM_ATTR hci_driver_uart_dma_rxinfo_memory_get(void)
{
hci_message_t *rx_info;
rx_info = os_memblock_get(s_hci_driver_uart_dma_env.hci_rxinfo_pool);
return rx_info;
}
void IRAM_ATTR hci_driver_uart_dma_cache_rxinfo(hci_message_t *hci_rxinfo)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
STAILQ_INSERT_TAIL(&g_hci_rxinfo_head, hci_rxinfo, next);
OS_EXIT_CRITICAL(sr);
}
void IRAM_ATTR hci_driver_uart_dma_continue_rx_enable(bool enable)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
s_hci_driver_uart_dma_env.is_continue_rx = enable;
OS_EXIT_CRITICAL(sr);
}
void IRAM_ATTR hci_driver_uart_dma_rxinfo_mem_exhausted_set(bool is_exhausted)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
s_hci_driver_uart_dma_env.rxinfo_mem_exhausted = is_exhausted;
OS_EXIT_CRITICAL(sr);
}
void IRAM_ATTR hci_driver_uart_dma_recv_callback(void *arg, uint8_t status)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
hci_message_t *hci_rxinfo;
uint8_t *rx_data;
if (s_hci_driver_uart_dma_env.rxinfo_mem_exhausted) {
ESP_LOGE(TAG, "Will lost rx data, need adjust rxinfo memory count\n");
assert(0);
}
hci_rxinfo = hci_driver_uart_dma_rxinfo_memory_get();
if (!hci_rxinfo) {
ESP_LOGW(TAG, "set rxinfo mem exhausted flag\n");
hci_driver_uart_dma_rxinfo_mem_exhausted_set(true);
xSemaphoreGiveFromISR(s_hci_driver_uart_dma_env.process_sem, &xHigherPriorityTaskWoken);
return;
}
hci_rxinfo->ptr = (void *)uart_env.rx.link_head->buf;
hci_rxinfo->length = uart_env.rx.link_head->length;
hci_driver_uart_dma_cache_rxinfo(hci_rxinfo);
xSemaphoreGiveFromISR(s_hci_driver_uart_dma_env.process_sem, &xHigherPriorityTaskWoken);
rx_data = hci_driver_uart_dma_rxdata_memory_get();
if (!rx_data) {
hci_driver_uart_dma_continue_rx_enable(true);
}else {
hci_driver_uart_dma_rx_start(rx_data, HCI_RX_DATA_BLOCK_SIZE);
}
}
void IRAM_ATTR hci_driver_uart_dma_txstate_set(hci_trans_tx_state_t tx_state)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
s_hci_driver_uart_dma_env.hci_tx_state = tx_state;
OS_EXIT_CRITICAL(sr);
}
void IRAM_ATTR hci_driver_uart_dma_send_callback(void *arg, uint8_t status)
{
uhci_lldesc_t *lldesc_head;
uhci_lldesc_t *lldesc_nxt;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
lldesc_head = uart_env.tx.link_head;
while (lldesc_head) {
lldesc_nxt = lldesc_head->qe.stqe_next;
os_memblock_put(&s_hci_driver_uart_dma_env.lldesc_mem_pool, lldesc_head);
lldesc_head = lldesc_nxt;
}
uart_env.tx.link_head = NULL;
hci_driver_uart_dma_txstate_set(HCI_TRANS_TX_IDLE);
xSemaphoreGiveFromISR(s_hci_driver_uart_dma_env.process_sem, &xHigherPriorityTaskWoken);
}
static IRAM_ATTR void hci_driver_uart_dma_recv_async(uint8_t *buf, uint32_t size, esp_bt_hci_tl_callback_t callback, void *arg)
{
uhci_lldesc_t *lldesc_head;
assert(buf != NULL);
assert(size != 0);
assert(callback != NULL);
uart_env.rx.callback = callback;
uart_env.rx.arg = arg;
lldesc_head = uart_env.rx.link_head;
while (lldesc_head) {
os_memblock_put(&s_hci_driver_uart_dma_env.lldesc_mem_pool, lldesc_head),
lldesc_head = lldesc_head->qe.stqe_next;
}
uart_env.rx.link_head = NULL;
lldesc_head = os_memblock_get(&s_hci_driver_uart_dma_env.lldesc_mem_pool);
assert(lldesc_head);
memset(lldesc_head, 0, sizeof(uhci_lldesc_t));
lldesc_head->buf = buf;
lldesc_head->size = size;
lldesc_head->eof = 0;
s_uhci_hw->pkt_thres.pkt_thrs = size;
uart_env.rx.link_head = lldesc_head;
gdma_start(s_rx_channel, (intptr_t)(uart_env.rx.link_head));
}
int IRAM_ATTR hci_driver_uart_dma_rx_start(uint8_t *rx_data, uint32_t length)
{
hci_driver_uart_dma_recv_async(rx_data, length, hci_driver_uart_dma_recv_callback, NULL);
return 0;
}
int hci_driver_uart_dma_tx_start(esp_bt_hci_tl_callback_t callback, void *arg)
{
void *data;
bool last_frame;
bool head_is_setted;
uint32_t tx_len;
uhci_lldesc_t *lldesc_data;
uhci_lldesc_t *lldesc_head;
uhci_lldesc_t *lldesc_tail;
lldesc_head = NULL;
lldesc_tail = NULL;
head_is_setted = false;
last_frame = false;
while (true) {
// The length in DMA is 12 bits
tx_len = hci_driver_util_tx_list_dequeue(0xfff, &data, &last_frame);
if (!tx_len) {
break;
}
lldesc_data = os_memblock_get(&s_hci_driver_uart_dma_env.lldesc_mem_pool);
/* According to the current processing logic It should not be empty */
assert(lldesc_data);
memset(lldesc_data, 0, sizeof(uhci_lldesc_t));
lldesc_data->length = tx_len;
lldesc_data->buf = data;
lldesc_data->eof = 0;
if (!head_is_setted) {
lldesc_head = lldesc_data;
head_is_setted = true;
} else {
lldesc_tail->qe.stqe_next = lldesc_data;
}
lldesc_tail = lldesc_data;
if (last_frame) {
break;
}
}
if (lldesc_head) {
lldesc_tail->eof = 1;
uart_env.tx.link_head = lldesc_head;
uart_env.tx.callback = callback;
uart_env.tx.arg = arg;
/* The DMA interrupt may have been triggered before setting the tx_state,
* So we set it first.
*/
hci_driver_uart_dma_txstate_set(HCI_TRANS_TX_START);
gdma_start(s_tx_channel, (intptr_t)(uart_env.tx.link_head));
return 0;
} else {
return -1;
}
}
static void hci_driver_uart_dma_install(void)
{
#if __PERIPH_CTRL_DEPRECATE_ATTR
periph_module_enable(PERIPH_UHCI0_MODULE);
periph_module_reset(PERIPH_UHCI0_MODULE);
#else
PERIPH_RCC_ATOMIC() {
uhci_ll_enable_bus_clock(1);
uhci_ll_reset_register();
}
#endif
// install DMA driver
gdma_channel_alloc_config_t tx_channel_config = {
.flags.reserve_sibling = 1,
.direction = GDMA_CHANNEL_DIRECTION_TX,
};
ESP_ERROR_CHECK(gdma_new_ahb_channel(&tx_channel_config, &s_tx_channel));
gdma_channel_alloc_config_t rx_channel_config = {
.direction = GDMA_CHANNEL_DIRECTION_RX,
.sibling_chan = s_tx_channel,
};
ESP_ERROR_CHECK(gdma_new_ahb_channel(&rx_channel_config, &s_rx_channel));
gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
gdma_strategy_config_t strategy_config = {
.auto_update_desc = false,
.owner_check = false
};
ESP_ERROR_CHECK(gdma_apply_strategy(s_tx_channel, &strategy_config));
ESP_ERROR_CHECK(gdma_apply_strategy(s_rx_channel, &strategy_config));
gdma_rx_event_callbacks_t rx_cbs = {
.on_recv_eof = hci_uart_tl_rx_eof_callback
};
ESP_ERROR_CHECK(gdma_register_rx_event_callbacks(s_rx_channel, &rx_cbs, NULL));
gdma_tx_event_callbacks_t tx_cbs = {
.on_trans_eof = hci_uart_tl_tx_eof_callback
};
ESP_ERROR_CHECK(gdma_register_tx_event_callbacks(s_tx_channel, &tx_cbs, NULL));
// configure UHCI
uhci_ll_init((uhci_dev_t *)s_uhci_hw);
// uhci_ll_set_eof_mode((uhci_dev_t *)s_uhci_hw, UHCI_RX_LEN_EOF);
uhci_ll_set_eof_mode((uhci_dev_t *)s_uhci_hw, UHCI_RX_IDLE_EOF);
// disable software flow control
s_uhci_hw->escape_conf.val = 0;
uhci_ll_attach_uart_port((uhci_dev_t *)s_uhci_hw, s_hci_driver_uart_dma_env.hci_uart_params->hci_uart_port);
}
static int
hci_driver_uart_dma_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir)
{
uint8_t data_source;
int rc;
data_source = 0;
/* By now, this layer is only used by controller. */
ESP_LOGD(TAG, "dma tx len:%d\n", length);
if (dir == HCI_DRIVER_DIR_BTDMC2H) {
if (data_type == HCI_DRIVER_TYPE_EVT) {
data_source = HCI_DRIVER_BTDM_EVT;
}
} else if (dir == HCI_DRIVER_DIR_LEC2H) {
if (data_type == HCI_DRIVER_TYPE_ACL) {
data_source = HCI_DRIVER_LE_ACL;
} else if (data_type == HCI_DRIVER_TYPE_EVT) {
data_source = HCI_DRIVER_LE_EVT;
} else if (data_type == HCI_DRIVER_TYPE_ISO) {
data_source = HCI_DRIVER_LE_ISO;
}
}
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
else if (dir == HCI_DRIVER_DIR_BREDRC2H) {
if (data_type == HCI_DRIVER_TYPE_ACL) {
data_source = HCI_DRIVER_BREDR_ACL;
} else if (data_type == HCI_DRIVER_TYPE_SYNC) {
data_source = HCI_DRIVER_BREDR_SYNC;
} else if (data_type == HCI_DRIVER_TYPE_EVT) {
data_source = HCI_DRIVER_BREDR_EVT;
}
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
else {
assert(0);
}
rc = hci_driver_util_tx_list_enqueue(data_type, data, length, data_source);
if (rc < 0) {
ESP_LOGE(TAG, "dma tx data enqueue failed!\n");
return rc;
}
xSemaphoreGive(s_hci_driver_uart_dma_env.process_sem);
return rc;
}
static int
hci_driver_uart_dma_h4_frame_cb(uint8_t pkt_type, void *data, int pkt_len, uint8_t data_source)
{
hci_driver_forward_fn *forward_cb = s_hci_driver_uart_dma_env.forward_cb;
if (!forward_cb) {
ESP_LOGW(TAG, "rx cb is NULL\n");
return -1;
}
ESP_LOGD(TAG, "h4 frame\n");
return forward_cb(pkt_type, data, pkt_len, HCI_DRIVER_DIR_H2C, data_source);
}
static void
hci_driver_uart_dma_process_task(void *p)
{
hci_message_t *rxinfo_container;
os_sr_t sr;
int ret;
uint8_t* rx_data;
uint32_t rx_len;
while (true) {
xSemaphoreTake(s_hci_driver_uart_dma_env.process_sem, portMAX_DELAY);
ESP_LOGD(TAG, "task run:%d\n",s_hci_driver_uart_dma_env.hci_tx_state);
/* Process Tx data */
if (s_hci_driver_uart_dma_env.hci_tx_state == HCI_TRANS_TX_IDLE) {
hci_driver_uart_dma_tx_start(hci_driver_uart_dma_send_callback, (void*)&uart_env);
}
if (s_hci_driver_uart_dma_env.rxinfo_mem_exhausted) {
rx_data = (void *)uart_env.rx.link_head->buf;
rx_len = uart_env.rx.link_head->length;
ESP_LOGD(TAG, "rxinfo exhausted:");
ESP_LOG_BUFFER_HEXDUMP(TAG, rx_data, rx_len, ESP_LOG_DEBUG);
ret = hci_h4_sm_rx(s_hci_driver_uart_dma_env.h4_sm, rx_data, rx_len);
hci_driver_uart_dma_rx_start(rx_data, HCI_RX_DATA_BLOCK_SIZE);
hci_driver_uart_dma_rxinfo_mem_exhausted_set(false);
if (ret < 0) {
ESP_LOGW(TAG, "parse rx data error!\n");
r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR);
}
}
while (!STAILQ_EMPTY(&g_hci_rxinfo_head)) {
OS_ENTER_CRITICAL(sr);
rxinfo_container = STAILQ_FIRST(&g_hci_rxinfo_head);
STAILQ_REMOVE_HEAD(&g_hci_rxinfo_head, next);
OS_EXIT_CRITICAL(sr);
rx_data = rxinfo_container->ptr;
rx_len = rxinfo_container->length;
ESP_LOGD(TAG, "uart rx");
ESP_LOG_BUFFER_HEXDUMP(TAG, rx_data, rx_len, ESP_LOG_DEBUG);
ret = hci_h4_sm_rx(s_hci_driver_uart_dma_env.h4_sm, rx_data, rx_len);
if (ret < 0) {
ESP_LOGW(TAG, "parse rx data error!\n");
r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR);
}
os_memblock_put(s_hci_driver_uart_dma_env.hci_rxinfo_pool, rxinfo_container);
/* No need to enter CRITICAL */
if (s_hci_driver_uart_dma_env.is_continue_rx) {
/* We should set continux rx flag first, RX interrupted may happened when rx start soon */
hci_driver_uart_dma_continue_rx_enable(false);
hci_driver_uart_dma_rx_start(rx_data, HCI_RX_DATA_BLOCK_SIZE);
} else {
os_memblock_put(s_hci_driver_uart_dma_env.hci_rx_data_pool, rx_data);
}
}
}
}
static int
hci_driver_uart_dma_task_create(void)
{
/* !TODO: Set the core id by menuconfig */
xTaskCreatePinnedToCore(hci_driver_uart_dma_process_task, "hci_driver_uart_dma_process_task",
UC_BT_CTRL_HCI_TRANS_TASK_STACK_SIZE, NULL,
ESP_TASK_BT_CONTROLLER_PRIO, &s_hci_driver_uart_dma_env.task_handler,
0);
assert(s_hci_driver_uart_dma_env.task_handler);
ESP_LOGI(TAG, "hci transport task create successfully, prio:%d, stack size: %ld",
ESP_TASK_BT_CONTROLLER_PRIO, UC_BT_CTRL_HCI_TRANS_TASK_STACK_SIZE);
return 0;
}
static void
hci_driver_uart_dma_deinit(void)
{
if (s_hci_driver_uart_dma_env.task_handler) {
vTaskDelete(s_hci_driver_uart_dma_env.task_handler);
s_hci_driver_uart_dma_env.task_handler = NULL;
}
ESP_ERROR_CHECK(uart_driver_delete(s_hci_driver_uart_dma_env.hci_uart_params->hci_uart_port));
hci_driver_uart_dma_memory_deinit();
if (!s_hci_driver_uart_dma_env.process_sem) {
vSemaphoreDelete(s_hci_driver_uart_dma_env.process_sem);
}
hci_driver_util_deinit();
memset(&s_hci_driver_uart_dma_env, 0, sizeof(hci_driver_uart_dma_env_t));
}
static int
hci_driver_uart_dma_init(hci_driver_forward_fn *cb)
{
int rc;
memset(&s_hci_driver_uart_dma_env, 0, sizeof(hci_driver_uart_dma_env_t));
s_hci_driver_uart_dma_env.h4_sm = &s_hci_driver_uart_h4_sm;
hci_h4_sm_init(s_hci_driver_uart_dma_env.h4_sm, &s_hci_driver_mem_alloc, &s_hci_driver_mem_free, hci_driver_uart_dma_h4_frame_cb);
rc = hci_driver_util_init();
if (rc) {
goto error;
}
s_hci_driver_uart_dma_env.process_sem = xSemaphoreCreateBinary();
if (!s_hci_driver_uart_dma_env.process_sem) {
goto error;
}
rc = hci_driver_uart_dma_memory_init();
if (rc) {
goto error;
}
s_hci_driver_uart_dma_env.forward_cb = cb;
s_hci_driver_uart_dma_env.hci_uart_params = hci_driver_uart_config_param_get();
hci_driver_uart_config(s_hci_driver_uart_dma_env.hci_uart_params);
ESP_LOGI(TAG, "uart attach uhci!");
hci_driver_uart_dma_install();
STAILQ_INIT(&g_hci_rxinfo_head);
rc = hci_driver_uart_dma_task_create();
if (rc) {
goto error;
}
s_hci_driver_uart_dma_env.hci_tx_state = HCI_TRANS_TX_IDLE;
s_hci_driver_uart_dma_env.rxinfo_mem_exhausted = false;
s_hci_driver_uart_dma_env.is_continue_rx = false;
hci_driver_uart_dma_rx_start(os_memblock_get(s_hci_driver_uart_dma_env.hci_rx_data_pool),
HCI_RX_DATA_BLOCK_SIZE);
return 0;
error:
hci_driver_uart_dma_deinit();
return rc;
}
int
hci_driver_uart_dma_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin)
{
return hci_driver_uart_pin_update(tx_pin, rx_pin, cts_pin, rts_pin);
}
hci_driver_ops_t hci_driver_uart_dma_ops = {
.hci_driver_tx = hci_driver_uart_dma_tx,
.hci_driver_init = hci_driver_uart_dma_init,
.hci_driver_deinit = hci_driver_uart_dma_deinit,
};
@@ -0,0 +1,109 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdio.h>
#include "esp_hci_driver.h"
#include "esp_hci_internal.h"
typedef struct {
hci_driver_forward_fn *forward_cb;
hci_driver_host_recv_fn *host_recv_cb;
} hci_driver_vhci_env_t;
static hci_driver_vhci_env_t s_hci_driver_vhci_env;
static int
hci_driver_vhci_host_recv(hci_driver_data_type_t type, uint8_t *data, uint16_t len)
{
static hci_driver_host_recv_fn *host_recv_cb;
host_recv_cb = s_hci_driver_vhci_env.host_recv_cb;
if (host_recv_cb) {
return host_recv_cb(type, data, len);
}
return -1;
}
static int
hci_driver_vhci_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir)
{
#if 1
hci_driver_packet_t *pkt;
if (dir == HCI_DRIVER_DIR_BTDMC2H) {
uint8_t *hci_evt = r_ble_hci_trans_buf_alloc(ESP_HCI_INTERNAL_BUF_CMD);
assert(hci_evt);
pkt = (hci_driver_packet_t *)data;
memcpy(hci_evt, pkt->data, length);
btdm_hci_trans_buf_free(pkt);
data = hci_evt;
}
#endif
return hci_driver_vhci_host_recv(data_type, data, length);
}
static int
hci_driver_vhci_init(hci_driver_forward_fn *cb)
{
s_hci_driver_vhci_env.forward_cb = cb;
return 0;
}
static void
hci_driver_vhci_deinit(void)
{
memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t));
}
hci_driver_ops_t hci_driver_vhci_ops = {
.hci_driver_tx = hci_driver_vhci_tx,
.hci_driver_init = hci_driver_vhci_init,
.hci_driver_deinit = hci_driver_vhci_deinit,
};
/* Special APIs used by host to send message. */
int
hci_driver_host_cmd_tx(uint8_t *data, uint32_t length)
{
#if 0
hci_driver_packet_t *pkt = NULL;
uint16_t pkt_len;
pkt_len = data[2] + 3;
pkt = btdm_hci_trans_buf_alloc(HCI_DRIVER_TYPE_CMD, 0);
assert(pkt);
pkt->type = HCI_DRIVER_TYPE_CMD;
pkt->length = pkt_len;
memcpy(pkt->data, &data[0], pkt_len);
r_ble_hci_trans_buf_free(data);
return s_hci_driver_vhci_env.forward_cb(HCI_DRIVER_TYPE_CMD, (uint8_t *)pkt, pkt_len, HCI_DRIVER_DIR_H2C, HCI_DRIVER_CMD);
#else
return s_hci_driver_vhci_env.forward_cb(HCI_DRIVER_TYPE_CMD, data, length, HCI_DRIVER_DIR_H2C, HCI_DRIVER_CMD);
#endif
}
int
hci_driver_host_acl_tx(uint8_t *data, uint32_t length)
{
return s_hci_driver_vhci_env.forward_cb(HCI_DRIVER_TYPE_ACL, data, length, HCI_DRIVER_DIR_H2C, HCI_DRIVER_LE_ACL);
}
#if CONFIG_BT_LE_ISO_SUPPORT
int
hci_driver_host_iso_tx(uint8_t *data, uint32_t length)
{
return s_hci_driver_vhci_env.forward_cb(HCI_DRIVER_TYPE_ISO, data, length, HCI_DRIVER_DIR_H2C, HCI_DRIVER_LE_ISO);
}
#endif // CONFIG_BT_LE_ISO_SUPPORT
int
hci_driver_host_callback_register(hci_driver_host_recv_fn *callback)
{
s_hci_driver_vhci_env.host_recv_cb = callback;
return 0;
}
@@ -0,0 +1,302 @@
/*
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdio.h>
#include "ble_mbuf.h"
#include "esp_hci_driver.h"
#include "esp_hci_internal.h"
#include "esp_bt.h"
typedef struct {
hci_driver_forward_fn *forward_cb;
const esp_vhci_host_callback_t *host_recv_cb;
} hci_driver_vhci_env_t;
static hci_driver_vhci_env_t s_hci_driver_vhci_env;
#if 0
typedef int ble_host_rx_iso_data_fn(uint8_t *data, uint16_t len);
static ble_host_rx_iso_data_fn *ble_host_iso_rx_cb = NULL;
void ble_hci_register_rx_iso_data_cb(void *cb)
{
/* If the iso rx cb is already registered, we will give
* a warning log here, and the cb will still be updated.
*/
if (ble_host_iso_rx_cb) {
printf("iso rx cb %p already registered\n", ble_host_iso_rx_cb);
}
ble_host_iso_rx_cb = cb;
}
#endif // CONFIG_BT_LE_ISO_SUPPORT
static int
hci_driver_vhci_host_recv_with_type(uint8_t data_type, uint8_t *data, uint16_t len)
{
static const esp_vhci_host_callback_t *host_recv_cb;
host_recv_cb = s_hci_driver_vhci_env.host_recv_cb;
if (!host_recv_cb) {
return -1;
}
#if 0
if (data_type == HCI_DRIVER_TYPE_ISO) {
if (ble_host_iso_rx_cb) {
return ble_host_iso_rx_cb(data, len);
}
} else
#endif // CONFIG_BT_LE_ISO_SUPPORT
{
if (host_recv_cb->notify_host_recv) {
return host_recv_cb->notify_host_recv(data, len);
}
}
return -1;
}
static void
hci_driver_vhci_host_send_available(void)
{
static const esp_vhci_host_callback_t *host_recv_cb;
host_recv_cb = s_hci_driver_vhci_env.host_recv_cb;
if (host_recv_cb && host_recv_cb->notify_host_send_available) {
host_recv_cb->notify_host_send_available();
}
}
static int
hci_driver_vhci_controller_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length, hci_driver_direction_t dir)
{
int rc = 0;
uint16_t buf_len = length + 1;;
uint8_t *buf = NULL;
struct ble_mbuf *om;
uint8_t old_value = 0;
hci_driver_packet_t *pkt = (hci_driver_packet_t *)data;
if (data_type == HCI_DRIVER_TYPE_ACL) {
#if UC_BT_CTRL_BLE_IS_ENABLE
if (dir == HCI_DRIVER_DIR_LEC2H) {
om = (struct ble_mbuf *)data;
buf = malloc(buf_len);
/* TODO: If there is no memory, should handle it in the controller. */
assert(buf);
buf[0] = HCI_DRIVER_TYPE_ACL;
ble_mbuf_copydata(om, 0, length, &buf[1]);
ble_mbuf_free_chain(om);
rc = hci_driver_vhci_host_recv_with_type(data_type, buf, buf_len);
free(buf);
}
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
if (dir == HCI_DRIVER_DIR_BREDRC2H) {
buf = pkt->data - 1;
old_value = *buf;
*buf = data_type;
rc = hci_driver_vhci_host_recv_with_type(data_type, buf, buf_len);
*buf = old_value;
if (rc >= 0) {
bredr_hci_trans_acl_tx_done(pkt);
bredr_hci_trans_acl_free(pkt);
}
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
} else if (data_type == HCI_DRIVER_TYPE_EVT) {
/* TODO: If there is no memory, should handle it in the controller. */
if (dir == HCI_DRIVER_DIR_LEC2H) {
buf = malloc(buf_len);
assert(buf != NULL);
buf[0] = HCI_DRIVER_TYPE_EVT;
memcpy(&buf[1], data, length);
rc = hci_driver_vhci_host_recv_with_type(data_type, buf, buf_len);
r_ble_hci_trans_buf_free(data);
free(buf);
}
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
else if (dir == HCI_DRIVER_DIR_BREDRC2H) {
buf = pkt->data - 1;
old_value = *buf;
*buf = data_type;
rc = hci_driver_vhci_host_recv_with_type(data_type, buf, buf_len);
*buf = old_value;
if (rc >= 0) {
bredr_hci_trans_evt_tx_done((hci_driver_packet_t *)data);
bredr_hci_trans_evt_free((hci_driver_packet_t *)data);
}
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
else {
buf = pkt->data - 1;
old_value = *buf;
*buf = data_type;
rc = hci_driver_vhci_host_recv_with_type(data_type, buf, buf_len);
*buf = old_value;
btdm_hci_trans_buf_free(pkt);
}
}
#if CONFIG_BT_LE_ISO_SUPPORT
else if (data_type == HCI_DRIVER_TYPE_ISO) {
rc = hci_driver_vhci_host_recv_with_type(data_type, data, length);
free(data);
}
#endif // CONFIG_BT_LE_ISO_SUPPORT
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
else if (data_type == HCI_DRIVER_TYPE_SYNC) {
/* SCO/ESCO data */
buf = pkt->data - 1;
old_value = *buf;
*buf = data_type;
rc = hci_driver_vhci_host_recv_with_type(data_type, buf, buf_len);
*buf = old_value;
if (rc >= 0) {
bredr_hci_trans_sync_tx_done(pkt);
bredr_hci_trans_sync_free(pkt);
}
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
else {
assert(0);
}
return rc;
}
static int
hci_driver_vhci_host_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length)
{
struct ble_mbuf *om;
uint16_t pkt_len;
uint16_t conn_handle;
hci_driver_packet_t *pkt = NULL;
uint8_t data_source = 0xFF;
pkt_len = length - 1;
switch (data_type) {
case HCI_DRIVER_TYPE_CMD:
pkt = btdm_hci_trans_buf_alloc(data_type, 0);
assert(pkt);
//TODO: check if pkt_len is not larger than the allocated one.
memcpy(pkt->data, &data[1], pkt_len);
data = (uint8_t *)pkt;
break;
case HCI_DRIVER_TYPE_ACL:
conn_handle = btdm_get_le16(&data[1]) & HCI_INTERNAL_CONN_MASK;
#if UC_BT_CTRL_BLE_IS_ENABLE
if (HCI_INTERNAL_CONN_IS_BLE(conn_handle)) {
om = ble_msys_get_pkthdr(pkt_len, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE);
assert(om);
assert(ble_mbuf_append(om, &data[1], length - 1) == 0);
data = (uint8_t *)om;
data_source = HCI_DRIVER_LE_ACL;
}
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
if (HCI_INTERNAL_CONN_IS_BREDR(conn_handle)) {
pkt = btdm_hci_trans_buf_alloc(data_type, conn_handle);
assert(pkt);
memcpy(pkt->data, &data[1], pkt_len);
data = (uint8_t *)pkt;
data_source = HCI_DRIVER_BREDR_ACL;
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
break;
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
case HCI_DRIVER_TYPE_SYNC:
conn_handle = btdm_get_le16(&data[1]) & HCI_INTERNAL_CONN_MASK;
pkt = btdm_hci_trans_buf_alloc(data_type, conn_handle);
assert(pkt);
memcpy(pkt->data, &data[1], pkt_len);
data = (uint8_t *)pkt;
data_source = HCI_DRIVER_BREDR_SYNC;
break;
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
case HCI_DRIVER_TYPE_ISO:
data_source = HCI_DRIVER_LE_ISO;
break;
default:
assert(0);
break;
}
if (pkt) {
pkt->length = pkt_len;
}
return s_hci_driver_vhci_env.forward_cb(data_type, data, pkt_len, HCI_DRIVER_DIR_H2C, data_source);
}
static int
hci_driver_vhci_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir)
{
int rc;
if (dir == HCI_DRIVER_DIR_H2C) {
rc = hci_driver_vhci_host_tx(data_type, data, length);
} else {
rc = hci_driver_vhci_controller_tx(data_type, data, length, dir);
}
return rc;
}
static int
hci_driver_vhci_init(hci_driver_forward_fn *cb)
{
memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t));
s_hci_driver_vhci_env.forward_cb = cb;
return 0;
}
static void
hci_driver_vhci_deinit(void)
{
memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t));
}
hci_driver_ops_t hci_driver_vhci_ops = {
.hci_driver_tx = hci_driver_vhci_tx,
.hci_driver_init = hci_driver_vhci_init,
.hci_driver_deinit = hci_driver_vhci_deinit,
};
/* Special APIs declared in the `esp_bt.h'. */
esp_err_t
esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback)
{
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return ESP_FAIL;
}
s_hci_driver_vhci_env.host_recv_cb = callback;
return ESP_OK;
}
void
esp_vhci_host_send_packet(uint8_t *data, uint16_t len)
{
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return;
}
hci_driver_vhci_tx(data[0], data, len, HCI_DRIVER_DIR_H2C);
}
bool
esp_vhci_host_check_send_available(void)
{
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return false;
}
return true;
}
@@ -0,0 +1,133 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdio.h>
#include "os/os_mbuf.h"
#include "esp_hci_transport.h"
#include "esp_hci_internal.h"
#include "esp_hci_driver.h"
typedef struct {
hci_driver_forward_fn *forward_cb;
} hci_driver_vhci_env_t;
static hci_driver_vhci_env_t s_hci_driver_vhci_env;
static int
hci_driver_vhci_controller_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length)
{
int rc;
uint16_t len = 0;
uint8_t *buf = NULL;
struct os_mbuf *om;
if (data_type == HCI_DRIVER_TYPE_ACL) {
/* The ACL data will be packaged as structure of `os_mbuf`.
* 1. Allocate a buffer suitable for the host. Use the following method to copy the data
* from the os_mbuf to the newly allocated memory.
* ```c
* buf = malloc(length);
* os_mbuf_copydata(om, 0, length, buf);
* ```
* 2. Free the controller's os_mbuf
* ```c
* os_mbuf_free_chain(om);
* ```
*/
} else if (data_type == HCI_DRIVER_TYPE_EVT) {
/* The event data will be packaged as an array.
* 1. Allocate a buffer suitable for the host. Use the following method to copy the data
* from the controller buffer to the newly allocated memory.
* ```c
* buf = malloc(length);
* memcpy(buf, data, length);
* ```
* 2. Free the controller's buffer.
* ```c
* r_ble_hci_trans_buf_free(data);
* ```
*/
} else {
assert(0);
}
rc = s_hci_driver_vhci_env.forward_cb(data_type, buf, len, HCI_DRIVER_DIR_C2H);
free(buf);
return rc;
}
static int
hci_driver_vhci_host_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length)
{
uint8_t *hci_data;
struct os_mbuf *om;
if (data_type == HCI_DRIVER_TYPE_ACL) {
/* The ACL data needs to be packaged as structure of `os_mbuf`.
* 1. Get an os_mbuf in the following way.
* ```c
* om = os_msys_get_pkthdr(length, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE);
* ```
* 2. Copy the host's data into this os_mbuf using the following method.
* ```c
* assert(os_mbuf_append(om, data, length) == 0);
* hci_data = (uint8_t *)om;
* ```
* 3. Free the host's buffer if needed.
*/
} else if (data_type == HCI_DRIVER_TYPE_CMD) {
/* The COMMAND data needs to be packaged as an array.
* 1. Get a command buffer from the controller.
* ```c
* hci_data = r_ble_hci_trans_buf_alloc(ESP_HCI_INTERNAL_BUF_CMD);
* ```
* 2. Copy the host's data into this buffer.
* ```c
* memcpy(hci_data, data, length);
* ```
* 3. Free the host's buffer if needed.
*/
} else {
assert(0);
}
return s_hci_driver_vhci_env.forward_cb(data_type, hci_data, length, HCI_DRIVER_DIR_H2C);
}
static int
hci_driver_vhci_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir)
{
int rc;
if (dir == HCI_DRIVER_DIR_C2H) {
rc = hci_driver_vhci_controller_tx(data_type, data, length);
} else {
rc = hci_driver_vhci_host_tx(data_type, data, length);
}
return rc;
}
static int
hci_driver_vhci_init(hci_driver_forward_fn *cb)
{
memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t));
s_hci_driver_vhci_env.forward_cb = cb;
return 0;
}
static void
hci_driver_vhci_deinit(void)
{
memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t));
}
hci_driver_ops_t hci_driver_vhci_ops = {
.hci_driver_tx = hci_driver_vhci_tx,
.hci_driver_init = hci_driver_vhci_init,
.hci_driver_deinit = hci_driver_vhci_deinit,
};
@@ -0,0 +1,108 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _HCI_H4_H_
#define _HCI_H4_H_
#include <stdint.h>
#include "esp_hci_internal.h"
#define HCI_H4_NONE 0x00
#define HCI_H4_CMD 0x01
#define HCI_H4_ACL 0x02
#define HCI_H4_SYNC 0x03
#define HCI_H4_EVT 0x04
#define HCI_H4_ISO 0x05
typedef hci_driver_packet_t *(hci_h4_alloc_cmd)(void);
typedef void *(hci_h4_alloc_evt)(int);
typedef struct ble_mbuf *(hci_h4_alloc_acl)(void);
typedef void *(hci_h4_alloc_iso)(uint32_t);
#if CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM
typedef hci_driver_packet_t *(hci_h4_alloc_sync)(uint16_t);
typedef hci_driver_packet_t *(hci_h4_alloc_bredr_acl)(uint16_t);
#endif // CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM
struct hci_h4_allocators {
hci_h4_alloc_cmd *cmd;
hci_h4_alloc_acl *acl;
hci_h4_alloc_evt *evt;
hci_h4_alloc_iso *iso;
#if CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM
hci_h4_alloc_sync *sync;
hci_h4_alloc_bredr_acl *bredr_acl;
#endif // CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM
};
extern const struct hci_h4_allocators hci_h4_allocs_from_ll;
extern const struct hci_h4_allocators hci_h4_allocs_from_hs;
typedef void (hci_h4_free_cmd)(void * ptr);
typedef void (hci_h4_free_evt)(void * ptr);
typedef int (hci_h4_free_acl)(struct ble_mbuf *om);
typedef void (hci_h4_free_iso)(void *ptr);
typedef void (hci_h4_free_le_evt)(uint8_t *buf);
#if CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM
typedef void (hci_h4_free_sync)(void *ptr);
typedef void (hci_h4_free_bredr_acl)(void *ptr);
#endif // CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM
struct hci_h4_frees {
hci_h4_free_cmd *cmd;
hci_h4_free_acl *acl;
hci_h4_free_evt *evt;
hci_h4_free_iso *iso;
hci_h4_free_le_evt *le_evt;
#if CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM
hci_h4_free_sync *sync;
hci_h4_free_bredr_acl *bredr_acl;
#endif // CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM
};
typedef int (hci_h4_frame_cb)(uint8_t pkt_type, void *data, int len, uint8_t data_source);
struct hci_h4_sm {
uint8_t state;
uint8_t pkt_type;
uint8_t min_len;
uint16_t len;
uint16_t exp_len;
uint8_t hdr[4];
union {
uint8_t *buf;
struct ble_mbuf *om;
hci_driver_packet_t *pkt;
};
const struct hci_h4_allocators *allocs;
const struct hci_h4_frees *frees;
hci_h4_frame_cb *frame_cb;
};
void hci_h4_sm_init(struct hci_h4_sm *h4sm,
const struct hci_h4_allocators *allocs,
const struct hci_h4_frees *frees,
hci_h4_frame_cb *frame_cb);
int hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len);
#endif /* _HCI_H4_H_ */
@@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _H_HCI_DRIVER_MEM_
#define _H_HCI_DRIVER_MEM_
#include <stdint.h>
#include "esp_hci_internal.h"
hci_driver_packet_t *hci_driver_mem_cmd_alloc(void);
void *hci_driver_mem_evt_alloc(int discardable);
struct ble_mbuf *hci_driver_mem_acl_alloc(void);
struct ble_mbuf *hci_driver_mem_acl_len_alloc(uint32_t len);
void *hci_driver_mem_iso_alloc(uint32_t len);
struct ble_mbuf *hci_driver_mem_iso_len_alloc(uint32_t len);
extern const struct hci_h4_allocators s_hci_driver_mem_alloc;
extern const struct hci_h4_frees s_hci_driver_mem_free;
#if CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM
hci_driver_packet_t *hci_driver_mem_bredr_acl_alloc(uint16_t len);
hci_driver_packet_t *hci_driver_mem_sync_alloc(uint16_t len);
#endif // CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY || CONFIG_BTDM_CTRL_MODE_BTDM
#endif // _H_HCI_DRIVER_MEM_
@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _H_HCI_DRIVER_UTIL_
#define _H_HCI_DRIVER_UTIL_
#include <stdint.h>
int hci_driver_util_init(void);
void hci_driver_util_deinit(void);
int hci_driver_util_tx_list_enqueue(hci_driver_data_type_t type, uint8_t *data, uint32_t len, hci_driver_data_source_t data_source);
uint32_t hci_driver_util_tx_list_dequeue(uint32_t max_tx_len, void **tx_data, bool *last_frame);
void hci_driver_util_assert_check(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2);
#define HCI_TRANS_ASSERT(cond, p1, p2) \
if (!(cond)) { \
hci_driver_util_assert_check(__LINE__, __func__, p1, p2); \
}
#endif // _H_HCI_DRIVER_UTIL_
@@ -0,0 +1,116 @@
/*
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_ESP_HCI_DRIVER_
#define H_ESP_HCI_DRIVER_
#include <stdint.h>
#include "queue.h"
#include "esp_bt.h"
#include "esp_hci_transport.h"
/**
* @brief Enumeration of HCI transport direction.
*/
typedef enum {
HCI_DRIVER_DIR_LEC2H = 0x00, ///< From controller to host.
HCI_DRIVER_DIR_BREDRC2H,
HCI_DRIVER_DIR_BTDMC2H,
HCI_DRIVER_DIR_H2C, ///< From host to controller.
} hci_driver_direction_t;
typedef enum {
HCI_DRIVER_TYPE_CMD = 0x01, ///< HCI Command Indicator.
HCI_DRIVER_TYPE_ACL, ///< HCI ACL Data Indicator.
HCI_DRIVER_TYPE_SYNC, ///< HCI Synchronous Data Indicator.
HCI_DRIVER_TYPE_EVT, ///< HCI Event Indicator.
HCI_DRIVER_TYPE_ISO, ///< HCI Isochronous Data Indicator.
HCI_DRIVER_TYPE_VENDOR, ///< HCI Vendor data Indicator.
} hci_driver_data_type_t;
typedef enum {
HCI_DRIVER_CMD = 0x00,
HCI_DRIVER_LE_EVT,
HCI_DRIVER_BREDR_EVT,
HCI_DRIVER_BTDM_EVT,
HCI_DRIVER_LE_ACL,
HCI_DRIVER_LE_ISO,
HCI_DRIVER_BREDR_ACL,
HCI_DRIVER_BREDR_SYNC,
} hci_driver_data_source_t;
struct hci_driver_packet
{
STAILQ_ENTRY(hci_driver_packet) next;
uint8_t *data;
uint16_t length;
uint8_t flags;
uint8_t type;
};
typedef struct hci_driver_packet hci_driver_packet_t;
typedef int hci_driver_forward_fn(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir, uint8_t data_source);
#define HCI_DRIVER_D2P(data) ((void *)((uint32_t)data - sizeof(hci_driver_packet_t)))
/**
* @brief Structure of HCI driver operations.
*/
typedef struct hci_driver_ops {
int (*hci_driver_tx)(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length,
hci_driver_direction_t dir);
int (*hci_driver_init)(hci_driver_forward_fn *cb);
void (*hci_driver_deinit)(void);
} hci_driver_ops_t;
#if CONFIG_BT_NIMBLE_ENABLED
typedef int hci_driver_host_recv_fn(hci_driver_data_type_t type, uint8_t *data, uint16_t len);
/**
* @brief Set the host's HCI callback which will be invoked when receiving ACL/Events from controller.
* @param callback hci_driver_host_recv_fn type variable
* @return int 0 on success, non-zero error code on failure.
*/
int hci_driver_host_callback_register(hci_driver_host_recv_fn *callback);
/**
* @brief Called to send HCI commands form host to controller.
* @param data Point to the commands data
* @param length Length of data
* @return int 0 on success, non-zero error code on failure.
*/
int hci_driver_host_cmd_tx(uint8_t *data, uint32_t length);
/**
* @brief Called to send HCI ACL form host to controller.
* @param data Point to the ACL data
* @param length Length of data
* @return int 0 on success, non-zero error code on failure.
*/
int hci_driver_host_acl_tx(uint8_t *data, uint32_t length);
#if CONFIG_BT_LE_ISO_SUPPORT
/**
* @brief Called to send HCI ISO daata form host to controller.
* @param data Point to the ISO data
* @param length Length of data
* @return int 0 on success, non-zero error code on failure.
*/
int hci_driver_host_iso_tx(uint8_t *data, uint32_t length);
#endif // CONFIG_BT_LE_ISO_SUPPORT
#endif // CONFIG_BT_NIMBLE_ENABLED
#if UC_BT_CTRL_HCI_INTERFACE_USE_RAM
extern hci_driver_ops_t hci_driver_vhci_ops;
#endif // UC_BT_CTRL_HCI_INTERFACE_USE_RAM
#if UC_BT_CTRL_HCI_INTERFACE_USE_UART
extern hci_driver_ops_t hci_driver_uart_ops;
#if UC_BT_CTRL_UART_HCI_DMA_MODE
extern hci_driver_ops_t hci_driver_uart_dma_ops;
#endif // UC_BT_CTRL_UART_HCI_DMA_MODE
#endif // UC_BT_CTRL_HCI_INTERFACE_USE_UART
#endif // H_ESP_HCI_DRIVER_
@@ -0,0 +1,186 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_ESP_HCI_INTERNAL_
#define H_ESP_HCI_INTERNAL_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "esp_hci_driver.h"
#include "ble_mbuf.h"
/* The leadingspace in user info header for ACL data */
#define ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE (4)
#define ESP_HCI_INTERNAL_BUF_CMD (3)
/**
* @brief Define the HCI hardware error code for synchronization loss.
* This error code is used to indicate a loss of synchronization between the controller and the host.
*/
#define ESP_HCI_SYNC_LOSS_ERR (0x1)
/** Callback function types; executed when HCI packets are received. */
typedef int esp_hci_internal_rx_cmd_fn(uint8_t *cmd, void *arg);
typedef int esp_hci_internal_rx_acl_fn(struct ble_mbuf *om, void *arg);
#if CONFIG_BT_LE_ISO_SUPPORT
typedef int esp_hci_internal_rx_iso_fn(const uint8_t *data, uint16_t len, void *arg);
/**
* @brief Configure the ISO data receive callback for BLE HCI transport.
*
* @param iso_cb The callback to execute upon receiving ISO data.
*
* @param iso_arg Optional argument to pass to the ISO callback.
*/
void r_ble_iso_trans_cfg_hs(esp_hci_internal_rx_iso_fn *iso_cb, void *iso_arg);
#define ble_iso_trans_cfg_hs r_ble_iso_trans_cfg_hs
/**
* @brief Transmit ISO (Isochronous) data over BLE HCItransport.
*
* @param data Pointer to the ISO data buffer to be transmitted.
* @param length Length of the ISO data in bytes.
* @param arg Optional user-defined argument, passed through
* the transport layer and may be used by the underlying driver or callback.
*
* @return 0 on success, or a non-zero error code on failure.
*/
int r_ble_hci_trans_hs_iso_tx(const uint8_t *data, uint16_t length, void *arg);
#define ble_hci_trans_hs_iso_tx r_ble_hci_trans_hs_iso_tx
#endif // CONFIG_BT_LE_ISO_SUPPORT
/**
* Configures the HCI transport to operate with a host. The transport will
* execute specified callbacks upon receiving HCI packets from the controller.
*
* @param evt_cb The callback to execute upon receiving an HCI
* event.
* @param evt_arg Optional argument to pass to the event
* callback.
* @param acl_cb The callback to execute upon receiving ACL
* data.
* @param acl_arg Optional argument to pass to the ACL
* callback.
*/
void r_ble_hci_trans_cfg_hs(esp_hci_internal_rx_cmd_fn *evt_cb, void *evt_arg,
esp_hci_internal_rx_acl_fn *acl_cb, void *acl_arg);
/**
* Sends ACL data from host to controller.
*
* @param om The ACL data packet to send.
*
* @return 0 on success;
* A BLE_ERR_[...] error code on failure.
*/
int r_ble_hci_trans_hs_acl_tx(struct ble_mbuf *om);
/**
* Sends an HCI command from the host to the controller.
*
* @param cmd The HCI command to send. This buffer must be
* allocated via ble_hci_trans_buf_alloc().
*
* @return 0 on success;
* A BLE_ERR_[...] error code on failure.
*/
int r_ble_hci_trans_hs_cmd_tx(uint8_t *cmd);
#if CONFIG_BT_LE_ISO_SUPPORT
int ble_hci_trans_hs_iso_tx(const uint8_t *data, uint16_t length, void *arg);
#endif /* CONFIG_BT_LE_ISO_SUPPORT */
/**
* Allocates a flat buffer of the specified type.
*
* @param type The type of buffer to allocate; one of the
* BLE_HCI_TRANS_BUF_[...] constants.
*
* @return The allocated buffer on success;
* NULL on buffer exhaustion.
*/
uint8_t * r_ble_hci_trans_buf_alloc(int type);
/**
* Frees the specified flat buffer. The buffer must have been allocated via
* ble_hci_trans_buf_alloc().
*
* @param buf The buffer to free.
*/
void r_ble_hci_trans_buf_free(uint8_t *buf);
/**
* @brief Handle an HCI hardware error event.
* This function processes a hardware error code and generates the appropriate HCI hardware error event.
*
* @param hw_err The hardware error code that needs to be processed. The specific meaning of the error code
* depends on the implementation and the hardware.
*
* @return int Returns 0 on success, or a non-zero error code on failure.
*
* @note This function should be called whenever a hardware error is detected in the HCI Layer.
*/
int r_ble_ll_hci_ev_hw_err(uint8_t hw_err);
//!TODO: Check what this API is used for
int r_ble_hci_trans_reset(void);
//!TODO: Should we initialize the hci layer in IDF ?
void esp_ble_hci_trans_init(uint8_t);
// ********************************************************************************************
// btdm common
// ********************************************************************************************
typedef int (*btdm_hci_trans_tx_func_t)(hci_driver_packet_t *pkt);
#define HCI_INTERNAL_CONN_MASK (0x0fff)
#define HCI_INTERNAL_CONN_IS_BLE(conn_handle) (!(conn_handle & 0x0800))
#define HCI_INTERNAL_CONN_IS_BREDR(conn_handle) (conn_handle & 0x0800)
#define HCI_INTERNAL_CONN_IS_BREDR_ACL(conn_handle) ((conn_handle & 0x0800) && (conn_handle & 0x000f))
#define HCI_INTERNAL_CONN_IS_BREDR_SYNC(conn_handle) ((conn_handle & 0x0800) && (conn_handle & 0x00f0))
int r_btdm_hci_trans_register_tx(btdm_hci_trans_tx_func_t *tx_func, bool async);
int r_btdm_hci_trans_rx(hci_driver_packet_t *pkt);
hci_driver_packet_t *r_btdm_hci_trans_buf_alloc(uint8_t type, uint16_t conn_handle);
void r_btdm_hci_trans_buf_free(hci_driver_packet_t *pkt);
uint16_t r_btdm_get_le16(const void *buf);
#define btdm_hci_trans_buf_alloc r_btdm_hci_trans_buf_alloc
#define btdm_hci_trans_buf_free r_btdm_hci_trans_buf_free
#define btdm_get_le16 r_btdm_get_le16
#define btdm_hci_trans_register_tx r_btdm_hci_trans_register_tx
#define btdm_hci_trans_rx r_btdm_hci_trans_rx
void btdm_hci_pkt_flag_ble_setf(hci_driver_packet_t *pkt, uint8_t is_ble);
uint8_t btdm_hci_pkt_flag_ble_getf(hci_driver_packet_t *pkt);
uint8_t btdm_hci_pkt_flag_bredr_getf(hci_driver_packet_t *pkt);
uint8_t btdm_hci_pkt_flag_cmdpool_getf(hci_driver_packet_t *pkt);
// ********************************************************************************************
// BREDR
// ********************************************************************************************
int bredr_hci_trans_acl_rx(hci_driver_packet_t *pkt);
int bredr_hci_trans_sync_rx(hci_driver_packet_t *pkt);
void bredr_hci_trans_register_tx(btdm_hci_trans_tx_func_t *acl_tx_func,
btdm_hci_trans_tx_func_t *sync_tx_func,
btdm_hci_trans_tx_func_t *evt_tx_func);
void bredr_hci_trans_acl_tx_done(hci_driver_packet_t *pkt);
void bredr_hci_trans_sync_tx_done(hci_driver_packet_t *pkt);
void bredr_hci_trans_evt_tx_done(hci_driver_packet_t *pkt);
int bredr_hci_trans_acl_free(hci_driver_packet_t *pkt);
int bredr_hci_trans_sync_free(hci_driver_packet_t *pkt);
int bredr_hci_trans_evt_free(hci_driver_packet_t *pkt);
#ifdef __cplusplus
}
#endif
#endif /* H_ESP_HCI_INTERNAL_ */
@@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_ESP_HCI_TRANSPORT_
#define H_ESP_HCI_TRANSPORT_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "ble_mbuf.h"
#include "esp_hci_driver.h"
/**
* @brief Enumeration of HCI packet indicators
*/
typedef enum {
HCI_CMD_IND = 0x01, /*!< HCI Command Indicator */
HCI_ACL_IND, /*!< HCI ACL Data Indicator */
HCI_SYNC_IND, /*!< HCI Synchronous Data Indicator */
HCI_EVT_IND, /*!< HCI Event Indicator */
HCI_ISO_IND, /*!< HCI Isochronous Data Indicator */
HCI_VENDOR_IND, /*!< HCI Vendor data Indicator */
} hci_trans_pkt_ind_t;
/**
* @brief Enumeration of HCI Transport Mode
*/
typedef enum {
HCI_TRANSPORT_VHCI, /*!< VHCI Transport Mode */
HCI_TRANSPORT_UART_NO_DMA, /*!< UART_NO_DMA Transport Mode */
HCI_TRANSPORT_UART_UHCI, /*!< UART_UHCI Transport Mode */
HCI_TRANSPORT_SDIO, /*!< SDIO Transport Mode */
HCI_TRANSPORT_USB, /*!< USB Transport Mode */
} hci_trans_mode_t;
/**
* @brief Initialize the HCI transport layer.
* It should be called before using any other functions in the transport layer.
*
* @param hci_transport_mode The mode in which the HCI transport should operate.
*
* @return int Returns 0 on success, or a non-zero error code on failure.
*/
int hci_transport_init(uint8_t hci_transport_mode);
/**
* @brief Deinitialize the HCI transport layer for releasing any allocated resources.
*/
void hci_transport_deinit(void);
#ifdef __cplusplus
}
#endif
#endif /* H_ESP_HCI_TRANSPORT_ */
@@ -0,0 +1,287 @@
/*
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "esp_hci_transport.h"
#include "esp_hci_internal.h"
#include "esp_bt.h"
typedef struct hci_transport_env
{
hci_driver_ops_t *driver_ops;
} hci_transport_env_t;
static hci_transport_env_t s_hci_transport_env;
/* Functions for controller Rx. */
static int
hci_transport_controller_rx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length, hci_driver_direction_t dir, uint8_t data_source)
{
int rc;
hci_driver_packet_t *pkt;
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return -1;
}
rc = 0;
assert(dir == HCI_DRIVER_DIR_H2C);
if (data_type == HCI_DRIVER_TYPE_CMD) {
pkt = (hci_driver_packet_t *)data;
rc = btdm_hci_trans_rx(pkt);
} else if (data_type == HCI_DRIVER_TYPE_ACL) {
if (data_source == HCI_DRIVER_LE_ACL) {
#if UC_BT_CTRL_BLE_IS_ENABLE
rc = r_ble_hci_trans_hs_acl_tx((struct ble_mbuf *) data);
#endif // UC_BT_CTRL_BLE_IS_ENABLE
} else {
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
pkt = (hci_driver_packet_t *)data;
pkt->length = length;
rc = bredr_hci_trans_acl_rx(pkt);
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
}
}
#if CONFIG_BT_LE_ISO_SUPPORT
else if (data_type == HCI_DRIVER_TYPE_ISO) {
rc = ble_hci_trans_hs_iso_tx(data, length, NULL);
}
#endif // CONFIG_BT_LE_ISO_SUPPORT
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
else if (data_type == HCI_DRIVER_TYPE_SYNC) {
pkt = (hci_driver_packet_t *)data;
pkt->length = length;
rc = bredr_hci_trans_sync_rx(pkt);
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
else {
rc = -1;
}
return rc;
}
#if UC_BT_CTRL_BLE_IS_ENABLE
/* Functions for controller Tx. */
static int
hci_transport_controller_le_evt_tx(uint8_t *hci_ev, void *arg)
{
/* TODO: In order to support dual-host mode, use legacy interfaces for ble when nimble host is enabled */
uint32_t len;
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
r_ble_hci_trans_buf_free(hci_ev);
return -1;
}
len = hci_ev[1] + 2;
return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_EVT, hci_ev, len,
HCI_DRIVER_DIR_LEC2H);
}
static int
hci_transport_controller_le_acl_tx(struct ble_mbuf *om, void *arg)
{
/* TODO: In order to support dual-host mode, use legacy interfaces for ble when nimble host is enabled */
uint16_t len;
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
ble_mbuf_free_chain(om);
return -1;
}
len = BLE_MBUF_PKTHDR(om)->omp_len;
return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_ACL, (uint8_t *)om, len,
HCI_DRIVER_DIR_LEC2H);
}
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
static int
hci_transport_controller_bredr_tx_dummy(hci_driver_packet_t *pkt, void *arg)
{
return -1;
}
static int
hci_transport_controller_bredr_acl_tx(hci_driver_packet_t *pkt, void *arg)
{
return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_ACL, (uint8_t *)pkt, pkt->length,
HCI_DRIVER_DIR_BREDRC2H);
}
static int
hci_transport_controller_bredr_sync_tx(hci_driver_packet_t *pkt, void *arg)
{
return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_SYNC, (uint8_t *)pkt, pkt->length,
HCI_DRIVER_DIR_BREDRC2H);
}
static int
hci_transport_controller_bredr_evt_tx(hci_driver_packet_t *pkt, void *arg)
{
return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_EVT, (uint8_t *)pkt, pkt->length,
HCI_DRIVER_DIR_BREDRC2H);
}
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
#if CONFIG_BT_LE_ISO_SUPPORT
typedef void ble_host_rx_iso_data_fn(uint8_t *data, uint16_t len);
static ble_host_rx_iso_data_fn *ble_host_iso_rx_cb = NULL;
void ble_host_register_rx_iso_data_cb(void *cb)
{
/* If the iso rx cb is already registered, we will give
* a warning log here, and the cb will still be updated.
*/
if (ble_host_iso_rx_cb) {
printf("iso rx cb %p already registered\n", ble_host_iso_rx_cb);
}
ble_host_iso_rx_cb = cb;
}
void ble_hci_register_rx_iso_data_cb(void *cb)
{
ble_host_register_rx_iso_data_cb(cb);
}
static int
hci_transport_controller_le_iso_tx_dummy(const uint8_t *data, uint16_t len, void *arg)
{
return -1;
}
static int
hci_transport_controller_le_iso_tx(const uint8_t *data, uint16_t len, void *arg)
{
//ISO_TODO: arg is not used
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
//ISO_TODO: free this tx buffer
return -1;
}
#if CONFIG_BT_NIMBLE_ENABLED
return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_ISO, (uint8_t *)data, len,
HCI_DRIVER_DIR_LEC2H);
#elif CONFIG_BT_BLUEDROID_ENABLED
if (ble_host_iso_rx_cb) {
ble_host_iso_rx_cb((uint8_t *)data, len);
}
free((void *)data);
#endif // CONFIG_BT_NIMBLE_ENABLED
return 0;
}
#endif // CONFIG_BT_LE_ISO_SUPPORT
/* Functions for controller Tx. */
static int
hci_transport_controller_le_tx_dummy(void *data, void *arg)
{
return -1;
}
static int
hci_transport_controller_tx_dummy(hci_driver_packet_t *pkt)
{
return -1;
}
static int
hci_transport_controller_tx(hci_driver_packet_t *pkt)
{
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_INITED
&& esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return -1;
}
return s_hci_transport_env.driver_ops->hci_driver_tx(pkt->type, (uint8_t *)pkt, pkt->length,
HCI_DRIVER_DIR_BTDMC2H);
}
int
hci_transport_init(uint8_t hci_transport_mode)
{
int rc;
hci_driver_ops_t *ops;
memset(&s_hci_transport_env, 0, sizeof(hci_transport_env_t));
switch(hci_transport_mode) {
#if UC_BT_CTRL_HCI_INTERFACE_USE_RAM
case HCI_TRANSPORT_VHCI:
ops = &hci_driver_vhci_ops;
break;
#endif // UC_BT_CTRL_HCI_INTERFACE_USE_RAM
#if UC_BT_CTRL_HCI_INTERFACE_USE_UART
#if UC_BT_CTRL_UART_HCI_DMA_MODE
case HCI_TRANSPORT_UART_UHCI:
ops = &hci_driver_uart_dma_ops;
break;
#else
case HCI_TRANSPORT_UART_NO_DMA:
ops = &hci_driver_uart_ops;
break;
#endif // UC_BT_CTRL_UART_HCI_DMA_MODE
#endif // UC_BT_CTRL_HCI_INTERFACE_USE_UART
default:
assert(0);
}
rc = ops->hci_driver_init(hci_transport_controller_rx);
if (rc) {
goto error;
}
s_hci_transport_env.driver_ops = ops;
#if UC_BT_CTRL_BLE_IS_ENABLE
r_ble_hci_trans_cfg_hs((esp_hci_internal_rx_cmd_fn *)hci_transport_controller_le_evt_tx, NULL,
(esp_hci_internal_rx_acl_fn *)hci_transport_controller_le_acl_tx, NULL);
#if CONFIG_BT_LE_ISO_SUPPORT
ble_iso_trans_cfg_hs((esp_hci_internal_rx_iso_fn *)hci_transport_controller_le_iso_tx, NULL);
#endif // CONFIG_BT_LE_ISO_SUPPORT
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
bredr_hci_trans_register_tx((btdm_hci_trans_tx_func_t *)hci_transport_controller_bredr_acl_tx,
(btdm_hci_trans_tx_func_t *)hci_transport_controller_bredr_sync_tx,
(btdm_hci_trans_tx_func_t *)hci_transport_controller_bredr_evt_tx);
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
btdm_hci_trans_register_tx((btdm_hci_trans_tx_func_t *)hci_transport_controller_tx, false);
return 0;
error:
hci_transport_deinit();
return rc;
}
void
hci_transport_deinit(void)
{
hci_driver_ops_t *ops;
btdm_hci_trans_register_tx((btdm_hci_trans_tx_func_t *)hci_transport_controller_tx_dummy, false);
#if UC_BT_CTRL_BLE_IS_ENABLE
r_ble_hci_trans_cfg_hs((esp_hci_internal_rx_cmd_fn *)hci_transport_controller_le_tx_dummy, NULL,
(esp_hci_internal_rx_acl_fn *)hci_transport_controller_le_tx_dummy, NULL);
#if CONFIG_BT_LE_ISO_SUPPORT
ble_iso_trans_cfg_hs((esp_hci_internal_rx_iso_fn *)hci_transport_controller_le_iso_tx_dummy, NULL);
#endif // CONFIG_BT_LE_ISO_SUPPORT
#endif // UC_BT_CTRL_BLE_IS_ENABLE
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
bredr_hci_trans_register_tx((btdm_hci_trans_tx_func_t *)hci_transport_controller_bredr_tx_dummy,
(btdm_hci_trans_tx_func_t *)hci_transport_controller_bredr_tx_dummy,
(btdm_hci_trans_tx_func_t *)hci_transport_controller_bredr_tx_dummy);
#endif // UC_BT_CTRL_BR_EDR_IS_ENABLE
ops = s_hci_transport_env.driver_ops;
if (ops) {
ops->hci_driver_deinit();
}
memset(&s_hci_transport_env, 0, sizeof(hci_transport_env_t));
}
@@ -34,7 +34,7 @@ uint32_t IRAM_ATTR modem_clock_get_module_deps(shared_periph_module_t module)
case PERIPH_PHY_MODULE: deps = PHY_CLOCK_DEPS; break;
case PERIPH_MODEM_ADC_COMMON_FE_MODULE: deps = MODEM_ADC_COMMON_FE_CLOCK_DEPS; break;
case PERIPH_COEX_MODULE: deps = COEXIST_CLOCK_DEPS; break;
// case PERIPH_BT_MODULE: deps = BLE_CLOCK_DEPS; break;
case PERIPH_BT_MODULE: deps = BLE_CLOCK_DEPS; break;
case PERIPH_PHY_CALIBRATION_MODULE: deps = PHY_CALIBRATION_CLOCK_DEPS; break;
case PERIPH_IEEE802154_MODULE: deps = IEEE802154_CLOCK_DEPS; break;
case PERIPH_MODEM_ETM_MODULE: deps = MODEM_ETM_CLOCK_DEPS; break;
@@ -44,23 +44,23 @@ uint32_t IRAM_ATTR modem_clock_get_module_deps(shared_periph_module_t module)
return deps;
}
// static void IRAM_ATTR modem_clock_ble_mac_configure(modem_clock_context_t *ctx, bool enable)
// {
// modem_syscon_ll_enable_bt_mac_clock(ctx->hal->syscon_dev, enable);
// modem_syscon_ll_enable_modem_sec_clock(ctx->hal->syscon_dev, enable);
// modem_syscon_ll_enable_ble_timer_clock(ctx->hal->syscon_dev, enable);
// }
static void IRAM_ATTR modem_clock_ble_mac_configure(modem_clock_context_t *ctx, bool enable)
{
modem_syscon_ll_enable_bt_mac_clock(ctx->hal->syscon_dev, enable);
modem_syscon_ll_enable_modem_sec_clock(ctx->hal->syscon_dev, enable);
modem_syscon_ll_enable_ble_timer_clock(ctx->hal->syscon_dev, enable);
}
// #if CONFIG_ESP_MODEM_CLOCK_ENABLE_CHECKING
// static esp_err_t IRAM_ATTR modem_clock_ble_mac_check_enable(modem_clock_context_t *ctx)
// {
// bool all_clock_enabled = true;
// all_clock_enabled &= modem_syscon_ll_bt_mac_clock_is_enabled(ctx->hal->syscon_dev);
// all_clock_enabled &= modem_syscon_ll_modem_sec_clock_is_enabled(ctx->hal->syscon_dev);
// all_clock_enabled &= modem_syscon_ll_ble_timer_clock_is_enabled(ctx->hal->syscon_dev);
// return all_clock_enabled ? ESP_OK : ESP_FAIL;
// }
// #endif
#if CONFIG_ESP_MODEM_CLOCK_ENABLE_CHECKING
static esp_err_t IRAM_ATTR modem_clock_ble_mac_check_enable(modem_clock_context_t *ctx)
{
bool all_clock_enabled = true;
all_clock_enabled &= modem_syscon_ll_bt_mac_clock_is_enabled(ctx->hal->syscon_dev);
all_clock_enabled &= modem_syscon_ll_modem_sec_clock_is_enabled(ctx->hal->syscon_dev);
all_clock_enabled &= modem_syscon_ll_ble_timer_clock_is_enabled(ctx->hal->syscon_dev);
return all_clock_enabled ? ESP_OK : ESP_FAIL;
}
#endif
static void IRAM_ATTR modem_clock_ble_i154_bb_configure(modem_clock_context_t *ctx, bool enable)
{
@@ -176,7 +176,7 @@ static void IRAM_ATTR modem_clock_configure_impl(modem_clock_context_t *ctx, int
: (dev_id == MODEM_CLOCK_COEXIST) ? modem_clock_coex_configure
: (dev_id == MODEM_CLOCK_I2C_MASTER) ? modem_clock_i2c_master_configure
: (dev_id == MODEM_CLOCK_ETM) ? modem_clock_etm_configure
// : (dev_id == MODEM_CLOCK_BLE_MAC) ? modem_clock_ble_mac_configure
: (dev_id == MODEM_CLOCK_BLE_MAC) ? modem_clock_ble_mac_configure
: (dev_id == MODEM_CLOCK_BT_I154_COMMON_BB) ? modem_clock_ble_i154_bb_configure
: (dev_id == MODEM_CLOCK_802154_MAC) ? modem_clock_ieee802154_mac_configure
: (dev_id == MODEM_CLOCK_DATADUMP) ? modem_clock_data_dump_configure
@@ -196,7 +196,7 @@ static esp_err_t IRAM_ATTR modem_clock_check_impl(modem_clock_context_t *ctx, in
: (dev_id == MODEM_CLOCK_COEXIST) ? modem_clock_coex_check_enable
: (dev_id == MODEM_CLOCK_I2C_MASTER) ? modem_clock_i2c_master_check_enable
: (dev_id == MODEM_CLOCK_ETM) ? modem_clock_etm_check_enable
// : (dev_id == MODEM_CLOCK_BLE_MAC) ? modem_clock_ble_mac_check_enable
: (dev_id == MODEM_CLOCK_BLE_MAC) ? modem_clock_ble_mac_check_enable
: (dev_id == MODEM_CLOCK_BT_I154_COMMON_BB) ? modem_clock_ble_i154_bb_check_enable
: (dev_id == MODEM_CLOCK_802154_MAC) ? modem_clock_ieee802154_mac_check_enable
: (dev_id == MODEM_CLOCK_DATADUMP) ? modem_clock_data_dump_check_enable
+7 -8
View File
@@ -30,10 +30,9 @@ void IRAM_ATTR modem_clock_hal_set_clock_domain_icg_bitmap(modem_clock_hal_conte
case MODEM_CLOCK_DOMAIN_MODEM_PERIPH:
modem_syscon_ll_set_modem_periph_icg_bitmap(hal->syscon_dev, bitmap);
break;
// TODO: PM-636
// case MODEM_CLOCK_DOMAIN_BT:
// modem_syscon_ll_set_bt_icg_bitmap(hal->syscon_dev, bitmap);
// break;
case MODEM_CLOCK_DOMAIN_BT:
modem_syscon_ll_set_bt_icg_bitmap(hal->syscon_dev, bitmap);
break;
case MODEM_CLOCK_DOMAIN_MODEM_FE:
modem_syscon_ll_set_fe_icg_bitmap(hal->syscon_dev, bitmap);
break;
@@ -58,6 +57,7 @@ uint32_t IRAM_ATTR modem_clock_hal_get_clock_domain_icg_bitmap(modem_clock_hal_c
{
HAL_ASSERT(domain < MODEM_CLOCK_DOMAIN_MAX);
uint32_t bitmap = 0;
switch (domain)
{
case MODEM_CLOCK_DOMAIN_MODEM_APB:
@@ -66,10 +66,9 @@ uint32_t IRAM_ATTR modem_clock_hal_get_clock_domain_icg_bitmap(modem_clock_hal_c
case MODEM_CLOCK_DOMAIN_MODEM_PERIPH:
bitmap = modem_syscon_ll_get_modem_periph_icg_bitmap(hal->syscon_dev);
break;
// TODO: PM-636
// case MODEM_CLOCK_DOMAIN_BT:
// bitmap = modem_syscon_ll_get_bt_icg_bitmap(hal->syscon_dev);
// break;
case MODEM_CLOCK_DOMAIN_BT:
bitmap = modem_syscon_ll_get_bt_icg_bitmap(hal->syscon_dev);
break;
case MODEM_CLOCK_DOMAIN_MODEM_FE:
bitmap = modem_syscon_ll_get_fe_icg_bitmap(hal->syscon_dev);
break;
@@ -55,6 +55,10 @@ config SOC_PARLIO_LCD_SUPPORTED
bool
default y
config SOC_BT_SUPPORTED
bool
default y
config SOC_IEEE802154_BLE_ONLY
bool
default y
@@ -1123,6 +1127,50 @@ config SOC_TOUCH_SAMPLE_CFG_NUM
int
default 3
config SOC_BLE_SUPPORTED
bool
default y
config SOC_ESP_NIMBLE_CONTROLLER
bool
default y
config SOC_BLE_50_SUPPORTED
bool
default y
config SOC_BLE_DEVICE_PRIVACY_SUPPORTED
bool
default y
config SOC_BLE_POWER_CONTROL_SUPPORTED
bool
default y
config SOC_BLE_MULTI_CONN_OPTIMIZATION
bool
default y
config SOC_BLE_PERIODIC_ADV_ENH_SUPPORTED
bool
default y
config SOC_BLE_CTE_SUPPORTED
bool
default y
config SOC_BLE_SUBRATE_SUPPORTED
bool
default y
config SOC_BLE_PERIODIC_ADV_WITH_RESPONSE
bool
default y
config SOC_BLE_ISO_SUPPORTED
bool
default y
config SOC_USB_OTG_PERIPH_NUM
int
default 1
+13 -10
View File
@@ -46,7 +46,7 @@
#define SOC_ETM_SUPPORTED 1
#define SOC_PARLIO_SUPPORTED 1
#define SOC_PARLIO_LCD_SUPPORTED 1
// #define SOC_BT_SUPPORTED 1
#define SOC_BT_SUPPORTED 1
#define SOC_IEEE802154_BLE_ONLY 1
#define SOC_PHY_SUPPORTED 1
#define SOC_IEEE802154_SUPPORTED 1
@@ -534,15 +534,18 @@
#define SOC_TOUCH_SAMPLE_CFG_NUM (3) /*!< The sample configurations number in total, each sampler can be used to sample on one frequency */
/*---------------------------------- Bluetooth CAPS ----------------------------------*/
// #define SOC_BLE_SUPPORTED (1) /*!< Support Bluetooth Low Energy hardware */
// #define SOC_BLE_MESH_SUPPORTED (1) /*!< Support BLE MESH */
// #define SOC_ESP_NIMBLE_CONTROLLER (1) /*!< Support BLE EMBEDDED controller V1 */
// #define SOC_BLE_50_SUPPORTED (1) /*!< Support Bluetooth 5.0 */
// #define SOC_BLE_DEVICE_PRIVACY_SUPPORTED (1) /*!< Support BLE device privacy mode */
// #define SOC_BLE_POWER_CONTROL_SUPPORTED (1) /*!< Support Bluetooth Power Control */
// #define SOC_BLE_PERIODIC_ADV_ENH_SUPPORTED (1) /*!< Support For BLE Periodic Adv Enhancements */
// #define SOC_BLUFI_SUPPORTED (1) /*!< Support BLUFI */
// #define SOC_BLE_MULTI_CONN_OPTIMIZATION (1) /*!< Support multiple connections optimization */
#define SOC_BLE_SUPPORTED (1) /*!< Support Bluetooth Low Energy hardware */
// #define SOC_BLE_MESH_SUPPORTED (1) /*!< Support BLE MESH */
#define SOC_ESP_NIMBLE_CONTROLLER (1) /*!< Support BLE EMBEDDED controller V1 */
#define SOC_BLE_50_SUPPORTED (1) /*!< Support Bluetooth 5.0 */
#define SOC_BLE_DEVICE_PRIVACY_SUPPORTED (1) /*!< Support BLE device privacy mode */
#define SOC_BLE_POWER_CONTROL_SUPPORTED (1) /*!< Support Bluetooth Power Control */
#define SOC_BLE_MULTI_CONN_OPTIMIZATION (1) /*!< Support multiple connections optimization */
#define SOC_BLE_PERIODIC_ADV_ENH_SUPPORTED (1) /*!< Support For BLE Periodic Adv Enhancements */
#define SOC_BLE_CTE_SUPPORTED (1) /*!< Support Bluetooth LE Constant Tone Extension (CTE) */
#define SOC_BLE_SUBRATE_SUPPORTED (1) /*!< Support Bluetooth LE Connection Subrating */
#define SOC_BLE_PERIODIC_ADV_WITH_RESPONSE (1) /*!< Support Bluetooth LE Periodic Advertising with Response (PAwR) */
#define SOC_BLE_ISO_SUPPORTED (1) /*!< Support Bluetooth ISO */
/*-------------------------- USB CAPS ----------------------------------------*/
#define SOC_USB_OTG_PERIPH_NUM (1U)
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# Bluedroid Beacon Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# Bluedroid Connection Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# Bluedroid GATT Server Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# NimBLE Beacon Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# NimBLE Connection Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# NimBLE GATT Server Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# NimBLE Security Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF BLE ACL Latency Test - Central
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF BLE ACL Latency Test - Peripheral
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF BLE ANCS Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF BLE Compatibility Test Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF Eddystone Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF Eddystone Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# BLE Encrypted Advertising Data Central Example (Bluedroid)
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# BLE Encrypted Advertising Data Peripheral Example (Bluedroid)
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF BLE HID Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF iBeacon demo
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# BLE Multiple Connection Central Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# BLE Multiple Connection Peripheral Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF SPP GATT CLIENT demo
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
## ESP-IDF GATT SERVER SPP Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF BLE throughput GATT CLIENT Test
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF BLE throughput GATT SERVER Test
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF Gatt Client Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF Gatt Security Client Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF Gatt Security Server Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF Gatt Server Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF Gatt Server Service Table Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF Gatt Client Multi Connection Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF Gatt Security Client Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF BLE50 Security Server Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF BLE 50 throughput GATT CLIENT Test
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# ESP-IDF BLE 50 throughput GATT SERVER Test
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 |
| ----------------- | -------- | -------- | --------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 |
| ----------------- | -------- | -------- | --------- | -------- | -------- |
# BLE Connection Subrating Central Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 |
| ----------------- | -------- | -------- | --------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 |
| ----------------- | -------- | -------- | --------- | -------- | -------- |
# BLE Connection Subrating Peripheral Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C5 | ESP32-C61 | ESP32-H2 |
| ----------------- | -------- | --------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-C61 | ESP32-H2 | ESP32-H4 |
| ----------------- | -------- | --------- | -------- | -------- |
# ESP-IDF BLE Connection Central with CTE Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C5 | ESP32-C61 | ESP32-H2 |
| ----------------- | -------- | --------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-C61 | ESP32-H2 | ESP32-H4 |
| ----------------- | -------- | --------- | -------- | -------- |
# ESP-IDF BLE Connection Peripheral with CTE Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 |
| ----------------- | -------- | -------- | --------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 |
| ----------------- | -------- | -------- | --------- | -------- | -------- |
# BLE Periodic Advertiser With Response (PAwR) Advertiser Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 |
| ----------------- | -------- | -------- | --------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 |
| ----------------- | -------- | -------- | --------- | -------- | -------- |
# BLE Periodic Advertiser With Response (PAwR) Advertiser Connection Example

Some files were not shown because too many files have changed in this diff Show More