diff --git a/.gitignore b/.gitignore index 193750f9..7776977d 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ test/dependencies.lock test/sdkconfig sdkconfig.bak *.ignore + +/sdkconfig.local diff --git a/BUILDING.md b/BUILDING.md index 571aa359..ee64b088 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -72,3 +72,15 @@ If you get errors involving missing C++ includes, then you may need to edit your editor's LSP invocation to include `--query-driver=**`. You should then get proper LSP integration via clangd. + +# ESP-IDF configuration + +Espressif exposes a large collection of configuration options[1] for its +framework; you can use `idf.py menuconfig` to generate a custom `sdkconfig` +file, eg. to change the logging level. + +To avoid needing to select the same set of options every time you regenerate +the sdkconfig, you can also set some defaults in `sdkconfig.local`; this is not +tracked in git, and is ideal for local / per-checkout changes. + +1. https://docs.espressif.com/projects/esp-idf/en/release-v3.3/api-reference/kconfig.html diff --git a/CMakeLists.txt b/CMakeLists.txt index f9d1f72c..3f0db812 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,12 @@ cmake_minimum_required(VERSION 3.16) include($ENV{PROJ_PATH}/tools/cmake/common.cmake) -set(SDKCONFIG_DEFAULTS "sdkconfig.common") +get_filename_component(_abs_curr_dir "." ABSOLUTE) +if (EXISTS ${_abs_curr_dir}/sdkconfig.local) + set(SDKCONFIG_DEFAULTS "sdkconfig.common;sdkconfig.local") +else() + set(SDKCONFIG_DEFAULTS "sdkconfig.common") +endif() # No exceptions in app builds (this is different in test builds). idf_build_set_property(COMPILE_OPTIONS "-DRESULT_DISABLE_EXCEPTIONS" APPEND) diff --git a/dependencies.lock b/dependencies.lock index 7f4a0fe4..7888ec4a 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -3,7 +3,7 @@ dependencies: component_hash: null source: type: idf - version: 5.2.1 + version: 5.3.0 manifest_hash: ef2ae3a0fda058a8cda5b69636300c99782b077919557a63f8f572a6a9e0707b target: esp32 version: 1.0.0 diff --git a/lib/bt/CMakeLists.txt b/lib/bt/CMakeLists.txt index bf74d08a..6dd5ef9b 100644 --- a/lib/bt/CMakeLists.txt +++ b/lib/bt/CMakeLists.txt @@ -24,12 +24,16 @@ elseif(CONFIG_IDF_TARGET_ESP32C6) elseif(CONFIG_IDF_TARGET_ESP32H2) set(target_specific_include_dirs include/esp32h2/include) + +elseif(CONFIG_IDF_TARGET_ESP32C5) + set(target_specific_include_dirs include/esp32c5/include) endif() set(common_include_dirs common/api/include/api common/btc/profile/esp/blufi/include common/btc/profile/esp/include + common/hci_log/include ) set(ble_mesh_include_dirs @@ -66,40 +70,44 @@ if(CONFIG_IDF_DOC_BUILD) ${nimble_hci_include_dirs}) endif() - if(CONFIG_BT_ENABLED) set(srcs "") set(include_dirs "") - set(ldfragments "linker.lf") + set(ldscripts "linker_common.lf") if(CONFIG_BT_CONTROLLER_ENABLED) if(CONFIG_IDF_TARGET_ESP32) list(APPEND srcs "controller/esp32/bt.c" "controller/esp32/hli_api.c" "controller/esp32/hli_vectors.S") + list(APPEND ldscripts "linker_rw_bt_controller.lf") elseif(CONFIG_IDF_TARGET_ESP32C3) list(APPEND srcs "controller/esp32c3/bt.c") + list(APPEND ldscripts "linker_rw_bt_controller.lf") elseif(CONFIG_IDF_TARGET_ESP32S3) list(APPEND srcs "controller/esp32c3/bt.c") + list(APPEND ldscripts "linker_rw_bt_controller.lf") elseif(CONFIG_IDF_TARGET_ESP32C2) list(APPEND srcs "controller/esp32c2/bt.c") - - elseif(CONFIG_IDF_TARGET_ESP32C2) - set(ldfragments "linker.lf.esp32c2") - list(APPEND srcs "controller/esp32c2/bt.c") + set(ldscripts "linker_esp32c2.lf") elseif(CONFIG_IDF_TARGET_ESP32C6) list(APPEND srcs "controller/esp32c6/bt.c") + list(APPEND ldscripts "linker_esp_ble_controller.lf") elseif(CONFIG_IDF_TARGET_ESP32H2) list(APPEND srcs "controller/esp32h2/bt.c") + list(APPEND ldscripts "linker_esp_ble_controller.lf") + + elseif(CONFIG_IDF_TARGET_ESP32C5) + list(APPEND srcs "controller/esp32c5/bt.c") + list(APPEND ldscripts "linker_esp_ble_controller.lf") endif() list(APPEND include_dirs ${target_specific_include_dirs}) - endif() # Common @@ -114,6 +122,7 @@ if(CONFIG_BT_ENABLED) list(APPEND srcs "common/btc/core/btc_alarm.c" "common/api/esp_blufi_api.c" + "common/hci_log/bt_hci_log.c" "common/btc/core/btc_manage.c" "common/btc/core/btc_task.c" "common/btc/profile/esp/blufi/blufi_prf.c" @@ -566,7 +575,7 @@ if(CONFIG_BT_ENABLED) if(CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT) list(APPEND srcs "porting/npl/freertos/src/npl_os_freertos.c" - "porting/nimble/src/os_msys_init.c" + "porting/mem/os_msys_init.c" ) if(CONFIG_BT_CONTROLLER_DISABLED) @@ -576,7 +585,6 @@ if(CONFIG_BT_ENABLED) endif() list(APPEND include_dirs porting/include - porting/nimble/include porting/npl/freertos/include porting/transport/include ) @@ -718,7 +726,6 @@ if(CONFIG_BT_ENABLED) "host/nimble/port/src/nvs_port.c" ) list(APPEND include_dirs - porting/include host/nimble/nimble/porting/nimble/include host/nimble/port/include host/nimble/nimble/nimble/transport/include @@ -747,9 +754,8 @@ if(CONFIG_BT_ENABLED) endif() list(APPEND include_dirs + porting/include host/nimble/nimble/porting/npl/freertos/include - host/nimble/nimble/porting/nimble/include - host/nimble/nimble/nimble/include ) endif() @@ -820,8 +826,8 @@ idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" PRIV_INCLUDE_DIRS "${priv_include_dirs}" REQUIRES esp_timer esp_wifi - PRIV_REQUIRES nvs_flash soc esp_pm esp_phy esp_coex mbedtls driver vfs - LDFRAGMENTS "${ldfragments}") + PRIV_REQUIRES nvs_flash soc esp_pm esp_phy esp_coex mbedtls esp_driver_uart vfs esp_ringbuf + LDFRAGMENTS "${ldscripts}") if(CONFIG_BT_ENABLED) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough -Wno-unused-const-variable) @@ -838,14 +844,8 @@ if(CONFIG_BT_ENABLED) target_link_directories(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32c3_family/esp32s3") target_link_libraries(${COMPONENT_LIB} PUBLIC btdm_app) - elseif(CONFIG_IDF_TARGET_ESP32C2) - add_prebuilt_library(libble_app "controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a") - target_link_libraries(${COMPONENT_LIB} PRIVATE libble_app) - elseif(CONFIG_IDF_TARGET_ESP32C6) - add_prebuilt_library(libble_app "controller/lib_esp32c6/esp32c6-bt-lib/libble_app.a") - target_link_libraries(${COMPONENT_LIB} PRIVATE libble_app) - elseif(CONFIG_IDF_TARGET_ESP32H2) - add_prebuilt_library(libble_app "controller/lib_esp32h2/esp32h2-bt-lib/libble_app.a") + elseif(CONFIG_BT_CONTROLLER_ENABLED) + add_prebuilt_library(libble_app "controller/lib_${target}/${target}-bt-lib/libble_app.a") target_link_libraries(${COMPONENT_LIB} PRIVATE libble_app) endif() @@ -875,6 +875,9 @@ if(CONFIG_BLE_MESH) elseif(CONFIG_IDF_TARGET_ESP32H2) add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32h2/libble_mesh.a") target_link_libraries(${COMPONENT_LIB} PRIVATE ble_mesh) + elseif(CONFIG_IDF_TARGET_ESP32C5) + add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32C5/libble_mesh.a") + target_link_libraries(${COMPONENT_LIB} PRIVATE ble_mesh) endif() endif() diff --git a/lib/bt/Kconfig b/lib/bt/Kconfig index 0eba5dd7..65c757a2 100644 --- a/lib/bt/Kconfig +++ b/lib/bt/Kconfig @@ -80,6 +80,37 @@ menu "Bluetooth" We cannot split the memory into 3 different regions (IRAM, BLE-IRAM, DRAM). So this option will disable the PMP (ESP_SYSTEM_PMP_IDRAM_SPLIT) + menu "Common Options" + visible if (BT_BLUEDROID_ENABLED || BT_NIMBLE_ENABLED) + + source "$IDF_PATH/components/bt/common/Kconfig.in" + endmenu + + config BT_HCI_LOG_DEBUG_EN + depends on BT_BLUEDROID_ENABLED || BT_NIMBLE_ENABLED + bool "Enable Bluetooth HCI debug mode" + default n + help + This option is used to enable bluetooth debug mode, which saves the hci layer data stream. + + config BT_HCI_LOG_DATA_BUFFER_SIZE + depends on BT_HCI_LOG_DEBUG_EN + int "Size of the cache used for HCI data in Bluetooth HCI debug mode (N*1024 bytes)" + range 1 100 + default 5 + help + This option is to configure the buffer size of the hci data steam cache in hci debug mode. + This is a ring buffer, the new data will overwrite the oldest data if the buffer is full. + + config BT_HCI_LOG_ADV_BUFFER_SIZE + depends on BT_HCI_LOG_DEBUG_EN + int "Size of the cache used for adv report in Bluetooth HCI debug mode (N*1024 bytes)" + range 1 100 + default 8 + help + This option is to configure the buffer size of the hci adv report cache in hci debug mode. + This is a ring buffer, the new data will overwrite the oldest data if the buffer is full. + endmenu menuconfig BLE_MESH diff --git a/lib/bt/common/Kconfig.in b/lib/bt/common/Kconfig.in new file mode 100644 index 00000000..6b19dd8e --- /dev/null +++ b/lib/bt/common/Kconfig.in @@ -0,0 +1,6 @@ +config BT_ALARM_MAX_NUM + int "Maximum number of Bluetooth alarms" + default 50 + help + This option decides the maximum number of alarms which + could be used by Bluetooth host. diff --git a/lib/bt/common/btc/core/btc_task.c b/lib/bt/common/btc/core/btc_task.c index 179d501e..0f2b6bc0 100644 --- a/lib/bt/common/btc/core/btc_task.c +++ b/lib/bt/common/btc/core/btc_task.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -98,7 +98,7 @@ osi_thread_t *btc_thread; static const btc_func_t profile_tab[BTC_PID_NUM] = { #ifdef CONFIG_BT_BLUEDROID_ENABLED [BTC_PID_MAIN_INIT] = {btc_main_call_handler, NULL }, - [BTC_PID_DEV] = {btc_dev_call_handler, NULL }, + [BTC_PID_DEV] = {btc_dev_call_handler, btc_dev_cb_handler }, #if (GATTS_INCLUDED == TRUE) [BTC_PID_GATTS] = {btc_gatts_call_handler, btc_gatts_cb_handler }, #endif ///GATTS_INCLUDED == TRUE @@ -405,6 +405,13 @@ static void btc_deinit_mem(void) { #endif #endif +#if BTC_HF_INCLUDED == TRUE && HFP_DYNAMIC_MEMORY == TRUE + if (hf_local_param_ptr) { + osi_free(hf_local_param_ptr); + hf_local_param_ptr = NULL; + } +#endif + #if BTC_HF_CLIENT_INCLUDED == TRUE && HFP_DYNAMIC_MEMORY == TRUE if (hf_client_local_param_ptr) { osi_free(hf_client_local_param_ptr); @@ -460,6 +467,13 @@ static bt_status_t btc_init_mem(void) { #endif #endif +#if BTC_HF_INCLUDED == TRUE && HFP_DYNAMIC_MEMORY == TRUE + if ((hf_local_param_ptr = (hf_local_param_t *)osi_malloc(BTC_HF_NUM_CB * sizeof(hf_local_param_t))) == NULL) { + goto error_exit; + } + memset((void *)hf_local_param_ptr, 0, BTC_HF_NUM_CB * sizeof(hf_local_param_t)); +#endif + #if BTC_HF_CLIENT_INCLUDED == TRUE && HFP_DYNAMIC_MEMORY == TRUE if ((hf_client_local_param_ptr = (hf_client_local_param_t *)osi_malloc(sizeof(hf_client_local_param_t))) == NULL) { goto error_exit; diff --git a/lib/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c b/lib/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c index a0da30f4..47022992 100644 --- a/lib/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c +++ b/lib/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c @@ -241,7 +241,7 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) case BTA_GATTS_CREATE_EVT: blufi_env.handle_srvc = p_data->create.service_id; - //add the frist blufi characteristic --> write characteristic + //add the first blufi characteristic --> write characteristic BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_p2e, (GATT_PERM_WRITE), (GATT_CHAR_PROP_BIT_WRITE), diff --git a/lib/bt/common/btc/profile/esp/blufi/include/blufi_int.h b/lib/bt/common/btc/profile/esp/blufi/include/blufi_int.h index 5730f143..e85ad73d 100644 --- a/lib/bt/common/btc/profile/esp/blufi/include/blufi_int.h +++ b/lib/bt/common/btc/profile/esp/blufi/include/blufi_int.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +9,11 @@ #include "btc/btc_task.h" #include "esp_blufi_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + #if (BLUFI_INCLUDED == TRUE) #define BTC_BLUFI_GREAT_VER 0x01 //Version + Subversion @@ -193,5 +198,10 @@ void btc_blufi_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); void btc_blufi_cb_deep_free(btc_msg_t *msg); -#endif /* __BLUFI_INT_H__ */ -#endif ///BLUFI_INCLUDED == TRUE +#endif ///BLUFI_INCLUDED == TRUE + +#ifdef __cplusplus +} +#endif + +#endif /* __BLUFI_INT_H__ */ diff --git a/lib/bt/common/btc/profile/esp/blufi/include/esp_blufi.h b/lib/bt/common/btc/profile/esp/blufi/include/esp_blufi.h index a368325d..db2203b1 100644 --- a/lib/bt/common/btc/profile/esp/blufi/include/esp_blufi.h +++ b/lib/bt/common/btc/profile/esp/blufi/include/esp_blufi.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,6 +20,10 @@ #include "esp_gap_ble_api.h" #endif +#ifdef __cplusplus +extern "C" { +#endif + #define BLUFI_APP_UUID 0xFFFF #define BLUFI_DEVICE_NAME "BLUFI_DEVICE" @@ -96,4 +100,7 @@ void esp_blufi_send_encap(void *arg); int esp_blufi_handle_gap_events(struct ble_gap_event *event, void *arg); #endif +#ifdef __cplusplus +} +#endif #endif/* _ESP_BLUFI_ */ diff --git a/lib/bt/common/btc/profile/esp/include/btc_blufi_prf.h b/lib/bt/common/btc/profile/esp/include/btc_blufi_prf.h index 347c4428..1174f01e 100644 --- a/lib/bt/common/btc/profile/esp/include/btc_blufi_prf.h +++ b/lib/bt/common/btc/profile/esp/include/btc_blufi_prf.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -21,6 +21,11 @@ #define ESP_BLUFI_SUCCESS 0x00 #endif + +#ifdef __cplusplus +extern "C" { +#endif + #define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x" #define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] @@ -100,4 +105,7 @@ void btc_blufi_call_deep_free(btc_msg_t *msg); uint16_t btc_blufi_get_version(void); +#ifdef __cplusplus +} +#endif #endif /* __BTC_BLUFI_PRF_H__ */ diff --git a/lib/bt/common/hci_log/bt_hci_log.c b/lib/bt/common/hci_log/bt_hci_log.c new file mode 100644 index 00000000..e35bf1a7 --- /dev/null +++ b/lib/bt/common/hci_log/bt_hci_log.c @@ -0,0 +1,334 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "hci_log/bt_hci_log.h" +#include "bt_common.h" +#include "osi/mutex.h" +#include "esp_attr.h" + +#if (BT_HCI_LOG_INCLUDED == TRUE) +#define BT_HCI_LOG_PRINT_TAG (1) +#define BT_HCI_LOG_DATA_BUF_SIZE (1024 * HCI_LOG_DATA_BUFFER_SIZE) +#define BT_HCI_LOG_ADV_BUF_SIZE (1024 * HCI_LOG_ADV_BUFFER_SIZE) + +typedef struct { + osi_mutex_t mutex_lock; + uint64_t log_record_in; + uint64_t log_record_out; + uint64_t buf_size; + uint8_t *p_hci_log_buffer; + uint8_t index; + bool overflow; +} bt_hci_log_t; + +static const char s_hex_to_char_mapping[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +static bt_hci_log_t g_bt_hci_log_data_ctl = {0}; +static bt_hci_log_t g_bt_hci_log_adv_ctl = {0}; + +esp_err_t bt_hci_log_init(void) +{ + uint8_t *g_bt_hci_log_data_buffer = NULL; + uint8_t *g_bt_hci_log_adv_buffer = NULL; + + g_bt_hci_log_data_buffer = malloc(BT_HCI_LOG_DATA_BUF_SIZE); + if (!g_bt_hci_log_data_buffer) { + return ESP_ERR_NO_MEM; + } + g_bt_hci_log_adv_buffer = malloc(BT_HCI_LOG_ADV_BUF_SIZE); + if (!g_bt_hci_log_adv_buffer) { + if (g_bt_hci_log_data_buffer) { + free(g_bt_hci_log_data_buffer); + g_bt_hci_log_data_buffer = NULL; + } + return ESP_ERR_NO_MEM; + } + + memset(g_bt_hci_log_data_buffer, 0, BT_HCI_LOG_DATA_BUF_SIZE); + memset(g_bt_hci_log_adv_buffer, 0, BT_HCI_LOG_ADV_BUF_SIZE); + + memset(&g_bt_hci_log_data_ctl, 0, sizeof(bt_hci_log_t)); + g_bt_hci_log_data_ctl.buf_size = BT_HCI_LOG_DATA_BUF_SIZE; + g_bt_hci_log_data_ctl.p_hci_log_buffer = g_bt_hci_log_data_buffer; + + memset(&g_bt_hci_log_adv_ctl, 0, sizeof(bt_hci_log_t)); + g_bt_hci_log_adv_ctl.buf_size = BT_HCI_LOG_ADV_BUF_SIZE; + g_bt_hci_log_adv_ctl.p_hci_log_buffer = g_bt_hci_log_adv_buffer; + + osi_mutex_new((osi_mutex_t *)&g_bt_hci_log_data_ctl.mutex_lock); + osi_mutex_new((osi_mutex_t *)&g_bt_hci_log_adv_ctl.mutex_lock); + + return ESP_OK; +} + +esp_err_t bt_hci_log_deinit(void) +{ + if (g_bt_hci_log_data_ctl.p_hci_log_buffer) { + free(g_bt_hci_log_data_ctl.p_hci_log_buffer); + g_bt_hci_log_data_ctl.p_hci_log_buffer = NULL; + } + + if (g_bt_hci_log_adv_ctl.p_hci_log_buffer) { + free(g_bt_hci_log_adv_ctl.p_hci_log_buffer); + g_bt_hci_log_adv_ctl.p_hci_log_buffer = NULL; + } + + osi_mutex_free((osi_mutex_t *)&g_bt_hci_log_data_ctl.mutex_lock); + osi_mutex_free((osi_mutex_t *)&g_bt_hci_log_adv_ctl.mutex_lock); + + memset(&g_bt_hci_log_data_ctl, 0, sizeof(bt_hci_log_t)); + memset(&g_bt_hci_log_adv_ctl, 0, sizeof(bt_hci_log_t)); + + return ESP_OK; +} + +#if (BT_HCI_LOG_PRINT_TAG) +static char IRAM_ATTR *bt_data_type_to_str(uint8_t data_type) +{ + char *tag = NULL; + switch (data_type) + { + case HCI_LOG_DATA_TYPE_COMMAND: + // hci cmd data + tag = "C"; + break; + case HCI_LOG_DATA_TYPE_H2C_ACL: + // host to controller hci acl data + tag = "H"; + break; + case HCI_LOG_DATA_TYPE_SCO: + // hci sco data + tag = "S"; + break; + case HCI_LOG_DATA_TYPE_EVENT: + // hci event + tag = "E"; + break; + case HCI_LOG_DATA_TYPE_ADV: + // controller adv report data + tag = NULL; + break; + case HCI_LOG_DATA_TYPE_C2H_ACL: + // controller to host hci acl data + tag = "D"; + break; + case HCI_LOG_DATA_TYPE_SELF_DEFINE: + // self-defining data + tag = "S"; + break; + default: + // unknown data type + tag = "U"; + break; + } + + return tag; +} +#endif + +void bt_hci_log_record_hex(bt_hci_log_t *p_hci_log_ctl, uint8_t *hex, uint8_t hex_len) +{ + uint8_t hci_log_char; + uint8_t *g_hci_log_buffer; + + g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer; + + while (hex_len--) + { + hci_log_char = ((*hex) >> 4); + + g_hci_log_buffer[p_hci_log_ctl->log_record_in] = s_hex_to_char_mapping [hci_log_char]; + + if (++ p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) { + p_hci_log_ctl->log_record_in = 0; + } + if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) { + p_hci_log_ctl->overflow = true; + } + + hci_log_char = ((*hex) & 0x0f); + + g_hci_log_buffer[p_hci_log_ctl->log_record_in] = s_hex_to_char_mapping [hci_log_char]; + + if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) { + p_hci_log_ctl->log_record_in = 0; + } + + if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) { + p_hci_log_ctl->overflow = true; + } + + g_hci_log_buffer[p_hci_log_ctl->log_record_in] = ' '; + + if (++ p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) { + p_hci_log_ctl->log_record_in = 0; + } + if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) { + p_hci_log_ctl->overflow = true; + } + + ++ hex; + } +} + +void bt_hci_log_record_string(bt_hci_log_t *p_hci_log_ctl, char *string) +{ + uint8_t *g_hci_log_buffer; + + g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer; + + while (*string != '\0') { + g_hci_log_buffer[p_hci_log_ctl->log_record_in] = *string; + ++string; + + if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) { + p_hci_log_ctl->log_record_in = 0; + } + + if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) { + p_hci_log_ctl->overflow = true; + } + } +} + +esp_err_t IRAM_ATTR bt_hci_log_record_data(bt_hci_log_t *p_hci_log_ctl, char *str, uint8_t data_type, uint8_t *data, uint8_t data_len) +{ + osi_mutex_t mutex_lock; + uint8_t *g_hci_log_buffer; + + if (!p_hci_log_ctl->p_hci_log_buffer) { + return ESP_FAIL; + } + + g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer; + + if (!g_hci_log_buffer) { + return ESP_FAIL; + } + + mutex_lock = p_hci_log_ctl->mutex_lock; + osi_mutex_lock(&mutex_lock, OSI_MUTEX_MAX_TIMEOUT); + +#if (1) + // Add hci data index + bt_hci_log_record_hex(p_hci_log_ctl, &p_hci_log_ctl->index, 1); +#endif + +#if (BT_HCI_LOG_PRINT_TAG) + char *tag = NULL; + tag = bt_data_type_to_str(data_type); + + if (tag) { + bt_hci_log_record_string(p_hci_log_ctl, tag); + + g_hci_log_buffer[p_hci_log_ctl->log_record_in] = ':'; + + if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) { + p_hci_log_ctl->log_record_in = 0; + } + + if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) { + p_hci_log_ctl->overflow = true; + } + } +#endif + + if (str) { + bt_hci_log_record_string(p_hci_log_ctl, str); + } + + bt_hci_log_record_hex(p_hci_log_ctl, data, data_len); + + g_hci_log_buffer[p_hci_log_ctl->log_record_in] = '\n'; + + if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) { + p_hci_log_ctl->log_record_in = 0; + } + + if (p_hci_log_ctl->log_record_in == p_hci_log_ctl->log_record_out) { + p_hci_log_ctl->overflow = true; + } + + p_hci_log_ctl->index ++; + + osi_mutex_unlock(&mutex_lock); + + return ESP_OK; +} + +void bt_hci_log_data_show(bt_hci_log_t *p_hci_log_ctl) +{ + volatile uint64_t log_record_in,log_record_out; + uint8_t *g_hci_log_buffer; + + if (!p_hci_log_ctl->p_hci_log_buffer) { + return; + } + + osi_mutex_t mutex_lock = p_hci_log_ctl->mutex_lock; + + osi_mutex_lock(&mutex_lock, OSI_MUTEX_MAX_TIMEOUT); + + log_record_in = p_hci_log_ctl->log_record_in; + log_record_out = p_hci_log_ctl->log_record_out; + + g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer; + + if (p_hci_log_ctl->overflow) { + log_record_out = log_record_in; + printf("%c",g_hci_log_buffer[log_record_out]); + + if (++log_record_out >= p_hci_log_ctl->buf_size) { + log_record_out = 0; + } + } + + while (log_record_in != log_record_out) + { + printf("%c",g_hci_log_buffer[log_record_out]); + + if (++log_record_out >= p_hci_log_ctl->buf_size) { + log_record_out = 0; + } + } + + p_hci_log_ctl->log_record_out = log_record_out; + p_hci_log_ctl->overflow = false; + + osi_mutex_unlock(&mutex_lock); +} + +esp_err_t IRAM_ATTR bt_hci_log_record_hci_data(uint8_t data_type, uint8_t *data, uint8_t data_len) +{ + return bt_hci_log_record_data(&g_bt_hci_log_data_ctl, NULL, data_type, data, data_len); +} + +esp_err_t IRAM_ATTR bt_hci_log_record_custom_data(char *string, uint8_t *data, uint8_t data_len) +{ + return bt_hci_log_record_data(&g_bt_hci_log_data_ctl, string, HCI_LOG_DATA_TYPE_SELF_DEFINE, data, data_len); +} + +esp_err_t IRAM_ATTR bt_hci_log_record_hci_adv(uint8_t data_type, uint8_t *data, uint8_t data_len) +{ + return bt_hci_log_record_data(&g_bt_hci_log_adv_ctl, NULL, data_type, data, data_len); +} + +void bt_hci_log_hci_data_show(void) +{ + bt_hci_log_data_show(&g_bt_hci_log_data_ctl); +} + +void bt_hci_log_hci_adv_show(void) +{ + bt_hci_log_data_show(&g_bt_hci_log_adv_ctl); +} + +#endif // (BT_HCI_LOG_INCLUDED == TRUE) diff --git a/lib/bt/common/hci_log/include/hci_log/bt_hci_log.h b/lib/bt/common/hci_log/include/hci_log/bt_hci_log.h new file mode 100644 index 00000000..512a307e --- /dev/null +++ b/lib/bt/common/hci_log/include/hci_log/bt_hci_log.h @@ -0,0 +1,108 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ESP_BT_HCI_LOG_H__ +#define __ESP_BT_HCI_LOG_H__ + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define HCI_LOG_DATA_TYPE_COMMAND (1) +#define HCI_LOG_DATA_TYPE_H2C_ACL (2) +#define HCI_LOG_DATA_TYPE_SCO (3) +#define HCI_LOG_DATA_TYPE_EVENT (4) +#define HCI_LOG_DATA_TYPE_ADV (5) +#define HCI_LOG_DATA_TYPE_SELF_DEFINE (6) +#define HCI_LOG_DATA_TYPE_C2H_ACL (7) + +/** + * + * @brief This function is called to record self-defining data + * @param string : data identification + * @param data : data + * @param data_len : the length of data + * + * @return ESP_OK - success, other - failed + * + */ +esp_err_t bt_hci_log_record_custom_data(char *string, uint8_t *data, uint8_t data_len); +/** + * + * @brief This function is called to print all hci data record + * + * + * @return None + * + */ +void bt_hci_log_hci_data_show(void); + +/** + * + * @brief This function is called to print all adv report + * + * + * @return None + * + */ +void bt_hci_log_hci_adv_show(void); + +/** + * + * @brief This function is called to init hci log env + * + * + * @return ESP_OK - success, other - failed + * + */ +esp_err_t bt_hci_log_init(void); + +/** + * + * @brief This function is called to deinit hci debug mode, + * and can only be called internally by Bluetooth + * + * + * @return ESP_OK - success, other - failed + * + */ +esp_err_t bt_hci_log_deinit(void); + +/** + * + * @brief This function is called to record hci data without adv report event, + * and can only be called internally by Bluetooth + * + * @param str : data type, define in bt_data_type_to_str() + * @param data : data + * @param data_len : the length of data + * + * @return ESP_OK - success, other - failed + * + */ +esp_err_t bt_hci_log_record_hci_data(uint8_t data_type, uint8_t *data, uint8_t data_len); + +/** + * + * @brief This function is called to record hci adv report event only + * and can only be called internally by Bluetooth + * + * @param str : data type, define in bt_data_type_to_str() + * @param data : data + * @param data_len : the length of data + * @return ESP_OK - success, other - failed + * + */ +esp_err_t bt_hci_log_record_hci_adv(uint8_t data_type, uint8_t *data, uint8_t data_len); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BT_HCI_LOG_H__ */ diff --git a/lib/bt/common/include/bt_common.h b/lib/bt/common/include/bt_common.h index 134cf33c..f3c5ba0e 100644 --- a/lib/bt/common/include/bt_common.h +++ b/lib/bt/common/include/bt_common.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -64,6 +64,24 @@ #define BT_BLE_DYNAMIC_ENV_MEMORY FALSE #endif +#if UC_BT_HCI_LOG_DEBUG_EN +#define BT_HCI_LOG_INCLUDED UC_BT_HCI_LOG_DEBUG_EN +#else +#define BT_HCI_LOG_INCLUDED FALSE +#endif + +#if UC_BT_HCI_LOG_DATA_BUFFER_SIZE +#define HCI_LOG_DATA_BUFFER_SIZE UC_BT_HCI_LOG_DATA_BUFFER_SIZE +#else +#define HCI_BUFFER_SIZE (5) +#endif + +#if UC_BT_HCI_ADV_BUFFER_SIZE +#define HCI_LOG_ADV_BUFFER_SIZE UC_BT_HCI_LOG_ADV_BUFFER_SIZE +#else +#define HCI_LOG_ADV_BUFFER_SIZE (5) +#endif + /* OS Configuration from User config (eg: sdkconfig) */ #define TASK_PINNED_TO_CORE UC_TASK_PINNED_TO_CORE #define BT_TASK_MAX_PRIORITIES configMAX_PRIORITIES diff --git a/lib/bt/common/include/bt_user_config.h b/lib/bt/common/include/bt_user_config.h index 738f4f2c..029766b7 100644 --- a/lib/bt/common/include/bt_user_config.h +++ b/lib/bt/common/include/bt_user_config.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,7 +39,7 @@ * Thread/Task reference **********************************************************/ #ifdef CONFIG_BT_BLUEDROID_PINNED_TO_CORE -#define UC_TASK_PINNED_TO_CORE (CONFIG_BT_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BT_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY) +#define UC_TASK_PINNED_TO_CORE (CONFIG_BT_BLUEDROID_PINNED_TO_CORE < CONFIG_FREERTOS_NUMBER_OF_CORES ? CONFIG_BT_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY) #else #define UC_TASK_PINNED_TO_CORE (0) #endif @@ -50,6 +50,15 @@ #define UC_BTC_TASK_STACK_SIZE 4096 #endif +/********************************************************** + * Alarm reference + **********************************************************/ +#ifdef CONFIG_BT_ALARM_MAX_NUM +#define UC_ALARM_MAX_NUM CONFIG_BT_ALARM_MAX_NUM +#else +#define UC_ALARM_MAX_NUM 50 +#endif + /********************************************************** * Trace reference **********************************************************/ @@ -98,4 +107,22 @@ #define UC_BT_BLUEDROID_MEM_DEBUG FALSE #endif +#ifdef CONFIG_BT_HCI_LOG_DEBUG_EN +#define UC_BT_HCI_LOG_DEBUG_EN TRUE +#else +#define UC_BT_HCI_LOG_DEBUG_EN FALSE +#endif + +#ifdef CONFIG_BT_HCI_LOG_DATA_BUFFER_SIZE +#define UC_BT_HCI_LOG_DATA_BUFFER_SIZE CONFIG_BT_HCI_LOG_DATA_BUFFER_SIZE +#else +#define UC_BT_HCI_LOG_DATA_BUFFER_SIZE (5) +#endif + +#ifdef CONFIG_BT_HCI_LOG_ADV_BUFFER_SIZE +#define UC_BT_HCI_LOG_ADV_BUFFER_SIZE CONFIG_BT_HCI_LOG_ADV_BUFFER_SIZE +#else +#define UC_BT_HCI_LOG_ADV_BUFFER_SIZE (5) +#endif + #endif /* __BT_USER_CONFIG_H__ */ diff --git a/lib/bt/common/osi/include/osi/alarm.h b/lib/bt/common/osi/include/osi/alarm.h index fe8344cd..0ac1d11c 100644 --- a/lib/bt/common/osi/include/osi/alarm.h +++ b/lib/bt/common/osi/include/osi/alarm.h @@ -21,6 +21,7 @@ #include #include "esp_timer.h" +#include "bt_user_config.h" typedef struct alarm_t osi_alarm_t; typedef uint64_t period_ms_t; @@ -33,7 +34,7 @@ typedef enum { OSI_ALARM_ERR_INVALID_STATE = -3, } osi_alarm_err_t; -#define ALARM_CBS_NUM 50 +#define ALARM_CBS_NUM UC_ALARM_MAX_NUM #define ALARM_ID_BASE 1000 int osi_alarm_create_mux(void); diff --git a/lib/bt/controller/esp32/Kconfig.in b/lib/bt/controller/esp32/Kconfig.in index 2d7cbf85..7254a6ae 100644 --- a/lib/bt/controller/esp32/Kconfig.in +++ b/lib/bt/controller/esp32/Kconfig.in @@ -172,7 +172,7 @@ config BTDM_CTRL_PINNED_TO_CORE choice BTDM_CTRL_HCI_MODE_CHOICE prompt "HCI mode" help - Speicify HCI mode as VHCI or UART(H4) + Specify HCI mode as VHCI or UART(H4) config BTDM_CTRL_HCI_MODE_VHCI bool "VHCI" @@ -398,6 +398,14 @@ config BTDM_CTRL_FULL_SCAN_SUPPORTED The full scan function is mainly used to provide BLE scan performance. This is required for scenes with high scan performance requirements, such as BLE Mesh scenes. +config BTDM_CTRL_SCAN_BACKOFF_UPPERLIMITMAX + bool "Disable active scan backoff" + default n + help + Disable active scan backoff. The bluetooth spec requires that scanners should run a backoff procedure to + minimize collision of scan request PDUs from nultiple scanners. If scan backoff is disabled, in active + scanning, scan request PDU will be sent every time when HW receives scannable ADV PDU. + config BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP bool "BLE adv report flow control supported" depends on (BTDM_CTRL_MODE_BTDM || BTDM_CTRL_MODE_BLE_ONLY) diff --git a/lib/bt/controller/esp32/bt.c b/lib/bt/controller/esp32/bt.c index d8792e0f..f26dd4bc 100644 --- a/lib/bt/controller/esp32/bt.c +++ b/lib/bt/controller/esp32/bt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,7 +25,9 @@ #include "esp_task.h" #include "esp_intr_alloc.h" #include "esp_attr.h" +#ifdef CONFIG_ESP_PHY_ENABLED #include "esp_phy_init.h" +#endif #include "esp_bt.h" #include "esp_err.h" #include "esp_log.h" @@ -35,7 +37,9 @@ #include "soc/rtc.h" #include "soc/soc_memory_layout.h" #include "soc/dport_reg.h" +#ifdef CONFIG_ESP_COEX_ENABLED #include "private/esp_coexist_internal.h" +#endif #include "esp_timer.h" #if !CONFIG_FREERTOS_UNICORE #include "esp_ipc.h" @@ -89,7 +93,7 @@ do{\ } while(0) #define OSI_FUNCS_TIME_BLOCKING 0xffffffff -#define OSI_VERSION 0x00010004 +#define OSI_VERSION 0x00010005 #define OSI_MAGIC_VALUE 0xFADEBEAD /* Types definition @@ -176,6 +180,7 @@ struct osi_funcs_t { void (*_interrupt_l3_restore)(void); void *(* _customer_queue_create)(uint32_t queue_len, uint32_t item_size); int (* _coex_version_get)(unsigned int *major, unsigned int *minor, unsigned int *patch); + void (* _patch_apply)(void); uint32_t _magic; }; @@ -232,16 +237,16 @@ extern uint32_t _data_end_btdm_rom; extern uint32_t _bt_bss_start; extern uint32_t _bt_bss_end; -extern uint32_t _nimble_bss_start; -extern uint32_t _nimble_bss_end; -extern uint32_t _btdm_bss_start; -extern uint32_t _btdm_bss_end; +extern uint32_t _bt_controller_bss_start; +extern uint32_t _bt_controller_bss_end; extern uint32_t _bt_data_start; extern uint32_t _bt_data_end; -extern uint32_t _nimble_data_start; -extern uint32_t _nimble_data_end; -extern uint32_t _btdm_data_start; -extern uint32_t _btdm_data_end; +extern uint32_t _bt_controller_data_start; +extern uint32_t _bt_controller_data_end; + +extern void config_bt_funcs_reset(void); +extern void config_ble_funcs_reset(void); +extern void config_btdm_funcs_reset(void); /* Local Function Declare ********************************************************************* @@ -315,6 +320,7 @@ static void *customer_queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t i static void interrupt_l3_disable(void); static void interrupt_l3_restore(void); static void bt_controller_deinit_internal(void); +static void patch_apply(void); /* Local variable definition *************************************************************************** @@ -402,6 +408,7 @@ static const struct osi_funcs_t osi_funcs_ro = { ._customer_queue_create = NULL, #endif /* CONFIG_BTDM_CTRL_HLI */ ._coex_version_get = coex_version_get_wrapper, + ._patch_apply = patch_apply, ._magic = OSI_MAGIC_VALUE, }; @@ -753,7 +760,7 @@ static int32_t queue_send_hlevel_wrapper(void *queue, void *item, uint32_t block * @param item The message which will be send * @param hptw need do task yield or not * @return send success or not - * There is an issue here: When the queue is full, it may reture true but it send fail to the queue, sometimes. + * There is an issue here: When the queue is full, it may return true but it send fail to the queue, sometimes. * But in Bluetooth controller's isr, We don't care about the return value. * It only required tp send success when the queue is empty all the time. * So, this function meets the requirement. @@ -823,7 +830,7 @@ static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, vo static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id) { - return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); + return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < CONFIG_FREERTOS_NUMBER_OF_CORES ? core_id : tskNO_AFFINITY)); } static void task_delete_wrapper(void *task_handle) @@ -1274,7 +1281,45 @@ static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) return ret; } -esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +typedef struct { + intptr_t start; + intptr_t end; + const char* name; +} bt_area_t; + + +static esp_err_t esp_bt_mem_release_area(const bt_area_t *area) +{ + esp_err_t ret = ESP_OK; + intptr_t mem_start = area->start; + intptr_t mem_end = area->end; + if (mem_start != mem_end) { + ESP_LOGD(BTDM_LOG_TAG, "Release %s [0x%08x] - [0x%08x], len %d", area->name, mem_start, mem_end, mem_end - mem_start); + ret = try_heap_caps_add_region(mem_start, mem_end); + } + return ret; +} + +static esp_err_t esp_bt_mem_release_areas(const bt_area_t *area1, const bt_area_t *area2) +{ + esp_err_t ret = ESP_OK; + + if (area1->end == area2->start) { + bt_area_t merged_area = { + .start = area1->start, + .end = area2->end, + .name = area1->name + }; + ret = esp_bt_mem_release_area(&merged_area); + } else { + esp_bt_mem_release_area(area1); + ret = esp_bt_mem_release_area(area2); + } + + return ret; +} + +static esp_err_t esp_bt_controller_rom_mem_release(esp_bt_mode_t mode) { bool update = true; intptr_t mem_start=(intptr_t) NULL, mem_end=(intptr_t) NULL; @@ -1325,61 +1370,86 @@ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) } } + return ESP_OK; +} + +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +{ + esp_err_t ret = ESP_OK; + + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; + } + if (mode == ESP_BT_MODE_BTDM) { - mem_start = (intptr_t)&_btdm_bss_start; - mem_end = (intptr_t)&_btdm_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(BTDM_LOG_TAG, "Release BTDM BSS [0x%08x] - [0x%08x]", mem_start, mem_end); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - mem_start = (intptr_t)&_btdm_data_start; - mem_end = (intptr_t)&_btdm_data_end; - if (mem_start != mem_end) { - ESP_LOGD(BTDM_LOG_TAG, "Release BTDM Data [0x%08x] - [0x%08x]", mem_start, mem_end); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + bt_area_t cont_bss = { + .start = (intptr_t)&_bt_controller_bss_start, + .end = (intptr_t)&_bt_controller_bss_end, + .name = "BT Controller BSS", + }; + bt_area_t cont_data = { + .start = (intptr_t)&_bt_controller_data_start, + .end = (intptr_t)&_bt_controller_data_end, + .name = "BT Controller Data" + }; + + ret = esp_bt_mem_release_areas(&cont_data, &cont_bss); } - return ESP_OK; + + if (ret == ESP_OK) { + ret = esp_bt_controller_rom_mem_release(mode); + } + + return ret; } esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) { - int ret; - intptr_t mem_start, mem_end; + esp_err_t ret = ESP_OK; - ret = esp_bt_controller_mem_release(mode); - if (ret != ESP_OK) { - return ret; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; } + bt_area_t bss = { + .start = (intptr_t)&_bt_bss_start, + .end = (intptr_t)&_bt_bss_end, + .name = "BT BSS", + }; + bt_area_t cont_bss = { + .start = (intptr_t)&_bt_controller_bss_start, + .end = (intptr_t)&_bt_controller_bss_end, + .name = "BT Controller BSS", + }; + bt_area_t data = { + .start = (intptr_t)&_bt_data_start, + .end = (intptr_t)&_bt_data_end, + .name = "BT Data", + }; + bt_area_t cont_data = { + .start = (intptr_t)&_bt_controller_data_start, + .end = (intptr_t)&_bt_controller_data_end, + .name = "BT Controller Data" + }; + if (mode == ESP_BT_MODE_BTDM) { - mem_start = (intptr_t)&_bt_bss_start; - mem_end = (intptr_t)&_bt_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(BTDM_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x]", mem_start, mem_end); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - mem_start = (intptr_t)&_bt_data_start; - mem_end = (intptr_t)&_bt_data_end; - if (mem_start != mem_end) { - ESP_LOGD(BTDM_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x]", mem_start, mem_end); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + /* Start by freeing Bluetooth BSS section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&bss, &cont_bss); } - mem_start = (intptr_t)&_nimble_bss_start; - mem_end = (intptr_t)&_nimble_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(BTDM_LOG_TAG, "Release NimBLE BSS [0x%08x] - [0x%08x]", mem_start, mem_end); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - mem_start = (intptr_t)&_nimble_data_start; - mem_end = (intptr_t)&_nimble_data_end; - if (mem_start != mem_end) { - ESP_LOGD(BTDM_LOG_TAG, "Release NimBLE Data [0x%08x] - [0x%08x]", mem_start, mem_end); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + /* Do the same thing with the Bluetooth data section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&data, &cont_data); } } - return ESP_OK; + + /* free data and BSS section for Bluetooth controller ROM code */ + if (ret == ESP_OK) { + ret = esp_bt_controller_rom_mem_release(mode); + } + + return ret; } #if CONFIG_BTDM_CTRL_HLI @@ -1643,6 +1713,18 @@ static void bt_shutdown(void) return; } +static void patch_apply(void) +{ + config_btdm_funcs_reset(); + +#ifndef CONFIG_BTDM_CTRL_MODE_BLE_ONLY + config_bt_funcs_reset(); +#endif + +#ifndef CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY + config_ble_funcs_reset(); +#endif +} esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) { @@ -1676,7 +1758,7 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) sdk_config_set_bt_pll_track_enable(true); - // inititalize bluetooth baseband + // initialize bluetooth baseband btdm_check_and_init_bb(); ret = btdm_controller_enable(mode); @@ -1839,7 +1921,7 @@ esp_err_t esp_ble_scan_dupilcate_list_flush(void) /** * This function re-write controller's function, - * As coredump can not show paramerters in function which is in a .a file. + * As coredump can not show parameters in function which is in a .a file. * * After coredump fixing this issue, just delete this function. */ diff --git a/lib/bt/controller/esp32c2/Kconfig.in b/lib/bt/controller/esp32c2/Kconfig.in index 05e15708..9a04ae63 100644 --- a/lib/bt/controller/esp32c2/Kconfig.in +++ b/lib/bt/controller/esp32c2/Kconfig.in @@ -147,7 +147,7 @@ if BT_LE_EXT_ADV Enable this option to start periodic advertisement. config BT_LE_PERIODIC_ADV_SYNC_TRANSFER - bool "Enable Transer Sync Events" + bool "Enable Transfer Sync Events" depends on BT_LE_ENABLE_PERIODIC_ADV default y help @@ -349,7 +349,6 @@ config BT_LE_CRYPTO_STACK_MBEDTLS bool "Override TinyCrypt with mbedTLS for crypto computations" default y depends on !BT_NIMBLE_ENABLED - select MBEDTLS_ECP_RESTARTABLE select MBEDTLS_CMAC_C help Enable this option to choose mbedTLS instead of TinyCrypt for crypto @@ -421,6 +420,26 @@ config BT_LE_SLEEP_ENABLE help Enable BLE sleep +choice BT_LE_LP_CLK_SRC + prompt "BLE low power clock source" + default BT_LE_LP_CLK_SRC_MAIN_XTAL + config BT_LE_LP_CLK_SRC_MAIN_XTAL + bool "Use main XTAL as RTC clock source" + help + User main XTAL as RTC clock source. + This option is recommended if external 32.768k XTAL is not available. + Using the external 32.768 kHz XTAL will have lower current consumption + in light sleep compared to using the main XTAL. + + config BT_LE_LP_CLK_SRC_DEFAULT + bool "Use system RTC slow clock source" + help + Use the same slow clock source as system RTC + Using any clock source other than external 32.768 kHz XTAL at pin0 supports only + legacy ADV and SCAN due to low clock accuracy. + +endchoice + config BT_LE_USE_ESP_TIMER bool "Use Esp Timer for callout" depends on !BT_NIMBLE_ENABLED @@ -430,6 +449,7 @@ config BT_LE_USE_ESP_TIMER config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP bool "BLE adv report flow control supported" + depends on BT_LE_ROLE_OBSERVER_ENABLE default y help The function is mainly used to enable flow control for advertising reports. When it is enabled, @@ -464,3 +484,45 @@ config BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD config BT_LE_RELEASE_IRAM_SUPPORTED bool 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. + +config BT_LE_ROLE_CENTROL_ENABLE + bool "Enable BLE Centrol role function" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable centrol role function. + +config BT_LE_ROLE_PERIPHERAL_ENABLE + bool "Enable BLE Peripheral role function" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable Peripheral role function. + +config BT_LE_ROLE_BROADCASTER_ENABLE + bool "Enable BLE Broadcaster role function" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable broadcaster role function. + +config BT_LE_ROLE_OBSERVER_ENABLE + bool "Enable BLE Observer role function" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable observer role function. diff --git a/lib/bt/controller/esp32c2/bt.c b/lib/bt/controller/esp32c2/bt.c index c1eff194..29c33326 100644 --- a/lib/bt/controller/esp32c2/bt.c +++ b/lib/bt/controller/esp32c2/bt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,26 +16,31 @@ #include "sdkconfig.h" +#if CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port.h" +#endif // CONFIG_BT_NIMBLE_ENABLED + #include "nimble/nimble_port_freertos.h" #ifdef ESP_PLATFORM #include "esp_log.h" #endif -#if CONFIG_SW_COEXIST_ENABLE +#ifdef CONFIG_ESP_COEX_ENABLED #include "private/esp_coexist_internal.h" #endif #include "nimble/nimble_npl_os.h" -#include "nimble/ble_hci_trans.h" +#include "ble_hci_trans.h" #include "os/endian.h" #include "esp_bt.h" #include "esp_intr_alloc.h" #include "esp_sleep.h" #include "esp_pm.h" +#ifdef CONFIG_ESP_PHY_ENABLED #include "esp_phy_init.h" +#endif #include "soc/syscon_reg.h" #include "soc/modem_clkrst_reg.h" #include "esp_private/periph_ctrl.h" @@ -54,12 +59,14 @@ #include "freertos/task.h" #include "esp_private/periph_ctrl.h" +#include "esp_private/esp_clk.h" #include "esp_sleep.h" #include "soc/syscon_reg.h" #include "soc/dport_access.h" #include "hal/efuse_ll.h" +#include "soc/rtc.h" /* Macro definition ************************************************************************ */ @@ -78,6 +85,11 @@ #define ACL_DATA_MBUF_LEADINGSPCAE 4 #endif // CONFIG_BT_BLUEDROID_ENABLED +typedef enum ble_rtc_slow_clk_src { + BT_SLOW_CLK_SRC_MAIN_XTAL, + BT_SLOW_CLK_SRC_32K_XTAL_ON_PIN0, +} ble_rtc_slow_clk_src_t; + /* Types definition ************************************************************************ */ @@ -156,14 +168,21 @@ extern int ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t hand extern int ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); extern int ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); extern void bt_track_pll_cap(void); - +extern char *ble_controller_get_compile_version(void); +extern const char *r_ble_controller_get_rom_compile_version(void); #if CONFIG_BT_RELEASE_IRAM extern uint32_t _iram_bt_text_start; extern uint32_t _bss_bt_end; -#else +#endif + +extern uint32_t _bt_bss_start; extern uint32_t _bt_bss_end; +extern uint32_t _bt_controller_bss_start; +extern uint32_t _bt_controller_bss_end; +extern uint32_t _bt_data_start; +extern uint32_t _bt_data_end; extern uint32_t _bt_controller_data_start; -#endif +extern uint32_t _bt_controller_data_end; /* Local Function Declaration ********************************************************************* @@ -362,7 +381,7 @@ esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callba #endif // CONFIG_BT_BLUEDROID_ENABLED static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id) { - return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); + return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < CONFIG_FREERTOS_NUMBER_OF_CORES ? core_id : tskNO_AFFINITY)); } static void task_delete_wrapper(void *task_handle) @@ -486,7 +505,7 @@ IRAM_ATTR void controller_wakeup_cb(void *arg) s_ble_active = true; } -esp_err_t controller_sleep_init(void) +esp_err_t controller_sleep_init(ble_rtc_slow_clk_src_t slow_clk_src) { esp_err_t rc = 0; #ifdef CONFIG_BT_LE_SLEEP_ENABLE @@ -494,7 +513,11 @@ esp_err_t controller_sleep_init(void) r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, 500 + BLE_RTC_DELAY_US); #ifdef CONFIG_PM_ENABLE - esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); + if (slow_clk_src == BT_SLOW_CLK_SRC_MAIN_XTAL) { + esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); + } else { + esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_AUTO); + } #endif // CONFIG_PM_ENABLE #endif // CONFIG_BT_LE_SLEEP_ENABLE @@ -545,37 +568,74 @@ void controller_sleep_deinit(void) #endif //CONFIG_PM_ENABLE } -void ble_rtc_clk_init(void) +static void esp_bt_rtc_slow_clk_select(ble_rtc_slow_clk_src_t slow_clk_src) { - // modem_clkrst_reg - // LP_TIMER_SEL_XTAL32K -> 0 - // LP_TIMER_SEL_XTAL -> 1 - // LP_TIMER_SEL_8M -> 0 - // LP_TIMER_SEL_RTC_SLOW -> 0 - SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_XTAL32K_S); - SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 1, MODEM_CLKRST_LP_TIMER_SEL_XTAL_S); - SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_8M_S); - SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_RTC_SLOW_S); - + /* Select slow clock source for BT momdule */ + switch (slow_clk_src) { + case BT_SLOW_CLK_SRC_MAIN_XTAL: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using main XTAL as clock source"); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_XTAL32K_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 1, MODEM_CLKRST_LP_TIMER_SEL_XTAL_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_8M_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_RTC_SLOW_S); #ifdef CONFIG_XTAL_FREQ_26 - // LP_TIMER_CLK_DIV_NUM -> 130 - SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM, 129, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM, 129, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM_S); #else - // LP_TIMER_CLK_DIV_NUM -> 250 - SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM, 249, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM, 249, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM_S); #endif // CONFIG_XTAL_FREQ_26 - - // MODEM_CLKRST_ETM_CLK_ACTIVE -> 1 - // MODEM_CLKRST_ETM_CLK_SEL -> 0 + break; + case BT_SLOW_CLK_SRC_32K_XTAL_ON_PIN0: + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using external 32.768 kHz XTAL as clock source"); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 1, MODEM_CLKRST_LP_TIMER_SEL_XTAL32K_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_XTAL_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_8M_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, 1, 0, MODEM_CLKRST_LP_TIMER_SEL_RTC_SLOW_S); + SET_PERI_REG_BITS(MODEM_CLKRST_MODEM_LP_TIMER_CONF_REG, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM, 0, MODEM_CLKRST_LP_TIMER_CLK_DIV_NUM_S); + break; + default: + ESP_LOGE(NIMBLE_PORT_LOG_TAG, "Unsupported slow clock"); + assert(0); + break; + } SET_PERI_REG_BITS(MODEM_CLKRST_ETM_CLK_CONF_REG, 1, 1, MODEM_CLKRST_ETM_CLK_ACTIVE_S); SET_PERI_REG_BITS(MODEM_CLKRST_ETM_CLK_CONF_REG, 1, 0, MODEM_CLKRST_ETM_CLK_SEL_S); +} +static ble_rtc_slow_clk_src_t ble_rtc_clk_init(esp_bt_controller_config_t *cfg) +{ + ble_rtc_slow_clk_src_t slow_clk_src; + +#if CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL +#ifdef CONFIG_XTAL_FREQ_26 + cfg->rtc_freq = 40000; +#else + cfg->rtc_freq = 32000; +#endif // CONFIG_XTAL_FREQ_26 + slow_clk_src = BT_SLOW_CLK_SRC_MAIN_XTAL; +#else + if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) { + cfg->rtc_freq = 32768; + slow_clk_src = BT_SLOW_CLK_SRC_32K_XTAL_ON_PIN0; + } else { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock"); +#ifdef CONFIG_XTAL_FREQ_26 + cfg->rtc_freq = 40000; +#else + cfg->rtc_freq = 32000; +#endif // CONFIG_XTAL_FREQ_26 + slow_clk_src = BT_SLOW_CLK_SRC_MAIN_XTAL; + } +#endif /* CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL */ + esp_bt_rtc_slow_clk_select(slow_clk_src); + return slow_clk_src; } esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) { esp_err_t ret = ESP_OK; ble_npl_count_info_t npl_info; + ble_rtc_slow_clk_src_t rtc_clk_src; + memset(&npl_info, 0, sizeof(ble_npl_count_info_t)); if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); @@ -587,7 +647,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) return ESP_ERR_INVALID_ARG; } - ble_rtc_clk_init(); + rtc_clk_src = ble_rtc_clk_init(cfg); ret = esp_register_ext_funcs(&ext_funcs_ro); if (ret != ESP_OK) { @@ -595,6 +655,15 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) return ret; } +#if DEFAULT_BT_LE_50_FEATURE_SUPPORT || DEFAULT_BT_LE_ROLE_CENTROL || DEFAULT_BT_LE_ROLE_OBSERVER + extern int esp_ble_rom_func_ptr_init_all(void); + esp_ble_rom_func_ptr_init_all(); +#else + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Init only legacy adv and slave function"); + extern int esp_ble_rom_func_ptr_init_legacy_adv_and_slave(void); + esp_ble_rom_func_ptr_init_legacy_adv_and_slave(); +#endif + /* Initialize the function pointers for OS porting */ npl_freertos_funcs_init(); struct npl_funcs_t *p_npl_funcs = npl_freertos_funcs_get(); @@ -643,13 +712,15 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #if CONFIG_SW_COEXIST_ENABLE coex_init(); #endif - ret = ble_controller_init(cfg); if (ret != ESP_OK) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_init failed %d", ret); goto modem_deint; } + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble rom commit:[%s]", r_ble_controller_get_rom_compile_version()); + #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED interface_func_t bt_controller_log_interface; bt_controller_log_interface = esp_bt_controller_log_interface; @@ -671,7 +742,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) } #endif // CONFIG_BT_CONTROLLER_LOG_ENABLED - ret = controller_sleep_init(); + ret = controller_sleep_init(rtc_clk_src); if (ret != ESP_OK) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "controller_sleep_init failed %d", ret); goto free_controller; @@ -840,9 +911,48 @@ static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) return ret; } +typedef struct { + intptr_t start; + intptr_t end; + const char* name; +} bt_area_t; + +static esp_err_t esp_bt_mem_release_area(const bt_area_t *area) +{ + esp_err_t ret = ESP_OK; + intptr_t mem_start = area->start; + intptr_t mem_end = area->end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release %s [0x%08x] - [0x%08x], len %d", area->name, mem_start, mem_end, mem_end - mem_start); + ret = try_heap_caps_add_region(mem_start, mem_end); + } + return ret; +} + +#ifndef CONFIG_BT_RELEASE_IRAM +static esp_err_t esp_bt_mem_release_areas(const bt_area_t *area1, const bt_area_t *area2) +{ + esp_err_t ret = ESP_OK; + + if(area1->end == area2->start) { + bt_area_t merged_area = { + .start = area1->start, + .end = area2->end, + .name = area1->name + }; + ret = esp_bt_mem_release_area(&merged_area); + } else { + esp_bt_mem_release_area(area1); + ret = esp_bt_mem_release_area(area2); + } + + return ret; +} +#endif + esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) { - intptr_t mem_start, mem_end; + esp_err_t ret = ESP_OK; #if CONFIG_BT_RELEASE_IRAM && CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT /* Release Bluetooth text section and merge Bluetooth data, bss & text into a large free heap @@ -851,26 +961,58 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) * memory into 3 different regions (IRAM, BLE-IRAM, DRAM). So `ESP_SYSTEM_PMP_IDRAM_SPLIT` needs * to be disabled. */ - ESP_LOGE(NIMBLE_PORT_LOG_TAG, "`ESP_SYSTEM_PMP_IDRAM_SPLIT` should be disabled!"); - assert(0); + #error "ESP_SYSTEM_PMP_IDRAM_SPLIT should be disabled to allow BT to be released" #endif // CONFIG_BT_RELEASE_IRAM && CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT - if (mode & ESP_BT_MODE_BLE) { + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; + } + + if ((mode & ESP_BT_MODE_BLE) == 0) { + return ret; + } + #if CONFIG_BT_RELEASE_IRAM - mem_start = (intptr_t)MAP_IRAM_TO_DRAM((intptr_t)&_iram_bt_text_start); - mem_end = (intptr_t)&_bss_bt_end; + bt_area_t merged_region = { + .start = (intptr_t)MAP_IRAM_TO_DRAM((intptr_t)&_iram_bt_text_start), + .end = (intptr_t)&_bss_bt_end, + .name = "BT Text, BSS and Data" + }; + ret = esp_bt_mem_release_area(&merged_region); #else - mem_start = (intptr_t)&_bt_controller_data_start; - mem_end = (intptr_t)&_bt_bss_end; -#endif // CONFIG_BT_RELEASE_IRAM - if (mem_start != mem_end) { - ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Release BLE [0x%08x] - [0x%08x], len %d", mem_start, - mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + bt_area_t bss = { + .start = (intptr_t)&_bt_bss_start, + .end = (intptr_t)&_bt_bss_end, + .name = "BT BSS", + }; + bt_area_t cont_bss = { + .start = (intptr_t)&_bt_controller_bss_start, + .end = (intptr_t)&_bt_controller_bss_end, + .name = "BT Controller BSS", + }; + bt_area_t data = { + .start = (intptr_t)&_bt_data_start, + .end = (intptr_t)&_bt_data_end, + .name = "BT Data", + }; + bt_area_t cont_data = { + .start = (intptr_t)&_bt_controller_data_start, + .end = (intptr_t)&_bt_controller_data_end, + .name = "BT Controller Data" + }; + + /* Start by freeing Bluetooth BSS section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&bss, &cont_bss); } - return ESP_OK; + /* Do the same thing with the Bluetooth data section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&data, &cont_data); + } +#endif + + return ret; } @@ -1235,4 +1377,3 @@ int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv) #endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC #endif // (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) - diff --git a/lib/bt/controller/esp32c2/esp_bt_cfg.h b/lib/bt/controller/esp32c2/esp_bt_cfg.h index 308d79e3..0cb4168e 100644 --- a/lib/bt/controller/esp32c2/esp_bt_cfg.h +++ b/lib/bt/controller/esp32c2/esp_bt_cfg.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -46,6 +46,10 @@ extern "C" { #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) #endif + #define DEFAULT_BT_LE_ROLE_OBSERVER MYNEWT_VAL(BLE_ROLE_OBSERVER) + #define DEFAULT_BT_LE_ROLE_CENTROL MYNEWT_VAL(BLE_ROLE_CENTRAL) + #define DEFAULT_BT_LE_ROLE_PERIPHERAL MYNEWT_VAL(BLE_ROLE_PERIPHERAL) + #define DEFAULT_BT_LE_ROLE_BROADCASTER MYNEWT_VAL(BLE_ROLE_BROADCASTER) #else #if CONFIG_BT_LE_LL_CFG_FEAT_LE_CODED_PHY @@ -57,13 +61,13 @@ extern "C" { #if defined(CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST) #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST (CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST) #else - #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST (5) + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST (0) #endif #if defined(CONFIG_BT_LE_MAX_PERIODIC_SYNCS) #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS (CONFIG_BT_LE_MAX_PERIODIC_SYNCS) #else - #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS (1) + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS (0) #endif #if defined(CONFIG_BT_LE_MAX_CONNECTIONS) @@ -125,6 +129,29 @@ extern "C" { #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) #endif + #if defined(CONFIG_BT_LE_ROLE_CENTROL_ENABLE) + #define DEFAULT_BT_LE_ROLE_CENTROL (1) + #else + #define DEFAULT_BT_LE_ROLE_CENTROL (0) + #endif + + #if defined(CONFIG_BT_LE_ROLE_PERIPHERAL_ENABLE) + #define DEFAULT_BT_LE_ROLE_PERIPHERAL (1) + #else + #define DEFAULT_BT_LE_ROLE_PERIPHERAL (0) + #endif + + #if defined(CONFIG_BT_LE_ROLE_BROADCASTER_ENABLE) + #define DEFAULT_BT_LE_ROLE_BROADCASTER (1) + #else + #define DEFAULT_BT_LE_ROLE_BROADCASTER (0) + #endif + + #if defined(CONFIG_BT_LE_ROLE_OBSERVER_ENABLE) + #define DEFAULT_BT_LE_ROLE_OBSERVER (1) + #else + #define DEFAULT_BT_LE_ROLE_OBSERVER (0) + #endif #endif #define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF diff --git a/lib/bt/controller/esp32c3/Kconfig.in b/lib/bt/controller/esp32c3/Kconfig.in index 078b215f..059e71da 100644 --- a/lib/bt/controller/esp32c3/Kconfig.in +++ b/lib/bt/controller/esp32c3/Kconfig.in @@ -23,7 +23,7 @@ config BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB default 0 help BLE ACL buffer have two methods to be allocated. One is persistent allocating - (alloate when controller initialise, never free until controller de-initialise) + (allocate when controller initialise, never free until controller de-initialise) another is dynamically allocating (allocate before TX and free after TX). choice BT_CTRL_PINNED_TO_CORE_CHOICE @@ -72,11 +72,11 @@ config BT_CTRL_HCI_TL HCI mode as VHCI or UART(H4) config BT_CTRL_ADV_DUP_FILT_MAX - int "The maxinum number of 5.0 extend duplicate scan filter" + int "The maximum number of 5.0 extend duplicate scan filter" range 1 500 default 30 help - The maxinum number of suplicate scan filter + The maximum number of suplicate scan filter choice BT_BLE_CCA_MODE prompt "BLE CCA mode" @@ -475,3 +475,17 @@ config BT_BLE_ADV_DATA_LENGTH_ZERO_AUX When this option is enabled, auxiliary packets will be present in the events of 'Non-Connectable and Non-Scannable' regardless of whether the advertising length is 0. If this option is not enabled, auxiliary packets will only be present when the advertising length is not 0. + +config BT_CTRL_CHAN_ASS_EN + bool "Enable channel assessment" + default y + help + If this option is enabled, The Controller will records the communication quality + for each channel and then start a timer to check and update the channel map every 4 seconds. + +config BT_CTRL_LE_PING_EN + bool "Enable LE Ping procedure" + default y + help + If this option is disabled, The Controller will not start the LE authenticated payload timer. + This option is used for some compatibility problems related to LE ping procedure. diff --git a/lib/bt/controller/esp32c3/bt.c b/lib/bt/controller/esp32c3/bt.c index f1e045d3..e053cfdf 100644 --- a/lib/bt/controller/esp32c3/bt.c +++ b/lib/bt/controller/esp32c3/bt.c @@ -22,7 +22,10 @@ #include "esp_random.h" #include "esp_task.h" #include "esp_attr.h" +#ifdef CONFIG_ESP_PHY_ENABLED #include "esp_phy_init.h" +#include "esp_private/phy.h" +#endif #include "esp_bt.h" #include "esp_err.h" #include "esp_log.h" @@ -34,11 +37,12 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "soc/soc_memory_layout.h" +#ifdef CONFIG_ESP_COEX_ENABLED #include "private/esp_coexist_internal.h" +#endif #include "esp_timer.h" #include "esp_sleep.h" #include "esp_rom_sys.h" -#include "esp_private/phy.h" #if CONFIG_IDF_TARGET_ESP32C3 #include "riscv/interrupt.h" #include "esp32c3/rom/rom_layout.h" @@ -64,6 +68,7 @@ // wakeup request sources enum { BTDM_ASYNC_WAKEUP_SRC_VHCI = 0, + BTDM_ASYNC_WAKEUP_REQ_COEX, BTDM_ASYNC_WAKEUP_SRC_DISA, BTDM_ASYNC_WAKEUP_SRC_TMR, BTDM_ASYNC_WAKEUP_SRC_MAX, @@ -73,12 +78,12 @@ enum { typedef union { struct { uint32_t enable : 1; // whether low power mode is required - uint32_t lpclk_sel : 2; // low power clock source + uint32_t lpclk_sel : 3; // low power clock source uint32_t mac_bb_pd : 1; // whether hardware(MAC, BB) force-power-down is required during sleep uint32_t wakeup_timer_required : 1; // whether system timer is needed uint32_t no_light_sleep : 1; // do not allow system to enter light sleep after bluetooth is enabled uint32_t main_xtal_pu : 1; // power up main XTAL - uint32_t reserved : 25; // reserved + uint32_t reserved : 24; // reserved }; uint32_t val; } btdm_lpcntl_t; @@ -110,7 +115,7 @@ do{\ } while(0) #define OSI_FUNCS_TIME_BLOCKING 0xffffffff -#define OSI_VERSION 0x00010007 +#define OSI_VERSION 0x00010008 #define OSI_MAGIC_VALUE 0xFADEBEAD /* Types definition @@ -184,8 +189,12 @@ struct osi_funcs_t { void (* _btdm_sleep_exit_phase3)(void); /* called from task */ void (* _coex_wifi_sleep_set)(bool sleep); int (* _coex_core_ble_conn_dyn_prio_get)(bool *low, bool *high); + int (* _coex_schm_register_btdm_callback)(void *callback); void (* _coex_schm_status_bit_set)(uint32_t type, uint32_t status); void (* _coex_schm_status_bit_clear)(uint32_t type, uint32_t status); + uint32_t (* _coex_schm_interval_get)(void); + uint8_t (* _coex_schm_curr_period_get)(void); + void *(* _coex_schm_curr_phase_get)(void); void (* _interrupt_on)(int intr_num); void (* _interrupt_off)(int intr_num); void (* _esp_hw_power_down)(void); @@ -193,6 +202,8 @@ struct osi_funcs_t { void (* _ets_backup_dma_copy)(uint32_t reg, uint32_t mem_addr, uint32_t num, bool to_rem); void (* _ets_delay_us)(uint32_t us); void (* _btdm_rom_table_ready)(void); + bool (* _coex_bt_wakeup_request)(void); + void (* _coex_bt_wakeup_request_end)(void); }; @@ -256,16 +267,12 @@ extern void btdm_cca_feature_enable(void); extern uint32_t _bt_bss_start; extern uint32_t _bt_bss_end; -extern uint32_t _btdm_bss_start; -extern uint32_t _btdm_bss_end; -extern uint32_t _nimble_bss_start; -extern uint32_t _nimble_bss_end; +extern uint32_t _bt_controller_bss_start; +extern uint32_t _bt_controller_bss_end; extern uint32_t _bt_data_start; extern uint32_t _bt_data_end; -extern uint32_t _btdm_data_start; -extern uint32_t _btdm_data_end; -extern uint32_t _nimble_data_start; -extern uint32_t _nimble_data_end; +extern uint32_t _bt_controller_data_start; +extern uint32_t _bt_controller_data_end; /* Local Function Declare ********************************************************************* @@ -306,14 +313,20 @@ static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles); static void btdm_sleep_enter_phase2_wrapper(void); static void btdm_sleep_exit_phase3_wrapper(void); static void coex_wifi_sleep_set_hook(bool sleep); +static int coex_schm_register_btdm_callback_wrapper(void *callback); static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status); static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status); +static uint32_t coex_schm_interval_get_wrapper(void); +static uint8_t coex_schm_curr_period_get_wrapper(void); +static void * coex_schm_curr_phase_get_wrapper(void); static void interrupt_on_wrapper(int intr_num); static void interrupt_off_wrapper(int intr_num); static void btdm_hw_mac_power_up_wrapper(void); static void btdm_hw_mac_power_down_wrapper(void); static void btdm_backup_dma_copy_wrapper(uint32_t reg, uint32_t mem_addr, uint32_t num, bool to_mem); static void btdm_funcs_table_ready_wrapper(void); +static bool coex_bt_wakeup_request(void); +static void coex_bt_wakeup_request_end(void); static void btdm_slp_tmr_callback(void *arg); @@ -371,8 +384,12 @@ static const struct osi_funcs_t osi_funcs_ro = { ._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper, ._coex_wifi_sleep_set = coex_wifi_sleep_set_hook, ._coex_core_ble_conn_dyn_prio_get = NULL, + ._coex_schm_register_btdm_callback = coex_schm_register_btdm_callback_wrapper, ._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper, ._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper, + ._coex_schm_interval_get = coex_schm_interval_get_wrapper, + ._coex_schm_curr_period_get = coex_schm_curr_period_get_wrapper, + ._coex_schm_curr_phase_get = coex_schm_curr_phase_get_wrapper, ._interrupt_on = interrupt_on_wrapper, ._interrupt_off = interrupt_off_wrapper, ._esp_hw_power_down = btdm_hw_mac_power_down_wrapper, @@ -380,6 +397,8 @@ static const struct osi_funcs_t osi_funcs_ro = { ._ets_backup_dma_copy = btdm_backup_dma_copy_wrapper, ._ets_delay_us = esp_rom_delay_us, ._btdm_rom_table_ready = btdm_funcs_table_ready_wrapper, + ._coex_bt_wakeup_request = coex_bt_wakeup_request, + ._coex_bt_wakeup_request_end = coex_bt_wakeup_request_end, }; static DRAM_ATTR struct osi_funcs_t *osi_funcs_p; @@ -400,7 +419,7 @@ static DRAM_ATTR uint8_t btdm_lpcycle_us_frac = 0; // semaphore used for blocking VHCI API to wait for controller to wake up static DRAM_ATTR QueueHandle_t s_wakeup_req_sem = NULL; // wakeup timer -static DRAM_ATTR esp_timer_handle_t s_btdm_slp_tmr; +static DRAM_ATTR esp_timer_handle_t s_btdm_slp_tmr = NULL; #ifdef CONFIG_PM_ENABLE static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock; @@ -463,9 +482,8 @@ static void interrupt_set_wrapper(int cpu_no, int intr_source, int intr_num, int { esp_rom_route_intr_matrix(cpu_no, intr_source, intr_num); #if __riscv - esprv_intc_int_set_priority(intr_num, intr_prio); - //esprv_intc_int_enable_level(1 << intr_num); - esprv_intc_int_set_type(intr_num, 0); + esprv_int_set_priority(intr_num, intr_prio); + esprv_int_set_type(intr_num, 0); #endif } @@ -637,7 +655,7 @@ static int IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void * static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id) { - return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); + return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < CONFIG_FREERTOS_NUMBER_OF_CORES ? core_id : tskNO_AFFINITY)); } static void task_delete_wrapper(void *task_handle) @@ -853,6 +871,22 @@ static bool async_wakeup_request(int event) semphr_take_wrapper(s_wakeup_req_sem, OSI_FUNCS_TIME_BLOCKING); } break; + case BTDM_ASYNC_WAKEUP_REQ_COEX: + if (!btdm_power_state_active()) { + do_wakeup_request = true; +#if CONFIG_PM_ENABLE + if (s_lp_stat.pm_lock_released) { + esp_pm_lock_acquire(s_pm_lock); + s_lp_stat.pm_lock_released = 0; + } +#endif + btdm_wakeup_request(); + + if (s_lp_cntl.wakeup_timer_required && s_lp_stat.wakeup_timer_started) { + esp_timer_stop(s_btdm_slp_tmr); + s_lp_stat.wakeup_timer_started = 0; + } + } default: break; } @@ -872,6 +906,9 @@ static void async_wakeup_request_end(int event) case BTDM_ASYNC_WAKEUP_SRC_DISA: allow_to_sleep = true; break; + case BTDM_ASYNC_WAKEUP_REQ_COEX: + allow_to_sleep = false; + break; default: allow_to_sleep = true; break; @@ -891,18 +928,25 @@ static void btdm_funcs_table_ready_wrapper(void) #endif } -static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status) +bool bt_async_wakeup_request(void) { -#if CONFIG_SW_COEXIST_ENABLE - coex_schm_status_bit_set(type, status); -#endif + return async_wakeup_request(BTDM_ASYNC_WAKEUP_SRC_VHCI); } -static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) +void bt_wakeup_request_end(void) { -#if CONFIG_SW_COEXIST_ENABLE - coex_schm_status_bit_clear(type, status); -#endif + async_wakeup_request_end(BTDM_ASYNC_WAKEUP_SRC_VHCI); +} + +static bool coex_bt_wakeup_request(void) +{ + return async_wakeup_request(BTDM_ASYNC_WAKEUP_REQ_COEX); +} + +static void coex_bt_wakeup_request_end(void) +{ + async_wakeup_request_end(BTDM_ASYNC_WAKEUP_REQ_COEX); + return; } bool esp_vhci_host_check_send_available(void) @@ -939,145 +983,175 @@ static void btdm_controller_mem_init(void) btdm_controller_rom_data_init(); } -esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +/** + * Release two memory areas to the heap. If both areas are consecutive, they will be released as + * a single area. + */ +typedef struct { + intptr_t start; + intptr_t end; + const char* name; +} bt_area_t; + +static esp_err_t esp_bt_mem_release_area(const bt_area_t *area) +{ + esp_err_t ret = ESP_OK; + intptr_t mem_start = area->start; + intptr_t mem_end = area->end; + if (mem_start != mem_end) { + ESP_LOGD(BT_LOG_TAG, "Release %s [0x%08x] - [0x%08x], len %d", area->name, mem_start, mem_end, mem_end - mem_start); + ret = try_heap_caps_add_region(mem_start, mem_end); + } + return ret; +} + +static esp_err_t esp_bt_mem_release_areas(const bt_area_t *area1, const bt_area_t *area2) { - intptr_t mem_start=(intptr_t) NULL, mem_end=(intptr_t) NULL; + esp_err_t ret = ESP_OK; + + if (area1->end == area2->start) { + bt_area_t merged_area = { + .start = area1->start, + .end = area2->end, + .name = area1->name + }; + ret = esp_bt_mem_release_area(&merged_area); + } else { + esp_bt_mem_release_area(area1); + ret = esp_bt_mem_release_area(area2); + } + + return ret; +} + +esp_err_t esp_bt_controller_rom_mem_release(esp_bt_mode_t mode) +{ + esp_err_t ret = ESP_OK; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { return ESP_ERR_INVALID_STATE; } - if (mode & ESP_BT_MODE_BLE) { - /* if the addresses of rom btdm .data and .bss are consecutive, - they are registered in the system heap as a piece of memory - */ - if(ets_rom_layout_p->data_end_btdm == ets_rom_layout_p->bss_start_btdm) { - mem_start = (intptr_t)ets_rom_layout_p->data_start_btdm; - mem_end = (intptr_t)ets_rom_layout_p->bss_end_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom btdm [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)ets_rom_layout_p->bss_start_btdm; - mem_end = (intptr_t)ets_rom_layout_p->bss_end_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom btdm BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + bt_area_t rom_btdm_data = { + .start = (intptr_t) ets_rom_layout_p->data_start_btdm, + .end = (intptr_t) ets_rom_layout_p->data_end_btdm, + .name = "ROM btdm data", + }; + bt_area_t rom_btdm_bss = { + .start = (intptr_t)ets_rom_layout_p->bss_start_btdm, + .end = (intptr_t)ets_rom_layout_p->bss_end_btdm, + .name = "ROM btdm BSS", + }; + bt_area_t rom_btdm_inter_data = { + .start = (intptr_t) ets_rom_layout_p->data_start_interface_btdm, + .end = (intptr_t) ets_rom_layout_p->data_end_interface_btdm, + .name = "ROM interface btdm data", + }; + bt_area_t rom_btdm_inter_bss = { + .start = (intptr_t)ets_rom_layout_p->bss_start_interface_btdm, + .end = (intptr_t)ets_rom_layout_p->bss_end_interface_btdm, + .name = "ROM interface btdm BSS", + }; - mem_start = (intptr_t)ets_rom_layout_p->data_start_btdm; - mem_end = (intptr_t)ets_rom_layout_p->data_end_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom btdm Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + ret = ESP_ERR_INVALID_STATE; + } + + if (mode & ESP_BT_MODE_BLE) { + /* Free BTDM memory used by the ROM */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&rom_btdm_data, &rom_btdm_bss); } - /* if the addresses of rom interface btdm .data and .bss are consecutive, - they are registered in the system heap as a piece of memory - */ - if(ets_rom_layout_p->data_end_interface_btdm == ets_rom_layout_p->bss_start_interface_btdm) { - mem_start = (intptr_t)ets_rom_layout_p->data_start_interface_btdm; - mem_end = (intptr_t)ets_rom_layout_p->bss_end_interface_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom interface btdm [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)ets_rom_layout_p->data_start_interface_btdm; - mem_end = (intptr_t)ets_rom_layout_p->data_end_interface_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom interface btdm Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - mem_start = (intptr_t)ets_rom_layout_p->bss_start_interface_btdm; - mem_end = (intptr_t)ets_rom_layout_p->bss_end_interface_btdm; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release rom interface btdm BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&rom_btdm_inter_data, &rom_btdm_inter_bss); } + } + + return ret; +} + +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +{ + esp_err_t ret = ESP_OK; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; } - return ESP_OK; + + bt_area_t cont_bss = { + .start = (intptr_t)&_bt_controller_bss_start, + .end = (intptr_t)&_bt_controller_bss_end, + .name = "BT Controller BSS", + }; + + bt_area_t cont_data = { + .start = (intptr_t)&_bt_controller_data_start, + .end = (intptr_t)&_bt_controller_data_end, + .name = "BT Controller Data" + }; + + if (mode & ESP_BT_MODE_BLE) { + /* free data and BSS section for libbtdm_app.a */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&cont_data, &cont_bss); + } + /* free data and BSS section for Bluetooth controller ROM code */ + if (ret == ESP_OK) { + ret = esp_bt_controller_rom_mem_release(mode); + } + } + + return ret; } esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) { - int ret; - intptr_t mem_start, mem_end; + esp_err_t ret = ESP_OK; - ret = esp_bt_controller_mem_release(mode); - if (ret != ESP_OK) { - return ret; + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; } - if (mode & ESP_BT_MODE_BLE) { - /* if the addresses of btdm .bss and bt .bss are consecutive, - they are registered in the system heap as a piece of memory - */ - if(_bt_bss_end == _btdm_bss_start) { - mem_start = (intptr_t)&_bt_bss_start; - mem_end = (intptr_t)&_btdm_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)&_bt_bss_start; - mem_end = (intptr_t)&_bt_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + bt_area_t bss = { + .start = (intptr_t)&_bt_bss_start, + .end = (intptr_t)&_bt_bss_end, + .name = "BT BSS", + }; + bt_area_t cont_bss = { + .start = (intptr_t)&_bt_controller_bss_start, + .end = (intptr_t)&_bt_controller_bss_end, + .name = "BT Controller BSS", + }; + bt_area_t data = { + .start = (intptr_t)&_bt_data_start, + .end = (intptr_t)&_bt_data_end, + .name = "BT Data", + }; + bt_area_t cont_data = { + .start = (intptr_t)&_bt_controller_data_start, + .end = (intptr_t)&_bt_controller_data_end, + .name = "BT Controller Data" + }; - mem_start = (intptr_t)&_btdm_bss_start; - mem_end = (intptr_t)&_btdm_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release BTDM BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + if (mode & ESP_BT_MODE_BLE) { + /* Start by freeing Bluetooth BSS section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&bss, &cont_bss); } - /* if the addresses of btdm .data and bt .data are consecutive, - they are registered in the system heap as a piece of memory - */ - if(_bt_data_end == _btdm_data_start) { - mem_start = (intptr_t)&_bt_data_start; - mem_end = (intptr_t)&_btdm_data_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)&_bt_data_start; - mem_end = (intptr_t)&_bt_data_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - mem_start = (intptr_t)&_btdm_data_start; - mem_end = (intptr_t)&_btdm_data_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release BTDM Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + /* Do the same thing with the Bluetooth data section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&data, &cont_data); } - mem_start = (intptr_t)&_nimble_bss_start; - mem_end = (intptr_t)&_nimble_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release NimBLE BSS [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - mem_start = (intptr_t)&_nimble_data_start; - mem_end = (intptr_t)&_nimble_data_end; - if (mem_start != mem_end) { - ESP_LOGD(BT_LOG_TAG, "Release NimBLE Data [0x%08x] - [0x%08x], len %d", mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + /* free data and BSS section for Bluetooth controller ROM code */ + if (ret == ESP_OK) { + ret = esp_bt_controller_rom_mem_release(mode); } } - return ESP_OK; + + return ret; } static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) @@ -1112,67 +1186,11 @@ static void IRAM_ATTR btdm_mac_bb_power_up_cb(void) } #endif -esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) +// init low-power control resources +static esp_err_t btdm_low_power_mode_init(esp_bt_controller_config_t *cfg) { - esp_err_t err = ESP_FAIL; - - if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { - return ESP_ERR_INVALID_STATE; - } - - if (cfg == NULL) { - return ESP_ERR_INVALID_ARG; - } - - if (cfg->controller_task_prio != ESP_TASK_BT_CONTROLLER_PRIO - || cfg->controller_task_stack_size < ESP_TASK_BT_CONTROLLER_STACK) { - ESP_LOGE(BT_LOG_TAG, "Invalid controller task prioriy or stack size"); - return ESP_ERR_INVALID_ARG; - } - - if (cfg->bluetooth_mode != ESP_BT_MODE_BLE) { - ESP_LOGE(BT_LOG_TAG, "%s controller only support BLE only mode", __func__); - return ESP_ERR_NOT_SUPPORTED; - } - - if (cfg->bluetooth_mode & ESP_BT_MODE_BLE) { - if ((cfg->ble_max_act <= 0) || (cfg->ble_max_act > BT_CTRL_BLE_MAX_ACT_LIMIT)) { - ESP_LOGE(BT_LOG_TAG, "Invalid value of ble_max_act"); - return ESP_ERR_INVALID_ARG; - } - } - - if (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) { - if (cfg->sleep_clock == ESP_BT_SLEEP_CLOCK_NONE) { - ESP_LOGE(BT_LOG_TAG, "SLEEP_MODE_1 enabled but sleep clock not configured"); - return ESP_ERR_INVALID_ARG; - } - } - - // overwrite some parameters - cfg->magic = ESP_BT_CTRL_CONFIG_MAGIC_VAL; - -#if CONFIG_MAC_BB_PD - esp_mac_bb_pd_mem_init(); -#endif - esp_phy_modem_init(); - esp_bt_power_domain_on(); - - btdm_controller_mem_init(); - - osi_funcs_p = (struct osi_funcs_t *)malloc_internal_wrapper(sizeof(struct osi_funcs_t)); - if (osi_funcs_p == NULL) { - return ESP_ERR_NO_MEM; - } - - memcpy(osi_funcs_p, &osi_funcs_ro, sizeof(struct osi_funcs_t)); - if (btdm_osi_funcs_register(osi_funcs_p) != 0) { - return ESP_ERR_INVALID_ARG; - } + esp_err_t err = ESP_OK; - ESP_LOGI(BT_LOG_TAG, "BT controller compile version [%s]", btdm_controller_get_compile_version()); - - // init low-power control resources do { // set default values for global states or resources s_lp_stat.val = 0; @@ -1183,13 +1201,14 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) // configure and initialize resources s_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? 1 : 0; + s_lp_cntl.lpclk_sel = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? cfg->sleep_clock : ESP_BT_SLEEP_CLOCK_MAIN_XTAL; s_lp_cntl.no_light_sleep = 0; if (s_lp_cntl.enable) { #if CONFIG_MAC_BB_PD if (!btdm_deep_sleep_mem_init()) { err = ESP_ERR_NO_MEM; - goto error; + break; } s_lp_cntl.mac_bb_pd = 1; #endif @@ -1200,58 +1219,55 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) s_wakeup_req_sem = semphr_create_wrapper(1, 0); if (s_wakeup_req_sem == NULL) { err = ESP_ERR_NO_MEM; - goto error; + break; } btdm_vnd_offload_task_register(BTDM_VND_OL_SIG_WAKEUP_TMR, btdm_sleep_exit_phase0); - } - if (s_lp_cntl.wakeup_timer_required) { - esp_timer_create_args_t create_args = { - .callback = btdm_slp_tmr_callback, - .arg = NULL, - .name = "btSlp", - }; - if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) { - goto error; + if (s_lp_cntl.wakeup_timer_required) { + esp_timer_create_args_t create_args = { + .callback = btdm_slp_tmr_callback, + .arg = NULL, + .name = "btSlp", + }; + if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) { + break; + } } - } - // set default bluetooth sleep clock cycle and its fractional bits - btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; - btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac); + // set default bluetooth sleep clock cycle and its fractional bits + btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; + btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac); - // set default bluetooth sleep clock source - s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value -#if CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL - // check whether or not EXT_CRYS is working - if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { - s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32 kHz XTAL - } else { - ESP_LOGW(BT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock"); + if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_EXT_32K_XTAL) { // External 32 kHz XTAL + // check whether or not EXT_CRYS is working + if (rtc_clk_slow_src_get() != SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + ESP_LOGW(BT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock"); + s_lp_cntl.lpclk_sel = ESP_BT_SLEEP_CLOCK_MAIN_XTAL; #if !CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP - s_lp_cntl.no_light_sleep = 1; + s_lp_cntl.no_light_sleep = 1; #endif - } -#elif (CONFIG_BT_CTRL_LPCLK_SEL_MAIN_XTAL) - ESP_LOGI(BT_LOG_TAG, "Bluetooth will use main XTAL as Bluetooth sleep clock."); + } + } else if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_RTC_SLOW) { // Internal 136kHz RC oscillator + if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) { + ESP_LOGW(BT_LOG_TAG, "Internal 136kHz RC oscillator. The accuracy of this clock is a lot larger than 500ppm which is " + "required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state."); + } else { + ESP_LOGW(BT_LOG_TAG, "Internal 136kHz RC oscillator not detected."); + assert(0); + } + } else if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_MAIN_XTAL) { + ESP_LOGI(BT_LOG_TAG, "Bluetooth will use main XTAL as Bluetooth sleep clock."); #if !CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP - s_lp_cntl.no_light_sleep = 1; + s_lp_cntl.no_light_sleep = 1; #endif -#elif (CONFIG_BT_CTRL_LPCLK_SEL_RTC_SLOW) - // check whether or not internal 150 kHz RC oscillator is working - if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) { - s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // Internal 150 kHz RC oscillator - ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC osciallator. The accuracy of this clock is a lot larger than 500ppm which is " - "required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state."); + } } else { - ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC oscillator not detected."); - assert(0); + s_lp_cntl.no_light_sleep = 1; } -#endif bool select_src_ret __attribute__((unused)); bool set_div_ret __attribute__((unused)); - if (s_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_XTAL) { + if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_MAIN_XTAL) { #ifdef CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON)); s_lp_cntl.main_xtal_pu = 1; @@ -1261,7 +1277,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) assert(select_src_ret && set_div_ret); btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT; btdm_lpcycle_us = 1 << (btdm_lpcycle_us_frac); - } else if (s_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_XTAL32K) { + } else if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_EXT_32K_XTAL) { select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_XTAL32K); set_div_ret = btdm_lpclk_set_div(0); assert(select_src_ret && set_div_ret); @@ -1269,7 +1285,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) btdm_lpcycle_us = (RTC_CLK_CAL_FRACT > 15) ? (1000000 << (RTC_CLK_CAL_FRACT - 15)) : (1000000 >> (15 - RTC_CLK_CAL_FRACT)); assert(btdm_lpcycle_us != 0); - } else if (s_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_RTC_SLOW) { + } else if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_RTC_SLOW) { select_src_ret = btdm_lpclk_select_src(BTDM_LPCLK_SEL_RTC_SLOW); set_div_ret = btdm_lpclk_set_div(0); assert(select_src_ret && set_div_ret); @@ -1277,7 +1293,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) btdm_lpcycle_us = esp_clk_slowclk_cal_get(); } else { err = ESP_ERR_INVALID_ARG; - goto error; + break; } #if CONFIG_SW_COEXIST_ENABLE coex_update_lpclk_interval(); @@ -1286,20 +1302,100 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #ifdef CONFIG_PM_ENABLE if (s_lp_cntl.no_light_sleep) { if ((err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "btLS", &s_light_sleep_pm_lock)) != ESP_OK) { - err = ESP_ERR_NO_MEM; - goto error; + break; } ESP_LOGW(BT_LOG_TAG, "light sleep mode will not be able to apply when bluetooth is enabled."); } if ((err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock)) != ESP_OK) { - err = ESP_ERR_NO_MEM; - goto error; + break; } else { s_lp_stat.pm_lock_released = 1; } #endif } while (0); + return err; +} + +esp_bt_sleep_clock_t esp_bt_get_lpclk_src(void) +{ + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED && + btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_BT_SLEEP_CLOCK_NONE; + } + + return s_lp_cntl.lpclk_sel; +} + +esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) +{ + esp_err_t err = ESP_FAIL; + + if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; + } + + if (cfg == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (cfg->controller_task_prio != ESP_TASK_BT_CONTROLLER_PRIO + || cfg->controller_task_stack_size < ESP_TASK_BT_CONTROLLER_STACK) { + ESP_LOGE(BT_LOG_TAG, "Invalid controller task prioriy or stack size"); + return ESP_ERR_INVALID_ARG; + } + + if (cfg->bluetooth_mode != ESP_BT_MODE_BLE) { + ESP_LOGE(BT_LOG_TAG, "%s controller only support BLE only mode", __func__); + return ESP_ERR_NOT_SUPPORTED; + } + + if (cfg->bluetooth_mode & ESP_BT_MODE_BLE) { + if ((cfg->ble_max_act <= 0) || (cfg->ble_max_act > BT_CTRL_BLE_MAX_ACT_LIMIT)) { + ESP_LOGE(BT_LOG_TAG, "Invalid value of ble_max_act"); + return ESP_ERR_INVALID_ARG; + } + } + + if (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) { + if (cfg->sleep_clock == ESP_BT_SLEEP_CLOCK_NONE) { + ESP_LOGE(BT_LOG_TAG, "SLEEP_MODE_1 enabled but sleep clock not configured"); + return ESP_ERR_INVALID_ARG; + } + if (cfg->sleep_clock > ESP_BT_SLEEP_CLOCK_RTC_SLOW) { + ESP_LOGE(BT_LOG_TAG, "SLEEP_MODE_1 is enabled but this sleep clock is not supported"); + return ESP_ERR_INVALID_ARG; + } + } + + // overwrite some parameters + cfg->magic = ESP_BT_CTRL_CONFIG_MAGIC_VAL; + +#if CONFIG_MAC_BB_PD + esp_mac_bb_pd_mem_init(); +#endif + esp_phy_modem_init(); + esp_bt_power_domain_on(); + + btdm_controller_mem_init(); + + osi_funcs_p = (struct osi_funcs_t *)malloc_internal_wrapper(sizeof(struct osi_funcs_t)); + if (osi_funcs_p == NULL) { + return ESP_ERR_NO_MEM; + } + + memcpy(osi_funcs_p, &osi_funcs_ro, sizeof(struct osi_funcs_t)); + if (btdm_osi_funcs_register(osi_funcs_p) != 0) { + return ESP_ERR_INVALID_ARG; + } + + ESP_LOGI(BT_LOG_TAG, "BT controller compile version [%s]", btdm_controller_get_compile_version()); + + if ((err = btdm_low_power_mode_init(cfg)) != ESP_OK) { + ESP_LOGE(BT_LOG_TAG, "Low power module initialization failed"); + goto error; + } + #if CONFIG_SW_COEXIST_ENABLE coex_init(); #endif @@ -1336,69 +1432,70 @@ esp_err_t esp_bt_controller_deinit(void) return ESP_OK; } -static void bt_controller_deinit_internal(void) +// deinit low power control resources +static void btdm_low_power_mode_deinit(void) { - periph_module_disable(PERIPH_BT_MODULE); - - // deinit low power control resources - do { - #if CONFIG_MAC_BB_PD - if (s_lp_cntl.mac_bb_pd) { - btdm_deep_sleep_mem_deinit(); - s_lp_cntl.mac_bb_pd = 0; - } + if (s_lp_cntl.mac_bb_pd) { + btdm_deep_sleep_mem_deinit(); + s_lp_cntl.mac_bb_pd = 0; + } #endif #ifdef CONFIG_PM_ENABLE - if (s_lp_cntl.no_light_sleep) { - if (s_light_sleep_pm_lock != NULL) { - esp_pm_lock_delete(s_light_sleep_pm_lock); - s_light_sleep_pm_lock = NULL; - } - } - - if (s_pm_lock != NULL) { - esp_pm_lock_delete(s_pm_lock); - s_pm_lock = NULL; - s_lp_stat.pm_lock_released = 0; + if (s_lp_cntl.no_light_sleep) { + if (s_light_sleep_pm_lock != NULL) { + esp_pm_lock_delete(s_light_sleep_pm_lock); + s_light_sleep_pm_lock = NULL; } + } + if (s_pm_lock != NULL) { + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; + s_lp_stat.pm_lock_released = 0; + } #endif - if (s_lp_cntl.wakeup_timer_required) { - if (s_lp_stat.wakeup_timer_started) { - esp_timer_stop(s_btdm_slp_tmr); - } - s_lp_stat.wakeup_timer_started = 0; - esp_timer_delete(s_btdm_slp_tmr); - s_btdm_slp_tmr = NULL; + if (s_lp_cntl.wakeup_timer_required && s_btdm_slp_tmr != NULL) { + if (s_lp_stat.wakeup_timer_started) { + esp_timer_stop(s_btdm_slp_tmr); } + s_lp_stat.wakeup_timer_started = 0; + esp_timer_delete(s_btdm_slp_tmr); + s_btdm_slp_tmr = NULL; + } - if (s_lp_cntl.enable) { - btdm_vnd_offload_task_deregister(BTDM_VND_OL_SIG_WAKEUP_TMR); - if (s_wakeup_req_sem != NULL) { - semphr_delete_wrapper(s_wakeup_req_sem); - s_wakeup_req_sem = NULL; - } + if (s_lp_cntl.enable) { + btdm_vnd_offload_task_deregister(BTDM_VND_OL_SIG_WAKEUP_TMR); + if (s_wakeup_req_sem != NULL) { + semphr_delete_wrapper(s_wakeup_req_sem); + s_wakeup_req_sem = NULL; } + } - if (s_lp_cntl.lpclk_sel == BTDM_LPCLK_SEL_XTAL) { + if (s_lp_cntl.lpclk_sel == ESP_BT_SLEEP_CLOCK_MAIN_XTAL) { #ifdef CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP - if (s_lp_cntl.main_xtal_pu) { - ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF)); - s_lp_cntl.main_xtal_pu = 0; - } + if (s_lp_cntl.main_xtal_pu) { + ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF)); + s_lp_cntl.main_xtal_pu = 0; + } #endif - btdm_lpclk_select_src(BTDM_LPCLK_SEL_RTC_SLOW); - btdm_lpclk_set_div(0); + btdm_lpclk_select_src(BTDM_LPCLK_SEL_RTC_SLOW); + btdm_lpclk_set_div(0); #if CONFIG_SW_COEXIST_ENABLE - coex_update_lpclk_interval(); + coex_update_lpclk_interval(); #endif - } + } - btdm_lpcycle_us = 0; - } while (0); + btdm_lpcycle_us = 0; +} + +static void bt_controller_deinit_internal(void) +{ + periph_module_disable(PERIPH_BT_MODULE); + + btdm_low_power_mode_deinit(); esp_bt_power_domain_off(); #if CONFIG_MAC_BB_PD @@ -1677,4 +1774,55 @@ static void coex_wifi_sleep_set_hook(bool sleep) { } + +static int coex_schm_register_btdm_callback_wrapper(void *callback) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_register_callback(COEX_SCHM_CALLBACK_TYPE_BT, callback); +#else + return 0; +#endif +} + +static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_clear(type, status); +#endif +} + +static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_set(type, status); +#endif +} + +static uint32_t coex_schm_interval_get_wrapper(void) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_interval_get(); +#else + return 0; +#endif +} + +static uint8_t coex_schm_curr_period_get_wrapper(void) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_curr_period_get(); +#else + return 1; +#endif +} + +static void * coex_schm_curr_phase_get_wrapper(void) +{ +#if CONFIG_SW_COEXIST_ENABLE + return coex_schm_curr_phase_get(); +#else + return NULL; +#endif +} + #endif /* CONFIG_BT_ENABLED */ diff --git a/lib/bt/controller/esp32c5/Kconfig.in b/lib/bt/controller/esp32c5/Kconfig.in new file mode 100644 index 00000000..02ac4995 --- /dev/null +++ b/lib/bt/controller/esp32c5/Kconfig.in @@ -0,0 +1,563 @@ + +menu "HCI Config" + + choice BT_LE_HCI_INTERFACE + prompt "Select HCI interface" + default BT_LE_HCI_INTERFACE_USE_RAM + + config BT_LE_HCI_INTERFACE_USE_RAM + bool "ram" + help + Use RAM as HCI interface + config BT_LE_HCI_INTERFACE_USE_UART + bool "uart" + help + Use UART as HCI interface + endchoice + + config BT_LE_HCI_UART_PORT + int "HCI UART port" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 1 + help + Set the port number of HCI UART + + config BT_LE_HCI_UART_FLOWCTRL + bool "HCI uart Hardware Flow ctrl" + depends on BT_LE_HCI_INTERFACE_USE_UART + default n + + config BT_LE_HCI_UART_TX_PIN + int "HCI uart Tx gpio" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 19 + + config BT_LE_HCI_UART_RX_PIN + int "HCI uart Rx gpio" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 10 + + config BT_LE_HCI_UART_RTS_PIN + int "HCI uart RTS gpio" + depends on BT_LE_HCI_UART_FLOWCTRL + default 4 + + config BT_LE_HCI_UART_CTS_PIN + int "HCI uart CTS gpio" + depends on BT_LE_HCI_UART_FLOWCTRL + default 5 + + config BT_LE_HCI_UART_BAUD + int "HCI uart baudrate" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 921600 + help + HCI uart baud rate 115200 ~ 1000000 + + choice BT_LE_HCI_UART_PARITY + prompt "select uart parity" + depends on BT_LE_HCI_INTERFACE_USE_UART + default BT_LE_HCI_UART_UART_PARITY_DISABLE + + config BT_LE_HCI_UART_UART_PARITY_DISABLE + bool "PARITY_DISABLE" + help + UART_PARITY_DISABLE + config BT_LE_HCI_UART_UART_PARITY_EVEN + bool "PARITY_EVEN" + help + UART_PARITY_EVEN + config BT_LE_HCI_UART_UART_PARITY_ODD + bool "PARITY_ODD" + help + UART_PARITY_ODD + endchoice + + config BT_LE_HCI_UART_TASK_STACK_SIZE + int "HCI uart task stack size" + depends on BT_LE_HCI_INTERFACE_USE_UART + default 1000 + help + Set the size of uart task stack +endmenu + +config BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT + bool + default y + help + Enable NPL porting for controller. + + +menuconfig BT_LE_50_FEATURE_SUPPORT + bool "Enable BLE 5 feature" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable BLE 5 feature + +config BT_LE_LL_CFG_FEAT_LE_2M_PHY + bool "Enable 2M Phy" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable 2M-PHY + +config BT_LE_LL_CFG_FEAT_LE_CODED_PHY + bool "Enable coded Phy" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable coded-PHY + +config BT_LE_EXT_ADV + bool "Enable extended advertising" + depends on BT_LE_50_FEATURE_SUPPORT + default y + help + Enable this option to do extended advertising. Extended advertising + will be supported from BLE 5.0 onwards. + +if BT_LE_EXT_ADV + config BT_LE_MAX_EXT_ADV_INSTANCES + int "Maximum number of extended advertising instances." + range 0 4 + default 1 + depends on BT_LE_EXT_ADV + help + Change this option to set maximum number of extended advertising + instances. Minimum there is always one instance of + advertising. Enter how many more advertising instances you + want. + Each extended advertising instance will take about 0.5k DRAM. + + config BT_LE_EXT_ADV_MAX_SIZE + int "Maximum length of the advertising data." + range 0 1650 + default 1650 + depends on BT_LE_EXT_ADV + help + Defines the length of the extended adv data. The value should not + exceed 1650. + + config BT_LE_ENABLE_PERIODIC_ADV + bool "Enable periodic advertisement." + default y + depends on BT_LE_EXT_ADV + help + Enable this option to start periodic advertisement. + + config BT_LE_PERIODIC_ADV_SYNC_TRANSFER + bool "Enable 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 && IDF_TARGET_ESP32C6 + default n + help + Set this option to enable the Power Control feature on controller + +menu "Memory Settings" + depends on !BT_NIMBLE_ENABLED + + config BT_LE_MSYS_1_BLOCK_COUNT + int "MSYS_1 Block Count" + default 12 + help + MSYS is a system level mbuf registry. For prepare write & prepare + responses MBUFs are allocated out of msys_1 pool. For NIMBLE_MESH + enabled cases, this block count is increased by 8 than user defined + count. + + config BT_LE_MSYS_1_BLOCK_SIZE + int "MSYS_1 Block Size" + default 256 + help + Dynamic memory size of block 1 + + config BT_LE_MSYS_2_BLOCK_COUNT + int "MSYS_2 Block Count" + default 24 + help + Dynamic memory count + + config BT_LE_MSYS_2_BLOCK_SIZE + int "MSYS_2 Block Size" + default 320 + help + Dynamic memory size of block 2 + + config BT_LE_MSYS_BUF_FROM_HEAP + bool "Get Msys Mbuf from heap" + default y + depends on BT_LE_MSYS_INIT_IN_CONTROLLER + help + This option sets the source of the shared msys mbuf memory between + the Host and the Controller. Allocate the memory from the heap if + this option is sets, from the mempool otherwise. + + config BT_LE_ACL_BUF_COUNT + int "ACL Buffer count" + default 10 + help + The number of ACL data buffers. + + config BT_LE_ACL_BUF_SIZE + int "ACL Buffer size" + default 517 + help + This is the maximum size of the data portion of HCI ACL data packets. + It does not include the HCI data header (of 4 bytes) + + config BT_LE_HCI_EVT_BUF_SIZE + int "HCI Event Buffer size" + default 257 if BT_LE_EXT_ADV + default 70 + help + This is the size of each HCI event buffer in bytes. In case of + extended advertising, packets can be fragmented. 257 bytes is the + maximum size of a packet. + + config BT_LE_HCI_EVT_HI_BUF_COUNT + int "High Priority HCI Event Buffer count" + default 30 + help + This is the high priority HCI events' buffer size. High-priority + event buffers are for everything except advertising reports. If there + are no free high-priority event buffers then host will try to allocate a + low-priority buffer instead + + config BT_LE_HCI_EVT_LO_BUF_COUNT + int "Low Priority HCI Event Buffer count" + default 8 + help + This is the low priority HCI events' buffer size. Low-priority event + buffers are only used for advertising reports. If there are no free + low-priority event buffers, then an incoming advertising report will + get dropped +endmenu + +config BT_LE_CONTROLLER_TASK_STACK_SIZE + int "Controller task stack size" + default 5120 if BLE_MESH + default 4096 + help + This configures stack size of NimBLE controller task + +menuconfig BT_LE_CONTROLLER_LOG_ENABLED + bool "Controller log enable" + default n + help + Enable controller log + +config BT_LE_CONTROLLER_LOG_CTRL_ENABLED + bool "enable controller log module" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Enable controller log module + +config BT_LE_CONTROLLER_LOG_HCI_ENABLED + bool "enable HCI log module" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Enable hci log module + +config BT_LE_CONTROLLER_LOG_DUMP_ONLY + bool "Controller log dump mode only" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default y + help + Only operate in dump mode + +config BT_LE_LOG_CTRL_BUF1_SIZE + int "size of the first BLE controller LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 4096 + help + Configure the size of the first BLE controller LOG buffer. + +config BT_LE_LOG_CTRL_BUF2_SIZE + int "size of the second BLE controller LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 1024 + help + Configure the size of the second BLE controller LOG buffer. + +config BT_LE_LOG_HCI_BUF_SIZE + int "size of the BLE HCI LOG buffer" + depends on BT_LE_CONTROLLER_LOG_ENABLED + default 4096 + help + Configure the size of the BLE HCI LOG buffer. + +config BT_LE_LL_RESOLV_LIST_SIZE + int "BLE LL Resolving list size" + range 1 5 + default 4 + help + Configure the size of resolving list used in link layer. + +menuconfig BT_LE_SECURITY_ENABLE + bool "Enable BLE SM feature" + depends on !BT_NIMBLE_ENABLED + default y + help + Enable BLE sm feature + +config BT_LE_SM_LEGACY + bool "Security manager legacy pairing" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable security manager legacy pairing + +config BT_LE_SM_SC + bool "Security manager secure connections (4.2)" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable security manager secure connections + +config BT_LE_SM_SC_DEBUG_KEYS + bool "Use predefined public-private key pair" + default n + depends on BT_LE_SECURITY_ENABLE && BT_LE_SM_SC + help + If this option is enabled, SM uses predefined DH key pair as described + in Core Specification, Vol. 3, Part H, 2.3.5.6.1. This allows to + decrypt air traffic easily and thus should only be used for debugging. + +config BT_LE_LL_CFG_FEAT_LE_ENCRYPTION + bool "Enable LE encryption" + depends on BT_LE_SECURITY_ENABLE + default y + help + Enable encryption connection + +config BT_LE_CRYPTO_STACK_MBEDTLS + bool "Override TinyCrypt with mbedTLS for crypto computations" + default y + depends on !BT_NIMBLE_ENABLED + select MBEDTLS_CMAC_C + help + Enable this option to choose mbedTLS instead of TinyCrypt for crypto + computations. + +config BT_LE_WHITELIST_SIZE + int "BLE white list size" + range 1 15 + default 12 + depends on !BT_NIMBLE_ENABLED + + help + BLE list size + +config BT_LE_LL_DUP_SCAN_LIST_COUNT + int "BLE duplicate scan list count" + range 5 100 + default 20 + help + config the max count of duplicate scan list + +config BT_LE_LL_SCA + int "BLE Sleep clock accuracy" + range 0 500 + default 60 + help + Sleep clock accuracy of our device (in ppm) + +config BT_LE_MAX_CONNECTIONS + int "Maximum number of concurrent connections" + depends on !BT_NIMBLE_ENABLED + range 1 70 + default 3 + help + Defines maximum number of concurrent BLE connections. For ESP32, user + is expected to configure BTDM_CTRL_BLE_MAX_CONN from controller menu + along with this option. Similarly for ESP32-C3 or ESP32-S3, user is expected to + configure BT_CTRL_BLE_MAX_ACT from controller menu. + Each connection will take about 1k DRAM. + +choice BT_LE_COEX_PHY_CODED_TX_RX_TLIM + prompt "Coexistence: limit on MAX Tx/Rx time for coded-PHY connection" + default BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + depends on ESP_COEX_SW_COEXIST_ENABLE + help + When using PHY-Coded in BLE connection, limitation on max tx/rx time can be applied to + better avoid dramatic performance deterioration of Wi-Fi. + + config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EN + bool "Force Enable" + help + Always enable the limitation on max tx/rx time for Coded-PHY connection + + config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + bool "Force Disable" + help + Disable the limitation on max tx/rx time for Coded-PHY connection +endchoice + +config BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF + int + default 0 if !ESP_COEX_SW_COEXIST_ENABLE + default 1 if BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EN + default 0 if BT_LE_COEX_PHY_CODED_TX_RX_TLIM_DIS + +config BT_LE_SLEEP_ENABLE + bool "Enable BLE sleep" + default n + help + Enable BLE sleep + +choice BT_LE_LP_CLK_SRC + prompt "BLE low power clock source" + default BT_LE_LP_CLK_SRC_MAIN_XTAL + config BT_LE_LP_CLK_SRC_MAIN_XTAL + bool "Use main XTAL as RTC clock source" + help + User main XTAL as RTC clock source. + This option is recommended if external 32.768k XTAL is not available. + Using the external 32.768 kHz XTAL will have lower current consumption + in light sleep compared to using the main XTAL. + + config BT_LE_LP_CLK_SRC_DEFAULT + bool "Use system RTC slow clock source" + help + Use the same slow clock source as system RTC + Using any clock source other than external 32.768 kHz XTAL supports only + legacy ADV and SCAN due to low clock accuracy. + +endchoice + +config BT_LE_USE_ESP_TIMER + bool "Enable Esp Timer for Callout" + depends on !BT_NIMBLE_ENABLED + default y + help + Set this option to use Esp Timer which has higher priority timer + instead of FreeRTOS timer +config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + bool "BLE adv report flow control supported" + default y + help + The function is mainly used to enable flow control for advertising reports. When it is enabled, + advertising reports will be discarded by the controller if the number of unprocessed advertising + reports exceeds the size of BLE adv report flow control. + +config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM + int "BLE adv report flow control number" + depends on BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 50 1000 + default 100 + help + The number of unprocessed advertising report that bluetooth host can save.If you set + `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a small value, this may cause adv packets lost. + If you set `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` to a large value, bluetooth host may cache a + lot of adv packets and this may cause system memory run out. For example, if you set + it to 50, the maximum memory consumed by host is 35 * 50 bytes. Please set + `BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM` according to your system free memory and handle adv + packets as fast as possible, otherwise it will cause adv packets lost. + +config BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD + int "BLE adv lost event threshold value" + depends on BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP + range 1 1000 + default 20 + help + When adv report flow control is enabled, The ADV lost event will be generated when the number + of ADV packets lost in the controller reaches this threshold. It is better to set a larger value. + If you set `BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it + may cause adv packets lost more. + +config BT_LE_SCAN_DUPL + bool "BLE Scan Duplicate Options" + default y + help + This select enables parameters setting of BLE scan duplicate. + +choice BT_LE_SCAN_DUPL_TYPE + prompt "Scan Duplicate Type" + default BT_LE_SCAN_DUPL_TYPE_DEVICE + depends on BT_LE_SCAN_DUPL + help + Scan duplicate have three ways. one is "Scan Duplicate By Device Address", This way is to use + advertiser address filtering. The adv packet of the same address is only allowed to be reported once. + Another way is "Scan Duplicate By Device Address And Advertising Data". This way is to use advertising + data and device address filtering. All different adv packets with the same address are allowed to be + reported. The last way is "Scan Duplicate By Advertising Data". This way is to use advertising data + filtering. All same advertising data only allow to be reported once even though they are from + different devices. + + config BT_LE_SCAN_DUPL_TYPE_DEVICE + bool "Scan Duplicate By Device Address" + help + This way is to use advertiser address filtering. The adv packet of the same address is only + allowed to be reported once + + config BT_LE_SCAN_DUPL_TYPE_DATA + bool "Scan Duplicate By Advertising Data" + help + This way is to use advertising data filtering. All same advertising data only allow to be reported + once even though they are from different devices. + + config BT_LE_SCAN_DUPL_TYPE_DATA_DEVICE + bool "Scan Duplicate By Device Address And Advertising Data" + help + This way is to use advertising data and device address filtering. All different adv packets with + the same address are allowed to be reported. +endchoice + +config BT_LE_SCAN_DUPL_TYPE + int + depends on BT_LE_SCAN_DUPL + default 0 if BT_LE_SCAN_DUPL_TYPE_DEVICE + default 1 if BT_LE_SCAN_DUPL_TYPE_DATA + default 2 if BT_LE_SCAN_DUPL_TYPE_DATA_DEVICE + default 0 + +config BT_LE_SCAN_DUPL_CACHE_REFRESH_PERIOD + int "Duplicate scan list refresh period (seconds)" + depends on BT_LE_SCAN_DUPL + range 0 1000 + default 0 + help + If the period value is non-zero, the controller will periodically clear the device information + stored in the scan duuplicate filter. If it is 0, the scan duuplicate filter will not be cleared + until the scanning is disabled. Duplicate advertisements for this period should not be sent to the + Host in advertising report events. + There are two scenarios where the ADV packet will be repeatedly reported: + 1. The duplicate scan cache is full, the controller will delete the oldest device information and + add new device information. + 2. When the refresh period is up, the controller will clear all device information and start filtering + again. + +config BT_LE_MSYS_INIT_IN_CONTROLLER + bool "Msys Mbuf Init in Controller" + default y diff --git a/lib/bt/controller/esp32c5/bt.c b/lib/bt/controller/esp32c5/bt.c new file mode 100644 index 00000000..17794564 --- /dev/null +++ b/lib/bt/controller/esp32c5/bt.c @@ -0,0 +1,1438 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +#include "esp_random.h" +#include "esp_heap_caps.h" +#include "esp_heap_caps_init.h" +#include + +#include "sdkconfig.h" + +#if CONFIG_BT_NIMBLE_ENABLED +#include "nimble/nimble_port.h" +#endif // CONFIG_BT_NIMBLE_ENABLED +#include "nimble/nimble_port_freertos.h" +#include "esp_private/esp_modem_clock.h" + +#ifdef ESP_PLATFORM +#include "esp_log.h" +#endif // ESP_PLATFORM + +#if CONFIG_SW_COEXIST_ENABLE +#include "private/esp_coexist_internal.h" +#endif // CONFIG_SW_COEXIST_ENABLE + +#include "nimble/nimble_npl_os.h" +#include "ble_hci_trans.h" +#include "os/endian.h" + +#include "esp_bt.h" +#include "esp_intr_alloc.h" +#include "esp_sleep.h" +#include "esp_pm.h" +#include "esp_phy_init.h" +#include "esp_private/periph_ctrl.h" +#include "hci_uart.h" +#include "bt_osi_mem.h" + +#if SOC_PM_RETENTION_HAS_CLOCK_BUG +#include "esp_private/sleep_retention.h" +#endif // SOC_PM_RETENTION_HAS_CLOCK_BUG + +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +#include "esp_private/sleep_modem.h" +#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +#include "hci/hci_hal.h" +#endif // CONFIG_BT_BLUEDROID_ENABLED + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_private/periph_ctrl.h" +#include "esp_sleep.h" + +#include "hal/efuse_hal.h" +#include "soc/rtc.h" +/* Macro definition + ************************************************************************ + */ +#define NIMBLE_PORT_LOG_TAG "BLE_INIT" +#define OSI_COEX_VERSION 0x00010006 +#define OSI_COEX_MAGIC_VALUE 0xFADEBEAD + +#define EXT_FUNC_VERSION 0x20221122 +#define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5 + +#define BT_ASSERT_PRINT ets_printf + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +/* ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data */ +#define ACL_DATA_MBUF_LEADINGSPCAE 4 +#endif // CONFIG_BT_BLUEDROID_ENABLED + +/* Types definition + ************************************************************************ + */ +struct osi_coex_funcs_t { + uint32_t _magic; + uint32_t _version; + void (* _coex_wifi_sleep_set)(bool sleep); + int (* _coex_core_ble_conn_dyn_prio_get)(bool *low, bool *high); + void (* _coex_schm_status_bit_set)(uint32_t type, uint32_t status); + void (* _coex_schm_status_bit_clear)(uint32_t type, uint32_t status); +}; + +struct ext_funcs_t { + uint32_t ext_version; + int (*_esp_intr_alloc)(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle); + int (*_esp_intr_free)(void **ret_handle); + void *(* _malloc)(size_t size); + void (*_free)(void *p); + void (*_hal_uart_start_tx)(int); + int (*_hal_uart_init_cbs)(int, hci_uart_tx_char, hci_uart_tx_done, hci_uart_rx_char, void *); + int (*_hal_uart_config)(int, int32_t, uint8_t, uint8_t, uart_parity_t, uart_hw_flowcontrol_t); + int (*_hal_uart_close)(int); + void (*_hal_uart_blocking_tx)(int, uint8_t); + int (*_hal_uart_init)(int, void *); + int (* _task_create)(void *task_func, const char *name, uint32_t stack_depth, void *param, + uint32_t prio, void *task_handle, uint32_t core_id); + void (* _task_delete)(void *task_handle); + void (*_osi_assert)(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2); + uint32_t (* _os_random)(void); + int (* _ecc_gen_key_pair)(uint8_t *public, uint8_t *priv); + int (* _ecc_gen_dh_key)(const uint8_t *remote_pub_key_x, const uint8_t *remote_pub_key_y, + const uint8_t *local_priv_key, uint8_t *dhkey); + void (* _esp_reset_rpa_moudle)(void); + uint32_t magic; +}; + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +typedef void (*interface_func_t) (uint32_t len, const uint8_t*addr, bool end); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +/* External functions or variables + ************************************************************************ + */ +extern int ble_osi_coex_funcs_register(struct osi_coex_funcs_t *coex_funcs); +extern int r_ble_controller_init(esp_bt_controller_config_t *cfg); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +extern int r_ble_log_init_async(interface_func_t bt_controller_log_interface, bool task_create, uint8_t buffers, uint32_t *bufs_size); +extern int r_ble_log_deinit_async(void); +extern void r_ble_log_async_select_dump_buffers(uint8_t buffers); +extern void r_ble_log_async_output_dump_all(bool output); +extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +extern int r_ble_controller_deinit(void); +extern int r_ble_controller_enable(uint8_t mode); +extern int r_ble_controller_disable(void); +extern int esp_register_ext_funcs (struct ext_funcs_t *); +extern void esp_unregister_ext_funcs (void); +extern int r_esp_ble_ll_set_public_addr(const uint8_t *addr); +extern int esp_register_npl_funcs (struct npl_funcs_t *p_npl_func); +extern void esp_unregister_npl_funcs (void); +extern void npl_freertos_mempool_deinit(void); +extern uint32_t r_os_cputime_get32(void); +extern uint32_t r_os_cputime_ticks_to_usecs(uint32_t ticks); +extern void r_ble_lll_rfmgmt_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, + void *w_arg, uint32_t us_to_enabled); +extern void r_ble_rtc_wake_up_state_clr(void); +extern int os_msys_init(void); +extern void os_msys_deinit(void); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +extern const sleep_retention_entries_config_t *esp_ble_mac_retention_link_get(uint8_t *size, uint8_t extra); +extern void esp_ble_set_wakeup_overhead(uint32_t overhead); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ +extern void r_esp_ble_change_rtc_freq(uint32_t freq); +extern int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, + const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey); +extern int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); +extern int r_ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); +extern int r_ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); +extern int r_ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); +extern char *ble_controller_get_compile_version(void); +extern int esp_ble_register_bb_funcs(void); +extern void esp_ble_unregister_bb_funcs(void); +extern uint32_t _bt_bss_start; +extern uint32_t _bt_bss_end; +extern uint32_t _bt_controller_bss_start; +extern uint32_t _bt_controller_bss_end; +extern uint32_t _bt_data_start; +extern uint32_t _bt_data_end; +extern uint32_t _bt_controller_data_start; +extern uint32_t _bt_controller_data_end; + +/* Local Function Declaration + ********************************************************************* + */ +static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status); +static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status); +static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, + void *param, uint32_t prio, void *task_handle, uint32_t core_id); +static void task_delete_wrapper(void *task_handle); +#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static void hci_uart_start_tx_wrapper(int uart_no); +static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, + hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg); +static int hci_uart_config_wrapper(int uart_no, int32_t speed, uint8_t databits, uint8_t stopbits, + uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl); +static int hci_uart_close_wrapper(int uart_no); +static void hci_uart_blocking_tx_wrapper(int port, uint8_t data); +static int hci_uart_init_wrapper(int uart_no, void *cfg); +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, + void *arg, void **ret_handle_in); +static int esp_intr_free_wrapper(void **ret_handle); +static void osi_assert_wrapper(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2); +static uint32_t osi_random_wrapper(void); +static void esp_reset_rpa_moudle(void); +static int esp_ecc_gen_key_pair(uint8_t *pub, uint8_t *priv); +static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +/* Local variable definition + *************************************************************************** + */ +/* Static variable declare */ +static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +/* This variable tells if BLE is running */ +static bool s_ble_active = false; +#ifdef CONFIG_PM_ENABLE +static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock = NULL; +#define BTDM_MIN_TIMER_UNCERTAINTY_US (200) +#endif // CONFIG_PM_ENABLE + +#define BLE_RTC_DELAY_US_LIGHT_SLEEP (2500) +#define BLE_RTC_DELAY_US_MODEM_SLEEP (500) + +static const struct osi_coex_funcs_t s_osi_coex_funcs_ro = { + ._magic = OSI_COEX_MAGIC_VALUE, + ._version = OSI_COEX_VERSION, + ._coex_wifi_sleep_set = NULL, + ._coex_core_ble_conn_dyn_prio_get = NULL, + ._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper, + ._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper, +}; + +struct ext_funcs_t ext_funcs_ro = { + .ext_version = EXT_FUNC_VERSION, + ._esp_intr_alloc = esp_intr_alloc_wrapper, + ._esp_intr_free = esp_intr_free_wrapper, + ._malloc = bt_osi_mem_malloc_internal, + ._free = bt_osi_mem_free, +#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART + ._hal_uart_start_tx = hci_uart_start_tx_wrapper, + ._hal_uart_init_cbs = hci_uart_init_cbs_wrapper, + ._hal_uart_config = hci_uart_config_wrapper, + ._hal_uart_close = hci_uart_close_wrapper, + ._hal_uart_blocking_tx = hci_uart_blocking_tx_wrapper, + ._hal_uart_init = hci_uart_init_wrapper, +#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART + ._task_create = task_create_wrapper, + ._task_delete = task_delete_wrapper, + ._osi_assert = osi_assert_wrapper, + ._os_random = osi_random_wrapper, + ._ecc_gen_key_pair = esp_ecc_gen_key_pair, + ._ecc_gen_dh_key = esp_ecc_gen_dh_key, + ._esp_reset_rpa_moudle = esp_reset_rpa_moudle, + .magic = EXT_FUNC_MAGIC_VALUE, +}; + +static void IRAM_ATTR esp_reset_rpa_moudle(void) +{ + +} + +static void IRAM_ATTR osi_assert_wrapper(const uint32_t ln, const char *fn, + uint32_t param1, uint32_t param2) +{ + BT_ASSERT_PRINT("BLE assert: line %d in function %s, param: 0x%x, 0x%x", ln, fn, param1, param2); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + esp_ble_controller_log_dump_all(true); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + assert(0); +} + +static uint32_t IRAM_ATTR osi_random_wrapper(void) +{ + return esp_random(); +} + +static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_set(type, status); +#endif // CONFIG_SW_COEXIST_ENABLE +} + +static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) +{ +#if CONFIG_SW_COEXIST_ENABLE + coex_schm_status_bit_clear(type, status); +#endif // CONFIG_SW_COEXIST_ENABLE +} + +#ifdef CONFIG_BT_BLUEDROID_ENABLED +bool esp_vhci_host_check_send_available(void) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return false; + } + return true; +} + +static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space) +{ + struct os_mbuf *om; + int rc; + + om = os_msys_get_pkthdr(0, 0); + if (om == NULL) { + return NULL; + } + + if (om->om_omp->omp_databuf_len < leading_space) { + rc = os_mbuf_free_chain(om); + assert(rc == 0); + return NULL; + } + + om->om_data += leading_space; + + return om; +} + +struct os_mbuf *ble_hs_mbuf_acl_pkt(void) +{ + return ble_hs_mbuf_gen_pkt(4 + 1); +} + +void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return; + } + + if (*(data) == DATA_TYPE_COMMAND) { + struct ble_hci_cmd *cmd = NULL; + cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + assert(cmd); + memcpy((uint8_t *)cmd, data + 1, len - 1); + ble_hci_trans_hs_cmd_tx((uint8_t *)cmd); + } + + if (*(data) == DATA_TYPE_ACL) { + struct os_mbuf *om = os_msys_get_pkthdr(len, ACL_DATA_MBUF_LEADINGSPCAE); + assert(om); + assert(os_mbuf_append(om, &data[1], len - 1) == 0); + ble_hci_trans_hs_acl_tx(om); + } +} + +esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) +{ + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_FAIL; + } + + ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL); + + return ESP_OK; +} +#endif // CONFIG_BT_BLUEDROID_ENABLED + +static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, + void *param, uint32_t prio, void *task_handle, uint32_t core_id) +{ + return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, + (core_id < CONFIG_FREERTOS_NUMBER_OF_CORES ? core_id : tskNO_AFFINITY)); +} + +static void task_delete_wrapper(void *task_handle) +{ + vTaskDelete(task_handle); +} + +static int esp_ecc_gen_key_pair(uint8_t *pub, uint8_t *priv) +{ + int rc = -1; +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + rc = ble_sm_alg_gen_key_pair(pub, priv); +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + return rc; +} + +static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey) +{ + int rc = -1; +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + rc = ble_sm_alg_gen_dhkey(peer_pub_key_x, peer_pub_key_y, our_priv_key, out_dhkey); +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC + return rc; +} + +#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART +static void hci_uart_start_tx_wrapper(int uart_no) +{ + hci_uart_start_tx(uart_no); +} + +static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, + hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg) +{ + int rc = -1; + rc = hci_uart_init_cbs(uart_no, tx_func, tx_done, rx_func, arg); + return rc; +} + + +static int hci_uart_config_wrapper(int port_num, int32_t baud_rate, uint8_t data_bits, + uint8_t stop_bits, uart_parity_t parity, + uart_hw_flowcontrol_t flow_ctl) +{ + int rc = -1; + rc = hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl); + return rc; +} + +static int hci_uart_close_wrapper(int uart_no) +{ + int rc = -1; + rc = hci_uart_close(uart_no); + return rc; +} + +static void hci_uart_blocking_tx_wrapper(int port, uint8_t data) +{ + //This function is nowhere to use. +} + +static int hci_uart_init_wrapper(int uart_no, void *cfg) +{ + //This function is nowhere to use. + return 0; +} + +#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART + +static int ble_hci_unregistered_hook(void*, void*) +{ + ESP_LOGD(NIMBLE_PORT_LOG_TAG,"%s ble hci rx_evt is not registered.",__func__); + return 0; +} + +static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, + void *arg, void **ret_handle_in) +{ + int rc = esp_intr_alloc(source, flags | ESP_INTR_FLAG_IRAM, handler, + arg, (intr_handle_t *)ret_handle_in); + return rc; +} + +static int esp_intr_free_wrapper(void **ret_handle) +{ + int rc = 0; + rc = esp_intr_free((intr_handle_t) * ret_handle); + *ret_handle = NULL; + return rc; +} + +void esp_bt_rtc_slow_clk_select(uint8_t slow_clk_src) +{ + /* Select slow clock source for BT momdule */ + // switch (slow_clk_src) { + // case MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL: + // ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using main XTAL as clock source"); + // uint32_t chip_version = efuse_hal_chip_revision(); + // if (chip_version == 0) { + // modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (400 - 1)); + // } else{ + // modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (5 - 1)); + // } + // break; + // case MODEM_CLOCK_LPCLK_SRC_RC_SLOW: + // ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using 136 kHz RC as clock source, can only run legacy ADV or SCAN due to low clock accuracy!"); + // modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (5 - 1)); + // break; + // case MODEM_CLOCK_LPCLK_SRC_XTAL32K: + // ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using external 32.768 kHz XTAL as clock source"); + // modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (1 - 1)); + // break; + // case MODEM_CLOCK_LPCLK_SRC_RC32K: + // ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using 32 kHz RC as clock source, can only run legacy ADV or SCAN due to low clock accuracy!"); + // modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (1 - 1)); + // break; + // case MODEM_CLOCK_LPCLK_SRC_EXT32K: + // ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Using 32 kHz oscillator as clock source, can only run legacy ADV or SCAN due to low clock accuracy!"); + // modem_clock_select_lp_clock_source(PERIPH_BT_MODULE, slow_clk_src, (1 - 1)); + // break; + // default: + // } +} + +IRAM_ATTR void controller_sleep_cb(uint32_t enable_tick, void *arg) +{ + if (!s_ble_active) { + return; + } +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + r_ble_rtc_wake_up_state_clr(); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + esp_phy_disable(PHY_MODEM_BT); +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + s_ble_active = false; +} + +IRAM_ATTR void controller_wakeup_cb(void *arg) +{ + if (s_ble_active) { + return; + } +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_acquire(s_pm_lock); + r_ble_rtc_wake_up_state_clr(); +#endif //CONFIG_PM_ENABLE + esp_phy_enable(PHY_MODEM_BT); + s_ble_active = true; +} + +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +static esp_err_t sleep_modem_ble_mac_modem_state_init(uint8_t extra) +{ + uint8_t size; + const sleep_retention_entries_config_t *ble_mac_modem_config = esp_ble_mac_retention_link_get(&size, extra); + esp_err_t err = sleep_retention_entries_create(ble_mac_modem_config, size, REGDMA_LINK_PRI_BT_MAC_BB, SLEEP_RETENTION_MODULE_BLE_MAC); + if (err == ESP_OK) { + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Modem BLE MAC retention initialization"); + } + return err; +} + +static void sleep_modem_ble_mac_modem_state_deinit(void) +{ + sleep_retention_entries_destroy(SLEEP_RETENTION_MODULE_BLE_MAC); +} + +void sleep_modem_light_sleep_overhead_set(uint32_t overhead) +{ + esp_ble_set_wakeup_overhead(overhead); +} +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + + +esp_err_t controller_sleep_init(void) +{ + esp_err_t rc = 0; + +#ifdef CONFIG_BT_LE_SLEEP_ENABLE + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "BLE modem sleep is enabled"); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + BLE_RTC_DELAY_US_LIGHT_SLEEP); +#else + r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + BLE_RTC_DELAY_US_MODEM_SLEEP); +#endif /* FREERTOS_USE_TICKLESS_IDLE */ +#endif // CONFIG_BT_LE_SLEEP_ENABLE + +#ifdef CONFIG_PM_ENABLE + rc = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "bt", &s_pm_lock); + if (rc != ESP_OK) { + goto error; + } +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + /* Create a new regdma link for BLE related register restoration */ + rc = sleep_modem_ble_mac_modem_state_init(1); + assert(rc == 0); + esp_sleep_enable_bt_wakeup(); + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "Enable light sleep, the wake up source is BLE timer"); + + rc = esp_pm_register_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); + if (rc != ESP_OK) { + goto error; + } + +#if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + sleep_modem_register_mac_bb_module_prepare_callback(sleep_modem_mac_bb_power_down_prepare, + sleep_modem_mac_bb_power_up_prepare); +#endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + return rc; + +error: + +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +#if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + sleep_modem_unregister_mac_bb_module_prepare_callback(sleep_modem_mac_bb_power_down_prepare, + sleep_modem_mac_bb_power_up_prepare); +#endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + esp_sleep_disable_bt_wakeup(); + esp_pm_unregister_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + /*lock should release first and then delete*/ + if (s_pm_lock != NULL) { + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; + } +#endif // CONFIG_PM_ENABLE + + return rc; +} + +void controller_sleep_deinit(void) +{ +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +#if SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + sleep_modem_unregister_mac_bb_module_prepare_callback(sleep_modem_mac_bb_power_down_prepare, + sleep_modem_mac_bb_power_up_prepare); +#endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD + r_ble_rtc_wake_up_state_clr(); + esp_sleep_disable_bt_wakeup(); + sleep_modem_ble_mac_modem_state_deinit(); + esp_pm_unregister_inform_out_light_sleep_overhead_callback(sleep_modem_light_sleep_overhead_set); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ +#ifdef CONFIG_PM_ENABLE + /* lock should be released first */ + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; +#endif //CONFIG_PM_ENABLE +} + +typedef enum { + FILTER_DUPLICATE_PDUTYPE = BIT(0), + FILTER_DUPLICATE_LENGTH = BIT(1), + FILTER_DUPLICATE_ADDRESS = BIT(2), + FILTER_DUPLICATE_ADVDATA = BIT(3), + FILTER_DUPLICATE_DEFAULT = FILTER_DUPLICATE_PDUTYPE | FILTER_DUPLICATE_ADDRESS, + FILTER_DUPLICATE_PDU_ALL = 0xF, + FILTER_DUPLICATE_EXCEPTION_FOR_MESH = BIT(4), + FILTER_DUPLICATE_AD_TYPE = BIT(5), +}disc_duplicate_mode_t; + + +extern void r_filter_duplicate_mode_enable(disc_duplicate_mode_t mode); +extern void r_filter_duplicate_mode_disable(disc_duplicate_mode_t mode); +extern void r_filter_duplicate_set_ring_list_max_num(uint32_t max_num); +extern void r_scan_duplicate_cache_refresh_set_time(uint32_t period_time); + +int +ble_vhci_disc_duplicate_mode_enable(int mode) +{ + // TODO: use vendor hci to update + r_filter_duplicate_mode_enable(mode); + return true; +} + +int +ble_vhci_disc_duplicate_mode_disable(int mode) +{ + // TODO: use vendor hci to update + r_filter_duplicate_mode_disable(mode); + return true; +} + +int ble_vhci_disc_duplicate_set_max_cache_size(int max_cache_size){ + // TODO: use vendor hci to update + r_filter_duplicate_set_ring_list_max_num(max_cache_size); + return true; +} + +int ble_vhci_disc_duplicate_set_period_refresh_time(int refresh_period_time){ + // TODO: use vendor hci to update + r_scan_duplicate_cache_refresh_set_time(refresh_period_time); + return true; +} + +/** + * @brief Config scan duplicate option mode from menuconfig (Adapt to the old configuration method.) + */ +void ble_controller_scan_duplicate_config(void) +{ + uint32_t duplicate_mode = FILTER_DUPLICATE_DEFAULT; + uint32_t cache_size = 100; +#if CONFIG_BT_LE_SCAN_DUPL == true + cache_size = CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT; + if (CONFIG_BT_LE_SCAN_DUPL_TYPE == 0) { + duplicate_mode = FILTER_DUPLICATE_ADDRESS | FILTER_DUPLICATE_PDUTYPE; + } else if (CONFIG_BT_LE_SCAN_DUPL_TYPE == 1) { + duplicate_mode = FILTER_DUPLICATE_ADVDATA; + } else if (CONFIG_BT_LE_SCAN_DUPL_TYPE == 2) { + duplicate_mode = FILTER_DUPLICATE_ADDRESS | FILTER_DUPLICATE_ADVDATA; + } + duplicate_mode |= FILTER_DUPLICATE_EXCEPTION_FOR_MESH; + + ble_vhci_disc_duplicate_set_period_refresh_time(CONFIG_BT_LE_SCAN_DUPL_CACHE_REFRESH_PERIOD); +#endif + + ble_vhci_disc_duplicate_mode_disable(0xFFFFFFFF); + ble_vhci_disc_duplicate_mode_enable(duplicate_mode); + ble_vhci_disc_duplicate_set_max_cache_size(cache_size); +} + +esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) +{ + uint8_t mac[6]; + esp_err_t ret = ESP_OK; + ble_npl_count_info_t npl_info; + uint32_t slow_clk_freq = 0; + + memset(&npl_info, 0, sizeof(ble_npl_count_info_t)); + + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_ERR_INVALID_STATE; + } + + if (!cfg) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "cfg is NULL"); + return ESP_ERR_INVALID_ARG; + } + + ret = esp_register_ext_funcs(&ext_funcs_ro); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "register extend functions failed"); + return ret; + } + + /* Initialize the function pointers for OS porting */ + npl_freertos_funcs_init(); + struct npl_funcs_t *p_npl_funcs = npl_freertos_funcs_get(); + if (!p_npl_funcs) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl functions get failed"); + return ESP_ERR_INVALID_ARG; + } + + ret = esp_register_npl_funcs(p_npl_funcs); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl functions register failed"); + goto free_mem; + } + + r_ble_get_npl_element_info(cfg, &npl_info); + npl_freertos_set_controller_npl_info(&npl_info); + if (npl_freertos_mempool_init() != 0) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl mempool init failed"); + ret = ESP_ERR_INVALID_ARG; + goto free_mem; + } + +#if CONFIG_BT_NIMBLE_ENABLED + /* ble_npl_eventq_init() needs to use npl functions in rom and + * must be called after esp_bt_controller_init(). + */ + ble_npl_eventq_init(nimble_port_get_dflt_eventq()); +#endif // CONFIG_BT_NIMBLE_ENABLED + /* Enable BT-related clocks */ + modem_clock_module_enable(PERIPH_BT_MODULE); + modem_clock_module_mac_reset(PERIPH_BT_MODULE); + /* Select slow clock source for BT momdule */ +#if CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL); + slow_clk_freq = 100000; +#else +#if CONFIG_RTC_CLK_SRC_INT_RC + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_RC_SLOW); + slow_clk_freq = 30000; +#elif CONFIG_RTC_CLK_SRC_EXT_CRYS + if (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_XTAL32K); + slow_clk_freq = 32768; + } else { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock"); + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL); + slow_clk_freq = 100000; + } +#elif CONFIG_RTC_CLK_SRC_INT_RC32K + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_RC32K); + slow_clk_freq = 32000; +#elif CONFIG_RTC_CLK_SRC_EXT_OSC + esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_EXT32K); + slow_clk_freq = 32000; +#else + ESP_LOGE(NIMBLE_PORT_LOG_TAG, "Unsupported clock source"); + assert(0); +#endif +#endif /* CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL */ + esp_phy_modem_init(); + + if (ble_osi_coex_funcs_register((struct osi_coex_funcs_t *)&s_osi_coex_funcs_ro) != 0) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "osi coex funcs reg failed"); + ret = ESP_ERR_INVALID_ARG; + goto modem_deint; + } + +#if CONFIG_SW_COEXIST_ENABLE + coex_init(); +#endif // CONFIG_SW_COEXIST_ENABLE + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + interface_func_t bt_controller_log_interface; + bt_controller_log_interface = esp_bt_controller_log_interface; + uint8_t buffers = 0; +#if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED + buffers |= ESP_BLE_LOG_BUF_CONTROLLER; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED +#if CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED + buffers |= ESP_BLE_LOG_BUF_HCI; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED +#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY + ret = r_ble_log_init_async(bt_controller_log_interface, false, buffers, (uint32_t *)log_bufs_size); +#else + ret = r_ble_log_init_async(bt_controller_log_interface, true, buffers, (uint32_t *)log_bufs_size); +#endif // CONFIG_BT_CONTROLLER_LOG_DUMP + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); + goto modem_deint; + } +#endif // CONFIG_BT_CONTROLLER_LOG_ENABLED + ret = esp_ble_register_bb_funcs(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "esp_ble_register_bb_funcs failed %d", ret); + goto modem_deint; + } + + ret = r_ble_controller_init(cfg); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "r_ble_controller_init failed %d", ret); + goto modem_deint; + } + + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); + r_esp_ble_change_rtc_freq(slow_clk_freq); + + ble_controller_scan_duplicate_config(); + + ret = os_msys_init(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "msys_init failed %d", ret); + goto free_controller; + } + + ret = controller_sleep_init(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "controller_sleep_init failed %d", ret); + goto free_controller; + } + ESP_ERROR_CHECK(esp_read_mac((uint8_t *)mac, ESP_MAC_BT)); + swap_in_place(mac, 6); + r_esp_ble_ll_set_public_addr(mac); + + ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + + ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hci_unregistered_hook,NULL, + (ble_hci_trans_rx_acl_fn *)ble_hci_unregistered_hook,NULL); + return ESP_OK; + +free_controller: + controller_sleep_deinit(); + os_msys_deinit(); + r_ble_controller_deinit(); +modem_deint: + esp_ble_unregister_bb_funcs(); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + r_ble_log_deinit_async(); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + esp_phy_modem_deinit(); + // modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); + modem_clock_module_disable(PERIPH_BT_MODULE); +#if CONFIG_BT_NIMBLE_ENABLED + ble_npl_eventq_deinit(nimble_port_get_dflt_eventq()); +#endif // CONFIG_BT_NIMBLE_ENABLED +free_mem: + npl_freertos_mempool_deinit(); + esp_unregister_npl_funcs(); + npl_freertos_funcs_deinit(); + esp_unregister_ext_funcs(); + return ret; +} + +esp_err_t esp_bt_controller_deinit(void) +{ + if ((ble_controller_status < ESP_BT_CONTROLLER_STATUS_INITED) || + (ble_controller_status >= ESP_BT_CONTROLLER_STATUS_ENABLED)) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + + controller_sleep_deinit(); + + os_msys_deinit(); + + esp_phy_modem_deinit(); + // modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); + modem_clock_module_disable(PERIPH_BT_MODULE); + + r_ble_controller_deinit(); + esp_ble_unregister_bb_funcs(); +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + r_ble_log_deinit_async(); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +#if CONFIG_BT_NIMBLE_ENABLED + /* De-initialize default event queue */ + ble_npl_eventq_deinit(nimble_port_get_dflt_eventq()); +#endif // CONFIG_BT_NIMBLE_ENABLED + + esp_unregister_npl_funcs(); + + esp_unregister_ext_funcs(); + + /* De-initialize npl functions */ + npl_freertos_funcs_deinit(); + + npl_freertos_mempool_deinit(); + + ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; + + return ESP_OK; +} + +esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) +{ + esp_err_t ret = ESP_OK; + + if (mode != ESP_BT_MODE_BLE) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller mode"); + return ESP_FAIL; + } + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + if (!s_ble_active) { +#if CONFIG_PM_ENABLE + esp_pm_lock_acquire(s_pm_lock); +#endif // CONFIG_PM_ENABLE + esp_phy_enable(PHY_MODEM_BT); + s_ble_active = true; + } + esp_btbb_enable(); +#if CONFIG_SW_COEXIST_ENABLE + coex_enable(); +#endif // CONFIG_SW_COEXIST_ENABLE + + if (r_ble_controller_enable(mode) != 0) { + ret = ESP_FAIL; + goto error; + } + ble_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED; + return ESP_OK; + +error: +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + esp_btbb_disable(); + if (s_ble_active) { + esp_phy_disable(PHY_MODEM_BT); +#if CONFIG_PM_ENABLE + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + s_ble_active = false; + } + return ret; +} + +esp_err_t esp_bt_controller_disable(void) +{ + if (ble_controller_status < ESP_BT_CONTROLLER_STATUS_ENABLED) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); + return ESP_FAIL; + } + if (r_ble_controller_disable() != 0) { + return ESP_FAIL; + } +#if CONFIG_SW_COEXIST_ENABLE + coex_disable(); +#endif + esp_btbb_disable(); + if (s_ble_active) { + esp_phy_disable(PHY_MODEM_BT); +#if CONFIG_PM_ENABLE + esp_pm_lock_release(s_pm_lock); +#endif // CONFIG_PM_ENABLE + s_ble_active = false; + } + ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; + return ESP_OK; +} + +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode) +{ + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "%s not implemented, return OK", __func__); + return ESP_OK; +} + +static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) +{ + int ret = heap_caps_add_region(start, end); + + /* heap_caps_add_region() returns ESP_ERR_INVALID_SIZE if the memory region is + * is too small to fit a heap. This cannot be termed as a fatal error and hence + * we replace it by ESP_OK + */ + if (ret == ESP_ERR_INVALID_SIZE) { + return ESP_OK; + } + return ret; +} + + +typedef struct { + intptr_t start; + intptr_t end; + const char* name; +} bt_area_t; + +static esp_err_t esp_bt_mem_release_area(const bt_area_t *area) +{ + esp_err_t ret = ESP_OK; + intptr_t mem_start = area->start; + intptr_t mem_end = area->end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release %s [0x%08x] - [0x%08x], len %d", area->name, mem_start, mem_end, mem_end - mem_start); + ret = try_heap_caps_add_region(mem_start, mem_end); + } + return ret; +} + +static esp_err_t esp_bt_mem_release_areas(const bt_area_t *area1, const bt_area_t *area2) +{ + esp_err_t ret = ESP_OK; + + if (area1->end == area2->start) { + bt_area_t merged_area = { + .start = area1->start, + .end = area2->end, + .name = area1->name + }; + ret = esp_bt_mem_release_area(&merged_area); + } else { + esp_bt_mem_release_area(area1); + ret = esp_bt_mem_release_area(area2); + } + + return ret; +} + +esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) +{ + esp_err_t ret = ESP_OK; + + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; + } + + bt_area_t bss = { + .start = (intptr_t)&_bt_bss_start, + .end = (intptr_t)&_bt_bss_end, + .name = "BT BSS", + }; + bt_area_t cont_bss = { + .start = (intptr_t)&_bt_controller_bss_start, + .end = (intptr_t)&_bt_controller_bss_end, + .name = "BT Controller BSS", + }; + bt_area_t data = { + .start = (intptr_t)&_bt_data_start, + .end = (intptr_t)&_bt_data_end, + .name = "BT Data", + }; + bt_area_t cont_data = { + .start = (intptr_t)&_bt_controller_data_start, + .end = (intptr_t)&_bt_controller_data_end, + .name = "BT Controller Data" + }; + + if (mode & ESP_BT_MODE_BLE) { + /* Start by freeing Bluetooth BSS section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&bss, &cont_bss); + } + + /* Do the same thing with the Bluetooth data section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&data, &cont_data); + } + } + + return ret; +} + + +esp_bt_controller_status_t esp_bt_controller_get_status(void) +{ + return ble_controller_status; +} + +esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_t power_level) +{ + esp_err_t stat = ESP_FAIL; + + switch (power_type) { + case ESP_BLE_PWR_TYPE_DEFAULT: + case ESP_BLE_PWR_TYPE_ADV: + case ESP_BLE_PWR_TYPE_SCAN: + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + stat = ESP_OK; + } + break; + case ESP_BLE_PWR_TYPE_CONN_HDL0: + case ESP_BLE_PWR_TYPE_CONN_HDL1: + case ESP_BLE_PWR_TYPE_CONN_HDL2: + case ESP_BLE_PWR_TYPE_CONN_HDL3: + case ESP_BLE_PWR_TYPE_CONN_HDL4: + case ESP_BLE_PWR_TYPE_CONN_HDL5: + case ESP_BLE_PWR_TYPE_CONN_HDL6: + case ESP_BLE_PWR_TYPE_CONN_HDL7: + case ESP_BLE_PWR_TYPE_CONN_HDL8: + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { + stat = ESP_OK; + } + break; + default: + stat = ESP_ERR_NOT_SUPPORTED; + break; + } + + return stat; +} + +esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle, + esp_power_level_t power_level) +{ + esp_err_t stat = ESP_FAIL; + switch (power_type) { + case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: + case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: + case ESP_BLE_ENHANCED_PWR_TYPE_INIT: + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + stat = ESP_OK; + } + break; + case ESP_BLE_ENHANCED_PWR_TYPE_ADV: + case ESP_BLE_ENHANCED_PWR_TYPE_CONN: + if (r_ble_txpwr_set(power_type, handle, power_level) == 0) { + stat = ESP_OK; + } + break; + default: + stat = ESP_ERR_NOT_SUPPORTED; + break; + } + + return stat; +} + +esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) +{ + int tx_level = 0; + + switch (power_type) { + case ESP_BLE_PWR_TYPE_ADV: + case ESP_BLE_PWR_TYPE_SCAN: + case ESP_BLE_PWR_TYPE_DEFAULT: + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + break; + case ESP_BLE_PWR_TYPE_CONN_HDL0: + case ESP_BLE_PWR_TYPE_CONN_HDL1: + case ESP_BLE_PWR_TYPE_CONN_HDL2: + case ESP_BLE_PWR_TYPE_CONN_HDL3: + case ESP_BLE_PWR_TYPE_CONN_HDL4: + case ESP_BLE_PWR_TYPE_CONN_HDL5: + case ESP_BLE_PWR_TYPE_CONN_HDL6: + case ESP_BLE_PWR_TYPE_CONN_HDL7: + case ESP_BLE_PWR_TYPE_CONN_HDL8: + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); + break; + default: + return ESP_PWR_LVL_INVALID; + } + + if (tx_level < 0) { + return ESP_PWR_LVL_INVALID; + } + + return (esp_power_level_t)tx_level; +} + +esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, + uint16_t handle) +{ + int tx_level = 0; + + switch (power_type) { + case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: + case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: + case ESP_BLE_ENHANCED_PWR_TYPE_INIT: + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + break; + case ESP_BLE_ENHANCED_PWR_TYPE_ADV: + case ESP_BLE_ENHANCED_PWR_TYPE_CONN: + tx_level = r_ble_txpwr_get(power_type, handle); + break; + default: + return ESP_PWR_LVL_INVALID; + } + + if (tx_level < 0) { + return ESP_PWR_LVL_INVALID; + } + + return (esp_power_level_t)tx_level; +} + +#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED +static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) +{ + for (int i = 0; i < len; i++) { + esp_rom_printf("%02x ", addr[i]); + } + if (end) { + esp_rom_printf("\n"); + } +} + +void esp_ble_controller_log_dump_all(bool output) +{ + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(5000); + BT_ASSERT_PRINT("\r\n[DUMP_START:"); + r_ble_log_async_output_dump_all(output); + BT_ASSERT_PRINT(":DUMP_END]\r\n"); + portEXIT_CRITICAL_SAFE(&spinlock); +} +#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED + +#if (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) +#if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC +#define BLE_SM_KEY_ERR 0x17 +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS +#include "mbedtls/aes.h" +#if CONFIG_BT_LE_SM_SC +#include "mbedtls/cipher.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/cmac.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/ecp.h" + +static mbedtls_ecp_keypair keypair; +#endif // CONFIG_BT_LE_SM_SC + +#else +#include "tinycrypt/aes.h" +#include "tinycrypt/constants.h" +#include "tinycrypt/utils.h" + +#if CONFIG_BT_LE_SM_SC +#include "tinycrypt/cmac_mode.h" +#include "tinycrypt/ecc_dh.h" +#endif // CONFIG_BT_LE_SM_SC +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + +/* Based on Core Specification 4.2 Vol 3. Part H 2.3.5.6.1 */ +static const uint8_t ble_sm_alg_dbg_priv_key[32] = { + 0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38, 0x74, 0xc9, 0xb3, 0xe3, + 0xd2, 0x10, 0x3f, 0x50, 0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99, + 0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd +}; + +int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, + const uint8_t *our_priv_key, uint8_t *out_dhkey) +{ + uint8_t dh[32]; + uint8_t pk[64]; + uint8_t priv[32]; + int rc = BLE_SM_KEY_ERR; + + swap_buf(pk, peer_pub_key_x, 32); + swap_buf(&pk[32], peer_pub_key_y, 32); + swap_buf(priv, our_priv_key, 32); + +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + struct mbedtls_ecp_point pt = {0}, Q = {0}; + mbedtls_mpi z = {0}, d = {0}; + mbedtls_ctr_drbg_context ctr_drbg = {0}; + mbedtls_entropy_context entropy = {0}; + + uint8_t pub[65] = {0}; + /* Hardcoded first byte of pub key for MBEDTLS_ECP_PF_UNCOMPRESSED */ + pub[0] = 0x04; + memcpy(&pub[1], pk, 64); + + /* Initialize the required structures here */ + mbedtls_ecp_point_init(&pt); + mbedtls_ecp_point_init(&Q); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_entropy_init(&entropy); + mbedtls_mpi_init(&d); + mbedtls_mpi_init(&z); + + /* Below 3 steps are to validate public key on curve secp256r1 */ + if (mbedtls_ecp_group_load(&keypair.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1) != 0) { + goto exit; + } + + if (mbedtls_ecp_point_read_binary(&keypair.MBEDTLS_PRIVATE(grp), &pt, pub, 65) != 0) { + goto exit; + } + + if (mbedtls_ecp_check_pubkey(&keypair.MBEDTLS_PRIVATE(grp), &pt) != 0) { + goto exit; + } + + /* Set PRNG */ + if ((rc = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0)) != 0) { + goto exit; + } + + /* Prepare point Q from pub key */ + if (mbedtls_ecp_point_read_binary(&keypair.MBEDTLS_PRIVATE(grp), &Q, pub, 65) != 0) { + goto exit; + } + + if (mbedtls_mpi_read_binary(&d, priv, 32) != 0) { + goto exit; + } + + rc = mbedtls_ecdh_compute_shared(&keypair.MBEDTLS_PRIVATE(grp), &z, &Q, &d, + mbedtls_ctr_drbg_random, &ctr_drbg); + if (rc != 0) { + goto exit; + } + + rc = mbedtls_mpi_write_binary(&z, dh, 32); + if (rc != 0) { + goto exit; + } + +exit: + mbedtls_ecp_point_free(&pt); + mbedtls_mpi_free(&z); + mbedtls_mpi_free(&d); + mbedtls_ecp_point_free(&Q); + mbedtls_entropy_free(&entropy); + mbedtls_ctr_drbg_free(&ctr_drbg); + if (rc != 0) { + return BLE_SM_KEY_ERR; + } + +#else + if (uECC_valid_public_key(pk, &curve_secp256r1) < 0) { + return BLE_SM_KEY_ERR; + } + + rc = uECC_shared_secret(pk, priv, dh, &curve_secp256r1); + if (rc == TC_CRYPTO_FAIL) { + return BLE_SM_KEY_ERR; + } +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + + swap_buf(out_dhkey, dh, 32); + return 0; +} + +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS +static int mbedtls_gen_keypair(uint8_t *public_key, uint8_t *private_key) +{ + int rc = BLE_SM_KEY_ERR; + mbedtls_entropy_context entropy = {0}; + mbedtls_ctr_drbg_context ctr_drbg = {0}; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_ecp_keypair_init(&keypair); + + if ((rc = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + NULL, 0)) != 0) { + goto exit; + } + + if ((rc = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, &keypair, + mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { + goto exit; + } + + if ((rc = mbedtls_mpi_write_binary(&keypair.MBEDTLS_PRIVATE(d), private_key, 32)) != 0) { + goto exit; + } + + size_t olen = 0; + uint8_t pub[65] = {0}; + + if ((rc = mbedtls_ecp_point_write_binary(&keypair.MBEDTLS_PRIVATE(grp), &keypair.MBEDTLS_PRIVATE(Q), MBEDTLS_ECP_PF_UNCOMPRESSED, + &olen, pub, 65)) != 0) { + goto exit; + } + + memcpy(public_key, &pub[1], 64); + +exit: + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + if (rc != 0) { + mbedtls_ecp_keypair_free(&keypair); + return BLE_SM_KEY_ERR; + } + + return 0; +} +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + +/** + * pub: 64 bytes + * priv: 32 bytes + */ +int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv) +{ +#if CONFIG_BT_LE_SM_SC_DEBUG_KEYS + swap_buf(pub, ble_sm_alg_dbg_pub_key, 32); + swap_buf(&pub[32], &ble_sm_alg_dbg_pub_key[32], 32); + swap_buf(priv, ble_sm_alg_dbg_priv_key, 32); +#else + uint8_t pk[64]; + + do { +#if CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + if (mbedtls_gen_keypair(pk, priv) != 0) { + return BLE_SM_KEY_ERR; + } +#else + if (uECC_make_key(pk, priv, &curve_secp256r1) != TC_CRYPTO_SUCCESS) { + return BLE_SM_KEY_ERR; + } +#endif // CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS + /* Make sure generated key isn't debug key. */ + } while (memcmp(priv, ble_sm_alg_dbg_priv_key, 32) == 0); + + swap_buf(pub, pk, 32); + swap_buf(&pub[32], &pk[32], 32); + swap_in_place(priv, 32); +#endif // CONFIG_BT_LE_SM_SC_DEBUG_KEYS + return 0; +} + +#endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC +#endif // (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) diff --git a/lib/bt/controller/esp32c5/esp_bt_cfg.h b/lib/bt/controller/esp32c5/esp_bt_cfg.h new file mode 100644 index 00000000..b9597034 --- /dev/null +++ b/lib/bt/controller/esp32c5/esp_bt_cfg.h @@ -0,0 +1,219 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ESP_BT_CFG_H__ +#define __ESP_BT_CFG_H__ + +#include +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_BT_NIMBLE_ENABLED +#include "syscfg/syscfg.h" +#endif + +#define NIMBLE_LL_STACK_SIZE CONFIG_BT_LE_CONTROLLER_TASK_STACK_SIZE + +#if CONFIG_BT_NIMBLE_ENABLED + + #if CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_CODED_PHY + #define BLE_LL_SCAN_PHY_NUMBER_N (2) + #else + #define BLE_LL_SCAN_PHY_NUMBER_N (1) + #endif + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST MYNEWT_VAL(BLE_MAX_PERIODIC_ADVERTISER_LIST) + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS) + #define DEFAULT_BT_LE_MAX_CONNECTIONS MYNEWT_VAL(BLE_MAX_CONNECTIONS) + #define DEFAULT_BT_LE_ACL_BUF_SIZE MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE) + #define DEFAULT_BT_LE_ACL_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE) + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE MYNEWT_VAL(BLE_LL_WHITELIST_SIZE) + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT) + #define DEFAULT_BT_LE_POWER_CONTROL_ENABLED MYNEWT_VAL(BLE_POWER_CONTROL) + #if defined(CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT) + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (1) + #else + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) + #endif +#else + + #if CONFIG_BT_LE_LL_CFG_FEAT_LE_CODED_PHY + #define BLE_LL_SCAN_PHY_NUMBER_N (2) + #else + #define BLE_LL_SCAN_PHY_NUMBER_N (1) + #endif + + #if defined(CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST) + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST (CONFIG_BT_LE_MAX_PERIODIC_ADVERTISER_LIST) + #else + #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST (5) + #endif + + #if defined(CONFIG_BT_LE_MAX_PERIODIC_SYNCS) + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS (CONFIG_BT_LE_MAX_PERIODIC_SYNCS) + #else + #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS (1) + #endif + + #if defined(CONFIG_BT_LE_MAX_CONNECTIONS) + #define DEFAULT_BT_LE_MAX_CONNECTIONS (CONFIG_BT_LE_MAX_CONNECTIONS) + #else + #define DEFAULT_BT_LE_MAX_CONNECTIONS (2) + #endif + + #if defined(CONFIG_BT_LE_ACL_BUF_SIZE) + #define DEFAULT_BT_LE_ACL_BUF_SIZE (CONFIG_BT_LE_ACL_BUF_SIZE) + #else + #define DEFAULT_BT_LE_ACL_BUF_SIZE (255) + #endif + + #if defined(CONFIG_BT_LE_ACL_BUF_COUNT) + #define DEFAULT_BT_LE_ACL_BUF_COUNT (CONFIG_BT_LE_ACL_BUF_COUNT) + #else + #define DEFAULT_BT_LE_ACL_BUF_COUNT (24) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_BUF_SIZE) + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE (CONFIG_BT_LE_HCI_EVT_BUF_SIZE) + #else + #define DEFAULT_BT_LE_HCI_EVT_BUF_SIZE (70) + #endif + + #if defined(CONFIG_BT_LE_EXT_ADV_MAX_SIZE) + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE (CONFIG_BT_LE_EXT_ADV_MAX_SIZE) + #else + #define DEFAULT_BT_LE_EXT_ADV_MAX_SIZE (31) + #endif + + #if defined(CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES) + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES (CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES) + #else + #define DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES (1) + #endif + + #if defined(CONFIG_BT_LE_WHITELIST_SIZE) + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE (CONFIG_BT_LE_WHITELIST_SIZE) + #else + #define DEFAULT_BT_NIMBLE_WHITELIST_SIZE (12) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT (CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT) + #else + #define DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT (30) + #endif + + #if defined(CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT) + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT (CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT) + #else + #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT (8) + #endif + + #if defined(CONFIG_BT_LE_POWER_CONTROL_ENABLED) + #define DEFAULT_BT_LE_POWER_CONTROL_ENABLED (CONFIG_BT_LE_POWER_CONTROL_ENABLED) + #else + #define DEFAULT_BT_LE_POWER_CONTROL_ENABLED (0) + #endif + #if defined(CONFIG_BT_LE_50_FEATURE_SUPPORT) + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (1) + #else + #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) + #endif +#endif + +#define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF + +#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART +#define HCI_UART_EN CONFIG_BT_LE_HCI_INTERFACE_USE_UART +#else +#define HCI_UART_EN 0 // hci ram mode +#endif + +#ifdef CONFIG_BT_LE_SLEEP_ENABLE +#define NIMBLE_SLEEP_ENABLE CONFIG_BT_LE_SLEEP_ENABLE +#else +#define NIMBLE_SLEEP_ENABLE 0 +#endif + + +#ifdef CONFIG_BT_LE_TX_CCA_ENABLED + #define DEFAULT_BT_LE_TX_CCA_ENABLED (CONFIG_BT_LE_TX_CCA_ENABLED) +#else + #define DEFAULT_BT_LE_TX_CCA_ENABLED (0) +#endif + +#ifdef CONFIG_BT_LE_CCA_RSSI_THRESH + #define DEFAULT_BT_LE_CCA_RSSI_THRESH (CONFIG_BT_LE_CCA_RSSI_THRESH) +#else + #define DEFAULT_BT_LE_CCA_RSSI_THRESH (50) +#endif + +#define DEFAULT_BT_LE_SCAN_RSP_DATA_MAX_LEN_N DEFAULT_BT_LE_EXT_ADV_MAX_SIZE + + +#if HCI_UART_EN + #define DEFAULT_BT_LE_HCI_UART_TX_PIN (CONFIG_BT_LE_HCI_UART_TX_PIN) + #define DEFAULT_BT_LE_HCI_UART_RX_PIN (CONFIG_BT_LE_HCI_UART_RX_PIN) + #define DEFAULT_BT_LE_HCI_UART_PORT (CONFIG_BT_LE_HCI_UART_PORT) + #define DEFAULT_BT_LE_HCI_UART_BAUD (CONFIG_BT_LE_HCI_UART_BAUD) + #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS) + #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1) + #define DEFAULT_BT_LE_HCI_UART_PARITY (0) + #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) +#else + #define DEFAULT_BT_LE_HCI_UART_TX_PIN (0) + #define DEFAULT_BT_LE_HCI_UART_RX_PIN (0) + #define DEFAULT_BT_LE_HCI_UART_PORT (0) + #define DEFAULT_BT_LE_HCI_UART_BAUD (0) + #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0) + #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0) + #define DEFAULT_BT_LE_HCI_UART_PARITY (0) + #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) +#endif + +/* Unchanged configuration */ + +#define BLE_LL_CTRL_PROC_TIMEOUT_MS_N (40000) /* ms */ + +#define BLE_LL_CFG_NUM_HCI_CMD_PKTS_N (1) + +#define BLE_LL_SCHED_ADV_MAX_USECS_N (852) + +#define BLE_LL_SCHED_DIRECT_ADV_MAX_USECS_N (502) + +#define BLE_LL_SCHED_MAX_ADV_PDU_USECS_N (376) + +#define BLE_LL_SUB_VERS_NR_N (0x0000) + +#define BLE_LL_JITTER_USECS_N (16) + +#define BLE_PHY_MAX_PWR_DBM_N (10) + +#define BLE_LL_CONN_DEF_AUTH_PYLD_TMO_N (3000) + +#define RTC_FREQ_N (32768) /* in Hz */ + +#define BLE_LL_TX_PWR_DBM_N (9) + + +#define RUN_BQB_TEST (0) +#define RUN_QA_TEST (0) +#define NIMBLE_DISABLE_SCAN_BACKOFF (0) + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_BT_CFG_H__ */ diff --git a/lib/bt/controller/esp32c6/Kconfig.in b/lib/bt/controller/esp32c6/Kconfig.in index 465d713e..0dcc8996 100644 --- a/lib/bt/controller/esp32c6/Kconfig.in +++ b/lib/bt/controller/esp32c6/Kconfig.in @@ -147,7 +147,7 @@ if BT_LE_EXT_ADV Enable this option to start periodic advertisement. config BT_LE_PERIODIC_ADV_SYNC_TRANSFER - bool "Enable Transer Sync Events" + bool "Enable Transfer Sync Events" depends on BT_LE_ENABLE_PERIODIC_ADV default y help @@ -365,7 +365,6 @@ config BT_LE_CRYPTO_STACK_MBEDTLS bool "Override TinyCrypt with mbedTLS for crypto computations" default y depends on !BT_NIMBLE_ENABLED - select MBEDTLS_ECP_RESTARTABLE select MBEDTLS_CMAC_C help Enable this option to choose mbedTLS instead of TinyCrypt for crypto @@ -562,3 +561,17 @@ config BT_LE_SCAN_DUPL_CACHE_REFRESH_PERIOD 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. diff --git a/lib/bt/controller/esp32c6/bt.c b/lib/bt/controller/esp32c6/bt.c index 30fdcd00..489327f0 100644 --- a/lib/bt/controller/esp32c6/bt.c +++ b/lib/bt/controller/esp32c6/bt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,7 +15,9 @@ #include "sdkconfig.h" +#if CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port.h" +#endif // CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port_freertos.h" #include "esp_private/esp_modem_clock.h" @@ -23,19 +25,21 @@ #include "esp_log.h" #endif // ESP_PLATFORM -#if CONFIG_SW_COEXIST_ENABLE +#ifdef CONFIG_ESP_COEX_ENABLED #include "private/esp_coexist_internal.h" -#endif // CONFIG_SW_COEXIST_ENABLE +#endif // CONFIG_ESP_COEX_ENABLED #include "nimble/nimble_npl_os.h" -#include "nimble/ble_hci_trans.h" +#include "ble_hci_trans.h" #include "os/endian.h" #include "esp_bt.h" #include "esp_intr_alloc.h" #include "esp_sleep.h" #include "esp_pm.h" +#ifdef CONFIG_ESP_PHY_ENABLED #include "esp_phy_init.h" +#endif #include "esp_private/periph_ctrl.h" #include "hci_uart.h" #include "bt_osi_mem.h" @@ -121,7 +125,7 @@ typedef void (*interface_func_t) (uint32_t len, const uint8_t*addr, bool end); ************************************************************************ */ extern int ble_osi_coex_funcs_register(struct osi_coex_funcs_t *coex_funcs); -extern int ble_controller_init(esp_bt_controller_config_t *cfg); +extern int r_ble_controller_init(esp_bt_controller_config_t *cfg); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED extern int r_ble_log_init_async(interface_func_t bt_controller_log_interface, bool task_create, uint8_t buffers, uint32_t *bufs_size); extern int r_ble_log_deinit_async(void); @@ -129,12 +133,12 @@ extern void r_ble_log_async_select_dump_buffers(uint8_t buffers); extern void r_ble_log_async_output_dump_all(bool output); extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -extern int ble_controller_deinit(void); -extern int ble_controller_enable(uint8_t mode); -extern int ble_controller_disable(void); +extern int r_ble_controller_deinit(void); +extern int r_ble_controller_enable(uint8_t mode); +extern int r_ble_controller_disable(void); extern int esp_register_ext_funcs (struct ext_funcs_t *); extern void esp_unregister_ext_funcs (void); -extern int esp_ble_ll_set_public_addr(const uint8_t *addr); +extern int r_esp_ble_ll_set_public_addr(const uint8_t *addr); extern int esp_register_npl_funcs (struct npl_funcs_t *p_npl_func); extern void esp_unregister_npl_funcs (void); extern void npl_freertos_mempool_deinit(void); @@ -147,17 +151,19 @@ extern int os_msys_init(void); extern void os_msys_deinit(void); #if CONFIG_FREERTOS_USE_TICKLESS_IDLE extern const sleep_retention_entries_config_t *esp_ble_mac_retention_link_get(uint8_t *size, uint8_t extra); -extern void esp_ble_set_wakeup_overhead(uint32_t overhead); +extern void r_esp_ble_set_wakeup_overhead(uint32_t overhead); #endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ -extern void esp_ble_change_rtc_freq(uint32_t freq); +extern void r_esp_ble_change_rtc_freq(uint32_t freq); extern int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, const uint8_t *our_priv_key, uint8_t *out_dhkey); extern int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); -extern int ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); -extern int ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -extern int ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); +extern int r_ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); +extern int r_ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); +extern int r_ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); extern char *ble_controller_get_compile_version(void); +extern int esp_ble_register_bb_funcs(void); +extern void esp_ble_unregister_bb_funcs(void); extern uint32_t _bt_bss_start; extern uint32_t _bt_bss_end; extern uint32_t _bt_controller_bss_start; @@ -357,7 +363,7 @@ static int task_create_wrapper(void *task_func, const char *name, uint32_t stack void *param, uint32_t prio, void *task_handle, uint32_t core_id) { return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, - (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); + (core_id < CONFIG_FREERTOS_NUMBER_OF_CORES ? core_id : tskNO_AFFINITY)); } static void task_delete_wrapper(void *task_handle) @@ -512,25 +518,44 @@ IRAM_ATTR void controller_wakeup_cb(void *arg) } #if CONFIG_FREERTOS_USE_TICKLESS_IDLE -static esp_err_t sleep_modem_ble_mac_modem_state_init(uint8_t extra) +static esp_err_t sleep_modem_ble_mac_retention_init(void *arg) { uint8_t size; + int extra = *(int *)arg; const sleep_retention_entries_config_t *ble_mac_modem_config = esp_ble_mac_retention_link_get(&size, extra); - esp_err_t err = sleep_retention_entries_create(ble_mac_modem_config, size, REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_BLE_MAC); + esp_err_t err = sleep_retention_entries_create(ble_mac_modem_config, size, REGDMA_LINK_PRI_BT_MAC_BB, SLEEP_RETENTION_MODULE_BLE_MAC); if (err == ESP_OK) { ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Modem BLE MAC retention initialization"); } return err; } +static esp_err_t sleep_modem_ble_mac_modem_state_init(uint8_t extra) +{ + int retention_args = extra; + sleep_retention_module_init_param_t init_param = { + .cbs = { .create = { .handle = sleep_modem_ble_mac_retention_init, .arg = &retention_args } }, + .depends = BIT(SLEEP_RETENTION_MODULE_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 sleep_modem_ble_mac_modem_state_deinit(void) { - sleep_retention_entries_destroy(SLEEP_RETENTION_MODULE_BLE_MAC); + 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); + } } void sleep_modem_light_sleep_overhead_set(uint32_t overhead) { - esp_ble_set_wakeup_overhead(overhead); + r_esp_ble_set_wakeup_overhead(overhead); } #endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ @@ -556,6 +581,9 @@ esp_err_t controller_sleep_init(void) goto error; } #if CONFIG_FREERTOS_USE_TICKLESS_IDLE +#if CONFIG_BT_LE_SLEEP_ENABLE && !CONFIG_MAC_BB_PD +#error "CONFIG_MAC_BB_PD required for BLE light sleep to run properly" +#endif // CONFIG_BT_LE_SLEEP_ENABLE && !CONFIG_MAC_BB_PD /* Create a new regdma link for BLE related register restoration */ rc = sleep_modem_ble_mac_modem_state_init(1); assert(rc == 0); @@ -723,7 +751,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) goto free_mem; } - ble_get_npl_element_info(cfg, &npl_info); + r_ble_get_npl_element_info(cfg, &npl_info); npl_freertos_set_controller_npl_info(&npl_info); if (npl_freertos_mempool_init() != 0) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl mempool init failed"); @@ -780,13 +808,6 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) coex_init(); #endif // CONFIG_SW_COEXIST_ENABLE - ret = ble_controller_init(cfg); - if (ret != ESP_OK) { - ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_init failed %d", ret); - goto modem_deint; - } - - ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED interface_func_t bt_controller_log_interface; bt_controller_log_interface = esp_bt_controller_log_interface; @@ -804,11 +825,23 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #endif // CONFIG_BT_CONTROLLER_LOG_DUMP if (ret != ESP_OK) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); - goto controller_init_err; + goto modem_deint; } #endif // CONFIG_BT_CONTROLLER_LOG_ENABLED + ret = esp_ble_register_bb_funcs(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "esp_ble_register_bb_funcs failed %d", ret); + goto modem_deint; + } + + ret = r_ble_controller_init(cfg); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "r_ble_controller_init failed %d", ret); + goto modem_deint; + } - esp_ble_change_rtc_freq(slow_clk_freq); + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); + r_esp_ble_change_rtc_freq(slow_clk_freq); ble_controller_scan_duplicate_config(); @@ -825,7 +858,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) } ESP_ERROR_CHECK(esp_read_mac((uint8_t *)mac, ESP_MAC_BT)); swap_in_place(mac, 6); - esp_ble_ll_set_public_addr(mac); + r_esp_ble_ll_set_public_addr(mac); ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; @@ -835,13 +868,13 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) free_controller: controller_sleep_deinit(); + os_msys_deinit(); + r_ble_controller_deinit(); +modem_deint: + esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -controller_init_err: r_ble_log_deinit_async(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - os_msys_deinit(); - ble_controller_deinit(); -modem_deint: esp_phy_modem_deinit(); modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); modem_clock_module_disable(PERIPH_BT_MODULE); @@ -872,10 +905,11 @@ esp_err_t esp_bt_controller_deinit(void) modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); modem_clock_module_disable(PERIPH_BT_MODULE); + r_ble_controller_deinit(); + esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED r_ble_log_deinit_async(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - ble_controller_deinit(); #if CONFIG_BT_NIMBLE_ENABLED /* De-initialize default event queue */ @@ -920,7 +954,7 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) coex_enable(); #endif // CONFIG_SW_COEXIST_ENABLE - if (ble_controller_enable(mode) != 0) { + if (r_ble_controller_enable(mode) != 0) { ret = ESP_FAIL; goto error; } @@ -948,7 +982,7 @@ esp_err_t esp_bt_controller_disable(void) ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); return ESP_FAIL; } - if (ble_controller_disable() != 0) { + if (r_ble_controller_disable() != 0) { return ESP_FAIL; } #if CONFIG_SW_COEXIST_ENABLE @@ -986,70 +1020,86 @@ static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) return ret; } + +typedef struct { + intptr_t start; + intptr_t end; + const char* name; +} bt_area_t; + +static esp_err_t esp_bt_mem_release_area(const bt_area_t *area) +{ + esp_err_t ret = ESP_OK; + intptr_t mem_start = area->start; + intptr_t mem_end = area->end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release %s [0x%08x] - [0x%08x], len %d", area->name, mem_start, mem_end, mem_end - mem_start); + ret = try_heap_caps_add_region(mem_start, mem_end); + } + return ret; +} + +static esp_err_t esp_bt_mem_release_areas(const bt_area_t *area1, const bt_area_t *area2) +{ + esp_err_t ret = ESP_OK; + + if (area1->end == area2->start) { + bt_area_t merged_area = { + .start = area1->start, + .end = area2->end, + .name = area1->name + }; + ret = esp_bt_mem_release_area(&merged_area); + } else { + esp_bt_mem_release_area(area1); + ret = esp_bt_mem_release_area(area2); + } + + return ret; +} + esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) { - intptr_t mem_start, mem_end; + esp_err_t ret = ESP_OK; - if (mode & ESP_BT_MODE_BLE) { - /* If the addresses of btdm .bss and bt .bss are consecutive, - * they are registered in the system heap as a piece of memory - */ - if(_bt_bss_end == _bt_controller_bss_start) { - mem_start = (intptr_t)&_bt_bss_start; - mem_end = (intptr_t)&_bt_controller_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BSS [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)&_bt_bss_start; - mem_end = (intptr_t)&_bt_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; + } - mem_start = (intptr_t)&_bt_controller_bss_start; - mem_end = (intptr_t)&_bt_controller_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release Controller BSS [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + bt_area_t bss = { + .start = (intptr_t)&_bt_bss_start, + .end = (intptr_t)&_bt_bss_end, + .name = "BT BSS", + }; + bt_area_t cont_bss = { + .start = (intptr_t)&_bt_controller_bss_start, + .end = (intptr_t)&_bt_controller_bss_end, + .name = "BT Controller BSS", + }; + bt_area_t data = { + .start = (intptr_t)&_bt_data_start, + .end = (intptr_t)&_bt_data_end, + .name = "BT Data", + }; + bt_area_t cont_data = { + .start = (intptr_t)&_bt_controller_data_start, + .end = (intptr_t)&_bt_controller_data_end, + .name = "BT Controller Data" + }; + + if (mode & ESP_BT_MODE_BLE) { + /* Start by freeing Bluetooth BSS section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&bss, &cont_bss); } - /* If the addresses of btdm .data and bt .data are consecutive, - * they are registered in the system heap as a piece of memory - */ - if(_bt_data_end == _bt_controller_data_start) { - mem_start = (intptr_t)&_bt_data_start; - mem_end = (intptr_t)&_bt_controller_data_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release data [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)&_bt_data_start; - mem_end = (intptr_t)&_bt_data_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - mem_start = (intptr_t)&_bt_controller_data_start; - mem_end = (intptr_t)&_bt_controller_data_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release Controller Data [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + /* Do the same thing with the Bluetooth data section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&data, &cont_data); } } - return ESP_OK; + return ret; } @@ -1066,7 +1116,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ case ESP_BLE_PWR_TYPE_DEFAULT: case ESP_BLE_PWR_TYPE_ADV: case ESP_BLE_PWR_TYPE_SCAN: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { stat = ESP_OK; } break; @@ -1079,7 +1129,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ case ESP_BLE_PWR_TYPE_CONN_HDL6: case ESP_BLE_PWR_TYPE_CONN_HDL7: case ESP_BLE_PWR_TYPE_CONN_HDL8: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { stat = ESP_OK; } break; @@ -1099,13 +1149,13 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: case ESP_BLE_ENHANCED_PWR_TYPE_INIT: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { stat = ESP_OK; } break; case ESP_BLE_ENHANCED_PWR_TYPE_ADV: case ESP_BLE_ENHANCED_PWR_TYPE_CONN: - if (ble_txpwr_set(power_type, handle, power_level) == 0) { + if (r_ble_txpwr_set(power_type, handle, power_level) == 0) { stat = ESP_OK; } break; @@ -1125,7 +1175,7 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) case ESP_BLE_PWR_TYPE_ADV: case ESP_BLE_PWR_TYPE_SCAN: case ESP_BLE_PWR_TYPE_DEFAULT: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); break; case ESP_BLE_PWR_TYPE_CONN_HDL0: case ESP_BLE_PWR_TYPE_CONN_HDL1: @@ -1136,7 +1186,7 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) case ESP_BLE_PWR_TYPE_CONN_HDL6: case ESP_BLE_PWR_TYPE_CONN_HDL7: case ESP_BLE_PWR_TYPE_CONN_HDL8: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); break; default: return ESP_PWR_LVL_INVALID; @@ -1158,11 +1208,11 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: case ESP_BLE_ENHANCED_PWR_TYPE_INIT: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); break; case ESP_BLE_ENHANCED_PWR_TYPE_ADV: case ESP_BLE_ENHANCED_PWR_TYPE_CONN: - tx_level = ble_txpwr_get(power_type, handle); + tx_level = r_ble_txpwr_get(power_type, handle); break; default: return ESP_PWR_LVL_INVALID; @@ -1410,4 +1460,3 @@ int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv) #endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC #endif // (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) - diff --git a/lib/bt/controller/esp32c61/Kconfig.in b/lib/bt/controller/esp32c61/Kconfig.in new file mode 100644 index 00000000..e69de29b diff --git a/lib/bt/controller/esp32h2/Kconfig.in b/lib/bt/controller/esp32h2/Kconfig.in index 9e8fabe7..e0c49361 100644 --- a/lib/bt/controller/esp32h2/Kconfig.in +++ b/lib/bt/controller/esp32h2/Kconfig.in @@ -147,7 +147,7 @@ if BT_LE_EXT_ADV Enable this option to start periodic advertisement. config BT_LE_PERIODIC_ADV_SYNC_TRANSFER - bool "Enable Transer Sync Events" + bool "Enable Transfer Sync Events" depends on BT_LE_ENABLE_PERIODIC_ADV default y help @@ -356,7 +356,6 @@ config BT_LE_CRYPTO_STACK_MBEDTLS bool "Override TinyCrypt with mbedTLS for crypto computations" default y depends on !BT_NIMBLE_ENABLED - select MBEDTLS_ECP_RESTARTABLE select MBEDTLS_CMAC_C help Enable this option to choose mbedTLS instead of TinyCrypt for crypto @@ -554,3 +553,17 @@ config BT_LE_SCAN_DUPL_CACHE_REFRESH_PERIOD config BT_LE_MSYS_INIT_IN_CONTROLLER bool 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. diff --git a/lib/bt/controller/esp32h2/bt.c b/lib/bt/controller/esp32h2/bt.c index 183799c4..adb10d49 100644 --- a/lib/bt/controller/esp32h2/bt.c +++ b/lib/bt/controller/esp32h2/bt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,7 +15,9 @@ #include "sdkconfig.h" +#if CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port.h" +#endif // CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port_freertos.h" #include "esp_private/esp_modem_clock.h" @@ -23,12 +25,12 @@ #include "esp_log.h" #endif // ESP_PLATFORM -#if CONFIG_SW_COEXIST_ENABLE +#ifdef CONFIG_ESP_COEX_ENABLED #include "private/esp_coexist_internal.h" -#endif // CONFIG_SW_COEXIST_ENABLE +#endif // CONFIG_ESP_COEX_ENABLED #include "nimble/nimble_npl_os.h" -#include "nimble/ble_hci_trans.h" +#include "ble_hci_trans.h" #include "os/endian.h" #include "esp_bt.h" @@ -59,8 +61,8 @@ ************************************************************************ */ #define NIMBLE_PORT_LOG_TAG "BLE_INIT" -#define OSI_COEX_VERSION 0x00010006 -#define OSI_COEX_MAGIC_VALUE 0xFADEBEAD +#define OSI_COEX_VERSION 0x00010006 +#define OSI_COEX_MAGIC_VALUE 0xFADEBEAD #define EXT_FUNC_VERSION 0x20221122 #define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5 @@ -115,7 +117,7 @@ typedef void (*interface_func_t) (uint32_t len, const uint8_t*addr, bool end); ************************************************************************ */ extern int ble_osi_coex_funcs_register(struct osi_coex_funcs_t *coex_funcs); -extern int ble_controller_init(esp_bt_controller_config_t *cfg); +extern int r_ble_controller_init(esp_bt_controller_config_t *cfg); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED extern int r_ble_log_init_async(interface_func_t bt_controller_log_interface, bool task_create, uint8_t buffers, uint32_t *bufs_size); extern int r_ble_log_deinit_async(void); @@ -123,35 +125,37 @@ extern void r_ble_log_async_select_dump_buffers(uint8_t buffers); extern void r_ble_log_async_output_dump_all(bool output); extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -extern int ble_controller_deinit(void); -extern int ble_controller_enable(uint8_t mode); -extern int ble_controller_disable(void); +extern int r_ble_controller_deinit(void); +extern int r_ble_controller_enable(uint8_t mode); +extern int r_ble_controller_disable(void); extern int esp_register_ext_funcs (struct ext_funcs_t *); extern void esp_unregister_ext_funcs (void); -extern int esp_ble_ll_set_public_addr(const uint8_t *addr); +extern int r_esp_ble_ll_set_public_addr(const uint8_t *addr); extern int esp_register_npl_funcs (struct npl_funcs_t *p_npl_func); extern void esp_unregister_npl_funcs (void); extern void npl_freertos_mempool_deinit(void); extern uint32_t r_os_cputime_get32(void); extern uint32_t r_os_cputime_ticks_to_usecs(uint32_t ticks); -#if CONFIG_FREERTOS_USE_TICKLESS_IDLE -extern const sleep_retention_entries_config_t *esp_ble_mac_retention_link_get(uint8_t *size, uint8_t extra); -extern void esp_ble_set_wakeup_overhead(uint32_t overhead); -#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ -extern void esp_ble_change_rtc_freq(uint32_t freq); extern void r_ble_lll_rfmgmt_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, void *w_arg, uint32_t us_to_enabled); extern void r_ble_rtc_wake_up_state_clr(void); extern int os_msys_init(void); extern void os_msys_deinit(void); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +extern const sleep_retention_entries_config_t *esp_ble_mac_retention_link_get(uint8_t *size, uint8_t extra); +extern void r_esp_ble_set_wakeup_overhead(uint32_t overhead); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ +extern void r_esp_ble_change_rtc_freq(uint32_t freq); extern int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, const uint8_t *our_priv_key, uint8_t *out_dhkey); extern int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); -extern int ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); -extern int ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -extern int ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); +extern int r_ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); +extern int r_ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); +extern int r_ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); extern char *ble_controller_get_compile_version(void); +extern int esp_ble_register_bb_funcs(void); +extern void esp_ble_unregister_bb_funcs(void); extern uint32_t _bt_bss_start; extern uint32_t _bt_bss_end; extern uint32_t _bt_controller_bss_start; @@ -351,7 +355,7 @@ static int task_create_wrapper(void *task_func, const char *name, uint32_t stack void *param, uint32_t prio, void *task_handle, uint32_t core_id) { return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, - (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY)); + (core_id < CONFIG_FREERTOS_NUMBER_OF_CORES ? core_id : tskNO_AFFINITY)); } static void task_delete_wrapper(void *task_handle) @@ -501,27 +505,47 @@ IRAM_ATTR void controller_wakeup_cb(void *arg) } #ifdef CONFIG_FREERTOS_USE_TICKLESS_IDLE -static esp_err_t sleep_modem_ble_mac_modem_state_init(uint8_t extra) +static esp_err_t sleep_modem_ble_mac_retention_init(void *arg) { uint8_t size; + int extra = *(int *)arg; const sleep_retention_entries_config_t *ble_mac_modem_config = esp_ble_mac_retention_link_get(&size, extra); - esp_err_t err = sleep_retention_entries_create(ble_mac_modem_config, size, REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_BLE_MAC); + esp_err_t err = sleep_retention_entries_create(ble_mac_modem_config, size, REGDMA_LINK_PRI_BT_MAC_BB, SLEEP_RETENTION_MODULE_BLE_MAC); if (err == ESP_OK) { ESP_LOGI(NIMBLE_PORT_LOG_TAG, "Modem BLE MAC retention initialization"); } return err; } +static esp_err_t sleep_modem_ble_mac_modem_state_init(uint8_t extra) +{ + int retention_args = extra; + sleep_retention_module_init_param_t init_param = { + .cbs = { .create = { .handle = sleep_modem_ble_mac_retention_init, .arg = &retention_args } }, + .depends = BIT(SLEEP_RETENTION_MODULE_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 sleep_modem_ble_mac_modem_state_deinit(void) { - sleep_retention_entries_destroy(SLEEP_RETENTION_MODULE_BLE_MAC); + 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); + } } void sleep_modem_light_sleep_overhead_set(uint32_t overhead) { - esp_ble_set_wakeup_overhead(overhead); + r_esp_ble_set_wakeup_overhead(overhead); } -#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + esp_err_t controller_sleep_init(void) { @@ -697,7 +721,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) goto free_mem; } - ble_get_npl_element_info(cfg, &npl_info); + r_ble_get_npl_element_info(cfg, &npl_info); npl_freertos_set_controller_npl_info(&npl_info); if (npl_freertos_mempool_init() != 0) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl mempool init failed"); @@ -711,10 +735,10 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) */ ble_npl_eventq_init(nimble_port_get_dflt_eventq()); #endif // CONFIG_BT_NIMBLE_ENABLED - /* Enable BT-related clocks */ modem_clock_module_enable(PERIPH_BT_MODULE); modem_clock_module_mac_reset(PERIPH_BT_MODULE); + /* Select slow clock source for BT momdule */ #if CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL); slow_clk_freq = 100000; @@ -753,13 +777,6 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) coex_init(); #endif // CONFIG_SW_COEXIST_ENABLE - ret = ble_controller_init(cfg); - if (ret != ESP_OK) { - ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_init failed %d", ret); - goto modem_deint; - } - - ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED interface_func_t bt_controller_log_interface; bt_controller_log_interface = esp_bt_controller_log_interface; @@ -777,11 +794,23 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #endif // CONFIG_BT_CONTROLLER_LOG_DUMP if (ret != ESP_OK) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); - goto controller_init_err; + goto modem_deint; } #endif // CONFIG_BT_CONTROLLER_LOG_ENABLED + ret = esp_ble_register_bb_funcs(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "esp_ble_register_bb_funcs failed %d", ret); + goto modem_deint; + } - esp_ble_change_rtc_freq(slow_clk_freq); + ret = r_ble_controller_init(cfg); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "r_ble_controller_init failed %d", ret); + goto modem_deint; + } + + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); + r_esp_ble_change_rtc_freq(slow_clk_freq); ble_controller_scan_duplicate_config(); @@ -796,10 +825,9 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) ESP_LOGW(NIMBLE_PORT_LOG_TAG, "controller_sleep_init failed %d", ret); goto free_controller; } - ESP_ERROR_CHECK(esp_read_mac((uint8_t *)mac, ESP_MAC_BT)); swap_in_place(mac, 6); - esp_ble_ll_set_public_addr(mac); + r_esp_ble_ll_set_public_addr(mac); ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; @@ -809,13 +837,13 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) free_controller: controller_sleep_deinit(); + os_msys_deinit(); + r_ble_controller_deinit(); +modem_deint: + esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -controller_init_err: r_ble_log_deinit_async(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - os_msys_deinit(); - ble_controller_deinit(); -modem_deint: modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); modem_clock_module_disable(PERIPH_BT_MODULE); #if CONFIG_BT_NIMBLE_ENABLED @@ -844,10 +872,11 @@ esp_err_t esp_bt_controller_deinit(void) modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); modem_clock_module_disable(PERIPH_BT_MODULE); + r_ble_controller_deinit(); + esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED r_ble_log_deinit_async(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - ble_controller_deinit(); #if CONFIG_BT_NIMBLE_ENABLED /* De-initialize default event queue */ @@ -892,7 +921,7 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) coex_enable(); #endif // CONFIG_SW_COEXIST_ENABLE - if (ble_controller_enable(mode) != 0) { + if (r_ble_controller_enable(mode) != 0) { ret = ESP_FAIL; goto error; } @@ -920,7 +949,7 @@ esp_err_t esp_bt_controller_disable(void) ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); return ESP_FAIL; } - if (ble_controller_disable() != 0) { + if (r_ble_controller_disable() != 0) { return ESP_FAIL; } #if CONFIG_SW_COEXIST_ENABLE @@ -958,70 +987,86 @@ static esp_err_t try_heap_caps_add_region(intptr_t start, intptr_t end) return ret; } + +typedef struct { + intptr_t start; + intptr_t end; + const char* name; +} bt_area_t; + +static esp_err_t esp_bt_mem_release_area(const bt_area_t *area) +{ + esp_err_t ret = ESP_OK; + intptr_t mem_start = area->start; + intptr_t mem_end = area->end; + if (mem_start != mem_end) { + ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release %s [0x%08x] - [0x%08x], len %d", area->name, mem_start, mem_end, mem_end - mem_start); + ret = try_heap_caps_add_region(mem_start, mem_end); + } + return ret; +} + +static esp_err_t esp_bt_mem_release_areas(const bt_area_t *area1, const bt_area_t *area2) +{ + esp_err_t ret = ESP_OK; + + if (area1->end == area2->start) { + bt_area_t merged_area = { + .start = area1->start, + .end = area2->end, + .name = area1->name + }; + ret = esp_bt_mem_release_area(&merged_area); + } else { + esp_bt_mem_release_area(area1); + ret = esp_bt_mem_release_area(area2); + } + + return ret; +} + esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) { - intptr_t mem_start, mem_end; + esp_err_t ret = ESP_OK; + + if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { + return ESP_ERR_INVALID_STATE; + } + + bt_area_t bss = { + .start = (intptr_t)&_bt_bss_start, + .end = (intptr_t)&_bt_bss_end, + .name = "BT BSS", + }; + bt_area_t cont_bss = { + .start = (intptr_t)&_bt_controller_bss_start, + .end = (intptr_t)&_bt_controller_bss_end, + .name = "BT Controller BSS", + }; + bt_area_t data = { + .start = (intptr_t)&_bt_data_start, + .end = (intptr_t)&_bt_data_end, + .name = "BT Data", + }; + bt_area_t cont_data = { + .start = (intptr_t)&_bt_controller_data_start, + .end = (intptr_t)&_bt_controller_data_end, + .name = "BT Controller Data" + }; if (mode & ESP_BT_MODE_BLE) { - /* If the addresses of btdm .bss and bt .bss are consecutive, - * they are registered in the system heap as a piece of memory - */ - if(_bt_bss_end == _bt_controller_bss_start) { - mem_start = (intptr_t)&_bt_bss_start; - mem_end = (intptr_t)&_bt_controller_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BSS [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)&_bt_bss_start; - mem_end = (intptr_t)&_bt_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BT BSS [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - - mem_start = (intptr_t)&_bt_controller_bss_start; - mem_end = (intptr_t)&_bt_controller_bss_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release Controller BSS [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + /* Start by freeing Bluetooth BSS section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&bss, &cont_bss); } - /* If the addresses of btdm .data and bt .data are consecutive, - * they are registered in the system heap as a piece of memory - */ - if(_bt_data_end == _bt_controller_data_start) { - mem_start = (intptr_t)&_bt_data_start; - mem_end = (intptr_t)&_bt_controller_data_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release data [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - } else { - mem_start = (intptr_t)&_bt_data_start; - mem_end = (intptr_t)&_bt_data_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } - - mem_start = (intptr_t)&_bt_controller_data_start; - mem_end = (intptr_t)&_bt_controller_data_end; - if (mem_start != mem_end) { - ESP_LOGD(NIMBLE_PORT_LOG_TAG, "Release Controller Data [0x%08x] - [0x%08x], len %d", - mem_start, mem_end, mem_end - mem_start); - ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); - } + + /* Do the same thing with the Bluetooth data section */ + if (ret == ESP_OK) { + ret = esp_bt_mem_release_areas(&data, &cont_data); } } - return ESP_OK; + return ret; } @@ -1038,7 +1083,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ case ESP_BLE_PWR_TYPE_DEFAULT: case ESP_BLE_PWR_TYPE_ADV: case ESP_BLE_PWR_TYPE_SCAN: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { stat = ESP_OK; } break; @@ -1051,7 +1096,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ case ESP_BLE_PWR_TYPE_CONN_HDL6: case ESP_BLE_PWR_TYPE_CONN_HDL7: case ESP_BLE_PWR_TYPE_CONN_HDL8: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { stat = ESP_OK; } break; @@ -1071,13 +1116,13 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: case ESP_BLE_ENHANCED_PWR_TYPE_INIT: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { stat = ESP_OK; } break; case ESP_BLE_ENHANCED_PWR_TYPE_ADV: case ESP_BLE_ENHANCED_PWR_TYPE_CONN: - if (ble_txpwr_set(power_type, handle, power_level) == 0) { + if (r_ble_txpwr_set(power_type, handle, power_level) == 0) { stat = ESP_OK; } break; @@ -1097,7 +1142,7 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) case ESP_BLE_PWR_TYPE_ADV: case ESP_BLE_PWR_TYPE_SCAN: case ESP_BLE_PWR_TYPE_DEFAULT: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); break; case ESP_BLE_PWR_TYPE_CONN_HDL0: case ESP_BLE_PWR_TYPE_CONN_HDL1: @@ -1108,7 +1153,7 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) case ESP_BLE_PWR_TYPE_CONN_HDL6: case ESP_BLE_PWR_TYPE_CONN_HDL7: case ESP_BLE_PWR_TYPE_CONN_HDL8: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); break; default: return ESP_PWR_LVL_INVALID; @@ -1130,11 +1175,11 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: case ESP_BLE_ENHANCED_PWR_TYPE_INIT: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); break; case ESP_BLE_ENHANCED_PWR_TYPE_ADV: case ESP_BLE_ENHANCED_PWR_TYPE_CONN: - tx_level = ble_txpwr_get(power_type, handle); + tx_level = r_ble_txpwr_get(power_type, handle); break; default: return ESP_PWR_LVL_INVALID; @@ -1382,4 +1427,3 @@ int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv) #endif // CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC #endif // (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) - diff --git a/lib/bt/controller/lib_esp32/esp32/libbtdm_app.a b/lib/bt/controller/lib_esp32/esp32/libbtdm_app.a index 7e859375..7e190d8a 100644 Binary files a/lib/bt/controller/lib_esp32/esp32/libbtdm_app.a and b/lib/bt/controller/lib_esp32/esp32/libbtdm_app.a differ diff --git a/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a b/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a index 3ae32051..4df30d81 100644 Binary files a/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a and b/lib/bt/controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a differ diff --git a/lib/bt/controller/lib_esp32c3_family/esp32c3/libbtdm_app.a b/lib/bt/controller/lib_esp32c3_family/esp32c3/libbtdm_app.a index c9774edd..8d1cc4fe 100644 Binary files a/lib/bt/controller/lib_esp32c3_family/esp32c3/libbtdm_app.a and b/lib/bt/controller/lib_esp32c3_family/esp32c3/libbtdm_app.a differ diff --git a/lib/bt/controller/lib_esp32c3_family/esp32s3/libbtdm_app.a b/lib/bt/controller/lib_esp32c3_family/esp32s3/libbtdm_app.a index 35adfbb0..7d450357 100644 Binary files a/lib/bt/controller/lib_esp32c3_family/esp32s3/libbtdm_app.a and b/lib/bt/controller/lib_esp32c3_family/esp32s3/libbtdm_app.a differ diff --git a/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/libble_app.a b/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/libble_app.a index 77fd8fd1..d39ed65a 100644 Binary files a/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/libble_app.a and b/lib/bt/controller/lib_esp32c6/esp32c6-bt-lib/libble_app.a differ diff --git a/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/libble_app.a b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/libble_app.a index 03761e55..184b2def 100644 Binary files a/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/libble_app.a and b/lib/bt/controller/lib_esp32h2/esp32h2-bt-lib/libble_app.a differ diff --git a/lib/bt/esp_ble_mesh/Kconfig.in b/lib/bt/esp_ble_mesh/Kconfig.in index 4ed4d876..216ab39a 100644 --- a/lib/bt/esp_ble_mesh/Kconfig.in +++ b/lib/bt/esp_ble_mesh/Kconfig.in @@ -19,10 +19,9 @@ if BLE_MESH bool "Support Duplicate Scan in BLE Mesh" select BTDM_BLE_SCAN_DUPL if IDF_TARGET_ESP32 select BTDM_BLE_MESH_SCAN_DUPL_EN if IDF_TARGET_ESP32 - select BT_CTRL_BLE_SCAN_DUPL if IDF_TARGET_ESP32C3 - select BT_CTRL_BLE_MESH_SCAN_DUPL_EN if IDF_TARGET_ESP32C3 - select BT_LE_SCAN_DUPL if IDF_TARGET_ESP32C6 - select BT_LE_SCAN_DUPL if IDF_TARGET_ESP32H2 + select BT_CTRL_BLE_SCAN_DUPL if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 + select BT_CTRL_BLE_MESH_SCAN_DUPL_EN if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 + select BT_LE_SCAN_DUPL if IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32H2 select BT_NIMBLE_VS_SUPPORT if BT_NIMBLE_ENABLED default y help diff --git a/lib/bt/esp_ble_mesh/README.md b/lib/bt/esp_ble_mesh/README.md index 58255a80..3cda5062 100644 --- a/lib/bt/esp_ble_mesh/README.md +++ b/lib/bt/esp_ble_mesh/README.md @@ -16,6 +16,6 @@ The ESP-BLE-MESH networking enables many-to-many (m:m) device communications and - [API Reference](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/bluetooth/esp-ble-mesh.html) -### [ESP-BLE-MESH Examples](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/esp_ble_mesh) +### [ESP-BLE-MESH Examples](../../../examples/bluetooth/esp_ble_mesh) - Refer to **ESP-BLE-MESH Examples** of [Getting Started](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/esp-ble-mesh/ble-mesh-index.html#getting-started-with-esp-ble-mesh) for the tutorials of ESP BLE Mesh examples. diff --git a/lib/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c b/lib/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c index 9a12de17..82128786 100644 --- a/lib/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c +++ b/lib/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c @@ -96,7 +96,7 @@ esp_err_t esp_ble_mesh_deinit(esp_ble_mesh_deinit_param_t *param) } /* Take the Semaphore, wait BLE Mesh de-initialization to finish. */ - xSemaphoreTake(semaphore, portMAX_DELAY); + __ASSERT(xSemaphoreTake(semaphore, 3000 / portTICK_PERIOD_MS) == pdTRUE, "BLE Mesh deinit take semaphore failed"); /* Don't forget to delete the semaphore at the end. */ vSemaphoreDelete(semaphore); diff --git a/lib/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c b/lib/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c index 16b0805d..4f6b4619 100644 --- a/lib/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c +++ b/lib/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -576,9 +576,9 @@ esp_err_t esp_ble_mesh_provisioner_set_heartbeat_filter_info(uint8_t op, esp_ble return ESP_ERR_INVALID_ARG; } - if (!ESP_BLE_MESH_ADDR_IS_UNICAST(info->hb_src) && - !ESP_BLE_MESH_ADDR_IS_UNICAST(info->hb_dst) && - !ESP_BLE_MESH_ADDR_IS_GROUP(info->hb_dst)) { + if (!(ESP_BLE_MESH_ADDR_IS_UNICAST(info->hb_src) && + (ESP_BLE_MESH_ADDR_IS_UNICAST(info->hb_dst) || + ESP_BLE_MESH_ADDR_IS_GROUP(info->hb_dst)))) { return ESP_ERR_INVALID_ARG; } diff --git a/lib/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h b/lib/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h index f7209d8e..556565e7 100644 --- a/lib/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h +++ b/lib/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,7 +33,10 @@ esp_err_t esp_ble_mesh_init(esp_ble_mesh_prov_t *prov, esp_ble_mesh_comp_t *comp /** * @brief De-initialize BLE Mesh module. * - * @note This function shall be invoked after esp_ble_mesh_client_model_deinit(). + * @note + * 1. This function shall be invoked after esp_ble_mesh_client_model_deinit(). + * 2. This function is strictly forbidden to run in any BTC Task Context + * (e.g. registered Mesh Event Callback). * * @param[in] param: Pointer to the structure of BLE Mesh deinit parameters. * diff --git a/lib/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c b/lib/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c index 38882680..67d5353b 100644 --- a/lib/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c +++ b/lib/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -71,6 +71,29 @@ #include "esp_ble_mesh_provisioning_api.h" #include "esp_ble_mesh_networking_api.h" +#if CONFIG_BLE_MESH_DEINIT +static SemaphoreHandle_t deinit_comp_semaphore; +#endif + +static inline void btc_ble_mesh_prov_cb_to_app_reprocess(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + switch (event) { +#if CONFIG_BLE_MESH_DEINIT + case ESP_BLE_MESH_DEINIT_MESH_COMP_EVT: + assert(deinit_comp_semaphore); + /* Give the semaphore when BLE Mesh de-initialization is finished. + * @note: At nimble host, once this lock is released, it will cause + * the btc task to be deleted. + */ + xSemaphoreGive(deinit_comp_semaphore); + break; +#endif + default: + break; + } +} + static inline void btc_ble_mesh_prov_cb_to_app(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param) { @@ -79,6 +102,8 @@ static inline void btc_ble_mesh_prov_cb_to_app(esp_ble_mesh_prov_cb_event_t even if (btc_ble_mesh_cb) { btc_ble_mesh_cb(event, param); } + + btc_ble_mesh_prov_cb_to_app_reprocess(event, param); } static inline void btc_ble_mesh_model_cb_to_app(esp_ble_mesh_model_cb_event_t event, @@ -2825,8 +2850,8 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) case BTC_BLE_MESH_ACT_DEINIT_MESH: act = ESP_BLE_MESH_DEINIT_MESH_COMP_EVT; param.deinit_mesh_comp.err_code = bt_mesh_deinit((struct bt_mesh_deinit_param *)&arg->mesh_deinit.param); - /* Give the semaphore when BLE Mesh de-initialization is finished. */ - xSemaphoreGive(arg->mesh_deinit.semaphore); + /* Temporarily save the deinit semaphore and release it after the mesh deinit complete event is handled in the app layer */ + deinit_comp_semaphore = arg->mesh_deinit.semaphore; break; #endif /* CONFIG_BLE_MESH_DEINIT */ default: diff --git a/lib/bt/esp_ble_mesh/common/include/mesh/kernel.h b/lib/bt/esp_ble_mesh/common/include/mesh/kernel.h index 025b269a..95624cf7 100644 --- a/lib/bt/esp_ble_mesh/common/include/mesh/kernel.h +++ b/lib/bt/esp_ble_mesh/common/include/mesh/kernel.h @@ -8,6 +8,7 @@ #ifndef _BLE_MESH_KERNEL_H_ #define _BLE_MESH_KERNEL_H_ +#include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" @@ -22,7 +23,7 @@ extern "C" { #ifdef CONFIG_BT_BLUEDROID_ENABLED #ifdef CONFIG_BT_BLUEDROID_PINNED_TO_CORE -#define BLE_MESH_ADV_TASK_CORE (CONFIG_BT_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BT_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY) +#define BLE_MESH_ADV_TASK_CORE (CONFIG_BT_BLUEDROID_PINNED_TO_CORE < CONFIG_FREERTOS_NUMBER_OF_CORES ? CONFIG_BT_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY) #else #define BLE_MESH_ADV_TASK_CORE (0) #endif @@ -30,7 +31,7 @@ extern "C" { #ifdef CONFIG_BT_NIMBLE_ENABLED #ifdef CONFIG_BT_NIMBLE_PINNED_TO_CORE -#define BLE_MESH_ADV_TASK_CORE (CONFIG_BT_NIMBLE_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BT_NIMBLE_PINNED_TO_CORE : tskNO_AFFINITY) +#define BLE_MESH_ADV_TASK_CORE (CONFIG_BT_NIMBLE_PINNED_TO_CORE < CONFIG_FREERTOS_NUMBER_OF_CORES ? CONFIG_BT_NIMBLE_PINNED_TO_CORE : tskNO_AFFINITY) #else #define BLE_MESH_ADV_TASK_CORE (0) #endif diff --git a/lib/bt/esp_ble_mesh/core/bluedroid_host/adapter.c b/lib/bt/esp_ble_mesh/core/bluedroid_host/adapter.c index 0d6b9e5a..e0fc33b4 100644 --- a/lib/bt/esp_ble_mesh/core/bluedroid_host/adapter.c +++ b/lib/bt/esp_ble_mesh/core/bluedroid_host/adapter.c @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA * SPDX-FileCopyrightText: 2015-2016 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -74,7 +74,7 @@ static struct bt_mesh_conn_cb *bt_mesh_gatts_conn_cb; static tBTA_GATTS_IF bt_mesh_gatts_if; static uint8_t bt_mesh_gatts_addr[BLE_MESH_ADDR_LEN]; static uint16_t svc_handle, char_handle; -static future_t *future_mesh; +static future_t *gatts_future_mesh; /* Static Functions */ static struct bt_mesh_gatt_attr *bt_mesh_gatts_find_attr_by_handle(uint16_t handle); @@ -561,6 +561,9 @@ static void bt_mesh_bta_gatts_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) case BTA_GATTS_REG_EVT: if (p_data->reg_oper.status == BTA_GATT_OK) { bt_mesh_gatts_if = p_data->reg_oper.server_if; + future_ready(gatts_future_mesh, FUTURE_SUCCESS); + } else { + future_ready(gatts_future_mesh, FUTURE_FAIL); } break; case BTA_GATTS_READ_EVT: { @@ -618,27 +621,27 @@ static void bt_mesh_bta_gatts_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) break; case BTA_GATTS_CREATE_EVT: svc_handle = p_data->create.service_id; - BT_DBG("svc_handle %d, future_mesh %p", svc_handle, future_mesh); - if (future_mesh != NULL) { - future_ready(future_mesh, FUTURE_SUCCESS); + BT_DBG("svc_handle %d, gatts_future_mesh %p", svc_handle, gatts_future_mesh); + if (gatts_future_mesh != NULL) { + future_ready(gatts_future_mesh, FUTURE_SUCCESS); } break; case BTA_GATTS_ADD_INCL_SRVC_EVT: svc_handle = p_data->add_result.attr_id; - if (future_mesh != NULL) { - future_ready(future_mesh, FUTURE_SUCCESS); + if (gatts_future_mesh != NULL) { + future_ready(gatts_future_mesh, FUTURE_SUCCESS); } break; case BTA_GATTS_ADD_CHAR_EVT: char_handle = p_data->add_result.attr_id; - if (future_mesh != NULL) { - future_ready(future_mesh, FUTURE_SUCCESS); + if (gatts_future_mesh != NULL) { + future_ready(gatts_future_mesh, FUTURE_SUCCESS); } break; case BTA_GATTS_ADD_CHAR_DESCR_EVT: char_handle = p_data->add_result.attr_id; - if (future_mesh != NULL) { - future_ready(future_mesh, FUTURE_SUCCESS); + if (gatts_future_mesh != NULL) { + future_ready(gatts_future_mesh, FUTURE_SUCCESS); } break; case BTA_GATTS_DELELTE_EVT: @@ -962,11 +965,11 @@ int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc) if (svc->attrs[i].uuid->type == BLE_MESH_UUID_TYPE_16) { switch (BLE_MESH_UUID_16(svc->attrs[i].uuid)->val) { case BLE_MESH_UUID_GATT_PRIMARY_VAL: { - future_mesh = future_new(); + gatts_future_mesh = future_new(); bta_uuid_to_bt_mesh_uuid(&bta_uuid, (struct bt_mesh_uuid *)svc->attrs[i].user_data); BTA_GATTS_CreateService(bt_mesh_gatts_if, &bta_uuid, 0, svc->attr_count, true); - if (future_await(future_mesh) == FUTURE_FAIL) { + if (future_await(gatts_future_mesh) == FUTURE_FAIL) { BT_ERR("Failed to add primary service"); return ESP_FAIL; } @@ -976,11 +979,11 @@ int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc) break; } case BLE_MESH_UUID_GATT_SECONDARY_VAL: { - future_mesh = future_new(); + gatts_future_mesh = future_new(); bta_uuid_to_bt_mesh_uuid(&bta_uuid, (struct bt_mesh_uuid *)svc->attrs[i].user_data); BTA_GATTS_CreateService(bt_mesh_gatts_if, &bta_uuid, 0, svc->attr_count, false); - if (future_await(future_mesh) == FUTURE_FAIL) { + if (future_await(gatts_future_mesh) == FUTURE_FAIL) { BT_ERR("Failed to add secondary service"); return ESP_FAIL; } @@ -993,11 +996,11 @@ int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc) break; } case BLE_MESH_UUID_GATT_CHRC_VAL: { - future_mesh = future_new(); + gatts_future_mesh = future_new(); struct bt_mesh_gatt_char *gatts_chrc = (struct bt_mesh_gatt_char *)svc->attrs[i].user_data; bta_uuid_to_bt_mesh_uuid(&bta_uuid, gatts_chrc->uuid); BTA_GATTS_AddCharacteristic(svc_handle, &bta_uuid, bt_mesh_perm_to_bta_perm(svc->attrs[i + 1].perm), gatts_chrc->properties, NULL, NULL); - if (future_await(future_mesh) == FUTURE_FAIL) { + if (future_await(gatts_future_mesh) == FUTURE_FAIL) { BT_ERR("Failed to add characteristic"); return ESP_FAIL; } @@ -1019,10 +1022,10 @@ int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc) case BLE_MESH_UUID_ES_CONFIGURATION_VAL: case BLE_MESH_UUID_ES_MEASUREMENT_VAL: case BLE_MESH_UUID_ES_TRIGGER_SETTING_VAL: { - future_mesh = future_new(); + gatts_future_mesh = future_new(); bta_uuid_to_bt_mesh_uuid(&bta_uuid, svc->attrs[i].uuid); BTA_GATTS_AddCharDescriptor(svc_handle, bt_mesh_perm_to_bta_perm(svc->attrs[i].perm), &bta_uuid, NULL, NULL); - if (future_await(future_mesh) == FUTURE_FAIL) { + if (future_await(gatts_future_mesh) == FUTURE_FAIL) { BT_ERR("Failed to add descriptor"); return ESP_FAIL; } @@ -1132,7 +1135,7 @@ int bt_mesh_gatts_service_start(struct bt_mesh_gatt_service *svc) int bt_mesh_gatts_set_local_device_name(const char *name) { - BTM_SetLocalDeviceName((char *)name); + BTM_SetLocalDeviceName((char *)name, BT_DEVICE_TYPE_BLE); return 0; } @@ -1481,7 +1484,7 @@ static void bt_mesh_bta_gattc_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) result = NULL; } - /* Register Notification fot Mesh Provisioning/Proxy Data Out Characteristic */ + /* Register Notification for Mesh Provisioning/Proxy Data Out Characteristic */ status = BTA_GATTC_RegisterForNotifications(bt_mesh_gattc_if, bt_mesh_gattc_info[i].addr.val, bt_mesh_gattc_info[i].data_out_handle); if (status != BTA_GATT_OK) { @@ -1768,7 +1771,19 @@ void bt_mesh_gatt_init(void) CONFIG_BLE_MESH_GATT_PROXY_SERVER tBT_UUID gatts_app_uuid = {LEN_UUID_128, {0}}; memset(&gatts_app_uuid.uu.uuid128, BLE_MESH_GATTS_APP_UUID_BYTE, LEN_UUID_128); + + gatts_future_mesh = future_new(); + if (!gatts_future_mesh) { + BT_ERR("Mesh gatts sync lock alloc failed"); + return; + } + BTA_GATTS_AppRegister(&gatts_app_uuid, bt_mesh_bta_gatts_cb); + + if (future_await(gatts_future_mesh) == FUTURE_FAIL) { + BT_ERR("Mesh gatts app register failed"); + return; + } #endif #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ diff --git a/lib/bt/esp_ble_mesh/core/net.c b/lib/bt/esp_ble_mesh/core/net.c index 66ae08c8..2f988966 100644 --- a/lib/bt/esp_ble_mesh/core/net.c +++ b/lib/bt/esp_ble_mesh/core/net.c @@ -34,7 +34,7 @@ #include "mesh_v1.1/utils.h" /* Minimum valid Mesh Network PDU length. The Network headers - * themselves take up 9 bytes. After that there is a minumum of 1 byte + * themselves take up 9 bytes. After that there is a minimum of 1 byte * payload for both CTL=1 and CTL=0 PDUs (smallest OpCode is 1 byte). CTL=1 * PDUs must use a 64-bit (8 byte) NetMIC, whereas CTL=0 PDUs have at least * a 32-bit (4 byte) NetMIC and AppMIC giving again a total of 8 bytes. @@ -1751,9 +1751,7 @@ static bool ignore_net_msg(uint16_t src, uint16_t dst) } if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && - bt_mesh_is_provisioner_en() && - BLE_MESH_ADDR_IS_UNICAST(dst) && - bt_mesh_elem_find(dst)) { + bt_mesh_is_provisioner_en()) { /* If the destination address of the message is the element * address of Provisioner, but Provisioner fails to find the * node in its provisioning database, then this message will @@ -1810,7 +1808,7 @@ void bt_mesh_net_recv(struct net_buf_simple *data, int8_t rssi, bt_mesh_elem_find(rx.ctx.recv_dst)); if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && - bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_DISABLED && + bt_mesh_private_gatt_proxy_state_get() != BLE_MESH_PRIVATE_GATT_PROXY_ENABLED && net_if == BLE_MESH_NET_IF_PROXY) { bt_mesh_proxy_server_addr_add(data, rx.ctx.addr); diff --git a/lib/bt/esp_ble_mesh/core/prov_pvnr.c b/lib/bt/esp_ble_mesh/core/prov_pvnr.c index 50811a30..e2e0fe58 100644 --- a/lib/bt/esp_ble_mesh/core/prov_pvnr.c +++ b/lib/bt/esp_ble_mesh/core/prov_pvnr.c @@ -366,7 +366,7 @@ static int provisioner_start_prov_pb_adv(const uint8_t uuid[16], const bt_mesh_a if (is_unprov_dev_being_provision(uuid)) { bt_mesh_pb_adv_unlock(); - return -EALREADY; + return 0; } for (i = 0; i < CONFIG_BLE_MESH_PBA_SAME_TIME; i++) { @@ -428,7 +428,7 @@ static int provisioner_start_prov_pb_gatt(const uint8_t uuid[16], const bt_mesh_ if (is_unprov_dev_being_provision(uuid)) { bt_mesh_pb_gatt_unlock(); - return -EALREADY; + return 0; } for (i = CONFIG_BLE_MESH_PBA_SAME_TIME; i < BLE_MESH_PROV_SAME_TIME; i++) { diff --git a/lib/bt/esp_ble_mesh/core/transport.enh.c b/lib/bt/esp_ble_mesh/core/transport.enh.c index 4951c582..6ef6c0a5 100644 --- a/lib/bt/esp_ble_mesh/core/transport.enh.c +++ b/lib/bt/esp_ble_mesh/core/transport.enh.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -121,22 +121,22 @@ static bt_mesh_mutex_t seg_rx_lock; static inline void bt_mesh_seg_tx_lock(void) { - bt_mesh_mutex_lock(&seg_tx_lock); + bt_mesh_r_mutex_lock(&seg_tx_lock); } static inline void bt_mesh_seg_tx_unlock(void) { - bt_mesh_mutex_unlock(&seg_tx_lock); + bt_mesh_r_mutex_unlock(&seg_tx_lock); } static inline void bt_mesh_seg_rx_lock(void) { - bt_mesh_mutex_lock(&seg_rx_lock); + bt_mesh_r_mutex_lock(&seg_rx_lock); } static inline void bt_mesh_seg_rx_unlock(void) { - bt_mesh_mutex_unlock(&seg_rx_lock); + bt_mesh_r_mutex_unlock(&seg_rx_lock); } uint8_t bt_mesh_seg_send_interval(void) @@ -368,7 +368,6 @@ static void seg_tx_reset(struct seg_tx *tx) tx->cb_data = NULL; tx->seq_auth = 0U; tx->sub = NULL; - tx->seg_n = 0; tx->last_seg_n = 0; tx->lsn_updated = 0; tx->dst = BLE_MESH_ADDR_UNASSIGNED; @@ -385,6 +384,7 @@ static void seg_tx_reset(struct seg_tx *tx) } tx->nack_count = 0U; + tx->seg_n = 0; bt_mesh_seg_tx_unlock(); @@ -517,6 +517,12 @@ static bool send_next_segment(struct seg_tx *tx, int *result) net_tx.ctx->net_idx = tx->sub->net_idx; + /** + * Add one to the ref count only if the segment can be further + * processed by the network. + */ + seg = net_buf_ref(seg); + err = bt_mesh_net_send(&net_tx, seg, &seg_sent_cb, tx); if (err) { BT_ERR("Send seg %u failed (err %d)", tx->last_seg_n, err); @@ -966,7 +972,18 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, } } - tx->seg[seg_o] = net_buf_ref(seg); + /** + * If the net buffer allocation of the subsequent + * segments of this segment message fails, it will + * cause the ref count of the previously allocated + * successful segments to not be unref, which will + * cause the net buffer leakage to occur, so it is + * necessary to wait until all the segments have been + * allocated, and then when the segment is confirmed + * that it will be network layer for further processing, + * then ref of the net buffer should be plus one. + */ + tx->seg[seg_o] = seg; BT_DBG("Seg %u/%u prepared", seg_o, tx->seg_n); } @@ -975,6 +992,11 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, * tx->seg[0] will be NULL here. */ if (tx->seg[0]) { + /** + * Add one to the ref count only if the segment can be further + * processed by the network. + */ + tx->seg[0] = net_buf_ref(tx->seg[0]); err = bt_mesh_net_send(net_tx, tx->seg[0], &seg_sent_cb, tx); if (err) { BT_ERR("Send 1st seg failed (err %d)", err); @@ -2327,8 +2349,8 @@ void bt_mesh_trans_init(void) seg_rx[i].buf.data = seg_rx[i].buf.__buf; } - bt_mesh_mutex_create(&seg_tx_lock); - bt_mesh_mutex_create(&seg_rx_lock); + bt_mesh_r_mutex_create(&seg_tx_lock); + bt_mesh_r_mutex_create(&seg_rx_lock); } #if CONFIG_BLE_MESH_DEINIT @@ -2338,7 +2360,7 @@ void bt_mesh_trans_deinit(bool erase) bt_mesh_tx_reset(); bt_mesh_rpl_reset(erase); - bt_mesh_mutex_free(&seg_tx_lock); - bt_mesh_mutex_free(&seg_rx_lock); + bt_mesh_r_mutex_free(&seg_tx_lock); + bt_mesh_r_mutex_free(&seg_rx_lock); } #endif /* CONFIG_BLE_MESH_DEINIT */ diff --git a/lib/bt/esp_ble_mesh/lib/lib/esp32/libble_mesh.a b/lib/bt/esp_ble_mesh/lib/lib/esp32/libble_mesh.a index b0c4dd71..5f8b75a3 100644 Binary files a/lib/bt/esp_ble_mesh/lib/lib/esp32/libble_mesh.a and b/lib/bt/esp_ble_mesh/lib/lib/esp32/libble_mesh.a differ diff --git a/lib/bt/esp_ble_mesh/lib/lib/esp32c3/libble_mesh.a b/lib/bt/esp_ble_mesh/lib/lib/esp32c3/libble_mesh.a index c4a21f20..ffc32db1 100644 Binary files a/lib/bt/esp_ble_mesh/lib/lib/esp32c3/libble_mesh.a and b/lib/bt/esp_ble_mesh/lib/lib/esp32c3/libble_mesh.a differ diff --git a/lib/bt/esp_ble_mesh/lib/lib/esp32c6/libble_mesh.a b/lib/bt/esp_ble_mesh/lib/lib/esp32c6/libble_mesh.a index c4a21f20..ffc32db1 100644 Binary files a/lib/bt/esp_ble_mesh/lib/lib/esp32c6/libble_mesh.a and b/lib/bt/esp_ble_mesh/lib/lib/esp32c6/libble_mesh.a differ diff --git a/lib/bt/esp_ble_mesh/lib/lib/esp32h2/libble_mesh.a b/lib/bt/esp_ble_mesh/lib/lib/esp32h2/libble_mesh.a index c4a21f20..ffc32db1 100644 Binary files a/lib/bt/esp_ble_mesh/lib/lib/esp32h2/libble_mesh.a and b/lib/bt/esp_ble_mesh/lib/lib/esp32h2/libble_mesh.a differ diff --git a/lib/bt/esp_ble_mesh/lib/lib/esp32s3/libble_mesh.a b/lib/bt/esp_ble_mesh/lib/lib/esp32s3/libble_mesh.a index b0c4dd71..5f8b75a3 100644 Binary files a/lib/bt/esp_ble_mesh/lib/lib/esp32s3/libble_mesh.a and b/lib/bt/esp_ble_mesh/lib/lib/esp32s3/libble_mesh.a differ diff --git a/lib/bt/host/bluedroid/Kconfig.in b/lib/bt/host/bluedroid/Kconfig.in index 4ef80cff..58859d35 100644 --- a/lib/bt/host/bluedroid/Kconfig.in +++ b/lib/bt/host/bluedroid/Kconfig.in @@ -54,6 +54,25 @@ config BT_CLASSIC_ENABLED help For now this option needs "SMP_ENABLE" to be set to yes +choice BT_ENC_KEY_SIZE_CTRL_ENABLED + prompt "configure encryption key size" + depends on BT_CLASSIC_ENABLED + default BT_ENC_KEY_SIZE_CTRL_VSC + help + This chooses the support status of configuring encryption key size + + config BT_ENC_KEY_SIZE_CTRL_STD + depends on (BT_CONTROLLER_DISABLED || (BT_CONTROLLER_ENABLED && SOC_BT_H2C_ENC_KEY_CTRL_ENH_STD_SUPPORTED)) + bool "Supported by standard HCI command" + + config BT_ENC_KEY_SIZE_CTRL_VSC + depends on (BT_CONTROLLER_DISABLED || (BT_CONTROLLER_ENABLED && SOC_BT_H2C_ENC_KEY_CTRL_ENH_VSC_SUPPORTED)) + bool "Supported by Vendor-specific HCI command" + + config BT_ENC_KEY_SIZE_CTRL_NONE + bool "Not supported" +endchoice + config BT_CLASSIC_BQB_ENABLED bool "Host Qualitifcation support for Classic Bluetooth" depends on BT_CLASSIC_ENABLED @@ -273,7 +292,7 @@ config BT_GATTC_CACHE_NVS_FLASH config BT_GATTC_CONNECT_RETRY_COUNT int "The number of attempts to reconnect if the connection establishment failed" depends on BT_GATTC_ENABLE - range 0 7 + range 0 255 default 3 help The number of attempts to reconnect if the connection establishment failed @@ -1168,21 +1187,21 @@ config BT_BLE_42_FEATURES_SUPPORTED config BT_BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER bool "Enable BLE periodic advertising sync transfer feature" - depends on (BT_BLE_50_FEATURES_SUPPORTED && ((BT_CONTROLLER_ENABLED && SOC_ESP_NIMBLE_CONTROLLER) || BT_CONTROLLER_DISABLED)) # NOERROR + depends on (BT_BLUEDROID_ENABLED && BT_BLE_50_FEATURES_SUPPORTED && ((BT_CONTROLLER_ENABLED && SOC_ESP_NIMBLE_CONTROLLER) || BT_CONTROLLER_DISABLED)) # NOERROR default n help This enables BLE periodic advertising sync transfer feature config BT_BLE_FEAT_PERIODIC_ADV_ENH bool "Enable periodic adv enhancements(adi support)" - depends on (BT_BLE_50_FEATURES_SUPPORTED && ((BT_CONTROLLER_ENABLED && SOC_ESP_NIMBLE_CONTROLLER) || BT_CONTROLLER_DISABLED)) # NOERROR + depends on (BT_BLUEDROID_ENABLED && BT_BLE_50_FEATURES_SUPPORTED && ((BT_CONTROLLER_ENABLED && SOC_ESP_NIMBLE_CONTROLLER) || BT_CONTROLLER_DISABLED)) # NOERROR default n help Enable the periodic advertising enhancements config BT_BLE_FEAT_CREATE_SYNC_ENH bool "Enable create sync enhancements(reporting disable and duplicate filtering enable support)" - depends on (BT_BLE_50_FEATURES_SUPPORTED && ((BT_CONTROLLER_ENABLED && SOC_ESP_NIMBLE_CONTROLLER) || BT_CONTROLLER_DISABLED)) # NOERROR + depends on (BT_BLUEDROID_ENABLED && BT_BLE_50_FEATURES_SUPPORTED && ((BT_CONTROLLER_ENABLED && SOC_ESP_NIMBLE_CONTROLLER) || BT_CONTROLLER_DISABLED)) # NOERROR default n help Enable the create sync enhancements diff --git a/lib/bt/host/bluedroid/api/esp_bluedroid_hci.c b/lib/bt/host/bluedroid/api/esp_bluedroid_hci.c index 892f6790..1676ae88 100644 --- a/lib/bt/host/bluedroid/api/esp_bluedroid_hci.c +++ b/lib/bt/host/bluedroid/api/esp_bluedroid_hci.c @@ -12,6 +12,7 @@ #if (BT_CONTROLLER_INCLUDED == TRUE) #include "esp_bt.h" #endif +#include "hci_log/bt_hci_log.h" #define LOG_TAG "HCI_API" @@ -59,6 +60,9 @@ bool hci_host_check_send_available(void) void hci_host_send_packet(uint8_t *data, uint16_t len) { +#if (BT_HCI_LOG_INCLUDED == TRUE) + bt_hci_log_record_hci_data(data[0], &data[1], len - 1); +#endif #if (BT_CONTROLLER_INCLUDED == TRUE) esp_vhci_host_send_packet(data, len); #else /* BT_CONTROLLER_INCLUDED == TRUE */ diff --git a/lib/bt/host/bluedroid/api/esp_bt_device.c b/lib/bt/host/bluedroid/api/esp_bt_device.c index c37b9adb..ae4ff8ec 100644 --- a/lib/bt/host/bluedroid/api/esp_bt_device.c +++ b/lib/bt/host/bluedroid/api/esp_bt_device.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,21 @@ #include "btc/btc_task.h" #include "btc/btc_dev.h" #include "btc/btc_config.h" +#include "btc/btc_manage.h" + +esp_err_t esp_bt_dev_register_callback(esp_bt_dev_cb_t callback) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (callback == NULL) { + return ESP_ERR_INVALID_ARG; + } + + btc_profile_cb_set(BTC_PID_DEV, callback); + return ESP_OK; +} const uint8_t *esp_bt_dev_get_address(void) { @@ -39,14 +54,24 @@ esp_err_t esp_bt_dev_set_device_name(const char *name) msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_DEV; msg.act = BTC_DEV_ACT_SET_DEVICE_NAME; - arg.set_dev_name.device_name = (char *)osi_malloc((BTC_MAX_LOC_BD_NAME_LEN + 1) * sizeof(char)); - if (!arg.set_dev_name.device_name) { - return ESP_ERR_NO_MEM; + arg.set_dev_name.device_name = (char *)name; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_dev_args_t), btc_dev_call_arg_deep_copy, btc_dev_call_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_bt_dev_get_device_name(void) +{ + btc_msg_t msg = {0}; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; } - strcpy(arg.set_dev_name.device_name, name); + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DEV; + msg.act = BTC_DEV_ACT_GET_DEVICE_NAME; - return (btc_transfer_context(&msg, &arg, sizeof(btc_dev_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); + return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } #if (ESP_COEX_VSC_INCLUDED == TRUE) diff --git a/lib/bt/host/bluedroid/api/esp_bt_main.c b/lib/bt/host/bluedroid/api/esp_bt_main.c index 497ba769..92576442 100644 --- a/lib/bt/host/bluedroid/api/esp_bt_main.c +++ b/lib/bt/host/bluedroid/api/esp_bt_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,8 @@ #include "osi/future.h" #include "osi/allocator.h" #include "config/stack_config.h" +#include "hci_log/bt_hci_log.h" +#include "bt_common.h" static bool bd_already_enable = false; static bool bd_already_init = false; @@ -180,6 +182,10 @@ esp_err_t esp_bluedroid_init_with_cfg(esp_bluedroid_config_t *cfg) bd_already_init = true; +#if (BT_HCI_LOG_INCLUDED == TRUE) + bt_hci_log_init(); +#endif // (BT_HCI_LOG_INCLUDED == TRUE) + return ESP_OK; } @@ -224,6 +230,10 @@ esp_err_t esp_bluedroid_deinit(void) bluedriod_config_deinit(); +#if (BT_HCI_LOG_INCLUDED == TRUE) + bt_hci_log_deinit(); +#endif // (BT_HCI_LOG_INCLUDED == TRUE) + bd_already_init = false; return ESP_OK; diff --git a/lib/bt/host/bluedroid/api/esp_gap_ble_api.c b/lib/bt/host/bluedroid/api/esp_gap_ble_api.c index 5db7b629..1d2267e8 100644 --- a/lib/bt/host/bluedroid/api/esp_gap_ble_api.c +++ b/lib/bt/host/bluedroid/api/esp_gap_ble_api.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,7 +13,7 @@ #include "btc/btc_manage.h" #include "btc_gap_ble.h" #include "btc/btc_ble_storage.h" - +#include "esp_random.h" esp_err_t esp_ble_gap_register_callback(esp_gap_ble_cb_t callback) { @@ -188,6 +188,25 @@ esp_err_t esp_ble_gap_set_pkt_data_len(esp_bd_addr_t remote_device, uint16_t tx_ return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } +esp_err_t esp_ble_gap_addr_create_static(esp_bd_addr_t rand_addr) +{ + // Static device address: First two bits are '11', rest is random + rand_addr[0] = 0xC0 | (esp_random() & 0x3F); + for (int i = 1; i < 6; i++) { + rand_addr[i] = esp_random() & 0xFF; // Randomize remaining bits + } + return ESP_OK; +} + +esp_err_t esp_ble_gap_addr_create_nrpa(esp_bd_addr_t rand_addr) +{ + // Non-resolvable private address: First two bits are '00', rest is random + rand_addr[0] = (esp_random() & 0x3F); + for (int i = 1; i < 6; i++) { + rand_addr[i] = esp_random() & 0xFF; // Randomize remaining bits + } + return ESP_OK; +} esp_err_t esp_ble_gap_set_rand_addr(esp_bd_addr_t rand_addr) { @@ -204,6 +223,48 @@ esp_err_t esp_ble_gap_set_rand_addr(esp_bd_addr_t rand_addr) return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } +esp_err_t esp_ble_gap_set_resolvable_private_address_timeout(uint16_t rpa_timeout) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + if (rpa_timeout < 0x0001 || rpa_timeout > 0x0E10) { + return ESP_ERR_INVALID_ARG; + } + + btc_msg_t msg = {0}; + btc_ble_gap_args_t arg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BLE; + msg.act = BTC_GAP_BLE_ACT_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT; + arg.set_rpa_timeout.rpa_timeout = rpa_timeout; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + + +esp_err_t esp_ble_gap_add_device_to_resolving_list(esp_bd_addr_t peer_addr, uint8_t addr_type, uint8_t *peer_irk) +{ + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + if (addr_type > BLE_ADDR_TYPE_RANDOM ||!peer_addr || (addr_type && ((peer_addr[0] & 0xC0) != 0xC0))) { + return ESP_ERR_INVALID_ARG; + } + + btc_msg_t msg = {0}; + btc_ble_gap_args_t arg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BLE; + msg.act = BTC_GAP_BLE_ACT_ADD_DEVICE_TO_RESOLVING_LIST; + + memcpy(arg.add_dev_to_resolving_list.addr, peer_addr, ESP_BD_ADDR_LEN); + arg.add_dev_to_resolving_list.addr_type = addr_type; + memcpy(arg.add_dev_to_resolving_list.irk, peer_irk, ESP_PEER_IRK_LEN); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + esp_err_t esp_ble_gap_clear_rand_addr(void) { btc_msg_t msg; @@ -299,6 +360,7 @@ esp_err_t esp_ble_gap_config_local_icon (uint16_t icon) case ESP_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV: case ESP_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD: case ESP_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV: + case ESP_BLE_APPEARANCE_STANDALONE_SPEAKER: msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_ACT_CONFIG_LOCAL_ICON; @@ -396,9 +458,25 @@ esp_err_t esp_ble_gap_set_prefer_conn_params(esp_bd_addr_t bd_addr, esp_err_t esp_ble_gap_set_device_name(const char *name) { - ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + btc_msg_t msg = {0}; + btc_ble_gap_args_t arg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + if (!name){ + return ESP_ERR_INVALID_ARG; + } + if (strlen(name) > BTC_MAX_LOC_BD_NAME_LEN) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BLE; + msg.act = BTC_GAP_BLE_ACT_SET_DEV_NAME; + arg.set_dev_name.device_name = (char *)name; - return esp_bt_dev_set_device_name(name); + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), btc_gap_ble_arg_deep_copy, btc_gap_ble_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } esp_err_t esp_ble_gap_get_device_name(void) @@ -936,6 +1014,25 @@ esp_err_t esp_ble_dtm_stop(void) return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } +esp_err_t esp_ble_gap_set_privacy_mode(esp_ble_addr_type_t addr_type, esp_bd_addr_t addr, esp_ble_privacy_mode_t mode) +{ + btc_msg_t msg; + btc_ble_gap_args_t arg; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BLE; + msg.act = BTC_GAP_BLE_SET_PRIVACY_MODE; + + arg.set_privacy_mode.addr_type = addr_type; + memcpy(arg.set_privacy_mode.addr, addr, sizeof(esp_bd_addr_t)); + arg.set_privacy_mode.privacy_mode = mode; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + #if (BLE_50_FEATURE_SUPPORT == TRUE) esp_err_t esp_ble_gap_read_phy(esp_bd_addr_t bd_addr) @@ -1599,3 +1696,31 @@ esp_err_t esp_ble_gap_set_periodic_adv_sync_trans_params(esp_bd_addr_t addr, con == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } #endif //#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) + +esp_err_t esp_ble_gap_vendor_command_send(esp_ble_vendor_cmd_params_t *vendor_cmd_param) +{ + btc_msg_t msg = {0}; + btc_ble_gap_args_t arg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (!vendor_cmd_param || !vendor_cmd_param->p_param_buf || !vendor_cmd_param->param_len) { + return ESP_ERR_NOT_ALLOWED; + } + // If command is not a VSC, return error + if ((vendor_cmd_param->opcode & VENDOR_HCI_CMD_MASK) != VENDOR_HCI_CMD_MASK) { + return ESP_ERR_NOT_ALLOWED; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BLE; + msg.act = BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT; + arg.vendor_cmd_send.opcode = vendor_cmd_param->opcode; + arg.vendor_cmd_send.param_len = vendor_cmd_param->param_len; + arg.vendor_cmd_send.p_param_buf = vendor_cmd_param->p_param_buf; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), btc_gap_ble_arg_deep_copy, btc_gap_ble_arg_deep_free) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} diff --git a/lib/bt/host/bluedroid/api/esp_gap_bt_api.c b/lib/bt/host/bluedroid/api/esp_gap_bt_api.c index 3e58847d..5973a663 100644 --- a/lib/bt/host/bluedroid/api/esp_gap_bt_api.c +++ b/lib/bt/host/bluedroid/api/esp_gap_bt_api.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -494,4 +494,63 @@ esp_err_t esp_bt_gap_set_acl_pkt_types(esp_bd_addr_t remote_bda, uint16_t pkt_ty return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +esp_err_t esp_bt_gap_set_min_enc_key_size(uint8_t key_size) +{ + btc_msg_t msg; + btc_gap_bt_args_t arg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (key_size < ESP_BT_ENC_KEY_SIZE_CTRL_MIN || key_size > ESP_BT_ENC_KEY_SIZE_CTRL_MAX) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BT; + msg.act = BTC_GAP_BT_ACT_SET_MIN_ENC_KEY_SIZE; + + arg.set_min_enc_key_size.key_size = key_size; + return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* #if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) */ + +esp_err_t esp_bt_gap_set_device_name(const char *name) +{ + btc_msg_t msg; + btc_gap_bt_args_t arg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + if ((!name) || (strlen(name) > BTC_MAX_LOC_BD_NAME_LEN)) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BT; + msg.act = BTC_GAP_BT_ACT_SET_DEV_NAME; + arg.bt_set_dev_name.device_name = (char *)name; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), btc_gap_bt_arg_deep_copy, + btc_gap_bt_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_bt_gap_get_device_name(void) +{ + btc_msg_t msg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BT; + msg.act = BTC_GAP_BT_ACT_GET_DEV_NAME; + + return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + #endif /* #if BTC_GAP_BT_INCLUDED == TRUE */ diff --git a/lib/bt/host/bluedroid/api/include/api/esp_bt_defs.h b/lib/bt/host/bluedroid/api/include/api/esp_bt_defs.h index 19419014..182f8760 100644 --- a/lib/bt/host/bluedroid/api/include/api/esp_bt_defs.h +++ b/lib/bt/host/bluedroid/api/include/api/esp_bt_defs.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,7 +19,7 @@ extern "C" { return ESP_ERR_INVALID_STATE; \ } -#define ESP_BT_STATUS_BASE_FOR_HCI_ERR 0X0100 /* base for coverting HCI error code to ESP status */ +#define ESP_BT_STATUS_BASE_FOR_HCI_ERR 0X0100 /* base for converting HCI error code to ESP status */ /* relate to BT_STATUS_xxx in bt_def.h */ /// Status Return Value @@ -163,6 +163,9 @@ typedef enum { /// Bluetooth address length #define ESP_BD_ADDR_LEN 6 +/// Bluetooth peer irk +#define ESP_PEER_IRK_LEN 16 + /// Bluetooth device address typedef uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN]; diff --git a/lib/bt/host/bluedroid/api/include/api/esp_bt_device.h b/lib/bt/host/bluedroid/api/include/api/esp_bt_device.h index 5c00c456..6e12765c 100644 --- a/lib/bt/host/bluedroid/api/include/api/esp_bt_device.h +++ b/lib/bt/host/bluedroid/api/include/api/esp_bt_device.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -37,6 +37,41 @@ typedef enum { ESP_BT_DEV_COEX_TYPE_BT, } esp_bt_dev_coex_type_t; +/// BT device callback events +typedef enum { + ESP_BT_DEV_NAME_RES_EVT = 0, /*!< Device name result event */ + ESP_BT_DEV_EVT_MAX, +} esp_bt_dev_cb_event_t; + +/// BT device callback parameters +typedef union { + /** + * @brief ESP_BT_DEV_NAME_RES_EVT + */ + struct name_res_param { + esp_bt_status_t status; /*!< Status of getting device name */ + char *name; /*!< Name of Bluetooth device */ + } name_res; /*!< discovery result parameter struct */ +} esp_bt_dev_cb_param_t; + +/** + * @brief bluetooth device callback function type + * + * @param event : Event type + * + * @param param : Pointer to callback parameter + */ +typedef void (* esp_bt_dev_cb_t)(esp_bt_dev_cb_event_t event, esp_bt_dev_cb_param_t *param); + +/** + * @brief register callback function. This function should be called after esp_bluedroid_enable() completes successfully + * + * @return + * - ESP_OK : Succeed + * - ESP_FAIL: others + */ +esp_err_t esp_bt_dev_register_callback(esp_bt_dev_cb_t callback); + /** * * @brief Get bluetooth device address. Must use after "esp_bluedroid_enable". @@ -61,7 +96,21 @@ const uint8_t *esp_bt_dev_get_address(void); * - ESP_ERR_INVALID_STATE : if bluetooth stack is not yet enabled * - ESP_FAIL : others */ -esp_err_t esp_bt_dev_set_device_name(const char *name); +esp_err_t esp_bt_dev_set_device_name(const char *name) __attribute__((deprecated("Please use esp_bt_gap_set_device_name or esp_ble_gap_set_device_name"))); + +/** + * @brief Get bluetooth device name. This function should be called after esp_bluedroid_enable() + * completes successfully. + * + * A BR/EDR/LE device type shall have a single Bluetooth device name which shall be + * identical irrespective of the physical channel used to perform the name discovery procedure. + * + * @return + * - ESP_OK : Succeed + * - ESP_ERR_INVALID_STATE : if bluetooth stack is not yet enabled + * - ESP_FAIL : others + */ +esp_err_t esp_bt_dev_get_device_name(void) __attribute__((deprecated("Please use esp_bt_gap_get_device_name or esp_ble_gap_get_device_name"))); /** * @brief Config bluetooth device coexis status. This function should be called after esp_bluedroid_enable() diff --git a/lib/bt/host/bluedroid/api/include/api/esp_bt_main.h b/lib/bt/host/bluedroid/api/include/api/esp_bt_main.h index db6826e3..b13ae94d 100644 --- a/lib/bt/host/bluedroid/api/include/api/esp_bt_main.h +++ b/lib/bt/host/bluedroid/api/include/api/esp_bt_main.h @@ -70,7 +70,7 @@ esp_err_t esp_bluedroid_disable(void); * - ESP_OK : Succeed * - Other : Failed */ -esp_err_t esp_bluedroid_init(void) __attribute__((deprecated("Please use esp_bluedroid_init_with_cfg"))); +esp_err_t esp_bluedroid_init(void); /** * @brief Init and alloc the resource for bluetooth, must be prior to every bluetooth stuff. diff --git a/lib/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h b/lib/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h index e3904d6d..ea52baf0 100644 --- a/lib/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h +++ b/lib/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h @@ -54,7 +54,7 @@ typedef uint8_t esp_ble_auth_req_t; /*!< combination of the above bit #define ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_DISABLE 0 /*!< authentication disable*/ #define ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE 1 /*!< authentication enable*/ -#define ESP_BLE_OOB_DISABLE 0 /*!< disbale the out of bond*/ +#define ESP_BLE_OOB_DISABLE 0 /*!< disable the out of bond*/ #define ESP_BLE_OOB_ENABLE 1 /*!< enable the out of bond*/ /// relate to BTM_IO_CAP_xxx in stack/btm_api.h @@ -104,6 +104,7 @@ typedef uint8_t esp_ble_auth_req_t; /*!< combination of the above bit #define ESP_BLE_APPEARANCE_CYCLING_CADENCE 0x0483 /*!< relate to BTM_BLE_APPEARANCE_CYCLING_CADENCE in stack/btm_ble_api.h */ #define ESP_BLE_APPEARANCE_CYCLING_POWER 0x0484 /*!< relate to BTM_BLE_APPEARANCE_CYCLING_POWER in stack/btm_ble_api.h */ #define ESP_BLE_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485 /*!< relate to BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_STANDALONE_SPEAKER 0x0841 /*!< relate to BTM_BLE_APPEARANCE_STANDALONE_SPEAKER in stack/btm_ble_api.h */ #define ESP_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40 /*!< relate to BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER in stack/btm_ble_api.h */ #define ESP_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41 /*!< relate to BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP in stack/btm_ble_api.h */ #define ESP_BLE_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42 /*!< relate to BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST in stack/btm_ble_api.h */ @@ -156,7 +157,7 @@ typedef enum { ESP_GAP_BLE_PASSKEY_REQ_EVT, /*!< passkey request event */ ESP_GAP_BLE_OOB_REQ_EVT, /*!< OOB request event */ ESP_GAP_BLE_LOCAL_IR_EVT, /*!< BLE local IR (identity Root 128-bit random static value used to generate Long Term Key) event */ - ESP_GAP_BLE_LOCAL_ER_EVT, /*!< BLE local ER (Encryption Root vakue used to genrate identity resolving key) event */ + ESP_GAP_BLE_LOCAL_ER_EVT, /*!< BLE local ER (Encryption Root value used to generate identity resolving key) event */ ESP_GAP_BLE_NC_REQ_EVT, /*!< Numeric Comparison request event */ //BLE_42_FEATURE_SUPPORT ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT, /*!< When stop adv complete, the event comes */ @@ -224,6 +225,10 @@ typedef enum { ESP_GAP_BLE_DTM_TEST_UPDATE_EVT, /*!< when direct test mode state changes, the event comes */ // BLE_INCLUDED ESP_GAP_BLE_ADV_CLEAR_COMPLETE_EVT, /*!< When clear advertising complete, the event comes */ + ESP_GAP_BLE_SET_RPA_TIMEOUT_COMPLETE_EVT, /*!< When set the Resolvable Private Address (RPA) timeout completes, the event comes */ + ESP_GAP_BLE_ADD_DEV_TO_RESOLVING_LIST_COMPLETE_EVT, /*!< when add a device to the resolving list completes, the event comes*/ + ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT, /*!< When vendor hci command complete, the event comes */ + ESP_GAP_BLE_SET_PRIVACY_MODE_COMPLETE_EVT, /*!< When set privacy mode complete, the event comes */ ESP_GAP_BLE_EVT_MAX, /*!< when maximum advertising event complete, the event comes */ } esp_gap_ble_cb_event_t; @@ -238,6 +243,8 @@ typedef uint8_t esp_gap_ble_channels[ESP_GAP_BLE_CHANNELS_LEN]; /// Scan response data maximum length #define ESP_BLE_SCAN_RSP_DATA_LEN_MAX 31 +#define VENDOR_HCI_CMD_MASK (0x3F << 10) /**!< 0xFC00 */ + /* relate to BTM_BLE_AD_TYPE_xxx in stack/btm_ble_api.h */ /// The type of advertising data(not adv_type) typedef enum { @@ -364,6 +371,15 @@ typedef enum { DTM_TEST_STOP_EVT, } esp_ble_dtm_update_evt_t; +/** + * @brief Vendor HCI command parameters + */ +typedef struct { + uint16_t opcode; /*!< vendor hci command opcode */ + uint8_t param_len; /*!< the length of parameter */ + uint8_t *p_param_buf; /*!< the point of parameter buffer */ +} esp_ble_vendor_cmd_params_t; + #if (BLE_42_FEATURE_SUPPORT == TRUE) /** * @brief DTM TX parameters @@ -786,9 +802,9 @@ typedef uint8_t esp_ble_gap_all_phys_t; #define ESP_BLE_GAP_PRI_PHY_CODED ESP_BLE_GAP_PHY_CODED /*!< Primary Phy is LE CODED */ typedef uint8_t esp_ble_gap_pri_phy_t; // primary phy -#define ESP_BLE_GAP_PHY_1M_PREF_MASK (1 << 0) /*!< The Host prefers use the LE1M transmitter or reciever PHY */ -#define ESP_BLE_GAP_PHY_2M_PREF_MASK (1 << 1) /*!< The Host prefers use the LE2M transmitter or reciever PHY */ -#define ESP_BLE_GAP_PHY_CODED_PREF_MASK (1 << 2) /*!< The Host prefers use the LE CODED transmitter or reciever PHY */ +#define ESP_BLE_GAP_PHY_1M_PREF_MASK (1 << 0) /*!< The Host prefers use the LE1M transmitter or receiver PHY */ +#define ESP_BLE_GAP_PHY_2M_PREF_MASK (1 << 1) /*!< The Host prefers use the LE2M transmitter or receiver PHY */ +#define ESP_BLE_GAP_PHY_CODED_PREF_MASK (1 << 2) /*!< The Host prefers use the LE CODED transmitter or receiver PHY */ typedef uint8_t esp_ble_gap_phy_mask_t; #define ESP_BLE_GAP_PHY_OPTIONS_NO_PREF 0 /*!< The Host has no preferred coding when transmitting on the LE Coded PHY */ @@ -945,7 +961,7 @@ typedef struct { esp_ble_gap_ext_adv_data_status_t data_status; /*!< data type */ uint8_t adv_data_len; /*!< extend advertising data length */ uint8_t adv_data[251]; /*!< extend advertising data */ -} esp_ble_gap_ext_adv_reprot_t; +} esp_ble_gap_ext_adv_report_t; /** * @brief periodic adv report parameters @@ -1015,6 +1031,11 @@ typedef struct { } esp_ble_gap_past_params_t; #endif // #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) +typedef enum{ + ESP_BLE_NETWORK_PRIVACY_MODE = 0X00, /*!< Network Privacy Mode for peer device (default) */ + ESP_BLE_DEVICE_PRIVACY_MODE = 0X01, /*!< Device Privacy Mode for peer device */ +} esp_ble_privacy_mode_t; + /** * @brief Gap callback parameters union */ @@ -1140,6 +1161,19 @@ typedef union { struct ble_local_privacy_cmpl_evt_param { esp_bt_status_t status; /*!< Indicate the set local privacy operation success status */ } local_privacy_cmpl; /*!< Event parameter of ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SET_RPA_TIMEOUT_COMPLETE_EVT + */ + struct ble_rpa_timeout_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the set RPA timeout operation success status */ + } set_rpa_timeout_cmpl; /*!< Event parameter of ESP_GAP_BLE_SET_RPA_TIMEOUT_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_ADD_DEV_TO_RESOLVING_LIST_COMPLETE_EVT + */ + struct ble_add_dev_to_resolving_list_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicates the success status of adding a device to the resolving list */ + } add_dev_to_resolving_list_cmpl; /*!< Event parameter of ESP_GAP_BLE_ADD_DEV_TO_RESOLVING_LIST_COMPLETE_EVT */ + /** * @brief ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT */ @@ -1410,7 +1444,7 @@ typedef union { * @brief ESP_GAP_BLE_EXT_ADV_REPORT_EVT */ struct ble_ext_adv_report_param { - esp_ble_gap_ext_adv_reprot_t params; /*!< extend advertising report parameters */ + esp_ble_gap_ext_adv_report_t params; /*!< extend advertising report parameters */ } ext_adv_report; /*!< Event parameter of ESP_GAP_BLE_EXT_ADV_REPORT_EVT */ /** * @brief ESP_GAP_BLE_PERIODIC_ADV_REPORT_EVT @@ -1471,6 +1505,20 @@ typedef union { esp_ble_dtm_update_evt_t update_evt; /*!< DTM state change event, 0x00: DTM TX start, 0x01: DTM RX start, 0x02:DTM end */ uint16_t num_of_pkt; /*!< number of packets received, only valid if update_evt is DTM_TEST_STOP_EVT and shall be reported as 0 for a transmitter */ } dtm_state_update; /*!< Event parameter of ESP_GAP_BLE_DTM_TEST_UPDATE_EVT */ + /** + * @brief ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT + */ + struct vendor_cmd_cmpl_evt_param { + uint16_t opcode; /*!< vendor hci command opcode */ + uint16_t param_len; /*!< The length of parameter buffer */ + uint8_t *p_param_buf; /*!< The point of parameter buffer */ + } vendor_cmd_cmpl; /*!< Event parameter of ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SET_PRIVACY_MODE_COMPLETE_EVT + */ + struct ble_set_privacy_mode_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate privacy mode set operation success status */ + } set_privacy_mode_cmpl; /*!< Event parameter of ESP_GAP_BLE_SET_PRIVACY_MODE_COMPLETE_EVT */ } esp_ble_gap_cb_param_t; /** @@ -1608,13 +1656,13 @@ esp_err_t esp_ble_gap_set_pkt_data_len(esp_bd_addr_t remote_device, uint16_t tx_ * * @param[in] rand_addr: The address to be configured. Refer to the table below for possible address subtypes: * - * | address [47:46] | Address Type | - * |-----------------|--------------------------| - * | 0b00 | Non-Resolvable Private | - * | | Address | - * |-----------------|--------------------------| - * | 0b11 | Static Random Address | - * |-----------------|--------------------------| + * | address [47:46] | Address Type | Corresponding API | + * |-----------------|-----------------------------|----------------------------------------| + * | 0b00 | Non-Resolvable Private | esp_ble_gap_addr_create_nrpa | + * | | Address (NRPA) | | + * |-----------------|-----------------------------|----------------------------------------| + * | 0b11 | Static Random Address | esp_ble_gap_addr_create_static | + * |-----------------|-----------------------------|----------------------------------------| * * @return * - ESP_OK : success @@ -1624,16 +1672,68 @@ esp_err_t esp_ble_gap_set_pkt_data_len(esp_bd_addr_t remote_device, uint16_t tx_ esp_err_t esp_ble_gap_set_rand_addr(esp_bd_addr_t rand_addr); /** - * @brief This function clears the random address for the application + * @brief Create a static device address + * @param[out] rand_addr: Pointer to the buffer where the static device address will be stored. + * @return - ESP_OK : Success + * - Other : Failed + */ +esp_err_t esp_ble_gap_addr_create_static(esp_bd_addr_t rand_addr); + +/** + * @brief Create a non-resolvable private address (NRPA) + * @param[out] rand_addr: Pointer to the buffer where the NRPA will be stored. + * @return - ESP_OK : Success + * - Other : Failed + */ +esp_err_t esp_ble_gap_addr_create_nrpa(esp_bd_addr_t rand_addr); + +/** + * @brief This function sets the length of time the Controller uses a Resolvable Private Address + * before generating and starting to use a new resolvable private address. + * + * @note Note: This function is currently not supported on the ESP32 but will be enabled in a future update. * + * @param[in] rpa_timeout: The timeout duration in seconds for how long a Resolvable Private Address + * is used before a new one is generated. The value must be within the range specified by + * the Bluetooth specification (0x0001 to 0x0E10), which corresponds to a time range of + * 1 second to 1 hour. The default value is 0x0384 (900 seconds or 15 minutes). * @return * - ESP_OK : success * - other : failed * */ -esp_err_t esp_ble_gap_clear_rand_addr(void); +esp_err_t esp_ble_gap_set_resolvable_private_address_timeout(uint16_t rpa_timeout); +/** + * @brief This function adds a device to the resolving list used to generate and resolve Resolvable Private Addresses + * in the Controller. + * + * @note Note: This function shall not be used when address resolution is enabled in the Controller and: + * - Advertising (other than periodic advertising) is enabled, + * - Scanning is enabled, or + * - an HCI_LE_Create_Connection, HCI_LE_Extended_Create_Connection, or HCI_LE_Periodic_Advertising_Create_Sync command is pending. + * This command may be used at any time when address resolution is disabled in the Controller. + * The added device shall be set to Network Privacy mode. + * + * @param[in] peer_addr: The peer identity address of the device to be added to the resolving list. + * @param[in] addr_type: The address type of the peer identity address (BLE_ADDR_TYPE_PUBLIC or BLE_ADDR_TYPE_RANDOM). + * @param[in] peer_irk: The Identity Resolving Key (IRK) of the device. + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_add_device_to_resolving_list(esp_bd_addr_t peer_addr, uint8_t addr_type, uint8_t *peer_irk); +/** + * @brief This function clears the random address for the application + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_clear_rand_addr(void); /** * @brief Enable/disable privacy (including address resolution) on the local device @@ -1949,7 +2049,6 @@ esp_err_t esp_ble_remove_bond_device(esp_bd_addr_t bd_addr); */ int esp_ble_get_bond_device_num(void); - /** * @brief Get the device from the security database list of peer device. * It will return the device bonded information immediately. @@ -2540,6 +2639,34 @@ esp_err_t esp_ble_dtm_stop(void); */ esp_err_t esp_ble_gap_clear_advertising(void); +/** + * @brief This function is called to send vendor hci command. + * + * + * + * @param[in] vendor_cmd_param: vendor hci command parameters + * + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_ble_gap_vendor_command_send(esp_ble_vendor_cmd_params_t *vendor_cmd_param); + +/** + * @brief This function set the privacy mode of the device in resolving list. + * + * @note This feature is not supported on ESP32. + * + * @param[in] addr_type: The address type of the peer identity address (BLE_ADDR_TYPE_PUBLIC or BLE_ADDR_TYPE_RANDOM). + * @param[in] addr: The peer identity address of the device. + * @param[in] mode: The privacy mode of the device. + * + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_ble_gap_set_privacy_mode(esp_ble_addr_type_t addr_type, esp_bd_addr_t addr, esp_ble_privacy_mode_t mode); + #ifdef __cplusplus } #endif diff --git a/lib/bt/host/bluedroid/api/include/api/esp_gap_bt_api.h b/lib/bt/host/bluedroid/api/include/api/esp_gap_bt_api.h index 6396534f..7c75927f 100644 --- a/lib/bt/host/bluedroid/api/include/api/esp_gap_bt_api.h +++ b/lib/bt/host/bluedroid/api/include/api/esp_gap_bt_api.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -105,7 +105,7 @@ typedef uint8_t esp_bt_eir_type_t; #define ESP_BT_ACL_PKT_TYPES_MASK_NO_2_DH5 0x1000 #define ESP_BT_ACL_PKT_TYPES_MASK_NO_3_DH5 0x2000 -// DM1 cann not be disabled. All options are mandatory to include DM1. +// DM1 can not be disabled. All options are mandatory to include DM1. #define ESP_BT_ACL_DM1_ONLY (ESP_BT_ACL_PKT_TYPES_MASK_DM1 | 0x330e) /* 0x330e */ #define ESP_BT_ACL_DH1_ONLY (ESP_BT_ACL_PKT_TYPES_MASK_DH1 | 0x330e) /* 0x331e */ #define ESP_BT_ACL_DM3_ONLY (ESP_BT_ACL_PKT_TYPES_MASK_DM3 | 0x330e) /* 0x370e */ @@ -121,6 +121,10 @@ typedef uint8_t esp_bt_eir_type_t; typedef uint16_t esp_bt_acl_pkt_type_t; +/* Range of encryption key size */ +#define ESP_BT_ENC_KEY_SIZE_CTRL_MAX (16) +#define ESP_BT_ENC_KEY_SIZE_CTRL_MIN (7) + /* ESP_BT_EIR_FLAG bit definition */ #define ESP_BT_EIR_FLAG_LIMIT_DISC (0x01 << 0) #define ESP_BT_EIR_FLAG_GEN_DISC (0x01 << 1) @@ -142,7 +146,7 @@ typedef struct { uint8_t *p_url; /*!< URL point */ } esp_bt_eir_data_t; -/// Major service class field of Class of Device, mutiple bits can be set +/// Major service class field of Class of Device, multiple bits can be set typedef enum { ESP_BT_COD_SRVC_NONE = 0, /*!< None indicates an invalid value */ ESP_BT_COD_SRVC_LMTD_DISCOVER = 0x1, /*!< Limited Discoverable Mode */ @@ -266,6 +270,8 @@ typedef enum { ESP_BT_GAP_GET_PAGE_TO_EVT, /*!< Get page timeout event */ ESP_BT_GAP_ACL_PKT_TYPE_CHANGED_EVT, /*!< Set ACL packet types event */ ESP_BT_GAP_ENC_CHG_EVT, /*!< Encryption change event */ + ESP_BT_GAP_SET_MIN_ENC_KEY_SIZE_EVT, /*!< Set minimum encryption key size */ + ESP_BT_GAP_GET_DEV_NAME_CMPL_EVT, /*!< Get device name complete event */ ESP_BT_GAP_EVT_MAX, } esp_bt_gap_cb_event_t; @@ -458,6 +464,13 @@ typedef union { uint16_t pkt_types; /*!< packet types successfully set */ } set_acl_pkt_types; /*!< set ACL packet types parameter struct */ + /** + * @brief ESP_BT_GAP_SET_MIN_ENC_KEY_SIZE_EVT + */ + struct set_min_enc_key_size_param { + esp_bt_status_t status; /*!< set minimum encryption key size status */ + } set_min_enc_key_size; /*!< set minimum encryption key size parameter struct */ + /** * @brief ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT */ @@ -475,6 +488,14 @@ typedef union { uint16_t handle; /*!< ACL connection handle */ esp_bd_addr_t bda; /*!< remote bluetooth device address */ } acl_disconn_cmpl_stat; /*!< ACL disconnection complete status parameter struct */ + + /** + * @brief ESP_GAP_BT_GET_DEV_NAME_CMPL_EVT + */ + struct get_dev_name_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the get device name success status */ + char *name; /*!< Name of bluetooth device */ + } get_dev_name_cmpl; /*!< Get device name complete status parameter struct */ } esp_bt_gap_cb_param_t; /** @@ -541,7 +562,7 @@ static inline uint32_t esp_bt_gap_get_cod_format_type(uint32_t cod) * * @return * - true if cod is valid - * - false otherise + * - false otherwise */ static inline bool esp_bt_gap_is_valid_cod(uint32_t cod) { @@ -909,6 +930,35 @@ esp_err_t esp_bt_gap_get_page_timeout(void); */ esp_err_t esp_bt_gap_set_acl_pkt_types(esp_bd_addr_t remote_bda, esp_bt_acl_pkt_type_t pkt_types); +/** + * @brief Set the minimal size of encryption key + * + * @return - ESP_OK: success + * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled + * - other: failed + */ +esp_err_t esp_bt_gap_set_min_enc_key_size(uint8_t key_size); + +/** + * @brief Set device name to the local device + * + * @param[in] name - device name. + * + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_bt_gap_set_device_name(const char *name); + +/** + * @brief Get device name of the local device + * + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_bt_gap_get_device_name(void); + #ifdef __cplusplus } #endif diff --git a/lib/bt/host/bluedroid/api/include/api/esp_gatt_defs.h b/lib/bt/host/bluedroid/api/include/api/esp_gatt_defs.h index f2d658a2..77f03e8b 100644 --- a/lib/bt/host/bluedroid/api/include/api/esp_gatt_defs.h +++ b/lib/bt/host/bluedroid/api/include/api/esp_gatt_defs.h @@ -1,337 +1,552 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __ESP_GATT_DEFS_H__ -#define __ESP_GATT_DEFS_H__ - +#pragma once #include "esp_bt_defs.h" #ifdef __cplusplus extern "C" { #endif -/// GATT INVALID UUID +/** @brief GATT INVALID UUID. */ #define ESP_GATT_ILLEGAL_UUID 0 -/// GATT INVALID HANDLE + +/** @brief GATT INVALID HANDLE. */ #define ESP_GATT_ILLEGAL_HANDLE 0 -/// GATT attribute max handle + +/** @brief GATT attribute max handle. */ #define ESP_GATT_ATTR_HANDLE_MAX UC_CONFIG_BT_GATT_MAX_SR_ATTRIBUTES -#define ESP_GATT_MAX_READ_MULTI_HANDLES 10 /* Max attributes to read in one request */ + +/** @brief Maximum number of attributes to read in one request. */ +#define ESP_GATT_MAX_READ_MULTI_HANDLES 10 -/**@{ - * All "ESP_GATT_UUID_xxx" is attribute types +/** + * @defgroup GATT_UUIDs GATT Service UUIDs + * @brief Definitions of GATT Service UUIDs. + * + * This module contains the definitions of standard GATT service UUIDs. These UUIDs + * identify the type of GATT service. + * @{ */ -#define ESP_GATT_UUID_IMMEDIATE_ALERT_SVC 0x1802 /* Immediate alert Service*/ -#define ESP_GATT_UUID_LINK_LOSS_SVC 0x1803 /* Link Loss Service*/ -#define ESP_GATT_UUID_TX_POWER_SVC 0x1804 /* TX Power Service*/ -#define ESP_GATT_UUID_CURRENT_TIME_SVC 0x1805 /* Current Time Service Service*/ -#define ESP_GATT_UUID_REF_TIME_UPDATE_SVC 0x1806 /* Reference Time Update Service*/ -#define ESP_GATT_UUID_NEXT_DST_CHANGE_SVC 0x1807 /* Next DST Change Service*/ -#define ESP_GATT_UUID_GLUCOSE_SVC 0x1808 /* Glucose Service*/ -#define ESP_GATT_UUID_HEALTH_THERMOM_SVC 0x1809 /* Health Thermometer Service*/ -#define ESP_GATT_UUID_DEVICE_INFO_SVC 0x180A /* Device Information Service*/ -#define ESP_GATT_UUID_HEART_RATE_SVC 0x180D /* Heart Rate Service*/ -#define ESP_GATT_UUID_PHONE_ALERT_STATUS_SVC 0x180E /* Phone Alert Status Service*/ -#define ESP_GATT_UUID_BATTERY_SERVICE_SVC 0x180F /* Battery Service*/ -#define ESP_GATT_UUID_BLOOD_PRESSURE_SVC 0x1810 /* Blood Pressure Service*/ -#define ESP_GATT_UUID_ALERT_NTF_SVC 0x1811 /* Alert Notification Service*/ -#define ESP_GATT_UUID_HID_SVC 0x1812 /* HID Service*/ -#define ESP_GATT_UUID_SCAN_PARAMETERS_SVC 0x1813 /* Scan Parameters Service*/ -#define ESP_GATT_UUID_RUNNING_SPEED_CADENCE_SVC 0x1814 /* Running Speed and Cadence Service*/ -#define ESP_GATT_UUID_Automation_IO_SVC 0x1815 /* Automation IO Service*/ -#define ESP_GATT_UUID_CYCLING_SPEED_CADENCE_SVC 0x1816 /* Cycling Speed and Cadence Service*/ -#define ESP_GATT_UUID_CYCLING_POWER_SVC 0x1818 /* Cycling Power Service*/ -#define ESP_GATT_UUID_LOCATION_AND_NAVIGATION_SVC 0x1819 /* Location and Navigation Service*/ -#define ESP_GATT_UUID_ENVIRONMENTAL_SENSING_SVC 0x181A /* Environmental Sensing Service*/ -#define ESP_GATT_UUID_BODY_COMPOSITION 0x181B /* Body Composition Service*/ -#define ESP_GATT_UUID_USER_DATA_SVC 0x181C /* User Data Service*/ -#define ESP_GATT_UUID_WEIGHT_SCALE_SVC 0x181D /* Weight Scale Service*/ -#define ESP_GATT_UUID_BOND_MANAGEMENT_SVC 0x181E /* Bond Management Service*/ -#define ESP_GATT_UUID_CONT_GLUCOSE_MONITOR_SVC 0x181F /* Continuous Glucose Monitoring Service*/ +/** @brief Immediate Alert Service UUID. */ +#define ESP_GATT_UUID_IMMEDIATE_ALERT_SVC 0x1802 +/** @brief Link Loss Service UUID. */ +#define ESP_GATT_UUID_LINK_LOSS_SVC 0x1803 +/** @brief TX Power Service UUID. */ +#define ESP_GATT_UUID_TX_POWER_SVC 0x1804 +/** @brief Current Time Service UUID. */ +#define ESP_GATT_UUID_CURRENT_TIME_SVC 0x1805 +/** @brief Reference Time Update Service UUID. */ +#define ESP_GATT_UUID_REF_TIME_UPDATE_SVC 0x1806 +/** @brief Next DST Change Service UUID. */ +#define ESP_GATT_UUID_NEXT_DST_CHANGE_SVC 0x1807 +/** @brief Glucose Service UUID. */ +#define ESP_GATT_UUID_GLUCOSE_SVC 0x1808 +/** @brief Health Thermometer Service UUID. */ +#define ESP_GATT_UUID_HEALTH_THERMOM_SVC 0x1809 +/** @brief Device Information Service UUID. */ +#define ESP_GATT_UUID_DEVICE_INFO_SVC 0x180A +/** @brief Heart Rate Service UUID. */ +#define ESP_GATT_UUID_HEART_RATE_SVC 0x180D +/** @brief Phone Alert Status Service UUID. */ +#define ESP_GATT_UUID_PHONE_ALERT_STATUS_SVC 0x180E +/** @brief Battery Service UUID. */ +#define ESP_GATT_UUID_BATTERY_SERVICE_SVC 0x180F +/** @brief Blood Pressure Service UUID. */ +#define ESP_GATT_UUID_BLOOD_PRESSURE_SVC 0x1810 +/** @brief Alert Notification Service UUID. */ +#define ESP_GATT_UUID_ALERT_NTF_SVC 0x1811 +/** @brief HID Service UUID. */ +#define ESP_GATT_UUID_HID_SVC 0x1812 +/** @brief Scan Parameters Service UUID. */ +#define ESP_GATT_UUID_SCAN_PARAMETERS_SVC 0x1813 +/** @brief Running Speed and Cadence Service UUID. */ +#define ESP_GATT_UUID_RUNNING_SPEED_CADENCE_SVC 0x1814 +/** @brief Automation IO Service UUID. */ +#define ESP_GATT_UUID_Automation_IO_SVC 0x1815 +/** @brief Cycling Speed and Cadence Service UUID. */ +#define ESP_GATT_UUID_CYCLING_SPEED_CADENCE_SVC 0x1816 +/** @brief Cycling Power Service UUID. */ +#define ESP_GATT_UUID_CYCLING_POWER_SVC 0x1818 +/** @brief Location and Navigation Service UUID. */ +#define ESP_GATT_UUID_LOCATION_AND_NAVIGATION_SVC 0x1819 +/** @brief Environmental Sensing Service UUID. */ +#define ESP_GATT_UUID_ENVIRONMENTAL_SENSING_SVC 0x181A +/** @brief Body Composition Service UUID. */ +#define ESP_GATT_UUID_BODY_COMPOSITION 0x181B +/** @brief User Data Service UUID. */ +#define ESP_GATT_UUID_USER_DATA_SVC 0x181C +/** @brief Weight Scale Service UUID. */ +#define ESP_GATT_UUID_WEIGHT_SCALE_SVC 0x181D +/** @brief Bond Management Service UUID. */ +#define ESP_GATT_UUID_BOND_MANAGEMENT_SVC 0x181E +/** @brief Continuous Glucose Monitoring Service UUID. */ +#define ESP_GATT_UUID_CONT_GLUCOSE_MONITOR_SVC 0x181F +/** @brief Primary Service UUID. */ #define ESP_GATT_UUID_PRI_SERVICE 0x2800 +/** @brief Secondary Service UUID. */ #define ESP_GATT_UUID_SEC_SERVICE 0x2801 +/** @brief Include Service UUID. */ #define ESP_GATT_UUID_INCLUDE_SERVICE 0x2802 -#define ESP_GATT_UUID_CHAR_DECLARE 0x2803 /* Characteristic Declaration*/ - -#define ESP_GATT_UUID_CHAR_EXT_PROP 0x2900 /* Characteristic Extended Properties */ -#define ESP_GATT_UUID_CHAR_DESCRIPTION 0x2901 /* Characteristic User Description*/ -#define ESP_GATT_UUID_CHAR_CLIENT_CONFIG 0x2902 /* Client Characteristic Configuration */ -#define ESP_GATT_UUID_CHAR_SRVR_CONFIG 0x2903 /* Server Characteristic Configuration */ -#define ESP_GATT_UUID_CHAR_PRESENT_FORMAT 0x2904 /* Characteristic Presentation Format*/ -#define ESP_GATT_UUID_CHAR_AGG_FORMAT 0x2905 /* Characteristic Aggregate Format*/ -#define ESP_GATT_UUID_CHAR_VALID_RANGE 0x2906 /* Characteristic Valid Range */ -#define ESP_GATT_UUID_EXT_RPT_REF_DESCR 0x2907 /* External Report Reference */ -#define ESP_GATT_UUID_RPT_REF_DESCR 0x2908 /* Report Reference */ -#define ESP_GATT_UUID_NUM_DIGITALS_DESCR 0x2909 /* Number of Digitals */ -#define ESP_GATT_UUID_VALUE_TRIGGER_DESCR 0x290A /* Value Trigger Setting */ -#define ESP_GATT_UUID_ENV_SENSING_CONFIG_DESCR 0x290B /* Environmental Sensing Configuration */ -#define ESP_GATT_UUID_ENV_SENSING_MEASUREMENT_DESCR 0x290C /* Environmental Sensing Measurement */ -#define ESP_GATT_UUID_ENV_SENSING_TRIGGER_DESCR 0x290D /* Environmental Sensing Trigger Setting */ -#define ESP_GATT_UUID_TIME_TRIGGER_DESCR 0x290E /* Time Trigger Setting */ +/** @brief Characteristic Declaration UUID. */ +#define ESP_GATT_UUID_CHAR_DECLARE 0x2803 +/** @brief Characteristic Extended Properties UUID. */ +#define ESP_GATT_UUID_CHAR_EXT_PROP 0x2900 +/** @brief Characteristic User Description UUID. */ +#define ESP_GATT_UUID_CHAR_DESCRIPTION 0x2901 +/** @brief Client Characteristic Configuration UUID. */ +#define ESP_GATT_UUID_CHAR_CLIENT_CONFIG 0x2902 +/** @brief Server Characteristic Configuration UUID. */ +#define ESP_GATT_UUID_CHAR_SRVR_CONFIG 0x2903 +/** @brief Characteristic Presentation Format UUID. */ +#define ESP_GATT_UUID_CHAR_PRESENT_FORMAT 0x2904 +/** @brief Characteristic Aggregate Format UUID. */ +#define ESP_GATT_UUID_CHAR_AGG_FORMAT 0x2905 +/** @brief Characteristic Valid Range UUID. */ +#define ESP_GATT_UUID_CHAR_VALID_RANGE 0x2906 +/** @brief External Report Reference Descriptor UUID. */ +#define ESP_GATT_UUID_EXT_RPT_REF_DESCR 0x2907 +/** @brief Report Reference Descriptor UUID. */ +#define ESP_GATT_UUID_RPT_REF_DESCR 0x2908 +/** @brief Number of Digitals Descriptor UUID. */ +#define ESP_GATT_UUID_NUM_DIGITALS_DESCR 0x2909 +/** @brief Value Trigger Setting Descriptor UUID. */ +#define ESP_GATT_UUID_VALUE_TRIGGER_DESCR 0x290A +/** @brief Environmental Sensing Configuration Descriptor UUID. */ +#define ESP_GATT_UUID_ENV_SENSING_CONFIG_DESCR 0x290B +/** @brief Environmental Sensing Measurement Descriptor UUID. */ +#define ESP_GATT_UUID_ENV_SENSING_MEASUREMENT_DESCR 0x290C +/** @brief Environmental Sensing Trigger Setting Descriptor UUID. */ +#define ESP_GATT_UUID_ENV_SENSING_TRIGGER_DESCR 0x290D +/** @brief Time Trigger Setting Descriptor UUID. */ +#define ESP_GATT_UUID_TIME_TRIGGER_DESCR 0x290E /* GAP Profile Attributes */ +/** @brief GAP Device Name UUID. */ #define ESP_GATT_UUID_GAP_DEVICE_NAME 0x2A00 +/** @brief GAP Icon UUID. */ #define ESP_GATT_UUID_GAP_ICON 0x2A01 +/** @brief GAP Preferred Connection Parameters UUID. */ #define ESP_GATT_UUID_GAP_PREF_CONN_PARAM 0x2A04 +/** @brief GAP Central Address Resolution UUID. */ #define ESP_GATT_UUID_GAP_CENTRAL_ADDR_RESOL 0x2AA6 /* Attribute Profile Attribute UUID */ +/** @brief GATT Service Changed UUID. */ #define ESP_GATT_UUID_GATT_SRV_CHGD 0x2A05 -/* Link ESP_Loss Service */ -#define ESP_GATT_UUID_ALERT_LEVEL 0x2A06 /* Alert Level */ -#define ESP_GATT_UUID_TX_POWER_LEVEL 0x2A07 /* TX power level */ +/* Link Loss Service */ +/** @brief Alert Level UUID. */ +#define ESP_GATT_UUID_ALERT_LEVEL 0x2A06 +/** @brief TX Power Level UUID. */ +#define ESP_GATT_UUID_TX_POWER_LEVEL 0x2A07 /* Current Time Service */ -#define ESP_GATT_UUID_CURRENT_TIME 0x2A2B /* Current Time */ -#define ESP_GATT_UUID_LOCAL_TIME_INFO 0x2A0F /* Local time info */ -#define ESP_GATT_UUID_REF_TIME_INFO 0x2A14 /* reference time information */ - -/* Network availability Profile */ -#define ESP_GATT_UUID_NW_STATUS 0x2A18 /* network availability status */ -#define ESP_GATT_UUID_NW_TRIGGER 0x2A1A /* Network availability trigger */ - -/* Phone alert */ -#define ESP_GATT_UUID_ALERT_STATUS 0x2A3F /* alert status */ -#define ESP_GATT_UUID_RINGER_CP 0x2A40 /* ringer control point */ -#define ESP_GATT_UUID_RINGER_SETTING 0x2A41 /* ringer setting */ +/** @brief Current Time UUID. */ +#define ESP_GATT_UUID_CURRENT_TIME 0x2A2B +/** @brief Local Time Info UUID. */ +#define ESP_GATT_UUID_LOCAL_TIME_INFO 0x2A0F +/** @brief Reference Time Information UUID. */ +#define ESP_GATT_UUID_REF_TIME_INFO 0x2A14 + +/* Network Availability Service */ +/** @brief Network Availability Status UUID. */ +#define ESP_GATT_UUID_NW_STATUS 0x2A18 +/** @brief Network Availability Trigger UUID. */ +#define ESP_GATT_UUID_NW_TRIGGER 0x2A1A + +/* Phone Alert Status Service */ +/** @brief Alert Status UUID. */ +#define ESP_GATT_UUID_ALERT_STATUS 0x2A3F +/** @brief Ringer Control Point UUID. */ +#define ESP_GATT_UUID_RINGER_CP 0x2A40 +/** @brief Ringer Setting UUID. */ +#define ESP_GATT_UUID_RINGER_SETTING 0x2A41 /* Glucose Service */ +/** @brief Glucose Measurement Characteristic UUID. */ #define ESP_GATT_UUID_GM_MEASUREMENT 0x2A18 +/** @brief Glucose Measurement Context Characteristic UUID. */ #define ESP_GATT_UUID_GM_CONTEXT 0x2A34 +/** @brief Glucose Control Point Characteristic UUID. */ #define ESP_GATT_UUID_GM_CONTROL_POINT 0x2A52 +/** @brief Glucose Feature Characteristic UUID. */ #define ESP_GATT_UUID_GM_FEATURE 0x2A51 -/* device information characteristic */ +/* Device Information Service Characteristics */ +/** @brief System ID Characteristic UUID. */ #define ESP_GATT_UUID_SYSTEM_ID 0x2A23 +/** @brief Model Number String Characteristic UUID. */ #define ESP_GATT_UUID_MODEL_NUMBER_STR 0x2A24 +/** @brief Serial Number String Characteristic UUID. */ #define ESP_GATT_UUID_SERIAL_NUMBER_STR 0x2A25 +/** @brief Firmware Revision String Characteristic UUID. */ #define ESP_GATT_UUID_FW_VERSION_STR 0x2A26 +/** @brief Hardware Revision String Characteristic UUID. */ #define ESP_GATT_UUID_HW_VERSION_STR 0x2A27 +/** @brief Software Revision String Characteristic UUID. */ #define ESP_GATT_UUID_SW_VERSION_STR 0x2A28 +/** @brief Manufacturer Name String Characteristic UUID. */ #define ESP_GATT_UUID_MANU_NAME 0x2A29 +/** @brief IEEE 11073-20601 Regulatory Certification Data List Characteristic UUID. */ #define ESP_GATT_UUID_IEEE_DATA 0x2A2A +/** @brief PnP ID Characteristic UUID. */ #define ESP_GATT_UUID_PNP_ID 0x2A50 -/* HID characteristics */ +/* HID Service Characteristics */ +/** @brief HID Information Characteristic UUID. */ #define ESP_GATT_UUID_HID_INFORMATION 0x2A4A +/** @brief HID Report Map Characteristic UUID. */ #define ESP_GATT_UUID_HID_REPORT_MAP 0x2A4B +/** @brief HID Control Point Characteristic UUID. */ #define ESP_GATT_UUID_HID_CONTROL_POINT 0x2A4C +/** @brief HID Report Characteristic UUID. */ #define ESP_GATT_UUID_HID_REPORT 0x2A4D +/** @brief HID Protocol Mode Characteristic UUID. */ #define ESP_GATT_UUID_HID_PROTO_MODE 0x2A4E +/** @brief HID Bluetooth Keyboard Input Characteristic UUID. */ #define ESP_GATT_UUID_HID_BT_KB_INPUT 0x2A22 +/** @brief HID Bluetooth Keyboard Output Characteristic UUID. */ #define ESP_GATT_UUID_HID_BT_KB_OUTPUT 0x2A32 +/** @brief HID Bluetooth Mouse Input Characteristic UUID. */ #define ESP_GATT_UUID_HID_BT_MOUSE_INPUT 0x2A33 - /// Heart Rate Measurement -#define ESP_GATT_HEART_RATE_MEAS 0x2A37 -/// Body Sensor Location -#define ESP_GATT_BODY_SENSOR_LOCATION 0x2A38 -/// Heart Rate Control Point -#define ESP_GATT_HEART_RATE_CNTL_POINT 0x2A39 +/* Heart Rate Service Characteristics */ +/** @brief Heart Rate Measurement Characteristic UUID. */ +#define ESP_GATT_HEART_RATE_MEAS 0x2A37 +/** @brief Body Sensor Location Characteristic UUID. */ +#define ESP_GATT_BODY_SENSOR_LOCATION 0x2A38 +/** @brief Heart Rate Control Point Characteristic UUID. */ +#define ESP_GATT_HEART_RATE_CNTL_POINT 0x2A39 -/* Battery Service characteristics */ +/* Battery Service Characteristics */ +/** @brief Battery Level Characteristic UUID. */ #define ESP_GATT_UUID_BATTERY_LEVEL 0x2A19 -/* Sensor Service */ +/* Sensor Service Characteristics */ +/** @brief Sensor Control Point Characteristic UUID. */ #define ESP_GATT_UUID_SC_CONTROL_POINT 0x2A55 +/** @brief Sensor Location Characteristic UUID. */ #define ESP_GATT_UUID_SENSOR_LOCATION 0x2A5D -/* Runners speed and cadence service */ +/* Running Speed and Cadence Service Characteristics */ +/** @brief RSC Measurement Characteristic UUID. */ #define ESP_GATT_UUID_RSC_MEASUREMENT 0x2A53 +/** @brief RSC Feature Characteristic UUID. */ #define ESP_GATT_UUID_RSC_FEATURE 0x2A54 -/* Cycling speed and cadence service */ +/* Cycling Speed and Cadence Service Characteristics */ +/** @brief CSC Measurement Characteristic UUID. */ #define ESP_GATT_UUID_CSC_MEASUREMENT 0x2A5B +/** @brief CSC Feature Characteristic UUID. */ #define ESP_GATT_UUID_CSC_FEATURE 0x2A5C -/* Scan ESP_Parameter characteristics */ +/* Scan Parameters Service Characteristics */ +/** @brief Scan Interval Window Characteristic UUID. */ #define ESP_GATT_UUID_SCAN_INT_WINDOW 0x2A4F +/** @brief Scan Refresh UUID. */ #define ESP_GATT_UUID_SCAN_REFRESH 0x2A31 +/* Additional GATT Services not covered yet */ +/** @} */ // End of group GATT_UUIDs + + /** - * @} + * @brief Defines the attribute write operation types from the client. + * + * These values are used to specify the type of write operation in a prepare write sequence. + * relate to BTA_GATT_PREP_WRITE_xxx in bta/bta_gatt_api.h. */ - -/* relate to BTA_GATT_PREP_WRITE_xxx in bta/bta_gatt_api.h */ -/// Attribute write data type from the client typedef enum { - ESP_GATT_PREP_WRITE_CANCEL = 0x00, /*!< Prepare write cancel */ /* relate to BTA_GATT_PREP_WRITE_CANCEL in bta/bta_gatt_api.h */ - ESP_GATT_PREP_WRITE_EXEC = 0x01, /*!< Prepare write execute */ /* relate to BTA_GATT_PREP_WRITE_EXEC in bta/bta_gatt_api.h */ + ESP_GATT_PREP_WRITE_CANCEL = 0x00, /*!< Prepare write cancel. Corresponds to BTA_GATT_PREP_WRITE_CANCEL. */ + ESP_GATT_PREP_WRITE_EXEC = 0x01, /*!< Prepare write execute. Corresponds to BTA_GATT_PREP_WRITE_EXEC. */ } esp_gatt_prep_write_type; -/* relate to BTA_GATT_xxx in bta/bta_gatt_api.h */ + /** - * @brief GATT success code and error codes + * @brief GATT operation status codes. + * + * These status codes are used to indicate the result of various GATT operations. + * relate to BTA_GATT_xxx in bta/bta_gatt_api.h . */ typedef enum { - ESP_GATT_OK = 0x0, /* relate to BTA_GATT_OK in bta/bta_gatt_api.h */ - ESP_GATT_INVALID_HANDLE = 0x01, /* 0x0001 */ /* relate to BTA_GATT_INVALID_HANDLE in bta/bta_gatt_api.h */ - ESP_GATT_READ_NOT_PERMIT = 0x02, /* 0x0002 */ /* relate to BTA_GATT_READ_NOT_PERMIT in bta/bta_gatt_api.h */ - ESP_GATT_WRITE_NOT_PERMIT = 0x03, /* 0x0003 */ /* relate to BTA_GATT_WRITE_NOT_PERMIT in bta/bta_gatt_api.h */ - ESP_GATT_INVALID_PDU = 0x04, /* 0x0004 */ /* relate to BTA_GATT_INVALID_PDU in bta/bta_gatt_api.h */ - ESP_GATT_INSUF_AUTHENTICATION = 0x05, /* 0x0005 */ /* relate to BTA_GATT_INSUF_AUTHENTICATION in bta/bta_gatt_api.h */ - ESP_GATT_REQ_NOT_SUPPORTED = 0x06, /* 0x0006 */ /* relate to BTA_GATT_REQ_NOT_SUPPORTED in bta/bta_gatt_api.h */ - ESP_GATT_INVALID_OFFSET = 0x07, /* 0x0007 */ /* relate to BTA_GATT_INVALID_OFFSET in bta/bta_gatt_api.h */ - ESP_GATT_INSUF_AUTHORIZATION = 0x08, /* 0x0008 */ /* relate to BTA_GATT_INSUF_AUTHORIZATION in bta/bta_gatt_api.h */ - ESP_GATT_PREPARE_Q_FULL = 0x09, /* 0x0009 */ /* relate to BTA_GATT_PREPARE_Q_FULL in bta/bta_gatt_api.h */ - ESP_GATT_NOT_FOUND = 0x0a, /* 0x000a */ /* relate to BTA_GATT_NOT_FOUND in bta/bta_gatt_api.h */ - ESP_GATT_NOT_LONG = 0x0b, /* 0x000b */ /* relate to BTA_GATT_NOT_LONG in bta/bta_gatt_api.h */ - ESP_GATT_INSUF_KEY_SIZE = 0x0c, /* 0x000c */ /* relate to BTA_GATT_INSUF_KEY_SIZE in bta/bta_gatt_api.h */ - ESP_GATT_INVALID_ATTR_LEN = 0x0d, /* 0x000d */ /* relate to BTA_GATT_INVALID_ATTR_LEN in bta/bta_gatt_api.h */ - ESP_GATT_ERR_UNLIKELY = 0x0e, /* 0x000e */ /* relate to BTA_GATT_ERR_UNLIKELY in bta/bta_gatt_api.h */ - ESP_GATT_INSUF_ENCRYPTION = 0x0f, /* 0x000f */ /* relate to BTA_GATT_INSUF_ENCRYPTION in bta/bta_gatt_api.h */ - ESP_GATT_UNSUPPORT_GRP_TYPE = 0x10, /* 0x0010 */ /* relate to BTA_GATT_UNSUPPORT_GRP_TYPE in bta/bta_gatt_api.h */ - ESP_GATT_INSUF_RESOURCE = 0x11, /* 0x0011 */ /* relate to BTA_GATT_INSUF_RESOURCE in bta/bta_gatt_api.h */ - - ESP_GATT_NO_RESOURCES = 0x80, /* 0x80 */ /* relate to BTA_GATT_NO_RESOURCES in bta/bta_gatt_api.h */ - ESP_GATT_INTERNAL_ERROR = 0x81, /* 0x81 */ /* relate to BTA_GATT_INTERNAL_ERROR in bta/bta_gatt_api.h */ - ESP_GATT_WRONG_STATE = 0x82, /* 0x82 */ /* relate to BTA_GATT_WRONG_STATE in bta/bta_gatt_api.h */ - ESP_GATT_DB_FULL = 0x83, /* 0x83 */ /* relate to BTA_GATT_DB_FULL in bta/bta_gatt_api.h */ - ESP_GATT_BUSY = 0x84, /* 0x84 */ /* relate to BTA_GATT_BUSY in bta/bta_gatt_api.h */ - ESP_GATT_ERROR = 0x85, /* 0x85 */ /* relate to BTA_GATT_ERROR in bta/bta_gatt_api.h */ - ESP_GATT_CMD_STARTED = 0x86, /* 0x86 */ /* relate to BTA_GATT_CMD_STARTED in bta/bta_gatt_api.h */ - ESP_GATT_ILLEGAL_PARAMETER = 0x87, /* 0x87 */ /* relate to BTA_GATT_ILLEGAL_PARAMETER in bta/bta_gatt_api.h */ - ESP_GATT_PENDING = 0x88, /* 0x88 */ /* relate to BTA_GATT_PENDING in bta/bta_gatt_api.h */ - ESP_GATT_AUTH_FAIL = 0x89, /* 0x89 */ /* relate to BTA_GATT_AUTH_FAIL in bta/bta_gatt_api.h */ - ESP_GATT_MORE = 0x8a, /* 0x8a */ /* relate to BTA_GATT_MORE in bta/bta_gatt_api.h */ - ESP_GATT_INVALID_CFG = 0x8b, /* 0x8b */ /* relate to BTA_GATT_INVALID_CFG in bta/bta_gatt_api.h */ - ESP_GATT_SERVICE_STARTED = 0x8c, /* 0x8c */ /* relate to BTA_GATT_SERVICE_STARTED in bta/bta_gatt_api.h */ - ESP_GATT_ENCRYPTED_MITM = ESP_GATT_OK, /* relate to BTA_GATT_ENCRYPED_MITM in bta/bta_gatt_api.h */ - ESP_GATT_ENCRYPTED_NO_MITM = 0x8d, /* 0x8d */ /* relate to BTA_GATT_ENCRYPED_NO_MITM in bta/bta_gatt_api.h */ - ESP_GATT_NOT_ENCRYPTED = 0x8e, /* 0x8e */ /* relate to BTA_GATT_NOT_ENCRYPTED in bta/bta_gatt_api.h */ - ESP_GATT_CONGESTED = 0x8f, /* 0x8f */ /* relate to BTA_GATT_CONGESTED in bta/bta_gatt_api.h */ - ESP_GATT_DUP_REG = 0x90, /* 0x90 */ /* relate to BTA_GATT_DUP_REG in bta/bta_gatt_api.h */ - ESP_GATT_ALREADY_OPEN = 0x91, /* 0x91 */ /* relate to BTA_GATT_ALREADY_OPEN in bta/bta_gatt_api.h */ - ESP_GATT_CANCEL = 0x92, /* 0x92 */ /* relate to BTA_GATT_CANCEL in bta/bta_gatt_api.h */ + ESP_GATT_OK = 0x0, /*!< 0x0, Operation successful. Corresponds to BTA_GATT_OK. */ + ESP_GATT_INVALID_HANDLE = 0x01, /*!< 0x01, Invalid handle. Corresponds to BTA_GATT_INVALID_HANDLE. */ + ESP_GATT_READ_NOT_PERMIT = 0x02, /*!< 0x02, Read operation not permitted. Corresponds to BTA_GATT_READ_NOT_PERMIT. */ + ESP_GATT_WRITE_NOT_PERMIT = 0x03, /*!< 0x03, Write operation not permitted. Corresponds to BTA_GATT_WRITE_NOT_PERMIT. */ + ESP_GATT_INVALID_PDU = 0x04, /*!< 0x04, Invalid PDU. Corresponds to BTA_GATT_INVALID_PDU. */ + ESP_GATT_INSUF_AUTHENTICATION = 0x05, /*!< 0x05, Insufficient authentication. Corresponds to BTA_GATT_INSUF_AUTHENTICATION. */ + ESP_GATT_REQ_NOT_SUPPORTED = 0x06, /*!< 0x06, Request not supported. Corresponds to BTA_GATT_REQ_NOT_SUPPORTED. */ + ESP_GATT_INVALID_OFFSET = 0x07, /*!< 0x07, Invalid offset. Corresponds to BTA_GATT_INVALID_OFFSET. */ + ESP_GATT_INSUF_AUTHORIZATION = 0x08, /*!< 0x08, Insufficient authorization. Corresponds to BTA_GATT_INSUF_AUTHORIZATION. */ + ESP_GATT_PREPARE_Q_FULL = 0x09, /*!< 0x09, Prepare queue full. Corresponds to BTA_GATT_PREPARE_Q_FULL. */ + ESP_GATT_NOT_FOUND = 0x0a, /*!< 0x0a, Not found. Corresponds to BTA_GATT_NOT_FOUND. */ + ESP_GATT_NOT_LONG = 0x0b, /*!< 0x0b, Not long. Corresponds to BTA_GATT_NOT_LONG. */ + ESP_GATT_INSUF_KEY_SIZE = 0x0c, /*!< 0x0c, Insufficient key size. Corresponds to BTA_GATT_INSUF_KEY_SIZE. */ + ESP_GATT_INVALID_ATTR_LEN = 0x0d, /*!< 0x0d, Invalid attribute length. Corresponds to BTA_GATT_INVALID_ATTR_LEN. */ + ESP_GATT_ERR_UNLIKELY = 0x0e, /*!< 0x0e, Unlikely error. Corresponds to BTA_GATT_ERR_UNLIKELY. */ + ESP_GATT_INSUF_ENCRYPTION = 0x0f, /*!< 0x0f, Insufficient encryption. Corresponds to BTA_GATT_INSUF_ENCRYPTION. */ + ESP_GATT_UNSUPPORT_GRP_TYPE = 0x10, /*!< 0x10, Unsupported group type. Corresponds to BTA_GATT_UNSUPPORT_GRP_TYPE. */ + ESP_GATT_INSUF_RESOURCE = 0x11, /*!< 0x11, Insufficient resource. Corresponds to BTA_GATT_INSUF_RESOURCE. */ + + /* Additional error codes specific to implementation or future use */ + ESP_GATT_NO_RESOURCES = 0x80, /*!< 0x80, No resources. Corresponds to BTA_GATT_NO_RESOURCES. */ + ESP_GATT_INTERNAL_ERROR = 0x81, /*!< 0x81, Internal error. Corresponds to BTA_GATT_INTERNAL_ERROR. */ + ESP_GATT_WRONG_STATE = 0x82, /*!< 0x82, Wrong state. Corresponds to BTA_GATT_WRONG_STATE. */ + ESP_GATT_DB_FULL = 0x83, /*!< 0x83, Database full. Corresponds to BTA_GATT_DB_FULL. */ + ESP_GATT_BUSY = 0x84, /*!< 0x84, Busy. Corresponds to BTA_GATT_BUSY. */ + ESP_GATT_ERROR = 0x85, /*!< 0x85, Generic error. Corresponds to BTA_GATT_ERROR. */ + ESP_GATT_CMD_STARTED = 0x86, /*!< 0x86, Command started. Corresponds to BTA_GATT_CMD_STARTED. */ + ESP_GATT_ILLEGAL_PARAMETER = 0x87, /*!< 0x87, Illegal parameter. Corresponds to BTA_GATT_ILLEGAL_PARAMETER. */ + ESP_GATT_PENDING = 0x88, /*!< 0x88, Operation pending. Corresponds to BTA_GATT_PENDING. */ + ESP_GATT_AUTH_FAIL = 0x89, /*!< 0x89, Authentication failed. Corresponds to BTA_GATT_AUTH_FAIL. */ + ESP_GATT_MORE = 0x8a, /*!< 0x8a, More data available. Corresponds to BTA_GATT_MORE. */ + ESP_GATT_INVALID_CFG = 0x8b, /*!< 0x8b, Invalid configuration. Corresponds to BTA_GATT_INVALID_CFG. */ + ESP_GATT_SERVICE_STARTED = 0x8c, /*!< 0x8c, Service started. Corresponds to BTA_GATT_SERVICE_STARTED. */ + ESP_GATT_ENCRYPTED_MITM = ESP_GATT_OK, /*!< 0x0, Encrypted, with MITM protection. Corresponds to BTA_GATT_ENCRYPTED_MITM. */ + ESP_GATT_ENCRYPTED_NO_MITM = 0x8d, /*!< 0x8d, Encrypted, without MITM protection. Corresponds to BTA_GATT_ENCRYPTED_NO_MITM. */ + ESP_GATT_NOT_ENCRYPTED = 0x8e, /*!< 0x8e, Not encrypted. Corresponds to BTA_GATT_NOT_ENCRYPTED. */ + ESP_GATT_CONGESTED = 0x8f, /*!< 0x8f, Congested. Corresponds to BTA_GATT_CONGESTED. */ + ESP_GATT_DUP_REG = 0x90, /*!< 0x90, Duplicate registration. Corresponds to BTA_GATT_DUP_REG. */ + ESP_GATT_ALREADY_OPEN = 0x91, /*!< 0x91, Already open. Corresponds to BTA_GATT_ALREADY_OPEN. */ + ESP_GATT_CANCEL = 0x92, /*!< 0x92, Operation cancelled. Corresponds to BTA_GATT_CANCEL. */ /* 0xE0 ~ 0xFC reserved for future use */ - ESP_GATT_STACK_RSP = 0xe0, /* 0xe0 */ /* relate to BTA_GATT_STACK_RSP in bta/bta_gatt_api.h */ - ESP_GATT_APP_RSP = 0xe1, /* 0xe1 */ /* relate to BTA_GATT_APP_RSP in bta/bta_gatt_api.h */ - //Error caused by customer application or stack bug - ESP_GATT_UNKNOWN_ERROR = 0xef, /* 0xef */ /* relate to BTA_GATT_UNKNOWN_ERROR in bta/bta_gatt_api.h */ - ESP_GATT_CCC_CFG_ERR = 0xfd, /* 0xFD Client Characteristic Configuration Descriptor Improperly Configured */ /* relate to BTA_GATT_CCC_CFG_ERR in bta/bta_gatt_api.h */ - ESP_GATT_PRC_IN_PROGRESS = 0xfe, /* 0xFE Procedure Already in progress */ /* relate to BTA_GATT_PRC_IN_PROGRESS in bta/bta_gatt_api.h */ - ESP_GATT_OUT_OF_RANGE = 0xff, /* 0xFF Attribute value out of range */ /* relate to BTA_GATT_OUT_OF_RANGE in bta/bta_gatt_api.h */ + ESP_GATT_STACK_RSP = 0xe0, /*!< 0xe0, Stack response. Corresponds to BTA_GATT_STACK_RSP. */ + ESP_GATT_APP_RSP = 0xe1, /*!< 0xe1, Application response. Corresponds to BTA_GATT_APP_RSP. */ + /* Error caused by customer application or stack bug */ + ESP_GATT_UNKNOWN_ERROR = 0xef, /*!< 0xef, Unknown error. Corresponds to BTA_GATT_UNKNOWN_ERROR. */ + ESP_GATT_CCC_CFG_ERR = 0xfd, /*!< 0xfd, Client Characteristic Configuration Descriptor improperly configured. Corresponds to BTA_GATT_CCC_CFG_ERR. */ + ESP_GATT_PRC_IN_PROGRESS = 0xfe, /*!< 0xfe, Procedure already in progress. Corresponds to BTA_GATT_PRC_IN_PROGRESS. */ + ESP_GATT_OUT_OF_RANGE = 0xff /*!< 0xff, Attribute value out of range. Corresponds to BTA_GATT_OUT_OF_RANGE. */ } esp_gatt_status_t; -/* relate to BTA_GATT_CONN_xxx in bta/bta_gatt_api.h */ + /** - * @brief Gatt Connection reason enum + * @brief Enumerates reasons for GATT connection. */ typedef enum { - ESP_GATT_CONN_UNKNOWN = 0, /*!< Gatt connection unknown */ /* relate to BTA_GATT_CONN_UNKNOWN in bta/bta_gatt_api.h */ - ESP_GATT_CONN_L2C_FAILURE = 1, /*!< General L2cap failure */ /* relate to BTA_GATT_CONN_L2C_FAILURE in bta/bta_gatt_api.h */ - ESP_GATT_CONN_TIMEOUT = 0x08, /*!< Connection timeout */ /* relate to BTA_GATT_CONN_TIMEOUT in bta/bta_gatt_api.h */ - ESP_GATT_CONN_TERMINATE_PEER_USER = 0x13, /*!< Connection terminate by peer user */ /* relate to BTA_GATT_CONN_TERMINATE_PEER_USER in bta/bta_gatt_api.h */ - ESP_GATT_CONN_TERMINATE_LOCAL_HOST = 0x16, /*!< Connection terminated by local host */ /* relate to BTA_GATT_CONN_TERMINATE_LOCAL_HOST in bta/bta_gatt_api.h */ - ESP_GATT_CONN_FAIL_ESTABLISH = 0x3e, /*!< Connection fail to establish */ /* relate to BTA_GATT_CONN_FAIL_ESTABLISH in bta/bta_gatt_api.h */ - ESP_GATT_CONN_LMP_TIMEOUT = 0x22, /*!< Connection fail for LMP response tout */ /* relate to BTA_GATT_CONN_LMP_TIMEOUT in bta/bta_gatt_api.h */ - ESP_GATT_CONN_CONN_CANCEL = 0x0100, /*!< L2CAP connection cancelled */ /* relate to BTA_GATT_CONN_CONN_CANCEL in bta/bta_gatt_api.h */ - ESP_GATT_CONN_NONE = 0x0101 /*!< No connection to cancel */ /* relate to BTA_GATT_CONN_NONE in bta/bta_gatt_api.h */ + ESP_GATT_CONN_UNKNOWN = 0, /*!< Unknown connection reason. Corresponds to BTA_GATT_CONN_UNKNOWN in bta/bta_gatt_api.h */ + ESP_GATT_CONN_L2C_FAILURE = 1, /*!< General L2CAP failure. Corresponds to BTA_GATT_CONN_L2C_FAILURE in bta/bta_gatt_api.h */ + ESP_GATT_CONN_TIMEOUT = 0x08, /*!< Connection timeout. Corresponds to BTA_GATT_CONN_TIMEOUT in bta/bta_gatt_api.h */ + ESP_GATT_CONN_TERMINATE_PEER_USER = 0x13, /*!< Connection terminated by peer user. Corresponds to BTA_GATT_CONN_TERMINATE_PEER_USER in bta/bta_gatt_api.h */ + ESP_GATT_CONN_TERMINATE_LOCAL_HOST = 0x16, /*!< Connection terminated by local host. Corresponds to BTA_GATT_CONN_TERMINATE_LOCAL_HOST in bta/bta_gatt_api.h */ + ESP_GATT_CONN_FAIL_ESTABLISH = 0x3e, /*!< Failure to establish connection. Corresponds to BTA_GATT_CONN_FAIL_ESTABLISH in bta/bta_gatt_api.h */ + ESP_GATT_CONN_LMP_TIMEOUT = 0x22, /*!< Connection failed due to LMP response timeout. Corresponds to BTA_GATT_CONN_LMP_TIMEOUT in bta/bta_gatt_api.h */ + ESP_GATT_CONN_CONN_CANCEL = 0x0100, /*!< L2CAP connection cancelled. Corresponds to BTA_GATT_CONN_CONN_CANCEL in bta/bta_gatt_api.h */ + ESP_GATT_CONN_NONE = 0x0101 /*!< No connection to cancel. Corresponds to BTA_GATT_CONN_NONE in bta/bta_gatt_api.h */ } esp_gatt_conn_reason_t; + /** - * @brief Gatt id, include uuid and instance id + * @brief Represents a GATT identifier. */ typedef struct { - esp_bt_uuid_t uuid; /*!< UUID */ - uint8_t inst_id; /*!< Instance id */ + esp_bt_uuid_t uuid; /*!< @brief The UUID component of the GATT ID. */ + uint8_t inst_id; /*!< @brief The instance ID component of the GATT ID, providing further differentiation of the GATT ID. */ } __attribute__((packed)) esp_gatt_id_t; + /** - * @brief Gatt service id, include id - * (uuid and instance id) and primary flag + * @brief Represents a GATT service identifier. */ typedef struct { - esp_gatt_id_t id; /*!< Gatt id, include uuid and instance */ - bool is_primary; /*!< This service is primary or not */ + esp_gatt_id_t id; /*!< @brief Encapsulates the UUID and instance ID of the GATT service. */ + bool is_primary; /*!< @brief Indicates if the service is primary. A value of true means it is a primary service, false indicates a secondary service. */ } __attribute__((packed)) esp_gatt_srvc_id_t; -/* relate to BTA_GATT_AUTH_REQ_xxx in bta/bta_gatt_api.h */ /** - * @brief Gatt authentication request type + * @brief Defines the GATT authentication request types. + * + * This enumeration lists the types of authentication requests that can be made. + * It corresponds to the `BTA_GATT_AUTH_REQ_xxx` values defined in `bta/bta_gatt_api.h`. + * The types include options for no authentication, unauthenticated encryption, authenticated encryption, + * and both signed versions with and without MITM (Man-In-The-Middle) protection. */ typedef enum { - ESP_GATT_AUTH_REQ_NONE = 0, /* relate to BTA_GATT_AUTH_REQ_NONE in bta/bta_gatt_api.h */ - ESP_GATT_AUTH_REQ_NO_MITM = 1, /* unauthenticated encryption */ /* relate to BTA_GATT_AUTH_REQ_NO_MITM in bta/bta_gatt_api.h */ - ESP_GATT_AUTH_REQ_MITM = 2, /* authenticated encryption */ /* relate to BTA_GATT_AUTH_REQ_MITM in bta/bta_gatt_api.h */ - ESP_GATT_AUTH_REQ_SIGNED_NO_MITM = 3, /* relate to BTA_GATT_AUTH_REQ_SIGNED_NO_MITM in bta/bta_gatt_api.h */ - ESP_GATT_AUTH_REQ_SIGNED_MITM = 4, /* relate to BTA_GATT_AUTH_REQ_SIGNED_MITM in bta/bta_gatt_api.h */ + ESP_GATT_AUTH_REQ_NONE = 0, /*!< No authentication required. Corresponds to BTA_GATT_AUTH_REQ_NONE. */ + ESP_GATT_AUTH_REQ_NO_MITM = 1, /*!< Unauthenticated encryption. Corresponds to BTA_GATT_AUTH_REQ_NO_MITM. */ + ESP_GATT_AUTH_REQ_MITM = 2, /*!< Authenticated encryption (MITM protection). Corresponds to BTA_GATT_AUTH_REQ_MITM. */ + ESP_GATT_AUTH_REQ_SIGNED_NO_MITM = 3, /*!< Signed data, no MITM protection. Corresponds to BTA_GATT_AUTH_REQ_SIGNED_NO_MITM. */ + ESP_GATT_AUTH_REQ_SIGNED_MITM = 4, /*!< Signed data with MITM protection. Corresponds to BTA_GATT_AUTH_REQ_SIGNED_MITM. */ } esp_gatt_auth_req_t; -/* relate to BTA_GATT_PERM_xxx in bta/bta_gatt_api.h */ + +/** + * @brief Defines GATT attribute permission flags. + * + * These permission flags are used to specify the security requirements for GATT attributes. + * They correlate directly with the BTA_GATT_PERM_xxx definitions found in bta/bta_gatt_api.h. + */ + +/** @defgroup GATT_PERMS GATT Attribute Permissions + * @brief Definitions of permission flags for GATT attributes. + * @{ + */ + +/** @brief Permission to read the attribute. Corresponds to BTA_GATT_PERM_READ. */ +#define ESP_GATT_PERM_READ (1 << 0) + +/** @brief Permission to read the attribute with encryption. Corresponds to BTA_GATT_PERM_READ_ENCRYPTED. */ +#define ESP_GATT_PERM_READ_ENCRYPTED (1 << 1) + +/** @brief Permission to read the attribute with encrypted MITM (Man In The Middle) protection. Corresponds to BTA_GATT_PERM_READ_ENC_MITM.*/ +#define ESP_GATT_PERM_READ_ENC_MITM (1 << 2) + +/** @brief Permission to write to the attribute. Corresponds to BTA_GATT_PERM_WRITE. */ +#define ESP_GATT_PERM_WRITE (1 << 4) + +/** @brief Permission to write to the attribute with encryption. Corresponds to BTA_GATT_PERM_WRITE_ENCRYPTED. */ +#define ESP_GATT_PERM_WRITE_ENCRYPTED (1 << 5) + +/** @brief Permission to write to the attribute with encrypted MITM protection. Corresponds to BTA_GATT_PERM_WRITE_ENC_MITM. */ +#define ESP_GATT_PERM_WRITE_ENC_MITM (1 << 6) + +/** @brief Permission for signed writes to the attribute. Corresponds to BTA_GATT_PERM_WRITE_SIGNED. */ +#define ESP_GATT_PERM_WRITE_SIGNED (1 << 7) + +/** @brief Permission for signed writes to the attribute with MITM protection. Corresponds to BTA_GATT_PERM_WRITE_SIGNED_MITM. */ +#define ESP_GATT_PERM_WRITE_SIGNED_MITM (1 << 8) + +/** @brief Permission to read the attribute with authorization. */ +#define ESP_GATT_PERM_READ_AUTHORIZATION (1 << 9) + +/** @brief Permission to write to the attribute with authorization. */ +#define ESP_GATT_PERM_WRITE_AUTHORIZATION (1 << 10) + +/** + * @brief Macro to specify minimum encryption key size. + * + * @param keysize The minimum size of the encryption key, in bytes. + */ +#define ESP_GATT_PERM_ENCRYPT_KEY_SIZE(keysize) (((keysize - 6) & 0xF) << 12) + +/** @} */ // End of GATT_PERMS group + +typedef uint16_t esp_gatt_perm_t; ///< Type to represent GATT attribute permissions. + + + +/** + * @brief Defines GATT characteristic properties. + * + * These properties are related to `BTA_GATT_CHAR_PROP_BIT_xxx` in `bta/bta_gatt_api.h`. + */ + +/** @defgroup GATT_CHAR_PROPERTIES GATT Characteristic Properties + * These properties define various capabilities of a GATT characteristic. + * @{ + */ +/** @brief Ability to broadcast.Corresponds to BTA_GATT_CHAR_PROP_BIT_BROADCAST. */ +#define ESP_GATT_CHAR_PROP_BIT_BROADCAST (1 << 0) + +/** @brief Ability to read.Corresponds to BTA_GATT_CHAR_PROP_BIT_READ. */ +#define ESP_GATT_CHAR_PROP_BIT_READ (1 << 1) + +/** @brief Ability to write without response.Corresponds to BTA_GATT_CHAR_PROP_BIT_WRITE_NR. */ +#define ESP_GATT_CHAR_PROP_BIT_WRITE_NR (1 << 2) + +/** @brief Ability to write.Corresponds to BTA_GATT_CHAR_PROP_BIT_WRITE. */ +#define ESP_GATT_CHAR_PROP_BIT_WRITE (1 << 3) + +/** @brief Ability to notify.Corresponds to BTA_GATT_CHAR_PROP_BIT_NOTIFY. */ +#define ESP_GATT_CHAR_PROP_BIT_NOTIFY (1 << 4) + +/** @brief Ability to indicate.Corresponds to BTA_GATT_CHAR_PROP_BIT_INDICATE. */ +#define ESP_GATT_CHAR_PROP_BIT_INDICATE (1 << 5) + +/** @brief Ability to authenticate.Corresponds to BTA_GATT_CHAR_PROP_BIT_AUTH. */ +#define ESP_GATT_CHAR_PROP_BIT_AUTH (1 << 6) + +/** @brief Has extended properties.Corresponds to BTA_GATT_CHAR_PROP_BIT_EXT_PROP. */ +#define ESP_GATT_CHAR_PROP_BIT_EXT_PROP (1 << 7) + +/** @} */ // end of GATT_CHAR_PROPERTIES + /** - * @brief Attribute permissions + * @typedef esp_gatt_char_prop_t + * @brief Type for characteristic properties bitmask. */ -#define ESP_GATT_PERM_READ (1 << 0) /* bit 0 - 0x0001 */ /* relate to BTA_GATT_PERM_READ in bta/bta_gatt_api.h */ -#define ESP_GATT_PERM_READ_ENCRYPTED (1 << 1) /* bit 1 - 0x0002 */ /* relate to BTA_GATT_PERM_READ_ENCRYPTED in bta/bta_gatt_api.h */ -#define ESP_GATT_PERM_READ_ENC_MITM (1 << 2) /* bit 2 - 0x0004 */ /* relate to BTA_GATT_PERM_READ_ENC_MITM in bta/bta_gatt_api.h */ -#define ESP_GATT_PERM_WRITE (1 << 4) /* bit 4 - 0x0010 */ /* relate to BTA_GATT_PERM_WRITE in bta/bta_gatt_api.h */ -#define ESP_GATT_PERM_WRITE_ENCRYPTED (1 << 5) /* bit 5 - 0x0020 */ /* relate to BTA_GATT_PERM_WRITE_ENCRYPTED in bta/bta_gatt_api.h */ -#define ESP_GATT_PERM_WRITE_ENC_MITM (1 << 6) /* bit 6 - 0x0040 */ /* relate to BTA_GATT_PERM_WRITE_ENC_MITM in bta/bta_gatt_api.h */ -#define ESP_GATT_PERM_WRITE_SIGNED (1 << 7) /* bit 7 - 0x0080 */ /* relate to BTA_GATT_PERM_WRITE_SIGNED in bta/bta_gatt_api.h */ -#define ESP_GATT_PERM_WRITE_SIGNED_MITM (1 << 8) /* bit 8 - 0x0100 */ /* relate to BTA_GATT_PERM_WRITE_SIGNED_MITM in bta/bta_gatt_api.h */ -#define ESP_GATT_PERM_READ_AUTHORIZATION (1 << 9) /* bit 9 - 0x0200 */ -#define ESP_GATT_PERM_WRITE_AUTHORIZATION (1 << 10) /* bit 10 - 0x0400 */ -#define ESP_GATT_PERM_ENCRYPT_KEY_SIZE(keysize) (((keysize - 6) & 0xF) << 12) /* bit 12:15 - 0xF000 */ -typedef uint16_t esp_gatt_perm_t; - -/* relate to BTA_GATT_CHAR_PROP_BIT_xxx in bta/bta_gatt_api.h */ -/* definition of characteristic properties */ -#define ESP_GATT_CHAR_PROP_BIT_BROADCAST (1 << 0) /* 0x01 */ /* relate to BTA_GATT_CHAR_PROP_BIT_BROADCAST in bta/bta_gatt_api.h */ -#define ESP_GATT_CHAR_PROP_BIT_READ (1 << 1) /* 0x02 */ /* relate to BTA_GATT_CHAR_PROP_BIT_READ in bta/bta_gatt_api.h */ -#define ESP_GATT_CHAR_PROP_BIT_WRITE_NR (1 << 2) /* 0x04 */ /* relate to BTA_GATT_CHAR_PROP_BIT_WRITE_NR in bta/bta_gatt_api.h */ -#define ESP_GATT_CHAR_PROP_BIT_WRITE (1 << 3) /* 0x08 */ /* relate to BTA_GATT_CHAR_PROP_BIT_WRITE in bta/bta_gatt_api.h */ -#define ESP_GATT_CHAR_PROP_BIT_NOTIFY (1 << 4) /* 0x10 */ /* relate to BTA_GATT_CHAR_PROP_BIT_NOTIFY in bta/bta_gatt_api.h */ -#define ESP_GATT_CHAR_PROP_BIT_INDICATE (1 << 5) /* 0x20 */ /* relate to BTA_GATT_CHAR_PROP_BIT_INDICATE in bta/bta_gatt_api.h */ -#define ESP_GATT_CHAR_PROP_BIT_AUTH (1 << 6) /* 0x40 */ /* relate to BTA_GATT_CHAR_PROP_BIT_AUTH in bta/bta_gatt_api.h */ -#define ESP_GATT_CHAR_PROP_BIT_EXT_PROP (1 << 7) /* 0x80 */ /* relate to BTA_GATT_CHAR_PROP_BIT_EXT_PROP in bta/bta_gatt_api.h */ typedef uint8_t esp_gatt_char_prop_t; -/// GATT maximum attribute length -#define ESP_GATT_MAX_ATTR_LEN 600 //as same as GATT_MAX_ATTR_LEN +/** + * @brief Defines the maximum length of a GATT attribute. + * + * This definition specifies the maximum number of bytes that a GATT attribute can hold. + */ +#define ESP_GATT_MAX_ATTR_LEN 512 /*!< As same as GATT_MAX_ATTR_LEN. */ + +/** + * @brief Enumerates the possible sources of a GATT service discovery. + * + * This enumeration identifies the source of a GATT service discovery process, + * indicating whether the service information was obtained from a remote device, + * from NVS (Non-Volatile Storage) flash, or the source is unknown. + */ typedef enum { - ESP_GATT_SERVICE_FROM_REMOTE_DEVICE = 0, /* relate to BTA_GATTC_SERVICE_INFO_FROM_REMOTE_DEVICE in bta_gattc_int.h */ - ESP_GATT_SERVICE_FROM_NVS_FLASH = 1, /* relate to BTA_GATTC_SERVICE_INFO_FROM_NVS_FLASH in bta_gattc_int.h */ - ESP_GATT_SERVICE_FROM_UNKNOWN = 2, /* relate to BTA_GATTC_SERVICE_INFO_FROM_UNKNOWN in bta_gattc_int.h */ + ESP_GATT_SERVICE_FROM_REMOTE_DEVICE = 0, /*!< Service information from a remote device. Relates to BTA_GATTC_SERVICE_INFO_FROM_REMOTE_DEVICE. */ + ESP_GATT_SERVICE_FROM_NVS_FLASH = 1, /*!< Service information from NVS flash. Relates to BTA_GATTC_SERVICE_INFO_FROM_NVS_FLASH. */ + ESP_GATT_SERVICE_FROM_UNKNOWN = 2, /*!< Service source is unknown. Relates to BTA_GATTC_SERVICE_INFO_FROM_UNKNOWN. */ } esp_service_source_t; + /** - * @brief Attribute description (used to create database) + * @brief Defines an attribute's description. + * + * This structure is used to describe an attribute in the GATT database. It includes + * details such as the UUID of the attribute, its permissions, and its value. */ - typedef struct - { - uint16_t uuid_length; /*!< UUID length */ - uint8_t *uuid_p; /*!< UUID value */ - uint16_t perm; /*!< Attribute permission */ - uint16_t max_length; /*!< Maximum length of the element*/ - uint16_t length; /*!< Current length of the element*/ - uint8_t *value; /*!< Element value array*/ - } esp_attr_desc_t; +typedef struct +{ + uint16_t uuid_length; /*!< Length of the UUID in bytes. */ + uint8_t *uuid_p; /*!< Pointer to the UUID value. */ + uint16_t perm; /*!< Attribute permissions, defined by esp_gatt_perm_t. */ + uint16_t max_length; /*!< Maximum length of the attribute's value. */ + uint16_t length; /*!< Current length of the attribute's value. */ + uint8_t *value; /*!< Pointer to the attribute's value array. */ +} esp_attr_desc_t; /** - * @brief attribute auto response flag + * @brief Defines attribute control for GATT operations. + * + * This module provides definitions for controlling attribute auto responses + * in GATT operations. + */ + +/** @brief Response to Write/Read operations should be handled by the application. */ +#define ESP_GATT_RSP_BY_APP 0 + +/** @brief Response to Write/Read operations should be automatically handled by the GATT stack. */ +#define ESP_GATT_AUTO_RSP 1 + +/** + * @brief Defines the auto response setting for attribute operations. + * + * This structure is used to control whether the GATT stack or the application + * will handle responses to Read/Write operations. */ typedef struct { -#define ESP_GATT_RSP_BY_APP 0 -#define ESP_GATT_AUTO_RSP 1 /** - * @brief if auto_rsp set to ESP_GATT_RSP_BY_APP, means the response of Write/Read operation will by replied by application. - if auto_rsp set to ESP_GATT_AUTO_RSP, means the response of Write/Read operation will be replied by GATT stack automatically. + * @brief Controls who handles the response to Read/Write operations. + * + * - If set to @c ESP_GATT_RSP_BY_APP, the application is responsible for + * generating the response. + * - If set to @c ESP_GATT_AUTO_RSP, the GATT stack will automatically generate + * the response. */ uint8_t auto_rsp; } esp_attr_control_t; + /** - * @brief attribute type added to the gatt server database + * @brief attribute type added to the GATT server database */ typedef struct { @@ -370,116 +585,103 @@ typedef struct uint16_t end_hdl; /*!< Gatt end handle value of included 128 bit service */ } esp_gatts_incl128_svc_desc_t; /*!< Gatt include 128 bit service entry element */ -/// Gatt attribute value +/** + * @brief Represents a GATT attribute's value. + */ typedef struct { - uint8_t value[ESP_GATT_MAX_ATTR_LEN]; /*!< Gatt attribute value */ - uint16_t handle; /*!< Gatt attribute handle */ - uint16_t offset; /*!< Gatt attribute value offset */ - uint16_t len; /*!< Gatt attribute value length */ - uint8_t auth_req; /*!< Gatt authentication request */ + uint8_t value[ESP_GATT_MAX_ATTR_LEN]; /*!< Array holding the value of the GATT attribute. */ + uint16_t handle; /*!< Unique identifier (handle) of the GATT attribute. */ + uint16_t offset; /*!< Offset within the attribute's value, for partial updates. */ + uint16_t len; /*!< Current length of the data in the value array. */ + uint8_t auth_req; /*!< Authentication requirements for accessing this attribute. */ } esp_gatt_value_t; -/// GATT remote read request response type +/** + * @brief Represents the response type for a GATT remote read request. + */ typedef union { - esp_gatt_value_t attr_value; /*!< Gatt attribute structure */ - uint16_t handle; /*!< Gatt attribute handle */ + esp_gatt_value_t attr_value; /*!< The GATT attribute value, including its data, handle, and metadata. */ + uint16_t handle; /*!< Only the handle of the GATT attribute, when that's the only required information. */ } esp_gatt_rsp_t; + /** - * @brief Gatt write type - */ + * @brief Defines the types of GATT write operations. + */ typedef enum { - ESP_GATT_WRITE_TYPE_NO_RSP = 1, /*!< Gatt write attribute need no response */ - ESP_GATT_WRITE_TYPE_RSP, /*!< Gatt write attribute need remote response */ + ESP_GATT_WRITE_TYPE_NO_RSP = 1, /*!< Write operation where no response is needed. */ + ESP_GATT_WRITE_TYPE_RSP = 2, /*!< Write operation that requires a remote response. */ } esp_gatt_write_type_t; -/** - * @brief Connection parameters information - */ + +/** @brief Connection parameters for GATT. */ typedef struct { - uint16_t interval; /*!< connection interval */ - uint16_t latency; /*!< Slave latency for the connection in number of connection events. Range: 0x0000 to 0x01F3 */ - uint16_t timeout; /*!< Supervision timeout for the LE Link. Range: 0x000A to 0x0C80. - Mandatory Range: 0x000A to 0x0C80 Time = N * 10 msec - Time Range: 100 msec to 32 seconds */ + uint16_t interval; /*!< Connection interval. */ + uint16_t latency; /*!< Slave latency for the connection in number of connection events. */ + uint16_t timeout; /*!< Supervision timeout for the LE Link. */ } esp_gatt_conn_params_t; -#define ESP_GATT_IF_NONE 0xff /*!< If callback report gattc_if/gatts_if as this macro, means this event is not correspond to any app */ +/** @brief Macro indicating no specific GATT interface. */ +#define ESP_GATT_IF_NONE 0xff /*!< No specific application GATT interface. */ -typedef uint8_t esp_gatt_if_t; /*!< Gatt interface type, different application on GATT client use different gatt_if */ +/** @brief GATT interface type for client applications. */ +typedef uint8_t esp_gatt_if_t; -/** - * @brief the type of attribute element - */ +/** @brief Enumerates types of GATT database attributes. */ typedef enum { - ESP_GATT_DB_PRIMARY_SERVICE, /*!< Gattc primary service attribute type in the cache */ - ESP_GATT_DB_SECONDARY_SERVICE, /*!< Gattc secondary service attribute type in the cache */ - ESP_GATT_DB_CHARACTERISTIC, /*!< Gattc characteristic attribute type in the cache */ - ESP_GATT_DB_DESCRIPTOR, /*!< Gattc characteristic descriptor attribute type in the cache */ - ESP_GATT_DB_INCLUDED_SERVICE, /*!< Gattc include service attribute type in the cache */ - ESP_GATT_DB_ALL, /*!< Gattc all the attribute (primary service & secondary service & include service & char & descriptor) type in the cache */ -} esp_gatt_db_attr_type_t; /*!< Gattc attribute type element */ - -/** - * @brief read multiple attribute - */ + ESP_GATT_DB_PRIMARY_SERVICE, /*!< Primary service attribute. */ + ESP_GATT_DB_SECONDARY_SERVICE, /*!< Secondary service attribute. */ + ESP_GATT_DB_CHARACTERISTIC, /*!< Characteristic attribute. */ + ESP_GATT_DB_DESCRIPTOR, /*!< Descriptor attribute. */ + ESP_GATT_DB_INCLUDED_SERVICE, /*!< Included service attribute. */ + ESP_GATT_DB_ALL, /*!< All attribute types. */ +} esp_gatt_db_attr_type_t; + +/** @brief Represents multiple attributes for reading. */ typedef struct { - uint8_t num_attr; /*!< The number of the attribute */ - uint16_t handles[ESP_GATT_MAX_READ_MULTI_HANDLES]; /*!< The handles list */ -} esp_gattc_multi_t; /*!< The gattc multiple read element */ + uint8_t num_attr; /*!< Number of attributes. */ + uint16_t handles[ESP_GATT_MAX_READ_MULTI_HANDLES]; /*!< List of attribute handles. */ +} esp_gattc_multi_t; -/** - * @brief data base attribute element - */ +/** @brief GATT database attribute element. */ typedef struct { - esp_gatt_db_attr_type_t type; /*!< The attribute type */ - uint16_t attribute_handle; /*!< The attribute handle, it's valid for all of the type */ - uint16_t start_handle; /*!< The service start handle, it's valid only when the type = ESP_GATT_DB_PRIMARY_SERVICE or ESP_GATT_DB_SECONDARY_SERVICE */ - uint16_t end_handle; /*!< The service end handle, it's valid only when the type = ESP_GATT_DB_PRIMARY_SERVICE or ESP_GATT_DB_SECONDARY_SERVICE */ - esp_gatt_char_prop_t properties; /*!< The characteristic properties, it's valid only when the type = ESP_GATT_DB_CHARACTERISTIC */ - esp_bt_uuid_t uuid; /*!< The attribute uuid, it's valid for all of the type */ -} esp_gattc_db_elem_t; /*!< The gattc service data base element in the cache */ - -/** - * @brief service element - */ + esp_gatt_db_attr_type_t type; /*!< Attribute type. */ + uint16_t attribute_handle; /*!< Attribute handle. */ + uint16_t start_handle; /*!< Service start handle. */ + uint16_t end_handle; /*!< Service end handle. */ + esp_gatt_char_prop_t properties; /*!< Characteristic properties. */ + esp_bt_uuid_t uuid; /*!< Attribute UUID. */ +} esp_gattc_db_elem_t; + +/** @brief Represents a GATT service element. */ typedef struct { - bool is_primary; /*!< The service flag, true if the service is primary service, else is secondary service */ - uint16_t start_handle; /*!< The start handle of the service */ - uint16_t end_handle; /*!< The end handle of the service */ - esp_bt_uuid_t uuid; /*!< The uuid of the service */ -} esp_gattc_service_elem_t; /*!< The gattc service element */ + bool is_primary; /*!< Indicates if the service is primary. */ + uint16_t start_handle; /*!< Service start handle. */ + uint16_t end_handle; /*!< Service end handle. */ + esp_bt_uuid_t uuid; /*!< Service UUID. */ +} esp_gattc_service_elem_t; -/** - * @brief characteristic element - */ +/** @brief Represents a GATT characteristic element. */ typedef struct { - uint16_t char_handle; /*!< The characteristic handle */ - esp_gatt_char_prop_t properties; /*!< The characteristic properties */ - esp_bt_uuid_t uuid; /*!< The characteristic uuid */ -} esp_gattc_char_elem_t; /*!< The gattc characteristic element */ + uint16_t char_handle; /*!< Characteristic handle. */ + esp_gatt_char_prop_t properties; /*!< Characteristic properties. */ + esp_bt_uuid_t uuid; /*!< Characteristic UUID. */ +} esp_gattc_char_elem_t; -/** - * @brief descriptor element - */ +/** @brief Represents a GATT descriptor element. */ typedef struct { - uint16_t handle; /*!< The characteristic descriptor handle */ - esp_bt_uuid_t uuid; /*!< The characteristic descriptor uuid */ -} esp_gattc_descr_elem_t; /*!< The gattc descriptor type element */ + uint16_t handle; /*!< Descriptor handle. */ + esp_bt_uuid_t uuid; /*!< Descriptor UUID. */ +} esp_gattc_descr_elem_t; -/** - * @brief include service element - */ +/** @brief Represents an included GATT service element. */ typedef struct { - uint16_t handle; /*!< The include service current attribute handle */ - uint16_t incl_srvc_s_handle; /*!< The start handle of the service which has been included */ - uint16_t incl_srvc_e_handle; /*!< The end handle of the service which has been included */ - esp_bt_uuid_t uuid; /*!< The include service uuid */ -} esp_gattc_incl_svc_elem_t; /*!< The gattc include service element */ - + uint16_t handle; /*!< Current attribute handle of the included service. */ + uint16_t incl_srvc_s_handle; /*!< Start handle of the included service. */ + uint16_t incl_srvc_e_handle; /*!< End handle of the included service. */ + esp_bt_uuid_t uuid; /*!< Included service UUID. */ +} esp_gattc_incl_svc_elem_t; #ifdef __cplusplus } #endif - -#endif /* __ESP_GATT_DEFS_H__ */ diff --git a/lib/bt/host/bluedroid/bta/dm/bta_dm_act.c b/lib/bt/host/bluedroid/bta/dm/bta_dm_act.c index f1eb9a12..ba5e8f02 100644 --- a/lib/bt/host/bluedroid/bta/dm/bta_dm_act.c +++ b/lib/bt/host/bluedroid/bta/dm/bta_dm_act.c @@ -615,6 +615,11 @@ void bta_dm_disable (tBTA_DM_MSG *p_data) btm_ble_resolving_list_cleanup (); //by TH, because cmn_ble_vsc_cb.max_filter has something mistake as btm_ble_adv_filter_cleanup #endif +#if BLE_INCLUDED == TRUE + // btm_ble_multi_adv_init is called when the host is enabled, so btm_ble_multi_adv_cleanup is called when the host is disabled. + btm_ble_multi_adv_cleanup(); +#endif + } /******************************************************************************* @@ -649,7 +654,7 @@ static void bta_dm_disable_timer_cback (TIMER_LIST_ENT *p_tle) } /* Retrigger disable timer in case ACL disconnect failed, DISABLE_EVT still need - to be sent out to avoid jave layer disable timeout */ + to be sent out to avoid the layer disable timeout */ if (trigger_disc) { bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK *)&bta_dm_disable_timer_cback; bta_dm_cb.disable_timer.param = 1; @@ -678,9 +683,11 @@ static void bta_dm_disable_timer_cback (TIMER_LIST_ENT *p_tle) *******************************************************************************/ void bta_dm_set_dev_name (tBTA_DM_MSG *p_data) { - BTM_SetLocalDeviceName((char *)p_data->set_name.name); + BTM_SetLocalDeviceName((char *)p_data->set_name.name, p_data->set_name.name_type); #if CLASSIC_BT_INCLUDED - bta_dm_set_eir ((char *)p_data->set_name.name); + if (p_data->set_name.name_type & BT_DEVICE_TYPE_BREDR) { + bta_dm_set_eir ((char *)p_data->set_name.name); + } #endif /// CLASSIC_BT_INCLUDED } @@ -699,7 +706,7 @@ void bta_dm_get_dev_name (tBTA_DM_MSG *p_data) tBTM_STATUS status; char *name = NULL; - status = BTM_ReadLocalDeviceName(&name); + status = BTM_ReadLocalDeviceName(&name, p_data->get_name.name_type); if (p_data->get_name.p_cback) { (*p_data->get_name.p_cback)(status, name); } @@ -709,7 +716,7 @@ void bta_dm_get_dev_name (tBTA_DM_MSG *p_data) ** ** Function bta_dm_cfg_coex_status ** -** Description config coexistance status +** Description config coexistence status ** ** ** Returns void @@ -724,6 +731,14 @@ void bta_dm_cfg_coex_status (tBTA_DM_MSG *p_data) } #endif +void bta_dm_send_vendor_hci(tBTA_DM_MSG *p_data) +{ + BTM_VendorSpecificCommand(p_data->vendor_hci_cmd.opcode, + p_data->vendor_hci_cmd.param_len, + p_data->vendor_hci_cmd.p_param_buf, + p_data->vendor_hci_cmd.vendor_hci_cb); +} + /******************************************************************************* ** ** Function bta_dm_set_afh_channels @@ -772,7 +787,7 @@ static BOOLEAN bta_dm_read_remote_device_name (BD_ADDR bd_addr, tBT_TRANSPORT tr APPL_TRACE_DEBUG("bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName is busy"); /* Remote name discovery is on going now so BTM cannot notify through "bta_dm_remname_cback" */ - /* adding callback to get notified that current reading remore name done */ + /* adding callback to get notified that current reading remote name done */ BTM_SecAddRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); return (TRUE); @@ -907,6 +922,23 @@ void bta_dm_set_acl_pkt_types (tBTA_DM_MSG *p_data) } } +/******************************************************************************* +** +** Function bta_dm_set_min_enc_key_size +** +** Description Sets the minimal size of encryption key +** +** +** Returns void +** +*******************************************************************************/ +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +void bta_dm_set_min_enc_key_size (tBTA_DM_MSG *p_data) +{ + BTM_SetMinEncKeySize(p_data->set_min_enc_key_size.key_size, p_data->set_min_enc_key_size.set_min_enc_key_size_cb); +} +#endif + #endif /******************************************************************************* ** @@ -1156,7 +1188,7 @@ void bta_dm_add_device (tBTA_DM_MSG *p_data) } if (p_dev->is_trusted) { - /* covert BTA service mask to BTM mask */ + /* convert BTA service mask to BTM mask */ while (p_dev->tm && (index < BTA_MAX_SERVICE_ID)) { if (p_dev->tm & (UINT32)(1 << index)) { @@ -1184,7 +1216,7 @@ void bta_dm_add_device (tBTA_DM_MSG *p_data) ** Function bta_dm_close_acl ** ** Description This function forces to close the connection to a remote device -** and optionaly remove the device from security database if +** and optionally remove the device from security database if ** required. **** *******************************************************************************/ @@ -2707,7 +2739,7 @@ static void bta_dm_discover_device(BD_ADDR remote_bd_addr) &bta_dm_search_cb.services_found ); } - /* if seaching with EIR is not completed */ + /* if searching with EIR is not completed */ if (bta_dm_search_cb.services_to_search) { /* check whether connection already exists to the device if connection exists, we don't have to wait for ACL @@ -3794,7 +3826,7 @@ static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle) tBTA_SYS_HW_MSG *sys_enable_event; #if (BTA_DM_PM_INCLUDED == TRUE) - /* disable the power managment module */ + /* disable the power management module */ bta_dm_disable_pm(); #endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ @@ -4138,7 +4170,7 @@ static void bta_dm_set_eir (char *local_name) if (p_bta_dm_eir_cfg->bta_dm_eir_included_name) { /* if local name is not provided, get it from controller */ if ( local_name == NULL ) { - if ( BTM_ReadLocalDeviceName( &local_name ) != BTM_SUCCESS ) { + if ( BTM_ReadLocalDeviceName( &local_name, BT_DEVICE_TYPE_BREDR) != BTM_SUCCESS ) { APPL_TRACE_ERROR("Fail to read local device name for EIR"); } } @@ -4181,7 +4213,7 @@ static void bta_dm_set_eir (char *local_name) p = (UINT8 *)p_buf + BTM_HCI_EIR_OFFSET; /* reset p */ #endif // BTA_EIR_CANNED_UUID_LIST - /* if UUID doesn't fit remaing space, shorten local name */ + /* if UUID doesn't fit remaining space, shorten local name */ if ( local_name_len > (free_eir_length - 4 - num_uuid * LEN_UUID_16)) { APPL_TRACE_WARNING("BTA EIR: local name is shortened"); local_name_len = p_bta_dm_eir_cfg->bta_dm_eir_min_name_len; @@ -5234,14 +5266,14 @@ void bta_dm_ble_disconnect (tBTA_DM_MSG *p_data) ** ** Description This function set the LE random address for the device. ** -** Parameters: rand_addr:the random address whitch should be setting +** Parameters: rand_addr:the random address which should be setting ** Explanation: This function added by Yulong at 2016/9/9 *******************************************************************************/ void bta_dm_ble_set_rand_address(tBTA_DM_MSG *p_data) { tBTM_STATUS status = BTM_SET_STATIC_RAND_ADDR_FAIL; if (p_data->set_addr.addr_type != BLE_ADDR_RANDOM) { - APPL_TRACE_ERROR("Invalid random adress type = %d\n", p_data->set_addr.addr_type); + APPL_TRACE_ERROR("Invalid random address type = %d\n", p_data->set_addr.addr_type); if(p_data->set_addr.p_set_rand_addr_cback) { (*p_data->set_addr.p_set_rand_addr_cback)(status); } @@ -5596,7 +5628,7 @@ void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data) } p_acl_cb->p_set_pkt_data_cback = p_data->ble_set_data_length.p_set_pkt_data_cback; - // if the value of the data length is same, triger callback directly + // if the value of the data length is same, trigger callback directly if(p_data->ble_set_data_length.tx_data_length == p_acl_cb->data_length_params.tx_len) { if(p_data->ble_set_data_length.p_set_pkt_data_cback) { (*p_data->ble_set_data_length.p_set_pkt_data_cback)(status, &p_acl_cb->data_length_params); @@ -5605,7 +5637,7 @@ void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data) } if(p_acl_cb->data_len_updating) { - // aleady have one cmd + // already have one cmd if(p_acl_cb->data_len_waiting) { status = BTM_ILLEGAL_ACTION; } else { @@ -5791,6 +5823,28 @@ void bta_dm_ble_gap_clear_adv(tBTA_DM_MSG *p_data) } } +void bta_dm_ble_gap_set_rpa_timeout(tBTA_DM_MSG *p_data) +{ + APPL_TRACE_API("%s, rpa_timeout = %d", __func__, p_data->set_rpa_timeout.rpa_timeout); + BTM_BleSetRpaTimeout(p_data->set_rpa_timeout.rpa_timeout,p_data->set_rpa_timeout.p_set_rpa_timeout_cback); +} + +void bta_dm_ble_gap_add_dev_to_resolving_list(tBTA_DM_MSG *p_data) +{ + APPL_TRACE_API("%s", __func__); + BTM_BleAddDevToResolvingList(p_data->add_dev_to_resolving_list.addr, + p_data->add_dev_to_resolving_list.addr_type, + p_data->add_dev_to_resolving_list.irk, + p_data->add_dev_to_resolving_list.p_add_dev_to_resolving_list_callback); +} + +void bta_dm_ble_gap_set_privacy_mode(tBTA_DM_MSG *p_data) +{ + APPL_TRACE_API("%s, privacy_mode = %d", __func__, p_data->ble_set_privacy_mode.privacy_mode); + BTM_BleSetPrivacyMode(p_data->ble_set_privacy_mode.addr_type, p_data->ble_set_privacy_mode.addr, + p_data->ble_set_privacy_mode.privacy_mode, p_data->ble_set_privacy_mode.p_cback); +} + #if (BLE_50_FEATURE_SUPPORT == TRUE) void bta_dm_ble_gap_dtm_enhance_tx_start(tBTA_DM_MSG *p_data) { @@ -6472,7 +6526,7 @@ static void bta_dm_gatt_disc_result(tBTA_GATT_ID service_id) } } else { - APPL_TRACE_ERROR("%s out of room to accomodate more service ids ble_raw_size = %d ble_raw_used = %d", __FUNCTION__, bta_dm_search_cb.ble_raw_size, bta_dm_search_cb.ble_raw_used ); + APPL_TRACE_ERROR("%s out of room to accommodate more service ids ble_raw_size = %d ble_raw_used = %d", __FUNCTION__, bta_dm_search_cb.ble_raw_size, bta_dm_search_cb.ble_raw_used ); } APPL_TRACE_API("%s service_id_uuid_len=%d ", __func__, service_id.uuid.len); diff --git a/lib/bt/host/bluedroid/bta/dm/bta_dm_api.c b/lib/bt/host/bluedroid/bta/dm/bta_dm_api.c index ecb6b6ee..a2282cd9 100644 --- a/lib/bt/host/bluedroid/bta/dm/bta_dm_api.c +++ b/lib/bt/host/bluedroid/bta/dm/bta_dm_api.c @@ -166,7 +166,7 @@ void BTA_DisableTestMode(void) ** Returns void ** *******************************************************************************/ -void BTA_DmSetDeviceName(const char *p_name) +void BTA_DmSetDeviceName(const char *p_name, tBT_DEVICE_TYPE name_type) { tBTA_DM_API_SET_NAME *p_msg; @@ -176,6 +176,7 @@ void BTA_DmSetDeviceName(const char *p_name) /* truncate the name if needed */ BCM_STRNCPY_S((char *)p_msg->name, p_name, BD_NAME_LEN); p_msg->name[BD_NAME_LEN] = '\0'; + p_msg->name_type = name_type; bta_sys_sendmsg(p_msg); } @@ -191,13 +192,14 @@ void BTA_DmSetDeviceName(const char *p_name) ** Returns void ** *******************************************************************************/ -void BTA_DmGetDeviceName(tBTA_GET_DEV_NAME_CBACK *p_cback) +void BTA_DmGetDeviceName(tBTA_GET_DEV_NAME_CBACK *p_cback, tBT_DEVICE_TYPE name_type) { tBTA_DM_API_GET_NAME *p_msg; if ((p_msg = (tBTA_DM_API_GET_NAME *) osi_malloc(sizeof(tBTA_DM_API_GET_NAME))) != NULL) { p_msg->hdr.event = BTA_DM_API_GET_NAME_EVT; p_msg->p_cback = p_cback; + p_msg->name_type = name_type; bta_sys_sendmsg(p_msg); } } @@ -227,6 +229,21 @@ void BTA_DmCfgCoexStatus(UINT8 op, UINT8 type, UINT8 status) } #endif +void BTA_DmsendVendorHciCmd(UINT16 opcode, UINT8 param_len, UINT8 *p_param_buf, tBTA_SEND_VENDOR_HCI_CMPL_CBACK p_vendor_cmd_complete_cback) +{ + tBTA_DM_API_SEND_VENDOR_HCI_CMD *p_msg; + if ((p_msg = (tBTA_DM_API_SEND_VENDOR_HCI_CMD *)osi_malloc(sizeof(tBTA_DM_API_SEND_VENDOR_HCI_CMD) + param_len)) != NULL) { + p_msg->hdr.event = BTA_DM_API_SEND_VENDOR_HCI_CMD_EVT; + p_msg->opcode = opcode; + p_msg->param_len = param_len; + p_msg->p_param_buf = (UINT8 *)(p_msg + 1); + memcpy(p_msg->p_param_buf, p_param_buf, param_len); + p_msg->vendor_hci_cb = p_vendor_cmd_complete_cback; + + bta_sys_sendmsg(p_msg); + } +} + #if (CLASSIC_BT_INCLUDED == TRUE) void BTA_DmConfigEir(tBTA_DM_EIR_CONF *eir_config) @@ -365,6 +382,31 @@ void BTA_DmSetAclPktTypes(BD_ADDR remote_addr, UINT16 pkt_types, tBTM_CMPL_CB *p bta_sys_sendmsg(p_msg); } } + +/******************************************************************************* +** +** Function BTA_DmSetMinEncKeySize +** +** Description This function sets the minimal size of encryption key. +** +** +** Returns void +** +*******************************************************************************/ +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +void BTA_DmSetMinEncKeySize(UINT8 key_size, tBTM_CMPL_CB *p_cb) +{ + tBTA_DM_API_SET_MIN_ENC_KEY_SIZE *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_MIN_ENC_KEY_SIZE *) osi_malloc(sizeof(tBTA_DM_API_SET_MIN_ENC_KEY_SIZE))) != NULL) { + p_msg->hdr.event = BTA_DM_API_SET_MIN_ENC_KEY_SIZE_EVT; + p_msg->key_size = key_size; + p_msg->set_min_enc_key_size_cb = p_cb; + + bta_sys_sendmsg(p_msg); + } +} +#endif #endif /// CLASSIC_BT_INCLUDED == TRUE #if (SDP_INCLUDED == TRUE) @@ -940,7 +982,7 @@ void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, LINK_KEY link_key, ** ** Function BTA_DmRemoveDevice ** -** Description This function removes a device fromthe security database list of +** Description This function removes a device from the security database list of ** peer device. It manages unpairing even while connected. ** ** @@ -1158,7 +1200,7 @@ void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, int auth_mode ** Description Send BLE SMP passkey reply. ** ** Parameters: bd_addr - BD address of the peer -** accept - passkey entry sucessful or declined. +** accept - passkey entry successful or declined. ** passkey - passkey value, must be a 6 digit number, ** can be lead by 0. ** @@ -1997,7 +2039,7 @@ void BTA_DmDiscoverExt(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services, ** p_services: if service is not empty, service discovery will be done. ** for all GATT based service condition, put num_uuid, and ** p_uuid is the pointer to the list of UUID values. -** p_cback: callback functino when search is completed. +** p_cback: callback function when search is completed. ** ** ** @@ -2085,7 +2127,7 @@ void BTA_DmBleUpdateConnectionParam(BD_ADDR bd_addr, UINT16 min_int, ** ** Description Enable/disable privacy on the local device ** -** Parameters: privacy_enable - enable/disabe privacy on remote device. +** Parameters: privacy_enable - enable/disable privacy on remote device. ** ** Returns void ** @@ -2137,7 +2179,7 @@ void BTA_DmBleConfigLocalIcon(uint16_t icon) ** ** Function BTA_BleEnableAdvInstance ** -** Description This function enable a Multi-ADV instance with the specififed +** Description This function enable a Multi-ADV instance with the specified ** adv parameters ** ** Parameters p_params: pointer to the adv parameter structure. @@ -2176,7 +2218,7 @@ void BTA_BleEnableAdvInstance (tBTA_BLE_ADV_PARAMS *p_params, ** ** Function BTA_BleUpdateAdvInstParam ** -** Description This function update a Multi-ADV instance with the specififed +** Description This function update a Multi-ADV instance with the specified ** adv parameters. ** ** Parameters inst_id: Adv instance to update the parameter. @@ -2207,7 +2249,7 @@ void BTA_BleUpdateAdvInstParam (UINT8 inst_id, tBTA_BLE_ADV_PARAMS *p_params) ** ** Function BTA_BleCfgAdvInstData ** -** Description This function configure a Multi-ADV instance with the specififed +** Description This function configure a Multi-ADV instance with the specified ** adv data or scan response data. ** ** Parameter inst_id: Adv instance to configure the adv data or scan response. @@ -2637,6 +2679,21 @@ void BTA_DmBleDtmStop(tBTA_DTM_CMD_CMPL_CBACK *p_dtm_cmpl_cback) } } +void BTA_DmBleSetPrivacyMode(uint8_t addr_type, BD_ADDR addr, uint8_t privacy_mode, tBTA_SET_PRIVACY_MODE_CMPL_CBACK *p_cback) +{ + tBTA_DM_API_SET_PRIVACY_MODE *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_PRIVACY_MODE *)osi_malloc(sizeof(tBTA_DM_API_SET_PRIVACY_MODE))) + != NULL) { + p_msg->hdr.event = BTA_DM_API_SET_PRIVACY_MODE_EVT; + p_msg->addr_type = addr_type; + memcpy(p_msg->addr, addr, sizeof(BD_ADDR)); + p_msg->privacy_mode = privacy_mode; + p_msg->p_cback = p_cback; + bta_sys_sendmsg(p_msg); + } +} + #endif /******************************************************************************* @@ -2650,7 +2707,7 @@ void BTA_DmBleDtmStop(tBTA_DTM_CMD_CMPL_CBACK *p_dtm_cmpl_cback) ** ** Parameters: bd_addr - Address of the peer device ** transport - transport of the link to be encruypted -** p_callback - Pointer to callback function to indicat the +** p_callback - Pointer to callback function to indicate the ** link encryption status ** sec_act - This is the security action to indicate ** what kind of BLE security level is required for @@ -2830,7 +2887,7 @@ extern void BTA_DmBleStopAdvertising(void) ** ** Description This function set the random address for the APP ** -** Parameters rand_addr: the random address whith should be setting +** Parameters rand_addr: the random address with should be setting ** p_set_rand_addr_cback: complete callback ** Returns void ** @@ -2846,7 +2903,68 @@ extern void BTA_DmSetRandAddress(BD_ADDR rand_addr, tBTA_SET_RAND_ADDR_CBACK *p_ p_msg->hdr.event = BTA_DM_API_SET_RAND_ADDR_EVT; p_msg->addr_type = BLE_ADDR_RANDOM; p_msg->p_set_rand_addr_cback = p_set_rand_addr_cback; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module + bta_sys_sendmsg(p_msg); + } +} +/******************************************************************************* +** +** Function BTA_DmBleSetRpaTimeout +** +** Description This function sets the Resolvable Private Address (RPA) timeout +** for the Bluetooth device. The RPA timeout defines how long an RPA +** remains in use before a new one is generated. +** +** Parameters rpa_timeout: The timeout in seconds within the range of 1s to 1 hour +** as defined by the Bluetooth specification. This duration +** specifies how long the controller uses an RPA before +** generating a new one. +** Returns void +** +** +*******************************************************************************/ +void BTA_DmBleSetRpaTimeout(uint16_t rpa_timeout,tBTA_SET_RPA_TIMEOUT_CMPL_CBACK *p_set_rpa_timeout_cback) +{ + tBTA_DM_API_SET_RPA_TIMEOUT *p_msg; + if ((p_msg = (tBTA_DM_API_SET_RPA_TIMEOUT *) osi_malloc(sizeof(tBTA_DM_API_SET_RPA_TIMEOUT))) != NULL) { + memset(p_msg, 0, sizeof(tBTA_DM_API_SET_RPA_TIMEOUT)); + p_msg->hdr.event = BTA_DM_API_SET_RPA_TIMEOUT_EVT; + p_msg->rpa_timeout = rpa_timeout; // Assign the RPA timeout value to the message + p_msg->p_set_rpa_timeout_cback = p_set_rpa_timeout_cback; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmBleAddDevToResolvingList +** +** Description This function adds a device to the resolving list of the +** Bluetooth controller. The resolving list is used for resolving +** the identity of devices using resolvable private addresses (RPAs). +** +** Parameters addr: Bluetooth device address to be added to the resolving list +** addr_type: Type of the address (public or random) +** irk: Identity Resolving Key (IRK) of the device +** add_dev_to_resolving_list_callback: Callback function to be invoked +** upon completion of the operation +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleAddDevToResolvingList(BD_ADDR addr, + uint8_t addr_type, + PEER_IRK irk, + tBTA_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK *add_dev_to_resolving_list_callback) +{ + tBTA_DM_API_ADD_DEV_TO_RESOLVING_LIST *p_msg; + if ((p_msg = (tBTA_DM_API_ADD_DEV_TO_RESOLVING_LIST *) osi_malloc(sizeof(tBTA_DM_API_ADD_DEV_TO_RESOLVING_LIST))) != NULL) { + memset(p_msg, 0, sizeof(tBTA_DM_API_ADD_DEV_TO_RESOLVING_LIST)); + p_msg->hdr.event = BTA_DM_API_ADD_DEV_TO_RESOLVING_LIST_EVT; + memcpy(p_msg->addr, addr, BD_ADDR_LEN); // Copy the device address to the message + p_msg->addr_type = addr_type; // Assign the address type to the message + memcpy(p_msg->irk, irk, PEER_IRK_LEN); // Copy the IRK to the message + p_msg->p_add_dev_to_resolving_list_callback = add_dev_to_resolving_list_callback; bta_sys_sendmsg(p_msg); } } @@ -2906,7 +3024,6 @@ void BTA_VendorCleanup (void) } #endif - btm_ble_multi_adv_cleanup(); } #if (BLE_50_FEATURE_SUPPORT == TRUE) void BTA_DmBleGapReadPHY(BD_ADDR addr) @@ -2917,7 +3034,7 @@ void BTA_DmBleGapReadPHY(BD_ADDR addr) memset(p_msg, 0, sizeof(tBTA_DM_API_READ_PHY)); p_msg->hdr.event = BTA_DM_API_READ_PHY_EVT; memcpy(p_msg->bd_addr, addr, BD_ADDR_LEN); - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -2929,13 +3046,13 @@ void BTA_DmBleGapSetPreferedDefaultPHY(tBTA_DM_BLE_GAP_PHY_MASK tx_phy_mask, tBTA_DM_BLE_GAP_PHY_MASK rx_phy_mask) { tBTA_DM_API_SET_PER_DEF_PHY *p_msg; - APPL_TRACE_API("%s, Set prefered default phy.", __func__); + APPL_TRACE_API("%s, Set preferred default phy.", __func__); if ((p_msg = (tBTA_DM_API_SET_PER_DEF_PHY *) osi_malloc(sizeof(tBTA_DM_API_SET_PER_DEF_PHY))) != NULL) { memset(p_msg, 0, sizeof(tBTA_DM_API_SET_PER_DEF_PHY)); p_msg->hdr.event = BTA_DM_API_SET_PER_DEF_PHY_EVT; p_msg->tx_phy_mask = tx_phy_mask; p_msg->rx_phy_mask = rx_phy_mask; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -2950,7 +3067,7 @@ void BTA_DmBleGapSetPreferedPHY(BD_ADDR addr, UINT16 phy_options) { tBTA_DM_API_SET_PER_PHY *p_msg; - APPL_TRACE_API("%s, Set prefered phy.", __func__); + APPL_TRACE_API("%s, Set preferred phy.", __func__); if ((p_msg = (tBTA_DM_API_SET_PER_PHY *) osi_malloc(sizeof(tBTA_DM_API_SET_PER_PHY))) != NULL) { memset(p_msg, 0, sizeof(tBTA_DM_API_SET_PER_PHY)); p_msg->hdr.event = BTA_DM_API_SET_PER_PHY_EVT; @@ -2959,7 +3076,7 @@ void BTA_DmBleGapSetPreferedPHY(BD_ADDR addr, p_msg->tx_phy_mask = tx_phy_mask; p_msg->rx_phy_mask = rx_phy_mask; p_msg->phy_options = phy_options; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -2975,7 +3092,7 @@ void BTA_DmBleGapExtAdvSetRandaddr(UINT16 instance, BD_ADDR addr) p_msg->hdr.event = BTA_DM_API_SET_EXT_ADV_RAND_ADDR_EVT; p_msg->instance = instance; memcpy(&p_msg->rand_addr, addr, BD_ADDR_LEN); - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -2993,7 +3110,7 @@ void BTA_DmBleGapExtAdvSetParams(UINT16 instance, p_msg->hdr.event = BTA_DM_API_SET_EXT_ADV_PARAMS_EVT; p_msg->instance = instance; memcpy(&p_msg->params, params, sizeof(tBTA_DM_BLE_GAP_EXT_ADV_PARAMS)); - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3016,7 +3133,7 @@ void BTA_DmBleGapConfigExtAdvDataRaw(BOOLEAN is_scan_rsp, UINT8 instance, UINT16 if (data) { memcpy(p_msg->data, data, length); } - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3036,7 +3153,7 @@ void BTA_DmBleGapExtAdvEnable(BOOLEAN enable, UINT8 num, tBTA_DM_BLE_EXT_ADV *ex if (ext_adv) { memcpy(p_msg->ext_adv, ext_adv, sizeof(tBTA_DM_BLE_EXT_ADV)*num); } - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3051,7 +3168,7 @@ void BTA_DmBleGapExtAdvSetRemove(UINT8 instance) memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_EXT_ADV_SET_REMOVE)); p_msg->hdr.event = BTA_DM_API_EXT_ADV_SET_REMOVE_EVT; p_msg->instance = instance; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3065,7 +3182,7 @@ void BTA_DmBleGapExtAdvSetClear(void) if ((p_msg = (tBTA_DM_API_BLE_EXT_ADV_SET_CLEAR *) osi_malloc(sizeof(tBTA_DM_API_BLE_EXT_ADV_SET_CLEAR))) != NULL) { memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_EXT_ADV_SET_CLEAR)); p_msg->hdr.event = BTA_DM_API_EXT_ADV_SET_CLEAR_EVT; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3082,7 +3199,7 @@ void BTA_DmBleGapPeriodicAdvSetParams(UINT8 instance, p_msg->hdr.event = BTA_DM_API_PERIODIC_ADV_SET_PARAMS_EVT; p_msg->instance = instance; memcpy(&p_msg->params, params, sizeof(tBTA_DM_BLE_Periodic_Adv_Params)); - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3104,7 +3221,7 @@ void BTA_DmBleGapPeriodicAdvCfgDataRaw(UINT8 instance, UINT16 length, memcpy(p_msg->data, data, length); p_msg->data = length != 0 ? (UINT8 *)(p_msg + 1) : NULL; p_msg->only_update_did = only_update_did; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3121,7 +3238,7 @@ void BTA_DmBleGapPeriodicAdvEnable(UINT8 enable, UINT8 instance) p_msg->hdr.event = BTA_DM_API_PERIODIC_ADV_ENABLE_EVT; p_msg->instance = instance; p_msg->enable = enable; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3137,7 +3254,7 @@ void BTA_DmBleGapPeriodicAdvCreateSync(tBTA_DM_BLE_Periodic_Sync_Params *params) memset(p_msg, 0, sizeof(tBTA_DM_API_PERIODIC_ADV_SYNC)); p_msg->hdr.event = BTA_DM_API_PERIODIC_ADV_SYNC_EVT; memcpy(&p_msg->params, params, sizeof(tBTA_DM_BLE_Periodic_Sync_Params)); - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3152,7 +3269,7 @@ void BTA_DmBleGapPeriodicAdvSyncCancel(void) if ((p_msg = (tBTA_DM_API_PERIODIC_ADV_SYNC_CANCEL *) osi_malloc(sizeof(tBTA_DM_API_PERIODIC_ADV_SYNC_CANCEL))) != NULL) { memset(p_msg, 0, sizeof(tBTA_DM_API_PERIODIC_ADV_SYNC_CANCEL)); p_msg->hdr.event = BTA_DM_API_PERIODIC_ADV_SYNC_CANCEL_EVT; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3168,7 +3285,7 @@ void BTA_DmBleGapPeriodicAdvSyncTerm(UINT16 sync_handle) memset(p_msg, 0, sizeof(tBTA_DM_API_PERIODIC_ADV_SYNC_TERM)); p_msg->hdr.event = BTA_DM_API_PERIODIC_ADV_SYNC_TERMINATE_EVT; p_msg->sync_handle = sync_handle; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3188,7 +3305,7 @@ void BTA_DmBleGapPeriodicAdvAddDevToList(tBLE_ADDR_TYPE addr_type, p_msg->addr_type = addr_type; p_msg->sid = sid; memcpy(p_msg->addr, addr, sizeof(BD_ADDR)); - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3208,7 +3325,7 @@ void BTA_DmBleGapPeriodicAdvRemoveDevFromList(tBLE_ADDR_TYPE addr_type, p_msg->addr_type = addr_type; p_msg->sid = sid; memcpy(p_msg->addr, addr, sizeof(BD_ADDR)); - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3223,7 +3340,7 @@ void BTA_DmBleGapPeriodicAdvClearDev(void) if ((p_msg = (tBTA_DM_API_PERIODIC_ADV_DEV_CLEAR *) osi_malloc(sizeof(tBTA_DM_API_PERIODIC_ADV_DEV_CLEAR))) != NULL) { memset(p_msg, 0, sizeof(tBTA_DM_API_PERIODIC_ADV_DEV_CLEAR)); p_msg->hdr.event = BTA_DM_API_PERIODIC_ADV_CLEAR_DEV_EVT; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3239,7 +3356,7 @@ void BTA_DmBleGapSetExtScanParams(tBTA_DM_BLE_EXT_SCAN_PARAMS *params) memset(p_msg, 0, sizeof(tBTA_DM_API_SET_EXT_SCAN_PARAMS)); p_msg->hdr.event = BTA_DM_API_SET_EXT_SCAN_PARAMS_EVT; memcpy(&p_msg->params, params, sizeof(tBTA_DM_BLE_EXT_SCAN_PARAMS)); - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3257,7 +3374,7 @@ void BTA_DmBleGapExtScan(BOOLEAN start, UINT32 duration, UINT16 period) p_msg->start = start; p_msg->duration = duration; p_msg->period = period; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3291,7 +3408,7 @@ void BTA_DmBleGapPreferExtConnectParamsSet(BD_ADDR bd_addr, if (phy_coded_conn_params) { memcpy(&p_msg->phy_coded_conn_params, phy_coded_conn_params, sizeof(tBTA_DM_BLE_CONN_PARAMS)); } - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3310,7 +3427,7 @@ void BTA_DmBleGapExtConnect(tBLE_ADDR_TYPE own_addr_type, const BD_ADDR peer_add p_msg->hdr.event = BTA_DM_API_EXT_CONN_EVT; p_msg->own_addr_type = own_addr_type; memcpy(p_msg->peer_addr, peer_addr, sizeof(BD_ADDR)); - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3363,7 +3480,7 @@ void BTA_DmBleGapPeriodicAdvRecvEnable(UINT16 sync_handle, UINT8 enable) p_msg->hdr.event = BTA_DM_API_PERIODIC_ADV_RECV_ENABLE_EVT; p_msg->sync_handle = sync_handle; p_msg->enable = enable; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3380,7 +3497,7 @@ void BTA_DmBleGapPeriodicAdvSyncTrans(BD_ADDR peer_addr, UINT16 service_data, UI memcpy(p_msg->addr, peer_addr, sizeof(BD_ADDR)); p_msg->service_data = service_data; p_msg->sync_handle = sync_handle; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3397,7 +3514,7 @@ void BTA_DmBleGapPeriodicAdvSetInfoTrans(BD_ADDR peer_addr, UINT16 service_data, memcpy(p_msg->addr, peer_addr, sizeof(BD_ADDR)); p_msg->service_data = service_data; p_msg->adv_hanlde = adv_handle; - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); @@ -3413,7 +3530,7 @@ void BTA_DmBleGapSetPeriodicAdvSyncTransParams(BD_ADDR peer_addr, tBTA_DM_BLE_PA p_msg->hdr.event = BTA_DM_API_SET_PERIODIC_ADV_SYNC_TRANS_PARAMS_EVT; memcpy(p_msg->addr, peer_addr, sizeof(BD_ADDR)); memcpy(&p_msg->params, params, sizeof(tBTA_DM_BLE_PAST_PARAMS)); - //start sent the msg to the bta system control moudle + //start sent the msg to the bta system control module bta_sys_sendmsg(p_msg); } else { APPL_TRACE_ERROR("%s malloc failed", __func__); diff --git a/lib/bt/host/bluedroid/bta/dm/bta_dm_main.c b/lib/bt/host/bluedroid/bta/dm/bta_dm_main.c index 42e67d77..99736d8e 100644 --- a/lib/bt/host/bluedroid/bta/dm/bta_dm_main.c +++ b/lib/bt/host/bluedroid/bta/dm/bta_dm_main.c @@ -31,7 +31,9 @@ #include "osi/allocator.h" #include +#ifdef CONFIG_ESP_COEX_ENABLED #include "esp_coexist.h" +#endif /***************************************************************************** ** Constants and types @@ -65,11 +67,15 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = { #if (ESP_COEX_VSC_INCLUDED == TRUE) bta_dm_cfg_coex_status, /* BTA_DM_API_CFG_COEX_ST_EVT */ #endif + bta_dm_send_vendor_hci, /* BTA_DM_API_SEND_VENDOR_HCI_CMD_EVT */ #if (CLASSIC_BT_INCLUDED == TRUE) bta_dm_config_eir, /* BTA_DM_API_CONFIG_EIR_EVT */ bta_dm_set_page_timeout, /* BTA_DM_API_PAGE_TO_SET_EVT */ bta_dm_get_page_timeout, /* BTA_DM_API_PAGE_TO_GET_EVT */ bta_dm_set_acl_pkt_types, /* BTA_DM_API_SET_ACL_PKT_TYPES_EVT */ +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) + bta_dm_set_min_enc_key_size, /* BTA_DM_API_SET_MIN_ENC_KEY_SIZE_EVT */ +#endif #endif bta_dm_set_afh_channels, /* BTA_DM_API_SET_AFH_CHANNELS_EVT */ #if (SDP_INCLUDED == TRUE) @@ -87,7 +93,7 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = { bta_dm_pin_reply, /* BTA_DM_API_PIN_REPLY_EVT */ #endif ///SMP_INCLUDED == TRUE #if (BTA_DM_PM_INCLUDED == TRUE) - /* power manger events */ + /* power manager events */ bta_dm_pm_btm_status, /* BTA_DM_PM_BTM_STATUS_EVT */ bta_dm_pm_timer, /* BTA_DM_PM_TIMER_EVT */ #endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ @@ -226,6 +232,9 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = { bta_dm_ble_gap_dtm_rx_start, /* BTA_DM_API_DTM_RX_START_EVT */ bta_dm_ble_gap_dtm_stop, /* BTA_DM_API_DTM_STOP_EVT */ bta_dm_ble_gap_clear_adv, /* BTA_DM_API_BLE_CLEAR_ADV_EVT */ + bta_dm_ble_gap_set_rpa_timeout, /* BTA_DM_API_SET_RPA_TIMEOUT_EVT */ + bta_dm_ble_gap_add_dev_to_resolving_list, /* BTA_DM_API_ADD_DEV_TO_RESOLVING_LIST_EVT */ + bta_dm_ble_gap_set_privacy_mode, /* BTA_DM_API_SET_PRIVACY_MODE_EVT */ #endif }; diff --git a/lib/bt/host/bluedroid/bta/dm/include/bta_dm_int.h b/lib/bt/host/bluedroid/bta/dm/include/bta_dm_int.h index a46651d3..8adc430b 100644 --- a/lib/bt/host/bluedroid/bta/dm/include/bta_dm_int.h +++ b/lib/bt/host/bluedroid/bta/dm/include/bta_dm_int.h @@ -57,11 +57,15 @@ enum { #if (ESP_COEX_VSC_INCLUDED == TRUE) BTA_DM_API_CFG_COEX_ST_EVT, #endif + BTA_DM_API_SEND_VENDOR_HCI_CMD_EVT, #if (CLASSIC_BT_INCLUDED == TRUE) BTA_DM_API_CONFIG_EIR_EVT, BTA_DM_API_PAGE_TO_SET_EVT, BTA_DM_API_PAGE_TO_GET_EVT, BTA_DM_API_SET_ACL_PKT_TYPES_EVT, +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) + BTA_DM_API_SET_MIN_ENC_KEY_SIZE_EVT, +#endif #endif BTA_DM_API_SET_AFH_CHANNELS_EVT, #if (SDP_INCLUDED == TRUE) @@ -80,7 +84,7 @@ enum { BTA_DM_API_PIN_REPLY_EVT, #endif ///SMP_INCLUDED == TRUE #if (BTA_DM_PM_INCLUDED == TRUE) - /* power manger events */ + /* power manager events */ BTA_DM_PM_BTM_STATUS_EVT, BTA_DM_PM_TIMER_EVT, #endif /* #if (BTA_DM_PM_INCLUDED == TRUE) */ @@ -219,6 +223,9 @@ enum { BTA_DM_API_DTM_RX_START_EVT, BTA_DM_API_DTM_STOP_EVT, BTA_DM_API_BLE_CLEAR_ADV_EVT, + BTA_DM_API_SET_RPA_TIMEOUT_EVT, + BTA_DM_API_ADD_DEV_TO_RESOLVING_LIST_EVT, + BTA_DM_API_SET_PRIVACY_MODE_EVT, #endif BTA_DM_MAX_EVT }; @@ -249,11 +256,13 @@ typedef struct { typedef struct { BT_HDR hdr; BD_NAME name; /* max 248 bytes name, plus must be Null terminated */ + tBT_DEVICE_TYPE name_type; /* name for BLE, name for BT or name for BTDM */ } tBTA_DM_API_SET_NAME; typedef struct { - BT_HDR hdr; + BT_HDR hdr; tBTA_GET_DEV_NAME_CBACK *p_cback; + tBT_DEVICE_TYPE name_type; } tBTA_DM_API_GET_NAME; #if (ESP_COEX_VSC_INCLUDED == TRUE) @@ -265,6 +274,14 @@ typedef struct { } tBTA_DM_API_CFG_COEX_STATUS; #endif +typedef struct { + BT_HDR hdr; + UINT16 opcode; + UINT8 param_len; + UINT8 *p_param_buf; + tBTA_SEND_VENDOR_HCI_CMPL_CBACK *vendor_hci_cb; +}tBTA_DM_API_SEND_VENDOR_HCI_CMD; + /* data type for BTA_DM_API_CONFIG_EIR_EVT */ typedef struct { BT_HDR hdr; @@ -308,6 +325,15 @@ typedef struct { tBTM_CMPL_CB *set_acl_pkt_types_cb; } tBTA_DM_API_SET_ACL_PKT_TYPES; +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +/* data type for BTA_DM_API_SET_MIN_ENC_KEY_SIZE_EVT */ +typedef struct { + BT_HDR hdr; + UINT8 key_size; + tBTM_CMPL_CB *set_min_enc_key_size_cb; +} tBTA_DM_API_SET_MIN_ENC_KEY_SIZE; +#endif + /* data type for BTA_DM_API_GET_REMOTE_NAME_EVT */ typedef struct { BT_HDR hdr; @@ -660,7 +686,7 @@ typedef struct { tBTA_DM_BLE_SEL_CBACK *p_select_cback; } tBTA_DM_API_BLE_SET_BG_CONN_TYPE; -/* set prefered BLE connection parameters for a device */ +/* set preferred BLE connection parameters for a device */ typedef struct { BT_HDR hdr; BD_ADDR peer_bda; @@ -761,6 +787,20 @@ typedef struct { BT_HDR hdr; } tBTA_DM_APT_CLEAR_ADDR; +typedef struct { + BT_HDR hdr; + UINT16 rpa_timeout; + tBTA_SET_RPA_TIMEOUT_CMPL_CBACK *p_set_rpa_timeout_cback; +} tBTA_DM_API_SET_RPA_TIMEOUT; + +typedef struct { + BT_HDR hdr; // Event header + esp_bd_addr_t addr; // Bluetooth device address + UINT8 addr_type; // Type of the address + UINT8 irk[PEER_IRK_LEN]; // Identity Resolving Key (IRK) + tBTA_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK *p_add_dev_to_resolving_list_callback; // Callback function pointer +} tBTA_DM_API_ADD_DEV_TO_RESOLVING_LIST; + /* set adv parameter for BLE advertising */ typedef struct { BT_HDR hdr; @@ -911,6 +951,14 @@ typedef struct { tBTA_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cback; } tBTA_DM_API_CLEAR_ADV; +typedef struct { + BT_HDR hdr; + tBLE_ADDR_TYPE addr_type; + BD_ADDR addr; + UINT8 privacy_mode; + tBTA_SET_PRIVACY_MODE_CMPL_CBACK *p_cback; +} tBTA_DM_API_SET_PRIVACY_MODE; + #endif /* BLE_INCLUDED */ /* data type for BTA_DM_API_REMOVE_ACL_EVT */ @@ -1162,12 +1210,16 @@ typedef union { #if (ESP_COEX_VSC_INCLUDED == TRUE) tBTA_DM_API_CFG_COEX_STATUS cfg_coex_status; #endif + tBTA_DM_API_SEND_VENDOR_HCI_CMD vendor_hci_cmd; tBTA_DM_API_CONFIG_EIR config_eir; tBTA_DM_API_SET_AFH_CHANNELS set_afh_channels; tBTA_DM_API_PAGE_TO_SET set_page_timeout; tBTA_DM_API_PAGE_TO_GET get_page_timeout; tBTA_DM_API_SET_ACL_PKT_TYPES set_acl_pkt_types; +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) + tBTA_DM_API_SET_MIN_ENC_KEY_SIZE set_min_enc_key_size; +#endif #if (SDP_INCLUDED == TRUE) tBTA_DM_API_GET_REMOTE_NAME get_rmt_name; #endif @@ -1261,6 +1313,8 @@ typedef union { tBTA_DM_API_BLE_SET_DATA_LENGTH ble_set_data_length; tBTA_DM_APT_SET_DEV_ADDR set_addr; tBTA_DM_APT_CLEAR_ADDR clear_addr; + tBTA_DM_API_SET_RPA_TIMEOUT set_rpa_timeout; + tBTA_DM_API_ADD_DEV_TO_RESOLVING_LIST add_dev_to_resolving_list; tBTA_DM_API_BLE_MULTI_ADV_ENB ble_multi_adv_enb; tBTA_DM_API_BLE_MULTI_ADV_PARAM ble_multi_adv_param; tBTA_DM_API_BLE_MULTI_ADV_DATA ble_multi_adv_data; @@ -1310,6 +1364,7 @@ typedef union { tBTA_DM_API_BLE_DTM_RX_START dtm_rx_start; tBTA_DM_API_BLE_DTM_STOP dtm_stop; tBTA_DM_API_CLEAR_ADV ble_clear_adv; + tBTA_DM_API_SET_PRIVACY_MODE ble_set_privacy_mode; #endif tBTA_DM_API_REMOVE_ACL remove_acl; @@ -1444,7 +1499,7 @@ typedef struct { UINT32 role_policy_mask; /* the bits set indicates the modules that wants to remove role switch from the default link policy */ UINT16 cur_policy; /* current default link policy */ UINT16 rs_event; /* the event waiting for role switch */ - UINT8 cur_av_count; /* current AV connecions */ + UINT8 cur_av_count; /* current AV connections */ BOOLEAN disable_pair_mode; /* disable pair mode or not */ BOOLEAN conn_paired_only; /* allow connectable to paired device only or not */ tBTA_DM_API_SEARCH search_msg; @@ -1676,11 +1731,15 @@ extern void bta_dm_get_dev_name (tBTA_DM_MSG *p_data); #if (ESP_COEX_VSC_INCLUDED == TRUE) extern void bta_dm_cfg_coex_status(tBTA_DM_MSG *p_data); #endif +extern void bta_dm_send_vendor_hci(tBTA_DM_MSG *p_data); #if (CLASSIC_BT_INCLUDED == TRUE) extern void bta_dm_config_eir (tBTA_DM_MSG *p_data); extern void bta_dm_set_page_timeout (tBTA_DM_MSG *p_data); extern void bta_dm_get_page_timeout (tBTA_DM_MSG *p_data); extern void bta_dm_set_acl_pkt_types (tBTA_DM_MSG *p_data); +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +extern void bta_dm_set_min_enc_key_size (tBTA_DM_MSG *p_data); +#endif #endif extern void bta_dm_set_afh_channels (tBTA_DM_MSG *p_data); extern void bta_dm_read_rmt_name(tBTA_DM_MSG *p_data); @@ -1751,7 +1810,9 @@ extern void bta_dm_ble_gap_dtm_tx_start(tBTA_DM_MSG *p_data); extern void bta_dm_ble_gap_dtm_rx_start(tBTA_DM_MSG *p_data); extern void bta_dm_ble_gap_dtm_stop(tBTA_DM_MSG *p_data); extern void bta_dm_ble_gap_clear_adv(tBTA_DM_MSG *p_data); - +extern void bta_dm_ble_gap_set_rpa_timeout(tBTA_DM_MSG *p_data); +extern void bta_dm_ble_gap_add_dev_to_resolving_list(tBTA_DM_MSG *p_data); +extern void bta_dm_ble_gap_set_privacy_mode(tBTA_DM_MSG *p_data); #if (BLE_50_FEATURE_SUPPORT == TRUE) extern void bta_dm_ble_gap_dtm_enhance_tx_start(tBTA_DM_MSG *p_data); extern void bta_dm_ble_gap_dtm_enhance_rx_start(tBTA_DM_MSG *p_data); diff --git a/lib/bt/host/bluedroid/bta/hd/bta_hd_act.c b/lib/bt/host/bluedroid/bta/hd/bta_hd_act.c index 8f655d73..220b86cf 100644 --- a/lib/bt/host/bluedroid/bta/hd/bta_hd_act.c +++ b/lib/bt/host/bluedroid/bta/hd/bta_hd_act.c @@ -722,6 +722,26 @@ extern void bta_hd_exit_suspend_act(tBTA_HD_DATA *p_data) bta_sys_idle(BTA_ID_HD, 1, p_cback->addr); } +/******************************************************************************* + * + * Function bta_hd_open_failure + * + * Description + * + * Returns void + * + ******************************************************************************/ +extern void bta_hd_open_failure(tBTA_HD_DATA *p_data) +{ + tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data; + tBTA_HD cback_data = {0}; + + bdcpy(cback_data.conn.bda, p_cback->addr); + cback_data.conn.status = BTA_HD_ERROR; + cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTED; + bta_hd_cb.p_cback(BTA_HD_OPEN_EVT, &cback_data); +} + /******************************************************************************* * * Function bta_hd_cback diff --git a/lib/bt/host/bluedroid/bta/hd/bta_hd_main.c b/lib/bt/host/bluedroid/bta/hd/bta_hd_main.c index a6a3b634..7faaf2d6 100644 --- a/lib/bt/host/bluedroid/bta/hd/bta_hd_main.c +++ b/lib/bt/host/bluedroid/bta/hd/bta_hd_main.c @@ -62,6 +62,7 @@ enum { BTA_HD_VC_UNPLUG_DONE_ACT, BTA_HD_SUSPEND_ACT, BTA_HD_EXIT_SUSPEND_ACT, + BTA_HD_OPEN_FAILURE, BTA_HD_NUM_ACTIONS }; @@ -74,7 +75,7 @@ const tBTA_HD_ACTION bta_hd_action[] = { bta_hd_disconnect_act, bta_hd_add_device_act, bta_hd_remove_device_act, bta_hd_send_report_act, bta_hd_report_error_act, bta_hd_vc_unplug_act, bta_hd_open_act, bta_hd_close_act, bta_hd_intr_data_act, bta_hd_get_report_act, bta_hd_set_report_act, bta_hd_set_protocol_act, - bta_hd_vc_unplug_done_act, bta_hd_suspend_act, bta_hd_exit_suspend_act, + bta_hd_vc_unplug_done_act, bta_hd_suspend_act, bta_hd_exit_suspend_act, bta_hd_open_failure }; /* state table information */ @@ -118,7 +119,7 @@ const uint8_t bta_hd_st_idle[][BTA_HD_NUM_COLS] = { /* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST}, /* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_VC_UNPLUG_ACT, BTA_HD_IDLE_ST}, /* BTA_HD_INT_OPEN_EVT */ {BTA_HD_OPEN_ACT, BTA_HD_CONN_ST}, - /* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST}, + /* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_OPEN_FAILURE, BTA_HD_IDLE_ST}, /* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST}, /* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST}, /* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST}, diff --git a/lib/bt/host/bluedroid/bta/hd/include/bta_hd_int.h b/lib/bt/host/bluedroid/bta/hd/include/bta_hd_int.h index 7a515970..48ac7ed8 100644 --- a/lib/bt/host/bluedroid/bta/hd/include/bta_hd_int.h +++ b/lib/bt/host/bluedroid/bta/hd/include/bta_hd_int.h @@ -164,5 +164,6 @@ extern void bta_hd_set_protocol_act(tBTA_HD_DATA *p_data); extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA *p_data); extern void bta_hd_suspend_act(tBTA_HD_DATA *p_data); extern void bta_hd_exit_suspend_act(tBTA_HD_DATA *p_data); +extern void bta_hd_open_failure(tBTA_HD_DATA *p_data); #endif diff --git a/lib/bt/host/bluedroid/bta/hh/bta_hh_act.c b/lib/bt/host/bluedroid/bta/hh/bta_hh_act.c index 604b5e95..6d933ee8 100644 --- a/lib/bt/host/bluedroid/bta/hh/bta_hh_act.c +++ b/lib/bt/host/bluedroid/bta/hh/bta_hh_act.c @@ -276,7 +276,7 @@ static void bta_hh_di_sdp_cback(UINT16 result) bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product, di_rec.rec.version, 0); } - } else { /* no DI recrod available */ + } else { /* no DI record available */ bta_hh_update_di_info(p_cb, BTA_HH_VENDOR_ID_INVALID, 0, 0, 0); } @@ -358,7 +358,7 @@ void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) return; } - /* GetSDPRecord. at one time only one SDP precedure can be active */ + /* GetSDPRecord. at one time only one SDP procedure can be active */ else if (!bta_hh_cb.p_disc_db) { bta_hh_cb.p_disc_db = (tSDP_DISCOVERY_DB *) osi_malloc(p_bta_hh_cfg->sdp_db_size); @@ -429,6 +429,7 @@ void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) APPL_TRACE_DEBUG ("bta_hh_sdp_cmpl: HID_HostOpenDev failed: \ Status 0x%2X", ret); #endif + conn_dat.is_orig = HID_HostConnectOrig(p_cb->hid_handle); /* open fail, remove device from management device list */ HID_HostRemoveDev( p_cb->hid_handle); status = BTA_HH_ERR; @@ -452,8 +453,6 @@ void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) HID_HostRemoveDev( p_cb->incoming_hid_handle); } conn_dat.status = status; - /* check if host initiate the connection*/ - conn_dat.is_orig = !p_cb->incoming_conn; (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat); /* move state machine W4_CONN ->IDLE */ @@ -523,8 +522,7 @@ void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) memset((void *)&conn, 0, sizeof (tBTA_HH_CONN)); conn.handle = dev_handle; - /* check if host initiate the connection*/ - conn.is_orig = !p_cb->incoming_conn; + conn.is_orig = HID_HostConnectOrig(dev_handle); bdcpy(conn.bda, p_cb->addr); /* increase connection number */ @@ -596,7 +594,7 @@ void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) if (p_cb->app_id != 0) { bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, p_data); } else - /* app_id == 0 indicates an incoming conenction request arrives without SDP + /* app_id == 0 indicates an incoming connection request arrives without SDP performed, do it first */ { /* store the handle here in case sdp fails - need to disconnect */ @@ -637,7 +635,7 @@ void bta_hh_data_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) ** ** Function bta_hh_handsk_act ** -** Description HID Host process a handshake acknoledgement. +** Description HID Host process a handshake acknowledgement. ** ** ** Returns void @@ -674,7 +672,7 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) p_cb->w4_evt = 0; break; - /* acknoledgement from HID device for SET_ transaction */ + /* acknowledgement from HID device for SET_ transaction */ case BTA_HH_SET_RPT_EVT: case BTA_HH_SET_PROTO_EVT: case BTA_HH_SET_IDLE_EVT : @@ -693,8 +691,7 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) case BTA_HH_OPEN_EVT: conn.status = p_data->hid_cback.data ? BTA_HH_ERR_PROTO : BTA_HH_OK; conn.handle = p_cb->hid_handle; - /* check if host initiate the connection*/ - conn.is_orig = !p_cb->incoming_conn; + conn.is_orig = HID_HostConnectOrig(p_cb->hid_handle); bdcpy(conn.bda, p_cb->addr); (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&conn); #if BTA_HH_DEBUG @@ -704,12 +701,12 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) break; default: - /* unknow transaction handshake response */ + /* unknown transaction handshake response */ APPL_TRACE_DEBUG("unknown transaction type"); break; } - /* transaction achknoledgement received, inform PM for mode change */ + /* transaction acknowledgement received, inform PM for mode change */ bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr); return; } @@ -799,7 +796,7 @@ void bta_hh_open_failure(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR; /* check if host initiate the connection*/ - conn_dat.is_orig = !p_cb->incoming_conn; + conn_dat.is_orig = HID_HostConnectOrig(p_cb->hid_handle); bdcpy(conn_dat.bda, p_cb->addr); HID_HostCloseDev(p_cb->hid_handle); @@ -844,13 +841,13 @@ void bta_hh_close_act (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) /* Check reason for closing */ if ((reason & (HID_L2CAP_CONN_FAIL | HID_L2CAP_REQ_FAIL)) || /* Failure to initialize connection (page timeout or l2cap error) */ - (reason == HID_ERR_AUTH_FAILED) || /* Authenication error (while initiating) */ + (reason == HID_ERR_AUTH_FAILED) || /* Authentication error (while initiating) */ (reason == HID_ERR_L2CAP_FAILED)) { /* Failure creating l2cap connection */ /* Failure in opening connection */ conn_dat.handle = p_cb->hid_handle; conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR; /* check if host initiate the connection*/ - conn_dat.is_orig = !p_cb->incoming_conn; + conn_dat.is_orig = HID_HostConnectOrig(p_cb->hid_handle); bdcpy(conn_dat.bda, p_cb->addr); HID_HostCloseDev(p_cb->hid_handle); diff --git a/lib/bt/host/bluedroid/bta/hh/bta_hh_main.c b/lib/bt/host/bluedroid/bta/hh/bta_hh_main.c index 663d28e9..19f1045b 100644 --- a/lib/bt/host/bluedroid/bta/hh/bta_hh_main.c +++ b/lib/bt/host/bluedroid/bta/hh/bta_hh_main.c @@ -293,7 +293,7 @@ void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA *p_data) cback_data.conn.status = BTA_HH_ERR_DB_FULL; cback_data.conn.handle = BTA_HH_INVALID_HANDLE; /* check if host initiate the connection*/ - cback_data.conn.is_orig = !p_cb->incoming_conn; + cback_data.conn.is_orig = TRUE; break; /* DB full, BTA_HhAddDev */ case BTA_HH_API_MAINT_DEV_EVT: diff --git a/lib/bt/host/bluedroid/bta/include/bta/bta_api.h b/lib/bt/host/bluedroid/bta/include/bta/bta_api.h index 8ba75884..75a81994 100644 --- a/lib/bt/host/bluedroid/bta/include/bta/bta_api.h +++ b/lib/bt/host/bluedroid/bta/include/bta/bta_api.h @@ -398,7 +398,7 @@ typedef tBTM_BLE_128SERVICE tBTA_BLE_128SERVICE; typedef tBTM_BLE_32SERVICE tBTA_BLE_32SERVICE; typedef struct { - tBTA_BLE_INT_RANGE int_range; /* slave prefered conn interval range */ + tBTA_BLE_INT_RANGE int_range; /* slave preferred conn interval range */ tBTA_BLE_MANU *p_manu; /* manufacturer data */ tBTA_BLE_SERVICE *p_services; /* 16 bits services */ tBTA_BLE_128SERVICE *p_services_128b; /* 128 bits service */ @@ -417,6 +417,8 @@ typedef void (tBTA_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK) (tBTA_STATUS st typedef void (tBTA_SET_ADV_DATA_CMPL_CBACK) (tBTA_STATUS status); +typedef tBTM_VSC_CMPL_CB tBTA_SEND_VENDOR_HCI_CMPL_CBACK; + typedef tBTM_START_ADV_CMPL_CBACK tBTA_START_ADV_CMPL_CBACK; typedef tBTM_START_STOP_ADV_CMPL_CBACK tBTA_START_STOP_ADV_CMPL_CBACK; @@ -431,8 +433,16 @@ typedef tBTM_SET_RAND_ADDR_CBACK tBTA_SET_RAND_ADDR_CBACK; typedef tBTM_SET_LOCAL_PRIVACY_CBACK tBTA_SET_LOCAL_PRIVACY_CBACK; +typedef tBTM_SET_RPA_TIMEOUT_CMPL_CBACK tBTA_SET_RPA_TIMEOUT_CMPL_CBACK; + +typedef tBTM_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK tBTA_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK; + +typedef tBTM_SET_PRIVACY_MODE_CMPL_CBACK tBTA_SET_PRIVACY_MODE_CMPL_CBACK; + typedef tBTM_CMPL_CB tBTA_CMPL_CB; +typedef tBTM_VSC_CMPL tBTA_VSC_CMPL; + typedef tBTM_TX_POWER_RESULTS tBTA_TX_POWER_RESULTS; typedef tBTM_RSSI_RESULTS tBTA_RSSI_RESULTS; @@ -445,6 +455,10 @@ typedef tBTM_GET_PAGE_TIMEOUT_RESULTS tBTA_GET_PAGE_TIMEOUT_RESULTS; typedef tBTM_SET_ACL_PKT_TYPES_RESULTS tBTA_SET_ACL_PKT_TYPES_RESULTS; +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +typedef tBTM_SET_MIN_ENC_KEY_SIZE_RESULTS tBTA_SET_MIN_ENC_KEY_SIZE_RESULTS; +#endif + typedef tBTM_REMOTE_DEV_NAME tBTA_REMOTE_DEV_NAME; /* advertising channel map */ @@ -661,7 +675,7 @@ typedef UINT8 tBTA_SIG_STRENGTH_MASK; // btla-specific -- #define BTA_DM_DEV_UNPAIRED_EVT 25 /* BT unpair event */ #define BTA_DM_HW_ERROR_EVT 26 /* BT Chip H/W error */ -#define BTA_DM_LE_FEATURES_READ 27 /* Cotroller specific LE features are read */ +#define BTA_DM_LE_FEATURES_READ 27 /* Controller specific LE features are read */ #define BTA_DM_ENER_INFO_READ 28 /* Energy info read */ #define BTA_DM_BLE_DEV_UNPAIRED_EVT 29 /* BLE unpair event */ #define BTA_DM_SP_KEY_REQ_EVT 30 /* Simple Pairing Passkey request */ @@ -1107,7 +1121,7 @@ typedef struct { #define BTA_DM_INQ_RES_EVT 0 /* Inquiry result for a peer device. */ #define BTA_DM_INQ_CMPL_EVT 1 /* Inquiry complete. */ #define BTA_DM_DISC_RES_EVT 2 /* Discovery result for a peer device. */ -#define BTA_DM_DISC_BLE_RES_EVT 3 /* Discovery result for BLE GATT based servoce on a peer device. */ +#define BTA_DM_DISC_BLE_RES_EVT 3 /* Discovery result for BLE GATT based service on a peer device. */ #define BTA_DM_DISC_CMPL_EVT 4 /* Discovery complete. */ #define BTA_DM_DI_DISC_CMPL_EVT 5 /* Discovery complete. */ #define BTA_DM_SEARCH_CANCEL_CMPL_EVT 6 /* Search cancelled */ @@ -1716,7 +1730,7 @@ extern void BTA_DisableTestMode(void); ** Returns void ** *******************************************************************************/ -extern void BTA_DmSetDeviceName(const char *p_name); +extern void BTA_DmSetDeviceName(const char *p_name, tBT_DEVICE_TYPE name_type); /******************************************************************************* ** @@ -1728,7 +1742,7 @@ extern void BTA_DmSetDeviceName(const char *p_name); ** Returns void ** *******************************************************************************/ -extern void BTA_DmGetDeviceName(tBTA_GET_DEV_NAME_CBACK *p_cback); +extern void BTA_DmGetDeviceName(tBTA_GET_DEV_NAME_CBACK *p_cback, tBT_DEVICE_TYPE name_type); /******************************************************************************* ** @@ -1744,6 +1758,8 @@ extern void BTA_DmGetDeviceName(tBTA_GET_DEV_NAME_CBACK *p_cback); extern void BTA_DmCfgCoexStatus(UINT8 op, UINT8 type, UINT8 status); #endif +extern void BTA_DmsendVendorHciCmd(UINT16 opcode, UINT8 param_len, UINT8 *p_param_buf, tBTA_SEND_VENDOR_HCI_CMPL_CBACK p_vendor_cmd_complete_cback); + /******************************************************************************* ** ** Function BTA_DmGetRemoteName @@ -1829,6 +1845,20 @@ void BTA_DmGetPageTimeout(tBTM_CMPL_CB *p_cb); *******************************************************************************/ void BTA_DmSetAclPktTypes(BD_ADDR remote_addr, UINT16 pkt_types, tBTM_CMPL_CB *p_cb); +/******************************************************************************* +** +** Function BTA_DmSetMinEncKeySize +** +** Description This function sets the minimal size of encryption key. +** +** +** Returns void +** +*******************************************************************************/ +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +void BTA_DmSetMinEncKeySize(UINT8 key_size, tBTM_CMPL_CB *p_cb); +#endif + #if (BLE_INCLUDED == TRUE) /******************************************************************************* ** @@ -1929,7 +1959,7 @@ extern void BTA_DmDiscoverUUID(BD_ADDR bd_addr, tSDP_UUID *uuid, ** ** Function BTA_DmGetCachedRemoteName ** -** Description Retieve cached remote name if available +** Description Retrieve cached remote name if available ** ** Returns BTA_SUCCESS if cached name was retrieved ** BTA_FAILURE if cached name is not available @@ -2280,7 +2310,7 @@ extern void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type, tBTA_DM_B ** Description Send BLE SMP passkey reply. ** ** Parameters: bd_addr - BD address of the peer -** accept - passkey entry sucessful or declined. +** accept - passkey entry successful or declined. ** passkey - passkey value, must be a 6 digit number, ** can be lead by 0. ** @@ -2446,7 +2476,7 @@ extern void BTA_DmSetBleScanFilterParams(tGATT_IF client_if, UINT32 scan_interva ** ** Parameters: adv_int_min - adv interval minimum ** adv_int_max - adv interval max -** p_dir_bda - directed adv initator address +** p_dir_bda - directed adv initiator address ** ** Returns void ** @@ -2472,7 +2502,7 @@ extern void BTA_DmSetBleAdvParamsAll (UINT16 adv_int_min, UINT16 adv_int_max, ** services: if service is not empty, service discovery will be done. ** for all GATT based service condition, put num_uuid, and ** p_uuid is the pointer to the list of UUID values. -** p_cback: callback functino when search is completed. +** p_cback: callback function when search is completed. ** ** ** @@ -2531,7 +2561,7 @@ extern void BTA_DmDiscoverByTransport(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_ ** ** Parameters: bd_addr - Address of the peer device ** transport - transport of the link to be encruypted -** p_callback - Pointer to callback function to indicat the +** p_callback - Pointer to callback function to indicate the ** link encryption status ** sec_act - This is the security action to indicate ** what knid of BLE security level is required for @@ -2588,7 +2618,11 @@ extern void BTA_DmBleStopAdvertising(void); extern void BTA_DmSetRandAddress(BD_ADDR rand_addr, tBTA_SET_RAND_ADDR_CBACK *p_set_rand_addr_cback); extern void BTA_DmClearRandAddress(void); - +extern void BTA_DmBleSetRpaTimeout(uint16_t rpa_timeout,tBTA_SET_RPA_TIMEOUT_CMPL_CBACK *p_set_rpa_timeout_cback); +extern void BTA_DmBleAddDevToResolvingList(BD_ADDR addr, + uint8_t addr_type, + PEER_IRK irk, + tBTA_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK *add_dev_to_resolving_list_callback); #endif #if BLE_INCLUDED == TRUE @@ -2599,7 +2633,7 @@ extern void BTA_DmClearRandAddress(void); ** ** Description Enable/disable privacy on the local device ** -** Parameters: privacy_enable - enable/disabe privacy on remote device. +** Parameters: privacy_enable - enable/disable privacy on remote device. ** set_local_privacy_cback -callback to be called with result ** Returns void ** @@ -2626,7 +2660,7 @@ extern void BTA_DmBleConfigLocalIcon(uint16_t icon); ** Description Enable/disable privacy on a remote device ** ** Parameters: bd_addr - BD address of the peer -** privacy_enable - enable/disabe privacy on remote device. +** privacy_enable - enable/disable privacy on remote device. ** ** Returns void ** @@ -2861,6 +2895,8 @@ extern void BTA_DmBleDtmTxStart(uint8_t tx_channel, uint8_t len_of_data, uint8_t extern void BTA_DmBleDtmRxStart(uint8_t rx_channel, tBTA_DTM_CMD_CMPL_CBACK *p_dtm_cmpl_cback); extern void BTA_DmBleDtmStop(tBTA_DTM_CMD_CMPL_CBACK *p_dtm_cmpl_cback); +extern void BTA_DmBleSetPrivacyMode(uint8_t addr_type, BD_ADDR addr, uint8_t privacy_mode, tBTA_SET_PRIVACY_MODE_CMPL_CBACK *p_cback); + /******************************************************************************* ** ** Function BTA_DmBleSetStorageParams diff --git a/lib/bt/host/bluedroid/bta/jv/bta_jv_api.c b/lib/bt/host/bluedroid/bta/jv/bta_jv_api.c index c0bd066d..74195015 100644 --- a/lib/bt/host/bluedroid/bta/jv/bta_jv_api.c +++ b/lib/bt/host/bluedroid/bta/jv/bta_jv_api.c @@ -19,7 +19,7 @@ /****************************************************************************** * * This is the implementation of the JAVA API for Bluetooth Wireless - * Technology (JABWT) as specified by the JSR82 specificiation + * Technology (JABWT) as specified by the JSR82 specification * ******************************************************************************/ @@ -118,6 +118,11 @@ void BTA_JvDisable(tBTA_JV_RFCOMM_CBACK *p_cback) APPL_TRACE_API( "BTA_JvDisable"); bta_sys_deregister(BTA_ID_JV); + memset(&bta_jv_cb, 0, sizeof(tBTA_JV_CB)); + /* set handle to invalid value by default */ + for (int i = 0; i < BTA_JV_PM_MAX_NUM; i++) { + bta_jv_cb.pm_cb[i].handle = BTA_JV_PM_HANDLE_CLEAR; + } if ((p_buf = (tBTA_JV_API_DISABLE *) osi_malloc(sizeof(tBTA_JV_API_DISABLE))) != NULL) { p_buf->hdr.event = BTA_JV_API_DISABLE_EVT; p_buf->p_cback = p_cback; @@ -893,7 +898,7 @@ tBTA_JV_STATUS BTA_JvRfcommConfig(BOOLEAN enable_l2cap_ertm) ** ** Function BTA_JvRfcommConnect ** -** Description This function makes an RFCOMM conection to a remote BD +** Description This function makes an RFCOMM connection to a remote BD ** Address. ** When the connection is initiated or failed to initiate, ** tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_CL_INIT_EVT @@ -1204,7 +1209,7 @@ tBTA_JV_STATUS BTA_JvRfcommFlowControl(UINT32 handle, UINT16 credits_given) ** Parameters: handle, JV handle from RFCOMM or L2CAP ** app_id: app specific pm ID, can be BTA_JV_PM_ALL, see bta_dm_cfg.c for details ** BTA_JV_PM_ID_CLEAR: removes pm management on the handle. init_st is ignored and - ** BTA_JV_CONN_CLOSE is called implicitely + ** BTA_JV_CONN_CLOSE is called implicitly ** init_st: state after calling this API. typically it should be BTA_JV_CONN_OPEN ** ** Returns BTA_JV_SUCCESS, if the request is being processed. diff --git a/lib/bt/host/bluedroid/btc/core/btc_dev.c b/lib/bt/host/bluedroid/btc/core/btc_dev.c index 1aceface..18cda3e0 100644 --- a/lib/bt/host/bluedroid/btc/core/btc_dev.c +++ b/lib/bt/host/bluedroid/btc/core/btc_dev.c @@ -1,32 +1,132 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include "osi/allocator.h" +#include "stack/bt_types.h" #include "bta/bta_api.h" #include "btc/btc_task.h" #include "btc/btc_manage.h" +#include "btc/btc_util.h" #include "btc/btc_dev.h" -void btc_dev_arg_deep_free(btc_msg_t *msg) +static inline void btc_dev_cb_to_app(esp_bt_dev_cb_event_t event, esp_bt_dev_cb_param_t *param) +{ + esp_bt_dev_cb_t btc_bt_dev_cb = (esp_bt_dev_cb_t)btc_profile_cb_get(BTC_PID_DEV); + if (btc_bt_dev_cb) { + btc_bt_dev_cb(event, param); + } +} + +static void btc_dev_get_dev_name_callback(UINT8 status, char *name) +{ + esp_bt_dev_cb_param_t param; + bt_status_t ret; + btc_msg_t msg = {0}; + + memset(¶m, 0, sizeof(esp_bt_dev_cb_param_t)); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_DEV; + msg.act = ESP_BT_DEV_NAME_RES_EVT; + + param.name_res.status = btc_btm_status_to_esp_status(status); + param.name_res.name = name; + + ret = btc_transfer_context(&msg, ¶m, sizeof(esp_bt_dev_cb_param_t), btc_dev_cb_arg_deep_copy, btc_dev_cb_arg_deep_free); + if (ret != BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + +void btc_dev_call_arg_deep_free(btc_msg_t *msg) { BTC_TRACE_DEBUG("%s \n", __func__); + btc_dev_args_t *arg = (btc_dev_args_t *)msg->arg; switch (msg->act) { case BTC_DEV_ACT_SET_DEVICE_NAME:{ - char *device_name = ((btc_dev_args_t *)msg->arg)->set_dev_name.device_name; - if (device_name) { - osi_free(device_name); + if (arg->set_dev_name.device_name) { + osi_free(arg->set_dev_name.device_name); } break; } + case BTC_DEV_ACT_GET_DEVICE_NAME: #if (ESP_COEX_VSC_INCLUDED == TRUE) case BTC_DEV_ACT_CFG_COEX_STATUS: +#endif + break; + default: + BTC_TRACE_DEBUG("Unhandled deep free %d\n", msg->act); break; + } +} + +void btc_dev_call_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + BTC_TRACE_DEBUG("%s \n", __func__); + btc_dev_args_t *dst = (btc_dev_args_t *)p_dest; + btc_dev_args_t *src = (btc_dev_args_t *)p_src; + + switch (msg->act) { + case BTC_DEV_ACT_SET_DEVICE_NAME:{ + dst->set_dev_name.device_name = (char *)osi_malloc((BTC_MAX_LOC_BD_NAME_LEN + 1) * sizeof(char)); + if (dst->set_dev_name.device_name) { + BCM_STRNCPY_S(dst->set_dev_name.device_name, src->set_dev_name.device_name, BTC_MAX_LOC_BD_NAME_LEN); + dst->set_dev_name.device_name[BTC_MAX_LOC_BD_NAME_LEN] = '\0'; + } else { + BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act); + } + break; + } + case BTC_DEV_ACT_GET_DEVICE_NAME: +#if (ESP_COEX_VSC_INCLUDED == TRUE) + case BTC_DEV_ACT_CFG_COEX_STATUS: #endif + break; + default: + BTC_TRACE_ERROR("Unhandled deep copy %d\n", msg->act); + break; + } +} + +void btc_dev_cb_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_bt_dev_cb_param_t *src = (esp_bt_dev_cb_param_t *)p_src; + esp_bt_dev_cb_param_t *dst = (esp_bt_dev_cb_param_t *) p_dest; + + switch (msg->act) { + case ESP_BT_DEV_NAME_RES_EVT:{ + dst->name_res.name = (char *)osi_malloc((BTC_MAX_LOC_BD_NAME_LEN + 1) * sizeof(char)); + if (dst->name_res.name) { + BCM_STRNCPY_S(dst->name_res.name, src->name_res.name, BTC_MAX_LOC_BD_NAME_LEN); + dst->name_res.name[BTC_MAX_LOC_BD_NAME_LEN] = '\0'; + } else { + BTC_TRACE_ERROR("%s, malloc failed\n", __func__); + } + break; + } + default: + BTC_TRACE_ERROR("%s, Unhandled deep copy %d\n", __func__, msg->act); + break; + } +} + +void btc_dev_cb_arg_deep_free(btc_msg_t *msg) +{ + BTC_TRACE_DEBUG("%s \n", __func__); + + switch (msg->act) { + case ESP_BT_DEV_NAME_RES_EVT:{ + char *name = ((esp_bt_dev_cb_param_t *)msg->arg)->name_res.name; + if (name) { + osi_free(name); + } + break; + } default: BTC_TRACE_DEBUG("Unhandled deep free %d\n", msg->act); break; @@ -41,7 +141,10 @@ void btc_dev_call_handler(btc_msg_t *msg) switch (msg->act) { case BTC_DEV_ACT_SET_DEVICE_NAME: - BTA_DmSetDeviceName(arg->set_dev_name.device_name); + BTA_DmSetDeviceName(arg->set_dev_name.device_name, BT_DEVICE_TYPE_DUMO); + break; + case BTC_DEV_ACT_GET_DEVICE_NAME: + BTA_DmGetDeviceName(btc_dev_get_dev_name_callback, BT_DEVICE_TYPE_DUMO); break; #if (ESP_COEX_VSC_INCLUDED == TRUE) case BTC_DEV_ACT_CFG_COEX_STATUS: @@ -54,5 +157,18 @@ void btc_dev_call_handler(btc_msg_t *msg) break; } - btc_dev_arg_deep_free(msg); + btc_dev_call_arg_deep_free(msg); +} + +void btc_dev_cb_handler(btc_msg_t *msg) +{ + esp_bt_dev_cb_param_t *param = (esp_bt_dev_cb_param_t *)msg->arg; + + if (msg->act < ESP_BT_DEV_EVT_MAX) { + btc_dev_cb_to_app(msg->act, param); + } else { + BTC_TRACE_ERROR("%s, unknown msg->act = %d", __func__, msg->act); + } + + btc_dev_cb_arg_deep_free(msg); } diff --git a/lib/bt/host/bluedroid/btc/core/btc_dm.c b/lib/bt/host/bluedroid/btc/core/btc_dm.c index b0afdad8..7e242a73 100644 --- a/lib/bt/host/bluedroid/btc/core/btc_dm.c +++ b/lib/bt/host/bluedroid/btc/core/btc_dm.c @@ -10,6 +10,7 @@ #include "btc/btc_common.h" #include "btc/btc_dm.h" #include "btc/btc_main.h" +#include "btc/btc_util.h" #include "common/bt_trace.h" #include "common/bt_target.h" #include "btc/btc_storage.h" @@ -717,14 +718,14 @@ static void btc_dm_acl_link_stat(tBTA_DM_ACL_LINK_STAT *p_acl_link_stat) switch (p_acl_link_stat->event) { case BTA_ACL_LINK_STAT_CONN_CMPL: { event = ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT; - param.acl_conn_cmpl_stat.stat = p_acl_link_stat->link_act.conn_cmpl.status | ESP_BT_STATUS_BASE_FOR_HCI_ERR; + param.acl_conn_cmpl_stat.stat = btc_hci_to_esp_status(p_acl_link_stat->link_act.conn_cmpl.status); param.acl_conn_cmpl_stat.handle = p_acl_link_stat->link_act.conn_cmpl.handle; memcpy(param.acl_conn_cmpl_stat.bda, p_acl_link_stat->link_act.conn_cmpl.bd_addr, ESP_BD_ADDR_LEN); break; } case BTA_ACL_LINK_STAT_DISCONN_CMPL: { event = ESP_BT_GAP_ACL_DISCONN_CMPL_STAT_EVT; - param.acl_disconn_cmpl_stat.reason = p_acl_link_stat->link_act.disconn_cmpl.reason | ESP_BT_STATUS_BASE_FOR_HCI_ERR; + param.acl_disconn_cmpl_stat.reason = btc_hci_to_esp_status(p_acl_link_stat->link_act.disconn_cmpl.reason); param.acl_disconn_cmpl_stat.handle = p_acl_link_stat->link_act.disconn_cmpl.handle; memcpy(param.acl_disconn_cmpl_stat.bda, p_acl_link_stat->link_act.disconn_cmpl.bd_addr, ESP_BD_ADDR_LEN); break; @@ -788,7 +789,7 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) /* Set initial device name, it can be overwritten later */ if (p_data->enable.status == BTA_SUCCESS) { const char *initial_device_name = "ESP32"; - BTA_DmSetDeviceName(initial_device_name); + BTA_DmSetDeviceName(initial_device_name, BT_DEVICE_TYPE_DUMO); } btc_enable_bluetooth_evt(p_data->enable.status); break; diff --git a/lib/bt/host/bluedroid/btc/core/btc_main.c b/lib/bt/host/bluedroid/btc/core/btc_main.c index 0b9b016d..28f70b4b 100644 --- a/lib/bt/host/bluedroid/btc/core/btc_main.c +++ b/lib/bt/host/bluedroid/btc/core/btc_main.c @@ -141,18 +141,34 @@ uint32_t btc_get_ble_status(void) } #if (SMP_INCLUDED == TRUE) + // Number of recorded devices + extern uint8_t btm_ble_sec_dev_active_count(void); + if (btm_ble_sec_dev_active_count()) { + status |= BIT(BTC_BLE_STATUS_KEYS); + } + // Number of saved bonded devices if (btc_storage_get_num_ble_bond_devices()) { status |= BIT(BTC_BLE_STATUS_BOND); } #endif + + #if (BLE_PRIVACY_SPT == TRUE) + // Privacy enabled + extern uint8_t btm_ble_privacy_is_enabled(void); + if (btm_ble_privacy_is_enabled()) { + status |= BIT(BTC_BLE_STATUS_PRIVACY); + } + #endif #endif - // Number of recorded devices - extern uint8_t btdm_sec_dev_active_count(void); - if (btdm_sec_dev_active_count()) { - status |= BIT(BTC_BLE_STATUS_DEV); + #if (BLE_50_FEATURE_SUPPORT == TRUE) + // Number of active extended advertsing + extern uint8_t btm_ble_ext_adv_active_count(void); + if (btm_ble_ext_adv_active_count()) { + status |= BIT(BTC_BLE_STATUS_EXT_ADV); } + #endif // Number of active ACL connection extern uint8_t btm_acl_active_count(void); diff --git a/lib/bt/host/bluedroid/btc/core/btc_util.c b/lib/bt/host/bluedroid/btc/core/btc_util.c index 9818e706..5e29aba8 100644 --- a/lib/bt/host/bluedroid/btc/core/btc_util.c +++ b/lib/bt/host/bluedroid/btc/core/btc_util.c @@ -338,8 +338,11 @@ esp_bt_status_t btc_hci_to_esp_status(uint8_t hci_status) case HCI_ERR_ILLEGAL_PARAMETER_FMT: esp_status = ESP_BT_STATUS_ERR_ILLEGAL_PARAMETER_FMT; break; + case HCI_ERR_UNSUPPORTED_VALUE: + esp_status = ESP_BT_STATUS_UNSUPPORTED; + break; default: - esp_status = ESP_BT_STATUS_FAIL; + esp_status = hci_status | ESP_BT_STATUS_BASE_FOR_HCI_ERR; break; } diff --git a/lib/bt/host/bluedroid/btc/include/btc/btc_dev.h b/lib/bt/host/bluedroid/btc/include/btc/btc_dev.h index 4cf085d7..f213309c 100644 --- a/lib/bt/host/bluedroid/btc/include/btc/btc_dev.h +++ b/lib/bt/host/bluedroid/btc/include/btc/btc_dev.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,7 @@ typedef enum { BTC_DEV_ACT_SET_DEVICE_NAME, + BTC_DEV_ACT_GET_DEVICE_NAME, #if (ESP_COEX_VSC_INCLUDED == TRUE) BTC_DEV_ACT_CFG_COEX_STATUS, #endif @@ -36,5 +37,10 @@ typedef union { } btc_dev_args_t; void btc_dev_call_handler(btc_msg_t *msg); +void btc_dev_cb_handler(btc_msg_t *msg); +void btc_dev_call_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); +void btc_dev_call_arg_deep_free(btc_msg_t *msg); +void btc_dev_cb_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); +void btc_dev_cb_arg_deep_free(btc_msg_t *msg); #endif /* __BTC_DEV_H__ */ diff --git a/lib/bt/host/bluedroid/btc/include/btc/btc_main.h b/lib/bt/host/bluedroid/btc/include/btc/btc_main.h index 935dc77e..df20a638 100644 --- a/lib/bt/host/bluedroid/btc/include/btc/btc_main.h +++ b/lib/bt/host/bluedroid/btc/include/btc/btc_main.h @@ -31,13 +31,15 @@ typedef enum { #define BTC_BLE_STATUS_IDLE 0 typedef enum { BTC_BLE_STATUS_ADV = 0, // Advertising exist + BTC_BLE_STATUS_EXT_ADV, // Extended advertising exist BTC_BLE_STATUS_SCAN, // Scanning exist BTC_BLE_STATUS_CONN, // Connection exist - BTC_BLE_STATUS_DEV, // Device record exist + BTC_BLE_STATUS_KEYS, // Device keys record exist BTC_BLE_STATUS_BOND, // Bond info exist BTC_BLE_STATUS_GATTC_CACHE, // GATTC cache exist BTC_BLE_STATUS_GATTC_APP, // GATTC application exist BTC_BLE_STATUS_GATTS_SRVC, // GATTS service exist + BTC_BLE_STATUS_PRIVACY, // Privacy enabled } tBTC_BLE_STATUS; future_t **btc_main_get_future_p(btc_main_future_type_t type); diff --git a/lib/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c b/lib/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c index 626ea473..4fcdd5b7 100644 --- a/lib/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c +++ b/lib/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c @@ -74,11 +74,11 @@ enum { /* Media task tick in milliseconds, must be set to multiple of (1000/TICKS_PER_SEC) */ -#define BTC_MEDIA_TIME_TICK_MS (30) +#define BTC_MEDIA_TIME_TICK_MS (20) #define A2DP_DATA_READ_POLL_MS (BTC_MEDIA_TIME_TICK_MS / 2) #ifndef MAX_PCM_FRAME_NUM_PER_TICK -#define MAX_PCM_FRAME_NUM_PER_TICK 21 // 14 for 20ms +#define MAX_PCM_FRAME_NUM_PER_TICK 14 // 14 for 20ms #endif #define BTC_MEDIA_AA_BUF_SIZE (4096+16) @@ -97,8 +97,8 @@ enum { #define BTC_A2DP_NON_EDR_MAX_RATE 229 #endif -/* Middle quality quality setting @ 44.1 khz */ -#define DEFAULT_SBC_BITRATE 328 +/* Extreme quality quality setting @ 48 khz */ +#define DEFAULT_SBC_BITRATE 672 /* * CONGESTION COMPENSATION CTRL :: @@ -120,8 +120,7 @@ enum { layers we might need to temporarily buffer up data */ /* 5 frames is equivalent to 6.89*5*2.9 ~= 100 ms @ 44.1 khz, 20 ms mediatick */ -#define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ (5) -#define MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ (27) // 18 for 20ms tick +#define MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ (50) // 18 for 20ms tick #define BTC_A2DP_SRC_DATA_QUEUE_IDX (1) diff --git a/lib/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/lib/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 2e6c7b8d..53d0b835 100644 --- a/lib/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/lib/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -891,6 +891,40 @@ static void btc_set_local_privacy_callback(UINT8 status) } } +static void btc_set_rpa_timeout_callback(UINT8 status) +{ + esp_ble_gap_cb_param_t param; + bt_status_t ret; + btc_msg_t msg = {0}; + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BLE; + msg.act = ESP_GAP_BLE_SET_RPA_TIMEOUT_COMPLETE_EVT; + param.set_rpa_timeout_cmpl.status = btc_btm_status_to_esp_status(status); + ret = btc_transfer_context(&msg, ¶m, + sizeof(esp_ble_gap_cb_param_t), NULL, NULL); + if (ret != BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + +static void btc_add_dev_to_resolving_list_callback(UINT8 status) +{ + esp_ble_gap_cb_param_t param; + bt_status_t ret; + btc_msg_t msg = {0}; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BLE; + msg.act = ESP_GAP_BLE_ADD_DEV_TO_RESOLVING_LIST_COMPLETE_EVT; + + param.add_dev_to_resolving_list_cmpl.status = btc_btm_status_to_esp_status(status); + + ret = btc_transfer_context(&msg, ¶m, sizeof(esp_ble_gap_cb_param_t), NULL, NULL); + + if (ret != BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); + } +} #if (SMP_INCLUDED == TRUE) static void btc_set_encryption_callback(BD_ADDR bd_addr, tBTA_TRANSPORT transport, tBTA_STATUS enc_status) @@ -1067,7 +1101,7 @@ static void btc_ble_5_gap_callback(tBTA_DM_BLE_5_GAP_EVENT event, break; case BTA_DM_BLE_5_GAP_EXT_ADV_REPORT_EVT: msg.act = ESP_GAP_BLE_EXT_ADV_REPORT_EVT; - memcpy(¶m.ext_adv_report.params, ¶ms->ext_adv_report, sizeof(esp_ble_gap_ext_adv_reprot_t)); + memcpy(¶m.ext_adv_report.params, ¶ms->ext_adv_report, sizeof(esp_ble_gap_ext_adv_report_t)); if (params->ext_adv_report.adv_data) { memcpy(param.ext_adv_report.params.adv_data, params->ext_adv_report.adv_data, params->ext_adv_report.adv_data_len); @@ -1256,6 +1290,61 @@ void btc_dtm_stop_callback(void *p1) } } +static void btc_ble_vendor_hci_cmd_complete_callback(tBTA_VSC_CMPL *p_param) +{ + bool param_invalid = false; + if ((!p_param) || (!p_param->param_len) || (!p_param->p_param_buf)) { + BTC_TRACE_ERROR("%s param error\n", __func__); + param_invalid = true; + } + + esp_ble_gap_cb_param_t param = {0}; + bt_status_t ret; + btc_msg_t msg = {0}; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BLE; + msg.act = ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT; + if (!param_invalid) { + param.vendor_cmd_cmpl.opcode = p_param->opcode; + param.vendor_cmd_cmpl.param_len = p_param->param_len; + param.vendor_cmd_cmpl.p_param_buf = p_param->p_param_buf; + } else { + if (p_param) { + param.vendor_cmd_cmpl.opcode = p_param->opcode; + } else { + param.vendor_cmd_cmpl.opcode = 0; + } + param.vendor_cmd_cmpl.param_len = 0; + param.vendor_cmd_cmpl.p_param_buf = NULL; + } + + ret = btc_transfer_context(&msg, ¶m, sizeof(esp_ble_gap_cb_param_t), btc_gap_ble_cb_deep_copy, btc_gap_ble_cb_deep_free); + + if (ret != BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + +static void btc_ble_set_privacy_mode_callback(UINT8 status) +{ + esp_ble_gap_cb_param_t param; + bt_status_t ret; + btc_msg_t msg = {0}; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BLE; + msg.act = ESP_GAP_BLE_SET_PRIVACY_MODE_COMPLETE_EVT; + + param.set_privacy_mode_cmpl.status = btc_btm_status_to_esp_status(status); + + ret = btc_transfer_context(&msg, ¶m, sizeof(esp_ble_gap_cb_param_t), NULL, NULL); + + if (ret != BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + void btc_get_whitelist_size(uint16_t *length) { BTM_BleGetWhiteListSize(length); @@ -1369,6 +1458,19 @@ static void btc_ble_set_rand_addr (BD_ADDR rand_addr, tBTA_SET_RAND_ADDR_CBACK * } } +static void btc_ble_set_rpa_timeout(uint16_t rpa_timeout,tBTA_SET_RPA_TIMEOUT_CMPL_CBACK *set_rpa_timeout_cback) +{ + BTA_DmBleSetRpaTimeout(rpa_timeout,set_rpa_timeout_cback); +} + +static void btc_ble_add_device_to_resolving_list(BD_ADDR addr, + uint8_t addr_type, + uint8_t irk[], + tBTA_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK *add_dev_to_resolving_list_callback) +{ + BTA_DmBleAddDevToResolvingList(addr, addr_type, irk, add_dev_to_resolving_list_callback); +} + static void btc_ble_clear_rand_addr (void) { BTA_DmClearRandAddress(); @@ -1421,6 +1523,13 @@ static void btc_ble_dtm_stop(tBTA_DTM_CMD_CMPL_CBACK *p_dtm_cmpl_cback) BTA_DmBleDtmStop(p_dtm_cmpl_cback); } +static void btc_ble_set_privacy_mode(uint8_t addr_type, + BD_ADDR addr, + uint8_t privacy_mode, + tBTA_SET_PRIVACY_MODE_CMPL_CBACK *p_cback) +{ + BTA_DmBleSetPrivacyMode(addr_type, addr, privacy_mode, p_cback); +} void btc_gap_ble_cb_handler(btc_msg_t *msg) { @@ -1429,7 +1538,7 @@ void btc_gap_ble_cb_handler(btc_msg_t *msg) if (msg->act < ESP_GAP_BLE_EVT_MAX) { btc_gap_ble_cb_to_app(msg->act, param); } else { - BTC_TRACE_ERROR("%s, unknow msg->act = %d", __func__, msg->act); + BTC_TRACE_ERROR("%s, unknown msg->act = %d", __func__, msg->act); } btc_gap_ble_cb_deep_free(msg); @@ -1598,6 +1707,31 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) break; } #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) + case BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT: { + btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src; + btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *)p_dest; + if (src->vendor_cmd_send.param_len) { + dst->vendor_cmd_send.p_param_buf = osi_malloc(src->vendor_cmd_send.param_len); + if (dst->vendor_cmd_send.p_param_buf) { + memcpy(dst->vendor_cmd_send.p_param_buf, src->vendor_cmd_send.p_param_buf, src->vendor_cmd_send.param_len); + } else { + BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act); + } + } + break; + } + case BTC_GAP_BLE_ACT_SET_DEV_NAME:{ + btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src; + btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *)p_dest; + dst->set_dev_name.device_name = (char *)osi_malloc((BTC_MAX_LOC_BD_NAME_LEN + 1) * sizeof(char)); + if (dst->set_dev_name.device_name) { + BCM_STRNCPY_S(dst->set_dev_name.device_name, src->set_dev_name.device_name, BTC_MAX_LOC_BD_NAME_LEN); + dst->set_dev_name.device_name[BTC_MAX_LOC_BD_NAME_LEN] = '\0'; + } else { + BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act); + } + break; + } default: BTC_TRACE_ERROR("Unhandled deep copy %d\n", msg->act); break; @@ -1606,7 +1740,22 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) void btc_gap_ble_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) { + esp_ble_gap_cb_param_t *src = (esp_ble_gap_cb_param_t *)p_src; + esp_ble_gap_cb_param_t *dst = (esp_ble_gap_cb_param_t *) p_dest; + switch (msg->act) { + case ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT: { + if (src->vendor_cmd_cmpl.param_len) { + dst->vendor_cmd_cmpl.p_param_buf = osi_malloc(src->vendor_cmd_cmpl.param_len); + if (dst->vendor_cmd_cmpl.p_param_buf) { + memcpy(dst->vendor_cmd_cmpl.p_param_buf, src->vendor_cmd_cmpl.p_param_buf, + src->vendor_cmd_cmpl.param_len); + } else { + BTC_TRACE_ERROR("%s, malloc failed\n", __func__); + } + } + break; + } default: BTC_TRACE_ERROR("%s, Unhandled deep copy %d\n", __func__, msg->act); break; @@ -1704,6 +1853,21 @@ void btc_gap_ble_arg_deep_free(btc_msg_t *msg) break; } #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) + case BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT: { + uint8_t *p_param_buf = ((btc_ble_gap_args_t *)msg->arg)->vendor_cmd_send.p_param_buf; + if (p_param_buf) { + osi_free(p_param_buf); + } + break; + } + case BTC_GAP_BLE_ACT_SET_DEV_NAME:{ + char *p_name = ((btc_ble_gap_args_t *)msg->arg)->set_dev_name.device_name; + if (p_name) { + osi_free((uint8_t *)p_name); + } + break; + } + break; default: BTC_TRACE_DEBUG("Unhandled deep free %d\n", msg->act); break; @@ -1721,6 +1885,13 @@ void btc_gap_ble_cb_deep_free(btc_msg_t *msg) } break; } + case ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT: { + uint8_t *value = ((esp_ble_gap_cb_param_t *)msg->arg)->vendor_cmd_cmpl.p_param_buf; + if (value) { + osi_free(value); + } + break; + } default: BTC_TRACE_DEBUG("Unhandled deep free %d", msg->act); break; @@ -1781,6 +1952,17 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) btc_ble_set_rand_addr(bd_addr, btc_set_rand_addr_callback); break; } + case BTC_GAP_BLE_ACT_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT: { + btc_ble_set_rpa_timeout(arg->set_rpa_timeout.rpa_timeout,btc_set_rpa_timeout_callback); + break; + } + case BTC_GAP_BLE_ACT_ADD_DEVICE_TO_RESOLVING_LIST: { + btc_ble_add_device_to_resolving_list(arg->add_dev_to_resolving_list.addr, + arg->add_dev_to_resolving_list.addr_type, + arg->add_dev_to_resolving_list.irk, + btc_add_dev_to_resolving_list_callback); + break; + } case BTC_GAP_BLE_ACT_CLEAR_RAND_ADDRESS: { btc_ble_clear_rand_addr(); break; @@ -1808,10 +1990,10 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) break; #endif // #if (BLE_42_FEATURE_SUPPORT == TRUE) case BTC_GAP_BLE_ACT_SET_DEV_NAME: - BTA_DmSetDeviceName(arg->set_dev_name.device_name); + BTA_DmSetDeviceName(arg->set_dev_name.device_name, BT_DEVICE_TYPE_BLE); break; case BTC_GAP_BLE_ACT_GET_DEV_NAME: - BTA_DmGetDeviceName(btc_gap_ble_get_dev_name_callback); + BTA_DmGetDeviceName(btc_gap_ble_get_dev_name_callback, BT_DEVICE_TYPE_BLE); break; #if (BLE_42_FEATURE_SUPPORT == TRUE) case BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW: @@ -2192,6 +2374,16 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) btc_ble_dtm_enhance_rx_start(arg_5->dtm_enh_rx_start.rx_channel, arg_5->dtm_enh_rx_start.phy, arg_5->dtm_enh_rx_start.modulation_index, btc_dtm_rx_start_callback); break; #endif // if (BLE_50_FEATURE_SUPPORT == TRUE) + case BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT: + BTA_DmsendVendorHciCmd(arg->vendor_cmd_send.opcode, + arg->vendor_cmd_send.param_len, + arg->vendor_cmd_send.p_param_buf, + btc_ble_vendor_hci_cmd_complete_callback); + break; + case BTC_GAP_BLE_SET_PRIVACY_MODE: + btc_ble_set_privacy_mode(arg->set_privacy_mode.addr_type, arg->set_privacy_mode.addr, + arg->set_privacy_mode.privacy_mode, btc_ble_set_privacy_mode_callback); + break; default: break; } @@ -2202,6 +2394,7 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) //register connection parameter update callback void btc_gap_callback_init(void) { + BTM_BleRegiseterPktLengthChangeCallback(btc_set_pkt_length_callback); BTM_BleRegiseterConnParamCallback(btc_update_conn_param_callback); #if (BLE_50_FEATURE_SUPPORT == TRUE) BTM_BleGapRegisterCallback(btc_ble_5_gap_callback); diff --git a/lib/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c b/lib/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c index 2f9dedfd..9e9d7b01 100644 --- a/lib/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c +++ b/lib/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -797,6 +797,31 @@ static void btc_gap_set_acl_pkt_types(btc_gap_bt_args_t *arg) btc_gap_bt_set_acl_pkt_types_cmpl_callback); } +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +static void btc_gap_bt_set_min_enc_key_size_cmpl_callback(void *p_data) +{ + tBTA_SET_MIN_ENC_KEY_SIZE_RESULTS *result = (tBTA_SET_MIN_ENC_KEY_SIZE_RESULTS *)p_data; + esp_bt_gap_cb_param_t param; + bt_status_t ret; + btc_msg_t msg; + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BT; + msg.act = BTC_GAP_BT_SET_MIN_ENC_KEY_SIZE_EVT; + + param.set_min_enc_key_size.status = btc_hci_to_esp_status(result->hci_status); + + ret = btc_transfer_context(&msg, ¶m, sizeof(esp_bt_gap_cb_param_t), NULL, NULL); + if (ret != BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + +static void btc_gap_set_min_enc_key_size(btc_gap_bt_args_t *arg) +{ + BTA_DmSetMinEncKeySize(arg->set_min_enc_key_size.key_size, btc_gap_bt_set_min_enc_key_size_cmpl_callback); +} +#endif + static void btc_gap_bt_read_remote_name_cmpl_callback(void *p_data) { tBTA_REMOTE_DEV_NAME *result = (tBTA_REMOTE_DEV_NAME *)p_data; @@ -853,6 +878,33 @@ static void btc_gap_bt_set_qos(btc_gap_bt_args_t *arg) #endif /// (BTA_DM_QOS_INCLUDED == TRUE) } +static void btc_gap_bt_get_dev_name_callback(UINT8 status, char *name) +{ + esp_bt_gap_cb_param_t param; + bt_status_t ret; + btc_msg_t msg = {0}; + + memset(¶m, 0, sizeof(esp_bt_gap_cb_param_t)); + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BT; + msg.act = BTC_GAP_BT_GET_DEV_NAME_CMPL_EVT; + + param.get_dev_name_cmpl.status = btc_btm_status_to_esp_status(status); + param.get_dev_name_cmpl.name = (char *)osi_malloc(BTC_MAX_LOC_BD_NAME_LEN + 1); + if (param.get_dev_name_cmpl.name) { + BCM_STRNCPY_S(param.get_dev_name_cmpl.name, name, BTC_MAX_LOC_BD_NAME_LEN); + param.get_dev_name_cmpl.name[BTC_MAX_LOC_BD_NAME_LEN] = '\0'; + } else { + param.get_dev_name_cmpl.status = ESP_BT_STATUS_NOMEM; + } + + ret = btc_transfer_context(&msg, ¶m, sizeof(esp_bt_gap_cb_param_t), NULL, NULL); + if (ret != BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) { switch (msg->act) { @@ -872,6 +924,10 @@ void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) case BTC_GAP_BT_ACT_SET_PAGE_TIMEOUT: case BTC_GAP_BT_ACT_GET_PAGE_TIMEOUT: case BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES: + case BTC_GAP_BT_ACT_GET_DEV_NAME: +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) + case BTC_GAP_BT_ACT_SET_MIN_ENC_KEY_SIZE: +#endif break; case BTC_GAP_BT_ACT_PASSKEY_REPLY: case BTC_GAP_BT_ACT_CONFIRM_REPLY: @@ -913,6 +969,18 @@ void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) } break; } + case BTC_GAP_BT_ACT_SET_DEV_NAME: { + btc_gap_bt_args_t *src = (btc_gap_bt_args_t *)p_src; + btc_gap_bt_args_t *dst = (btc_gap_bt_args_t *)p_dest; + dst->bt_set_dev_name.device_name = (char *)osi_malloc((BTC_MAX_LOC_BD_NAME_LEN + 1) * sizeof(char)); + if (dst->bt_set_dev_name.device_name) { + BCM_STRNCPY_S(dst->bt_set_dev_name.device_name, src->bt_set_dev_name.device_name, BTC_MAX_LOC_BD_NAME_LEN); + dst->bt_set_dev_name.device_name[BTC_MAX_LOC_BD_NAME_LEN] = '\0'; + } else { + BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act); + } + break; + } default: BTC_TRACE_ERROR("Unhandled deep copy %d\n", msg->act); break; @@ -939,6 +1007,10 @@ void btc_gap_bt_arg_deep_free(btc_msg_t *msg) case BTC_GAP_BT_ACT_SET_PAGE_TIMEOUT: case BTC_GAP_BT_ACT_GET_PAGE_TIMEOUT: case BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES: + case BTC_GAP_BT_ACT_GET_DEV_NAME: +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) + case BTC_GAP_BT_ACT_SET_MIN_ENC_KEY_SIZE: +#endif break; case BTC_GAP_BT_ACT_PASSKEY_REPLY: case BTC_GAP_BT_ACT_CONFIRM_REPLY: @@ -957,6 +1029,13 @@ void btc_gap_bt_arg_deep_free(btc_msg_t *msg) osi_free(arg->config_eir.eir_data.p_url); } break; + case BTC_GAP_BT_ACT_SET_DEV_NAME: { + char *p_name = arg->bt_set_dev_name.device_name; + if (p_name) { + osi_free((uint8_t *)p_name); + } + break; + } default: BTC_TRACE_ERROR("Unhandled deep copy %d, arg: %p\n", msg->act, arg); break; @@ -1049,6 +1128,20 @@ void btc_gap_bt_call_handler(btc_msg_t *msg) btc_gap_set_acl_pkt_types(arg); break; } +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) + case BTC_GAP_BT_ACT_SET_MIN_ENC_KEY_SIZE: { + btc_gap_set_min_enc_key_size(arg); + break; + } +#endif + case BTC_GAP_BT_ACT_SET_DEV_NAME: { + BTA_DmSetDeviceName(arg->bt_set_dev_name.device_name, BT_DEVICE_TYPE_BREDR); + break; + } + case BTC_GAP_BT_ACT_GET_DEV_NAME: { + BTA_DmGetDeviceName(btc_gap_bt_get_dev_name_callback, BT_DEVICE_TYPE_BREDR); + break; + } default: break; } @@ -1101,6 +1194,10 @@ void btc_gap_bt_cb_deep_free(btc_msg_t *msg) #if (BTC_DM_PM_INCLUDED == TRUE) case BTC_GAP_BT_MODE_CHG_EVT: #endif /// BTC_DM_PM_INCLUDED == TRUE +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) + case BTC_GAP_BT_SET_MIN_ENC_KEY_SIZE_EVT: +#endif /// ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE + case BTC_GAP_BT_GET_DEV_NAME_CMPL_EVT: break; default: BTC_TRACE_ERROR("%s: Unhandled event (%d)!\n", __FUNCTION__, msg->act); @@ -1192,6 +1289,16 @@ void btc_gap_bt_cb_handler(btc_msg_t *msg) btc_gap_bt_cb_to_app(ESP_BT_GAP_ACL_PKT_TYPE_CHANGED_EVT, (esp_bt_gap_cb_param_t *)msg->arg); break; } +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) + case BTC_GAP_BT_SET_MIN_ENC_KEY_SIZE_EVT: { + btc_gap_bt_cb_to_app(ESP_BT_GAP_SET_MIN_ENC_KEY_SIZE_EVT, (esp_bt_gap_cb_param_t *)msg->arg); + break; + } +#endif + case BTC_GAP_BT_GET_DEV_NAME_CMPL_EVT: { + btc_gap_bt_cb_to_app(ESP_BT_GAP_GET_DEV_NAME_CMPL_EVT, (esp_bt_gap_cb_param_t *)msg->arg); + break; + } default: BTC_TRACE_ERROR("%s: Unhandled event (%d)!\n", __FUNCTION__, msg->act); break; diff --git a/lib/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c b/lib/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c index 129d1b17..99f7a19f 100644 --- a/lib/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c +++ b/lib/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -68,7 +68,7 @@ static UINT16 btc_max_hf_clients = BTC_HF_NUM_CB; #if HFP_DYNAMIC_MEMORY == FALSE static hf_local_param_t hf_local_param[BTC_HF_NUM_CB]; #else -static hf_local_param_t *hf_local_param = NULL; +hf_local_param_t *hf_local_param_ptr = NULL; #endif #if (BTM_WBS_INCLUDED == TRUE) @@ -319,20 +319,18 @@ bt_status_t btc_hf_init(void) BTC_TRACE_DEBUG("%s - max_hf_clients=%d", __func__, btc_max_hf_clients); #if HFP_DYNAMIC_MEMORY == TRUE - if (hf_local_param != NULL) { - return BT_STATUS_FAIL; - } - - if ((hf_local_param = (hf_local_param_t *)osi_malloc(BTC_HF_NUM_CB * sizeof(hf_local_param_t))) == NULL) { - APPL_TRACE_ERROR("%s malloc failed!", __func__); - return BT_STATUS_NOMEM; + if (hf_local_param == NULL) { + if ((hf_local_param = (hf_local_param_t *)osi_malloc(BTC_HF_NUM_CB * sizeof(hf_local_param_t))) == NULL) { + BTC_TRACE_ERROR("%s malloc failed!", __func__); + return BT_STATUS_NOMEM; + } } memset((void *)hf_local_param, 0, BTC_HF_NUM_CB * sizeof(hf_local_param_t)); #endif /* Invoke the enable service API to the core to set the appropriate service_id * Internally, the HSP_SERVICE_ID shall also be enabled if HFP is enabled (phone) - * othwerwise only HSP is enabled (tablet)*/ + * otherwise only HSP is enabled (tablet)*/ #if (defined(BTC_HF_SERVICES) && (BTC_HF_SERVICES & BTA_HFP_SERVICE_MASK)) btc_dm_enable_service(BTA_HFP_SERVICE_ID); #else @@ -759,7 +757,7 @@ static bt_status_t btc_hf_phone_state_update(bt_bdaddr_t *bd_addr,int num_active } /* CIND response should have been updated. */ BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res); - /* Just open SCO conenction. */ + /* Just open SCO connection. */ BTA_AgAudioOpen(ag_res.audio_handle); activeCallUpdated = TRUE; } @@ -1572,7 +1570,7 @@ void btc_hf_cb_handler(btc_msg_t *msg) CHECK_HF_IDX(idx); BTC_TRACE_DEBUG("AG Bitmap of peer-codecs %d", p_data->val.num); #if (BTM_WBS_INCLUDED == TRUE) - /* If the peer supports mSBC and the BTC prefferred codec is also mSBC, then + /* If the peer supports mSBC and the BTC preferred codec is also mSBC, then ** we should set the BTA AG Codec to mSBC. This would trigger a +BCS to mSBC at the time ** of SCO connection establishment */ if ((btc_conf_hf_force_wbs == TRUE) && (p_data->val.num & BTA_AG_CODEC_MSBC)) { @@ -1608,7 +1606,7 @@ void btc_hf_cb_handler(btc_msg_t *msg) BTC_TRACE_DEBUG("AG final seleded codec is %d 1=CVSD 2=MSBC", p_data->val.num); memcpy(param.bcs_rep.remote_addr, &hf_local_param[idx].btc_hf_cb.connected_bda,sizeof(esp_bd_addr_t)); param.bcs_rep.mode = p_data->val.num; - /* No ESP_HF_WBS_NONE case, becuase HFP 1.6 supported device can send BCS */ + /* No ESP_HF_WBS_NONE case, because HFP 1.6 supported device can send BCS */ btc_hf_cb_to_app(ESP_HF_BCS_RESPONSE_EVT, ¶m); } while (0); break; diff --git a/lib/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c b/lib/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c index d280f8f7..0d99c030 100644 --- a/lib/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c +++ b/lib/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c @@ -261,7 +261,7 @@ static void btc_hd_deinit(void) } btc_hd_cb.service_dereg_active = FALSE; - // unresgister app will also relase the connection + // unregister app will also release the connection // and disable after receiving unregister event from lower layer if (is_hidd_app_register()) { btc_hd_unregister_app(true); @@ -844,6 +844,8 @@ void btc_hd_cb_handler(btc_msg_t *msg) // } // btc_storage_set_hidd((bt_bdaddr_t *)&p_data->conn.bda); btc_hd_cb.status = BTC_HD_CONNECTED; + } else if (p_data->conn.conn_status == BTA_HD_CONN_STATE_DISCONNECTED) { + btc_hd_cb.status = BTC_HD_DISCONNECTED; } param.open.status = p_data->conn.status; param.open.conn_status = p_data->conn.conn_status; diff --git a/lib/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c b/lib/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c index 7202371e..1d6f2020 100644 --- a/lib/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c +++ b/lib/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c @@ -189,7 +189,7 @@ static btc_hh_device_t *btc_hh_find_connected_dev_by_bda(BD_ADDR bd_addr) * * Function btc_hh_stop_vup_timer * - * Description stop vitual unplug timer + * Description stop virtual unplug timer * * Returns void ******************************************************************************/ @@ -316,7 +316,7 @@ void btc_hh_remove_device(BD_ADDR bd_addr) for (i = 0; i < BTC_HH_MAX_ADDED_DEV; i++) { p_added_dev = &btc_hh_cb.added_devices[i]; - if (p_added_dev->bd_addr == bd_addr) { + if (memcmp(p_added_dev->bd_addr, bd_addr, BD_ADDR_LEN) == 0) { BTA_HhRemoveDev(p_added_dev->dev_handle); btc_storage_remove_hid_info((bt_bdaddr_t *)p_added_dev->bd_addr); memset(p_added_dev->bd_addr, 0, 6); @@ -544,6 +544,11 @@ static void btc_hh_connect(btc_hidh_args_t *arg) BTC_TRACE_ERROR("%s exceeded the maximum supported HID device number %d!", __func__, BTC_HH_MAX_HID); ret = ESP_HIDH_ERR_NO_RES; break; + } else if (dev && dev->dev_status == ESP_HIDH_CONN_STATE_CONNECTED) { + BTC_TRACE_WARNING("%s Device[%s] already connected", __func__, + bdaddr_to_string((const bt_bdaddr_t *)arg->connect.bd_addr, bdstr, sizeof(bdstr))); + param.open.conn_status = ESP_HIDH_CONN_STATE_CONNECTED; + break; } for (int i = 0; i < BTC_HH_MAX_ADDED_DEV; i++) { @@ -662,7 +667,7 @@ static void btc_hh_virtual_unplug(btc_hidh_args_t *arg) param.unplug.conn_status = ESP_HIDH_CONN_STATE_DISCONNECTING; param.unplug.handle = p_dev->dev_handle; } else if ((p_dev != NULL) && (p_dev->dev_status == ESP_HIDH_CONN_STATE_CONNECTED)) { - BTC_TRACE_WARNING("%s: Virtual unplug not suported, disconnecting device", __func__); + BTC_TRACE_WARNING("%s: Virtual unplug not supported, disconnecting device", __func__); /* start the timer */ btc_hh_start_vup_timer(arg->unplug.bd_addr); p_dev->local_vup = true; diff --git a/lib/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h b/lib/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h index 3fb5f4b3..e540116d 100644 --- a/lib/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h +++ b/lib/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -102,6 +102,10 @@ typedef enum { #if (BLE_42_FEATURE_SUPPORT == TRUE) BTC_GAP_BLE_ACT_CLEAR_ADV, #endif // #if (BLE_42_FEATURE_SUPPORT == TRUE) + BTC_GAP_BLE_ACT_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT, + BTC_GAP_BLE_ACT_ADD_DEVICE_TO_RESOLVING_LIST, + BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT, + BTC_GAP_BLE_SET_PRIVACY_MODE, } btc_gap_ble_act_t; /* btc_ble_gap_args_t */ @@ -139,6 +143,16 @@ typedef union { struct set_rand_addr_args { esp_bd_addr_t rand_addr; } set_rand_addr; + // BTC_GAP_BLE_ACT_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT + struct set_rpa_timeout_args { + uint16_t rpa_timeout; + } set_rpa_timeout; + //BTC_GAP_BLE_ACT_ADD_DEVICE_TO_RESOLVING_LIST + struct add_dev_to_resolving_list_args { + esp_bd_addr_t addr; + uint8_t addr_type; + uint8_t irk[PEER_IRK_LEN]; + } add_dev_to_resolving_list; //BTC_GAP_BLE_ACT_CONFIG_LOCAL_PRIVACY, struct cfg_local_privacy_args { bool privacy_enable; @@ -172,7 +186,7 @@ typedef union { //BTC_GAP_BLE_ACT_SET_DEV_NAME, struct set_dev_name_args { #define ESP_GAP_DEVICE_NAME_MAX (32) - char device_name[ESP_GAP_DEVICE_NAME_MAX + 1]; + char *device_name; } set_dev_name; #if (BLE_42_FEATURE_SUPPORT == TRUE) //BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW, @@ -248,9 +262,21 @@ typedef union { struct dtm_rx_start_args { uint8_t rx_channel; } dtm_rx_start; + //BTC_DEV_VENDOR_HCI_CMD_EVT + struct vendor_cmd_send_args { + uint16_t opcode; + uint8_t param_len; + uint8_t *p_param_buf; + } vendor_cmd_send; + // BTC_GAP_BLE_SET_PRIVACY_MODE + struct set_privacy_mode { + esp_ble_addr_type_t addr_type; + esp_bd_addr_t addr; + uint8_t privacy_mode; + } set_privacy_mode; } btc_ble_gap_args_t; -#if (BLE_50_FEATURE_SUPPORT == TRUE) +#if (BLE_50_FEATURE_SUPPORT == TRUE) typedef union { struct read_phy_args { esp_bd_addr_t bd_addr; diff --git a/lib/bt/host/bluedroid/btc/profile/std/include/btc_gap_bt.h b/lib/bt/host/bluedroid/btc/profile/std/include/btc_gap_bt.h index 2b631da9..6855449c 100644 --- a/lib/bt/host/bluedroid/btc/profile/std/include/btc_gap_bt.h +++ b/lib/bt/host/bluedroid/btc/profile/std/include/btc_gap_bt.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,6 +35,10 @@ typedef enum { BTC_GAP_BT_SET_PAGE_TO_EVT, BTC_GAP_BT_GET_PAGE_TO_EVT, BTC_GAP_BT_SET_ACL_PKT_TYPES_EVT, +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) + BTC_GAP_BT_SET_MIN_ENC_KEY_SIZE_EVT, +#endif + BTC_GAP_BT_GET_DEV_NAME_CMPL_EVT, }btc_gap_bt_evt_t; typedef enum { @@ -58,6 +62,11 @@ typedef enum { BTC_GAP_BT_ACT_SET_PAGE_TIMEOUT, BTC_GAP_BT_ACT_GET_PAGE_TIMEOUT, BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES, +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) + BTC_GAP_BT_ACT_SET_MIN_ENC_KEY_SIZE, +#endif + BTC_GAP_BT_ACT_SET_DEV_NAME, + BTC_GAP_BT_ACT_GET_DEV_NAME, } btc_gap_bt_act_t; /* btc_bt_gap_args_t */ @@ -165,6 +174,17 @@ typedef union { uint16_t pkt_types; } set_acl_pkt_types; +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) + // BTC_GAP_BT_ACT_SET_MIN_ENC_KEY_SIZE + struct set_min_enc_key_size_args { + uint8_t key_size; + } set_min_enc_key_size; +#endif + + // BTC_GAP_BT_ACT_SET_DEV_NAME + struct bt_set_dev_name_args { + char *device_name; + } bt_set_dev_name; } btc_gap_bt_args_t; void btc_gap_bt_call_handler(btc_msg_t *msg); diff --git a/lib/bt/host/bluedroid/btc/profile/std/include/btc_hf_ag.h b/lib/bt/host/bluedroid/btc/profile/std/include/btc_hf_ag.h index f936d181..5cecdd99 100644 --- a/lib/bt/host/bluedroid/btc/profile/std/include/btc_hf_ag.h +++ b/lib/bt/host/bluedroid/btc/profile/std/include/btc_hf_ag.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -233,6 +233,11 @@ typedef struct esp_hf_outgoing_data_cb_t btc_hf_outgoing_data_cb; } hf_local_param_t; +#if HFP_DYNAMIC_MEMORY == TRUE +extern hf_local_param_t *hf_local_param_ptr; +#define hf_local_param (hf_local_param_ptr) +#endif + /******************************************************************************* ** BTC HF AG Handle Hub ********************************************************************************/ diff --git a/lib/bt/host/bluedroid/btc/profile/std/sdp/btc_sdp.c b/lib/bt/host/bluedroid/btc/profile/std/sdp/btc_sdp.c index 143ae336..6eaf6cfb 100644 --- a/lib/bt/host/bluedroid/btc/profile/std/sdp/btc_sdp.c +++ b/lib/bt/host/bluedroid/btc/profile/std/sdp/btc_sdp.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -285,8 +285,8 @@ static int free_sdp_slot(int id) // Record have already been freed handle = -1; } - osi_free(slot); - slot = NULL; + osi_free(sdp_local_param.sdp_slots[id]); + sdp_local_param.sdp_slots[id] = NULL; return handle; } @@ -1034,14 +1034,16 @@ static void btc_sdp_remove_record(btc_sdp_args_t *arg) } else { BTC_TRACE_ERROR("%s SDP record with handle %d not found", __func__, arg->remove_record.record_handle); - return; + ret = ESP_SDP_NO_CREATE_RECORD; + break; } /* Get the Record handle, and free the slot */ /* The application layer record_handle is equivalent to the id of the btc layer */ int slot = get_sdp_slot_id_by_handle(arg->remove_record.record_handle); if (slot < 0) { - return; + ret = ESP_SDP_NO_CREATE_RECORD; + break; } handle = free_sdp_slot(slot); diff --git a/lib/bt/host/bluedroid/common/include/common/bluedroid_user_config.h b/lib/bt/host/bluedroid/common/include/common/bluedroid_user_config.h index ce8e80a2..81cfbaac 100644 --- a/lib/bt/host/bluedroid/common/include/common/bluedroid_user_config.h +++ b/lib/bt/host/bluedroid/common/include/common/bluedroid_user_config.h @@ -95,6 +95,15 @@ #define UC_BT_CLASSIC_BQB_ENABLED FALSE #endif +//Set Encryption Key Size(BT) +#ifdef CONFIG_BT_ENC_KEY_SIZE_CTRL_STD +#define UC_BT_ENC_KEY_SIZE_CTRL_MODE 1 +#elif CONFIG_BT_ENC_KEY_SIZE_CTRL_VSC +#define UC_BT_ENC_KEY_SIZE_CTRL_MODE 2 +#else +#define UC_BT_ENC_KEY_SIZE_CTRL_MODE 0 +#endif + //BLE #ifdef CONFIG_BT_BLE_ENABLED #define UC_BT_BLE_ENABLED CONFIG_BT_BLE_ENABLED diff --git a/lib/bt/host/bluedroid/common/include/common/bt_target.h b/lib/bt/host/bluedroid/common/include/common/bt_target.h index b193805d..0adad84f 100644 --- a/lib/bt/host/bluedroid/common/include/common/bt_target.h +++ b/lib/bt/host/bluedroid/common/include/common/bt_target.h @@ -73,6 +73,11 @@ #define SDP_INCLUDED TRUE #define BTA_DM_QOS_INCLUDED TRUE +#define ENC_KEY_SIZE_CTRL_MODE_NONE 0 +#define ENC_KEY_SIZE_CTRL_MODE_STD 1 +#define ENC_KEY_SIZE_CTRL_MODE_VSC 2 +#define ENC_KEY_SIZE_CTRL_MODE UC_BT_ENC_KEY_SIZE_CTRL_MODE + #if (UC_BT_A2DP_ENABLED == TRUE) #define BTA_AR_INCLUDED TRUE #define BTA_AV_INCLUDED TRUE diff --git a/lib/bt/host/bluedroid/hci/hci_hal_h4.c b/lib/bt/host/bluedroid/hci/hci_hal_h4.c index 24047790..9663126a 100644 --- a/lib/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/lib/bt/host/bluedroid/hci/hci_hal_h4.c @@ -36,13 +36,14 @@ #include "stack/hcimsgs.h" #if ((BT_CONTROLLER_INCLUDED == TRUE) && SOC_ESP_NIMBLE_CONTROLLER) -#include "nimble/ble_hci_trans.h" +#include "ble_hci_trans.h" #endif #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) #include "l2c_int.h" #endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE #include "stack/hcimsgs.h" +#include "hci_log/bt_hci_log.h" #define HCI_BLE_EVENT 0x3e #define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type) - 2) @@ -441,7 +442,7 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet) uint8_t len = 0; STREAM_TO_UINT8(len, stream); #endif - HCI_TRACE_ERROR("Workround stream corrupted during LE SCAN: pkt_len=%d ble_event_len=%d\n", + HCI_TRACE_ERROR("Workaround stream corrupted during LE SCAN: pkt_len=%d ble_event_len=%d\n", packet->len, len); osi_free(packet); return; @@ -540,6 +541,26 @@ static void host_send_pkt_available_cb(void) hci_downstream_data_post(OSI_THREAD_MAX_TIMEOUT); } + +void bt_record_hci_data(uint8_t *data, uint16_t len) +{ +#if (BT_HCI_LOG_INCLUDED == TRUE) + if ((data[0] == DATA_TYPE_EVENT) && (data[1] == HCI_BLE_EVENT) && ((data[3] == HCI_BLE_ADV_PKT_RPT_EVT) || (data[3] == HCI_BLE_DIRECT_ADV_EVT) +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + || (data[3] == HCI_BLE_ADV_DISCARD_REPORT_EVT) +#endif // (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + #if (BLE_50_FEATURE_SUPPORT == TRUE) + || (data[3] == HCI_BLE_EXT_ADV_REPORT_EVT) || (data[3] == HCI_BLE_PERIOD_ADV_REPORT_EVT) +#endif // (BLE_50_FEATURE_SUPPORT == TRUE) + )) { + bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, &data[2], len - 2); + } else { + uint8_t data_type = ((data[0] == 2) ? HCI_LOG_DATA_TYPE_C2H_ACL : data[0]); + bt_hci_log_record_hci_data(data_type, &data[1], len - 1); + } +#endif // (BT_HCI_LOG_INCLUDED == TRUE) +} + static int host_recv_pkt_cb(uint8_t *data, uint16_t len) { //Target has packet to host, malloc new buffer for packet @@ -551,13 +572,15 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len) return 0; } + bt_record_hci_data(data, len); + bool is_adv_rpt = host_recv_adv_packet(data); if (!is_adv_rpt) { pkt_size = BT_HDR_SIZE + len; pkt = (BT_HDR *) osi_calloc(pkt_size); if (!pkt) { - HCI_TRACE_ERROR("%s couldn't aquire memory for inbound data buffer.\n", __func__); + HCI_TRACE_ERROR("%s couldn't acquire memory for inbound data buffer.\n", __func__); assert(0); } diff --git a/lib/bt/host/bluedroid/hci/hci_layer.c b/lib/bt/host/bluedroid/hci/hci_layer.c index 56ab8877..c9f1f5e3 100644 --- a/lib/bt/host/bluedroid/hci/hci_layer.c +++ b/lib/bt/host/bluedroid/hci/hci_layer.c @@ -144,6 +144,10 @@ void hci_shut_down(void) bool hci_downstream_data_post(uint32_t timeout) { + if (hci_host_env.downstream_data_ready == NULL) { + HCI_TRACE_WARNING("%s downstream_data_ready event not created", __func__); + return false; + } return osi_thread_post_event(hci_host_env.downstream_data_ready, timeout); } @@ -263,7 +267,7 @@ static void transmit_command( // in case the upper layer didn't already command->event = MSG_STACK_TO_HC_HCI_CMD; - HCI_TRACE_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", metadata->opcode); + HCI_TRACE_DEBUG("HCI Enqueue Command opcode=0x%x\n", metadata->opcode); BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len); fixed_pkt_queue_enqueue(hci_host_env.command_queue, linked_pkt, FIXED_PKT_QUEUE_MAX_TIMEOUT); diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble.c b/lib/bt/host/bluedroid/stack/btm/btm_ble.c index afa46b8a..334001fe 100644 --- a/lib/bt/host/bluedroid/stack/btm/btm_ble.c +++ b/lib/bt/host/bluedroid/stack/btm/btm_ble.c @@ -2931,4 +2931,31 @@ uint8_t btm_ble_scan_active_count(void) return count; } +#if (SMP_INCLUDED == TRUE) +uint8_t btm_ble_sec_dev_active_count(void) +{ + tBTM_SEC_DEV_REC *p_dev_rec = NULL; + list_node_t *p_node = NULL; + uint8_t count = 0; + + /* First look for the non-paired devices for the oldest entry */ + for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) { + p_dev_rec = list_node(p_node); + if (p_dev_rec && (p_dev_rec->sec_flags & BTM_SEC_IN_USE) && (p_dev_rec->ble.key_type != BTM_LE_KEY_NONE)) { + count++; + } + } + + return count; +} +#endif + +#if (BLE_PRIVACY_SPT == TRUE) +uint8_t btm_ble_privacy_is_enabled(void) +{ + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + return (p_cb->privacy_mode != BTM_PRIVACY_NONE); +} +#endif + #endif /* BLE_INCLUDED */ diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c index e5dc3b42..04ad4804 100644 --- a/lib/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c +++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c @@ -27,6 +27,7 @@ static tBTM_STATUS btm_ble_ext_adv_set_data_validate(UINT8 instance, UINT16 len, typedef struct { uint16_t ter_con_handle; bool invalid; + bool enabled; UINT8 instance; int duration; int max_events; @@ -331,7 +332,7 @@ tBTM_STATUS BTM_BleSetExtendedAdvRandaddr(UINT8 instance, BD_ADDR rand_addr) __func__, btm_ble_hci_status_to_str(err), err); status = BTM_ILLEGAL_VALUE; } else { - // set random address success, update address infor + // set random address success, update address info if(extend_adv_cb.inst[instance].configured && extend_adv_cb.inst[instance].connetable) { BTM_BleSetStaticAddr(rand_addr); BTM_UpdateAddrInfor(BLE_ADDR_RANDOM, rand_addr); @@ -415,7 +416,7 @@ end: BTM_TRACE_ERROR("LE EA SetParams: cmd err=0x%x", err); status = BTM_ILLEGAL_VALUE; } else { - // set addr success, update address infor + // set addr success, update address info BTM_UpdateAddrInfor(BLE_ADDR_RANDOM, rand_addr); } } @@ -540,6 +541,7 @@ end: for (uint8_t i = 0; i < MAX_BLE_ADV_INSTANCE; i++) { adv_record[i].invalid = false; + adv_record[i].enabled = false; adv_record[i].instance = INVALID_VALUE; adv_record[i].duration = INVALID_VALUE; adv_record[i].max_events = INVALID_VALUE; @@ -550,6 +552,7 @@ end: { uint8_t index = ext_adv[i].instance; adv_record[index].invalid = false; + adv_record[index].enabled = false; adv_record[index].instance = INVALID_VALUE; adv_record[index].duration = INVALID_VALUE; adv_record[index].max_events = INVALID_VALUE; @@ -563,6 +566,7 @@ end: { uint8_t index = ext_adv[i].instance; adv_record[index].invalid = true; + adv_record[index].enabled = true; adv_record[index].instance = ext_adv[i].instance; adv_record[index].duration = ext_adv[i].duration; adv_record[index].max_events = ext_adv[i].max_events; @@ -588,12 +592,12 @@ tBTM_STATUS BTM_BleStartExtAdvRestart(uint8_t con_handle) } } - if((index >= MAX_BLE_ADV_INSTANCE) || (!adv_record[index].invalid) || (adv_record[index].retry_count > GATTC_CONNECT_RETRY_COUNT)) { + if((index >= MAX_BLE_ADV_INSTANCE) || (!adv_record[index].invalid)) { return BTM_WRONG_MODE; } adv_record[index].retry_count ++; - BTM_TRACE_DEBUG("remote device did not reveive aux connect response, retatrt the extend adv to reconnect, adv handle %d con_handle %d\n", index, con_handle); + BTM_TRACE_DEBUG("remote device did not receive aux connect response, retatrt the extend adv to reconnect, adv handle %d con_handle %d\n", index, con_handle); ext_adv.instance = adv_record[index].instance; ext_adv.duration = adv_record[index].duration; ext_adv.max_events = adv_record[index].max_events; @@ -794,8 +798,13 @@ tBTM_STATUS BTM_BlePeriodicAdvCreateSync(tBTM_BLE_Periodic_Sync_Params *params) || (params->reports_disabled > 0x01) || (params->filter_duplicates > 0x01) #endif - || (params->addr_type > 0x01) || - (params->sid > 0xf) || (params->skip > 0x01F3)) { + /*If the Periodic Advertiser List is not used, + the Advertising_SID, Advertiser Address_Type, and Advertiser Address + parameters specify the periodic advertising device to listen to; otherwise they + shall be ignored.*/ + || (params->filter_policy == 0 && params->addr_type > 0x01) + || (params->filter_policy == 0 && params->sid > 0xf) + || (params->skip > 0x01F3)) { status = BTM_ILLEGAL_VALUE; BTM_TRACE_ERROR("%s, The sync parameters is invalid.", __func__); goto end; @@ -1196,6 +1205,7 @@ void btm_ble_adv_set_terminated_evt(tBTM_BLE_ADV_TERMINAT *params) adv_record[params->adv_handle].ter_con_handle = INVALID_VALUE; adv_record[params->adv_handle].invalid = false; } + adv_record[params->adv_handle].enabled = false; memcpy(&cb_params.adv_term, params, sizeof(tBTM_BLE_ADV_TERMINAT)); @@ -1311,6 +1321,19 @@ void btm_ble_periodic_adv_sync_establish_evt(tBTM_BLE_PERIOD_ADV_SYNC_ESTAB *par } +uint8_t btm_ble_ext_adv_active_count(void) +{ + uint8_t count = 0; + + for (uint8_t i = 0; i < MAX_BLE_ADV_INSTANCE; i++) { + if (adv_record[i].enabled == true) { + count++; + } + } + + return count; +} + #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_gap.c index fb27ba0f..df24fa08 100644 --- a/lib/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -70,7 +70,7 @@ static tBTM_BLE_VSC_CB *cmn_ble_gap_vsc_cb_ptr; static tBTM_BLE_CTRL_FEATURES_CBACK *p_ctrl_le_feature_rd_cmpl_cback = NULL; #endif -tBTM_CallbackFunc conn_param_update_cb; +tBTM_CallbackFunc conn_callback_func; /******************************************************************************* ** Local functions *******************************************************************************/ @@ -309,7 +309,21 @@ void btm_ble_sem_free(void) *******************************************************************************/ void BTM_BleRegiseterConnParamCallback(tBTM_UPDATE_CONN_PARAM_CBACK *update_conn_param_cb) { - conn_param_update_cb.update_conn_param_cb = update_conn_param_cb; + conn_callback_func.update_conn_param_cb = update_conn_param_cb; +} + +/******************************************************************************* +** +** Function BTM_BleRegiseterPktLengthChangeCallback +** +** Description Registers a callback function for packet length changes. +** +** Returns void +** +*******************************************************************************/ +void BTM_BleRegiseterPktLengthChangeCallback(tBTM_SET_PKT_DATA_LENGTH_CBACK *ptk_len_chane_cb) +{ + conn_callback_func.set_pkt_data_length_cb = ptk_len_chane_cb; } /******************************************************************************* @@ -1333,7 +1347,7 @@ tBTM_STATUS BTM_BleSetConnectableMode(tBTM_BLE_CONN_MODE connectable_mode) ** ** Function btm_set_conn_mode_adv_init_addr ** -** Description set initator address type and local address type based on adv +** Description set initiator address type and local address type based on adv ** mode. ** ** @@ -2001,7 +2015,7 @@ tBTM_STATUS BTM_BleSetRandAddress(BD_ADDR rand_addr) } if (btm_cb.ble_ctr_cb.inq_var.state != BTM_BLE_IDLE) { - BTM_TRACE_ERROR("Advertising or scaning now, can't set randaddress %d", btm_cb.ble_ctr_cb.inq_var.state); + BTM_TRACE_ERROR("Advertising or scanning now, can't set randaddress %d", btm_cb.ble_ctr_cb.inq_var.state); return BTM_SET_STATIC_RAND_ADDR_FAIL; } memcpy(btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, rand_addr, BD_ADDR_LEN); @@ -2030,7 +2044,7 @@ void BTM_BleClearRandAddress(void) { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; if (btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_RANDOM && (p_cb->inq_var.state != BTM_BLE_IDLE)) { - BTM_TRACE_ERROR("Advertising or scaning now, can't restore public address "); + BTM_TRACE_ERROR("Advertising or scanning now, can't restore public address "); return; } memset(btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr, 0, BD_ADDR_LEN); @@ -2236,16 +2250,16 @@ UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, /* device name */ #if BTM_MAX_LOC_BD_NAME_LEN > 0 if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_DEV_NAME) { - if (strlen(btm_cb.cfg.bd_name) > (UINT16)(len - MIN_ADV_LENGTH)) { + if (strlen(btm_cb.cfg.ble_bd_name) > (UINT16)(len - MIN_ADV_LENGTH)) { cp_len = (UINT16)(len - MIN_ADV_LENGTH); *p++ = cp_len + 1; *p++ = BTM_BLE_AD_TYPE_NAME_SHORT; - ARRAY_TO_STREAM(p, btm_cb.cfg.bd_name, cp_len); + ARRAY_TO_STREAM(p, btm_cb.cfg.ble_bd_name, cp_len); } else { - cp_len = (UINT16)strlen(btm_cb.cfg.bd_name); + cp_len = (UINT16)strlen(btm_cb.cfg.ble_bd_name); *p++ = cp_len + 1; *p++ = BTM_BLE_AD_TYPE_NAME_CMPL; - ARRAY_TO_STREAM(p, btm_cb.cfg.bd_name, cp_len); + ARRAY_TO_STREAM(p, btm_cb.cfg.ble_bd_name, cp_len); } len -= (cp_len + MIN_ADV_LENGTH); data_mask &= ~BTM_BLE_AD_BIT_DEV_NAME; @@ -3291,6 +3305,7 @@ static void btm_ble_appearance_to_cod(UINT16 appearance, UINT8 *dev_class) case BTM_BLE_APPEARANCE_CYCLING_CADENCE: case BTM_BLE_APPEARANCE_CYCLING_POWER: case BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE: + case BTM_BLE_APPEARANCE_STANDALONE_SPEAKER: case BTM_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS: case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION: case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV: @@ -3728,7 +3743,7 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt /* never been report as an LE device */ if (p_i && (!(p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) || - /* scan repsonse to be updated */ + /* scan response to be updated */ (!p_i->scan_rsp))) { update = TRUE; } else if (BTM_BLE_IS_DISCO_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) { @@ -4002,7 +4017,7 @@ static void btm_ble_stop_discover(void) ** ** Description Set or clear adv states in topology mask ** -** Returns operation status. TRUE if sucessful, FALSE otherwise. +** Returns operation status. TRUE if successful, FALSE otherwise. ** *******************************************************************************/ typedef BOOLEAN (BTM_TOPOLOGY_FUNC_PTR)(tBTM_BLE_STATE_MASK); @@ -4263,7 +4278,7 @@ void btm_ble_timeout(TIMER_LIST_ENT *p_tle) break; case BTU_TTYPE_BLE_GAP_LIM_DISC: - /* lim_timeout expiried, limited discovery should exit now */ + /* lim_timeout expired, limited discovery should exit now */ btm_cb.btm_inq_vars.discoverable_mode &= ~BTM_BLE_LIMITED_DISCOVERABLE; btm_ble_set_adv_flag(btm_cb.btm_inq_vars.connectable_mode, btm_cb.btm_inq_vars.discoverable_mode); break; @@ -4364,7 +4379,7 @@ void btm_ble_read_remote_features_complete(UINT8 *p) *******************************************************************************/ void btm_ble_write_adv_enable_complete(UINT8 *p) { - /* if write adv enable/disbale not succeed */ + /* if write adv enable/disable not succeed */ if (*p != HCI_SUCCESS) { BTM_TRACE_ERROR("%s failed", __func__); } @@ -4702,6 +4717,40 @@ BOOLEAN BTM_BleClearAdv(tBTM_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cback) p_cb->inq_var.p_clear_adv_cb = p_clear_adv_cback; return TRUE; } +BOOLEAN BTM_BleSetRpaTimeout(uint16_t rpa_timeout,tBTM_SET_RPA_TIMEOUT_CMPL_CBACK *p_set_rpa_timeout_cback) +{ + if ((btsnd_hcic_ble_set_rand_priv_addr_timeout(rpa_timeout)) != TRUE) { + BTM_TRACE_ERROR("Set RPA Timeout error, rpa_timeout:0x%04x",rpa_timeout); + return FALSE; + } + btm_cb.devcb.p_ble_set_rpa_timeout_cmpl_cb = p_set_rpa_timeout_cback; + return TRUE; +} + +BOOLEAN BTM_BleAddDevToResolvingList(BD_ADDR addr, + uint8_t addr_type, + uint8_t irk[], + tBTM_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK *p_add_dev_to_resolving_list_callback) +{ + UINT8 *local_irk = btm_cb.devcb.id_keys.irk; + if ((btsnd_hcic_ble_add_device_resolving_list(addr_type, addr, irk, local_irk)) != TRUE) { + BTM_TRACE_ERROR("Add device to resolving list error"); + return FALSE; + } + btm_cb.devcb.p_add_dev_to_resolving_list_cmpl_cb = p_add_dev_to_resolving_list_callback; + return TRUE; +} + +BOOLEAN BTM_BleSetPrivacyMode(UINT8 addr_type, BD_ADDR bd_addr, UINT8 privacy_mode, tBTM_SET_PRIVACY_MODE_CMPL_CBACK *p_callback) +{ + if (btsnd_hcic_ble_set_privacy_mode(addr_type, bd_addr, privacy_mode) != TRUE) { + BTM_TRACE_ERROR("LE SetPrivacyMode Mode=%d: error", privacy_mode); + return FALSE; + } + + btm_cb.devcb.p_set_privacy_mode_cmpl_cb = p_callback; + return TRUE; +} bool btm_ble_adv_pkt_ready(void) { diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c index 443dd64e..bc300b02 100644 --- a/lib/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c +++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c @@ -824,6 +824,13 @@ void btm_ble_multi_adv_init(void) *******************************************************************************/ void btm_ble_multi_adv_cleanup(void) { +#if BTM_DYNAMIC_MEMORY == TRUE + if (btm_multi_adv_cb_ptr == NULL) + { + BTM_TRACE_WARNING("%s memory has been freed", __func__); + return; + } +#endif if (btm_multi_adv_cb.p_adv_inst) { osi_free(btm_multi_adv_cb.p_adv_inst); btm_multi_adv_cb.p_adv_inst = NULL; diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_privacy.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_privacy.c index 7058df20..be4b9d15 100644 --- a/lib/bt/host/bluedroid/stack/btm/btm_ble_privacy.c +++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_privacy.c @@ -275,6 +275,14 @@ void btm_ble_add_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len) { UINT8 status; STREAM_TO_UINT8(status, p); + if (btm_cb.devcb.p_add_dev_to_resolving_list_cmpl_cb) { + tBTM_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK *p_cb = btm_cb.devcb.p_add_dev_to_resolving_list_cmpl_cb; + if (p_cb) { + (*p_cb)(status); + } + } else { + BTM_TRACE_DEBUG("no resolving list callback"); + } BTM_TRACE_DEBUG("%s status = %d", __func__, status); @@ -416,6 +424,64 @@ void btm_ble_set_addr_resolution_enable_complete(UINT8 *p, UINT16 evt_len) random_cb->set_local_privacy_cback(BTM_ILLEGAL_VALUE); } +/******************************************************************************* +** +** Function btm_ble_set_rpa_timeout_complete +** +** Description This function is called when the LE Set Resolvable Private +** Address Timeout command completes. +** +** Parameters p: Pointer to the command complete event data. +** evt_len: Length of the event data. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_set_rpa_timeout_complete(UINT8 *p, UINT16 evt_len) +{ + UINT8 status; + + // Extract the status of the command completion from the event data + STREAM_TO_UINT8(status, p); + + BTM_TRACE_DEBUG("%s status = %d", __func__, status); + + tBTM_SET_RPA_TIMEOUT_CMPL_CBACK *p_cb = btm_cb.devcb.p_ble_set_rpa_timeout_cmpl_cb; + + if (p_cb) { + (*p_cb)(status); + } + +} + +/******************************************************************************* +** +** Function btm_ble_set_privacy_mode_complete +** +** Description This function is called when the LE Set Privacy Mode command completes. +** +** Parameters p: Pointer to the command complete event data. +** evt_len: Length of the event data. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_set_privacy_mode_complete(UINT8 *p, UINT16 evt_len) +{ + UINT8 status; + + // Extract the status of the command completion from the event data + STREAM_TO_UINT8(status, p); + + BTM_TRACE_DEBUG("%s status = 0x%x", __func__, status); + + tBTM_SET_PRIVACY_MODE_CMPL_CBACK *p_cb = btm_cb.devcb.p_set_privacy_mode_cmpl_cb; + + if (p_cb) { + (*p_cb)(status); + } +} + /******************************************************************************* VSC that implement controller based privacy ********************************************************************************/ @@ -459,7 +525,7 @@ void btm_ble_resolving_list_vsc_op_cmpl (tBTM_VSC_CMPL *p_params) ** Description This function to remove an IRK entry from the list ** ** Parameters ble_addr_type: address type -** ble_addr: LE adddress +** ble_addr: LE address ** ** Returns status ** @@ -949,7 +1015,7 @@ void btm_ble_enable_resolving_list(UINT8 rl_mask) ** ** Function btm_ble_resolving_list_empty ** -** Description check to see if resoving list is empty or not +** Description check to see if resolving list is empty or not ** ** Returns TRUE: empty; FALSE non-empty ** @@ -1074,7 +1140,7 @@ void btm_ble_add_default_entry_to_resolving_list(void) /* * Add local IRK entry with 00:00:00:00:00:00 address. This entry will * be used to generate RPA for non-directed advertising if own_addr_type - * is set to rpa_pub since we use all-zero address as peer addres in + * is set to rpa_pub since we use all-zero address as peer address in * such case. Peer IRK should be left all-zero since this is not for an * actual peer. */ diff --git a/lib/bt/host/bluedroid/stack/btm/btm_devctl.c b/lib/bt/host/bluedroid/stack/btm/btm_devctl.c index bffb5bbe..bab88739 100644 --- a/lib/bt/host/bluedroid/stack/btm/btm_devctl.c +++ b/lib/bt/host/bluedroid/stack/btm/btm_devctl.c @@ -81,7 +81,8 @@ void btm_dev_init (void) /* Initialize nonzero defaults */ #if (BTM_MAX_LOC_BD_NAME_LEN > 0) - memset(btm_cb.cfg.bd_name, 0, sizeof(tBTM_LOC_BD_NAME)); + memset(btm_cb.cfg.ble_bd_name, 0, sizeof(tBTM_LOC_BD_NAME)); + memset(btm_cb.cfg.bredr_bd_name, 0, sizeof(tBTM_LOC_BD_NAME)); #endif btm_cb.devcb.reset_timer.param = (TIMER_PARAM_TYPE)TT_DEV_RESET; @@ -449,11 +450,11 @@ static void btm_decode_ext_features_page (UINT8 page_number, const BD_FEATURES p ** Returns status of the operation ** *******************************************************************************/ -tBTM_STATUS BTM_SetLocalDeviceName (char *p_name) +tBTM_STATUS BTM_SetLocalDeviceName (char *p_name, tBT_DEVICE_TYPE name_type) { UINT8 *p; - if (!p_name || !p_name[0] || (strlen ((char *)p_name) > BD_NAME_LEN)) { + if (!p_name || !p_name[0] || (strlen ((char *)p_name) > BD_NAME_LEN) || (name_type > BT_DEVICE_TYPE_DUMO)) { return (BTM_ILLEGAL_VALUE); } @@ -463,16 +464,26 @@ tBTM_STATUS BTM_SetLocalDeviceName (char *p_name) #if BTM_MAX_LOC_BD_NAME_LEN > 0 /* Save the device name if local storage is enabled */ - p = (UINT8 *)btm_cb.cfg.bd_name; - if (p != (UINT8 *)p_name) { - BCM_STRNCPY_S(btm_cb.cfg.bd_name, p_name, BTM_MAX_LOC_BD_NAME_LEN); - btm_cb.cfg.bd_name[BTM_MAX_LOC_BD_NAME_LEN] = '\0'; + if (name_type & BT_DEVICE_TYPE_BLE) { + p = (UINT8 *)btm_cb.cfg.ble_bd_name; + if (p != (UINT8 *)p_name) { + BCM_STRNCPY_S(btm_cb.cfg.ble_bd_name, p_name, BTM_MAX_LOC_BD_NAME_LEN); + btm_cb.cfg.ble_bd_name[BTM_MAX_LOC_BD_NAME_LEN] = '\0'; + } + } + + if (name_type & BT_DEVICE_TYPE_BREDR) { + p = (UINT8 *)btm_cb.cfg.bredr_bd_name; + if (p != (UINT8 *)p_name) { + BCM_STRNCPY_S(btm_cb.cfg.bredr_bd_name, p_name, BTM_MAX_LOC_BD_NAME_LEN); + btm_cb.cfg.bredr_bd_name[BTM_MAX_LOC_BD_NAME_LEN] = '\0'; + } } #else p = (UINT8 *)p_name; #endif #if CLASSIC_BT_INCLUDED - if (btsnd_hcic_change_name(p)) { + if ((name_type & BT_DEVICE_TYPE_BREDR) && btsnd_hcic_change_name(p)) { return (BTM_CMD_STARTED); } else #endif @@ -496,10 +507,33 @@ tBTM_STATUS BTM_SetLocalDeviceName (char *p_name) ** is returned and p_name is set to NULL ** *******************************************************************************/ -tBTM_STATUS BTM_ReadLocalDeviceName (char **p_name) +tBTM_STATUS BTM_ReadLocalDeviceName (char **p_name, tBT_DEVICE_TYPE name_type) { + /* + // name_type should be BT_DEVICE_TYPE_BLE or BT_DEVICE_TYPE_BREDR + if (name_type > BT_DEVICE_TYPE_BREDR) { + *p_name = NULL; + BTM_TRACE_ERROR("name_type unknown %d", name_type); + return (BTM_NO_RESOURCES); + } + */ + #if BTM_MAX_LOC_BD_NAME_LEN > 0 - *p_name = btm_cb.cfg.bd_name; + if ((name_type == BT_DEVICE_TYPE_DUMO) && + (BCM_STRNCMP_S(btm_cb.cfg.bredr_bd_name, btm_cb.cfg.ble_bd_name, BTM_MAX_LOC_BD_NAME_LEN) != 0)) { + *p_name = NULL; + BTM_TRACE_ERROR("Error, BLE and BREDR have different names, return NULL\n"); + return (BTM_NO_RESOURCES); + } + + if (name_type & BT_DEVICE_TYPE_BLE) { + *p_name = btm_cb.cfg.ble_bd_name; + } + + if (name_type & BT_DEVICE_TYPE_BREDR) { + *p_name = btm_cb.cfg.bredr_bd_name; + } + return (BTM_SUCCESS); #else *p_name = NULL; @@ -740,19 +774,20 @@ void btm_vsc_complete (UINT8 *p, UINT16 opcode, UINT16 evt_len, break; } default: - break; + break; } +#endif // (BLE_INCLUDED == TRUE) tBTM_VSC_CMPL vcs_cplt_params; /* If there was a callback address for vcs complete, call it */ if (p_vsc_cplt_cback) { - /* Pass paramters to the callback function */ + /* Pass parameters to the callback function */ vcs_cplt_params.opcode = opcode; /* Number of bytes in return info */ vcs_cplt_params.param_len = evt_len; /* Number of bytes in return info */ vcs_cplt_params.p_param_buf = p; (*p_vsc_cplt_cback)(&vcs_cplt_params); /* Call the VSC complete callback function */ } -#endif + } /******************************************************************************* @@ -876,6 +911,42 @@ tBTM_STATUS BTM_WritePageTimeout(UINT16 timeout, tBTM_CMPL_CB *p_cb) return (BTM_CMD_STARTED); } +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +void btm_set_min_enc_key_size_complete(const UINT8 *p) +{ + tBTM_SET_MIN_ENC_KEY_SIZE_RESULTS results; + tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_set_min_enc_key_size_cmpl_cb; + + STREAM_TO_UINT8(results.hci_status, p); + + if (p_cb) { + btm_cb.devcb.p_set_min_enc_key_size_cmpl_cb = NULL; + (*p_cb)(&results); + } +} + +tBTM_STATUS BTM_SetMinEncKeySize(UINT8 key_size, tBTM_CMPL_CB *p_cb) +{ + BTM_TRACE_EVENT ("BTM: BTM_SetMinEncKeySize: key_size: %d.", key_size); + + btm_cb.devcb.p_set_min_enc_key_size_cmpl_cb = p_cb; + tBTM_STATUS status = BTM_NO_RESOURCES; + +#if (ENC_KEY_SIZE_CTRL_MODE == ENC_KEY_SIZE_CTRL_MODE_VSC) + /* Send the HCI command */ + UINT8 param[1]; + UINT8 *p = (UINT8 *)param; + UINT8_TO_STREAM(p, key_size); + status = BTM_VendorSpecificCommand(HCI_VENDOR_BT_SET_MIN_ENC_KEY_SIZE, 1, param, NULL); +#else + if (btsnd_hcic_set_min_enc_key_size(key_size)) { + status = BTM_SUCCESS; + } +#endif + return status; +} +#endif + /******************************************************************************* ** ** Function btm_set_page_timeout_complete diff --git a/lib/bt/host/bluedroid/stack/btm/btm_main.c b/lib/bt/host/bluedroid/stack/btm/btm_main.c index 05ef1837..8e49aa3e 100644 --- a/lib/bt/host/bluedroid/stack/btm/btm_main.c +++ b/lib/bt/host/bluedroid/stack/btm/btm_main.c @@ -133,20 +133,3 @@ uint8_t btm_acl_active_count(void) return count; } - -uint8_t btdm_sec_dev_active_count(void) -{ - tBTM_SEC_DEV_REC *p_dev_rec = NULL; - list_node_t *p_node = NULL; - uint8_t count = 0; - - /* First look for the non-paired devices for the oldest entry */ - for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) { - p_dev_rec = list_node(p_node); - if (p_dev_rec && (p_dev_rec->sec_flags & BTM_SEC_IN_USE)) { - count++; - } - } - - return count; -} diff --git a/lib/bt/host/bluedroid/stack/btm/btm_sec.c b/lib/bt/host/bluedroid/stack/btm/btm_sec.c index 7d06a45e..ca5f99e1 100644 --- a/lib/bt/host/bluedroid/stack/btm/btm_sec.c +++ b/lib/bt/host/bluedroid/stack/btm/btm_sec.c @@ -809,7 +809,7 @@ void btm_sec_clr_temp_auth_service (BD_ADDR bda) return; } - /* Reset the temporary authorized flag so that next time (untrusted) service is accessed autorization will take place */ + /* Reset the temporary authorized flag so that next time (untrusted) service is accessed authorization will take place */ if (p_dev_rec->last_author_service_id != BTM_SEC_NO_LAST_SERVICE_ID && p_dev_rec->p_cur_service) { BTM_TRACE_DEBUG ("btm_sec_clr_auth_service_by_psm [clearing device: %02x:%02x:%02x:%02x:%02x:%02x]\n", bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); @@ -1364,7 +1364,7 @@ tBTM_STATUS BTM_SetEncryption (BD_ADDR bd_addr, tBT_TRANSPORT transport, tBTM_SE || (transport == BT_TRANSPORT_LE && p_dev_rec->ble_hci_handle == BTM_SEC_INVALID_HANDLE) #endif ) { - /* Connection should be up and runnning */ + /* Connection should be up and running */ BTM_TRACE_WARNING ("Security Manager: BTM_SetEncryption not connected\n"); if (p_callback) { @@ -1790,15 +1790,15 @@ UINT16 BTM_BuildOobData(UINT8 *p_data, UINT16 max_len, BT_OCTET16 c, } #if BTM_MAX_LOC_BD_NAME_LEN > 0 name_size = name_len; - if (name_size > strlen(btm_cb.cfg.bd_name)) { + if (name_size > strlen(btm_cb.cfg.bredr_bd_name)) { name_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE; - name_size = (UINT16)strlen(btm_cb.cfg.bd_name); + name_size = (UINT16)strlen(btm_cb.cfg.bredr_bd_name); } delta = name_size + 2; if (max_len >= delta) { *p++ = name_size + 1; *p++ = name_type; - ARRAY_TO_STREAM (p, btm_cb.cfg.bd_name, name_size); + ARRAY_TO_STREAM (p, btm_cb.cfg.bredr_bd_name, name_size); len += delta; max_len -= delta; } @@ -2118,7 +2118,7 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle /* If there is no application registered with this PSM do not allow connection */ if (!p_serv_rec) { - BTM_TRACE_WARNING ("%s() PSM: %d no application registerd\n", __func__, psm); + BTM_TRACE_WARNING ("%s() PSM: %d no application registered\n", __func__, psm); (*p_callback) (bd_addr, transport, p_ref_data, BTM_MODE_UNSUPPORTED); return (BTM_MODE_UNSUPPORTED); } @@ -2514,7 +2514,7 @@ tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_o if (rc == BTM_SUCCESS) { BTM_TRACE_EVENT("%s: allow to bypass, checking authorization\n", __FUNCTION__); - /* the security in BTM_SEC_IN_FLAGS is fullfilled so far, check the requirements in */ + /* the security in BTM_SEC_IN_FLAGS is fulfilled so far, check the requirements in */ /* btm_sec_execute_procedure */ if ((is_originator && (p_serv_rec->security_flags & BTM_SEC_OUT_AUTHORIZE)) || (!is_originator && (p_serv_rec->security_flags & BTM_SEC_IN_AUTHORIZE))) { @@ -3979,7 +3979,7 @@ void btm_sec_auth_complete (UINT16 handle, UINT8 status) /* or BR key is higher security than existing LE keys */ (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)))) { - BTM_TRACE_DEBUG ("link encrypted afer dedic bonding can use SMP_BR_CHNL\n"); + BTM_TRACE_DEBUG ("link encrypted after dedic bonding can use SMP_BR_CHNL\n"); if (btm_sec_is_master(p_dev_rec)) { // Encryption is required to start SM over BR/EDR @@ -4255,7 +4255,7 @@ static void btm_sec_connect_after_reject_timeout (TIMER_LIST_ENT *p_tle) ** Function btm_sec_connected ** ** Description This function is when a connection to the peer device is -** establsihed +** established ** ** Returns void ** @@ -5926,7 +5926,7 @@ static BOOLEAN btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC *p_dev_rec) ** ** Function btm_sec_auth_payload_tout ** -** Description Processes the HCI Autheniticated Payload Timeout Event +** Description Processes the HCI Authenticated Payload Timeout Event ** indicating that a packet containing a valid MIC on the ** connection handle was not received within the programmed ** timeout value. (Spec Default is 30 secs, but can be @@ -6294,7 +6294,7 @@ static BOOLEAN btm_sec_is_master(tBTM_SEC_DEV_REC *p_dev_rec) ** Description This function is called when legacy authentication is used ** and only remote device has completed the authentication ** -** Returns TRUE if aunthentication command sent successfully +** Returns TRUE if authentication command sent successfully ** *******************************************************************************/ BOOLEAN btm_sec_legacy_authentication_mutual (tBTM_SEC_DEV_REC *p_dev_rec) diff --git a/lib/bt/host/bluedroid/stack/btm/include/btm_ble_int.h b/lib/bt/host/bluedroid/stack/btm/include/btm_ble_int.h index 1f55289c..0f8888fb 100644 --- a/lib/bt/host/bluedroid/stack/btm/include/btm_ble_int.h +++ b/lib/bt/host/bluedroid/stack/btm/include/btm_ble_int.h @@ -313,7 +313,7 @@ typedef struct { #define BTM_PRIVACY_NONE 0 /* BLE no privacy */ #define BTM_PRIVACY_1_1 1 /* BLE privacy 1.1, do not support privacy 1.0 */ #define BTM_PRIVACY_1_2 2 /* BLE privacy 1.2 */ -#define BTM_PRIVACY_MIXED 3 /* BLE privacy mixed mode, broadcom propietary mode */ +#define BTM_PRIVACY_MIXED 3 /* BLE privacy mixed mode, broadcom proprietary mode */ typedef UINT8 tBTM_PRIVACY_MODE; /* data length change event callback */ @@ -486,6 +486,7 @@ void btm_ble_refresh_peer_resolvable_private_addr(BD_ADDR pseudo_bda, BD_ADDR rr void btm_ble_refresh_local_resolvable_private_addr(BD_ADDR pseudo_addr, BD_ADDR local_rpa); void btm_ble_read_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len) ; void btm_ble_set_addr_resolution_enable_complete(UINT8 *p, UINT16 evt_len) ; +void btm_ble_set_rpa_timeout_complete(UINT8 *p, UINT16 evt_len) ; void btm_ble_remove_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len); void btm_ble_add_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len); void btm_ble_clear_resolving_list_complete(UINT8 *p, UINT16 evt_len); @@ -496,6 +497,7 @@ void btm_ble_enable_resolving_list_for_platform (UINT8 rl_mask); void btm_ble_resolving_list_init(UINT8 max_irk_list_sz); void btm_ble_resolving_list_cleanup(void); void btm_ble_add_default_entry_to_resolving_list(void); +void btm_ble_set_privacy_mode_complete(UINT8 *p, UINT16 evt_len); #endif void btm_ble_multi_adv_configure_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst); diff --git a/lib/bt/host/bluedroid/stack/btm/include/btm_int.h b/lib/bt/host/bluedroid/stack/btm/include/btm_int.h index c22423a1..3d01a5c2 100644 --- a/lib/bt/host/bluedroid/stack/btm/include/btm_int.h +++ b/lib/bt/host/bluedroid/stack/btm/include/btm_int.h @@ -221,6 +221,8 @@ tBTM_CMPL_CB *p_page_to_set_cmpl_cb; /* Callback function to be called w TIMER_LIST_ENT set_acl_pkt_types_timer; tBTM_CMPL_CB *p_set_acl_pkt_types_cmpl_cb; /* Callback function to be called when */ /* set ACL packet types is completed */ +tBTM_CMPL_CB *p_set_min_enc_key_size_cmpl_cb; /* Callback function to be called when */ +/* set min encryption key size is completed */ #endif DEV_CLASS dev_class; /* Local device class */ @@ -231,6 +233,13 @@ TIMER_LIST_ENT ble_channels_timer; tBTM_CMPL_CB *p_ble_channels_cmpl_cb; /* Callback function to be called When ble set host channels is completed */ +tBTM_SET_RPA_TIMEOUT_CMPL_CBACK *p_ble_set_rpa_timeout_cmpl_cb; /* Callback function to be called When + ble set rpa timeout is completed */ + +tBTM_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK *p_add_dev_to_resolving_list_cmpl_cb; + +tBTM_SET_PRIVACY_MODE_CMPL_CBACK *p_set_privacy_mode_cmpl_cb; + tBTM_CMPL_CB *p_le_test_cmd_cmpl_cb; /* Callback function to be called when LE test mode command has been sent successfully */ @@ -355,7 +364,7 @@ typedef struct { UINT8 inqfilt_type; /* Contains the inquiry filter type (BD ADDR, COD, or Clear) */ #define BTM_INQ_INACTIVE_STATE 0 -#define BTM_INQ_CLR_FILT_STATE 1 /* Currently clearing the inquiry filter preceeding the inquiry request */ +#define BTM_INQ_CLR_FILT_STATE 1 /* Currently clearing the inquiry filter preceding the inquiry request */ /* (bypassed if filtering is not used) */ #define BTM_INQ_SET_FILT_STATE 2 /* Sets the new filter (or turns off filtering) in this state */ #define BTM_INQ_ACTIVE_STATE 3 /* Actual inquiry or periodic inquiry is in progress */ @@ -715,7 +724,8 @@ struct tBTM_SEC_DEV_REC{ */ typedef struct { #if BTM_MAX_LOC_BD_NAME_LEN > 0 - tBTM_LOC_BD_NAME bd_name; /* local Bluetooth device name */ + tBTM_LOC_BD_NAME bredr_bd_name; /* local BREDR device name */ + tBTM_LOC_BD_NAME ble_bd_name; /* local BLE device name */ #endif BOOLEAN pin_type; /* TRUE if PIN type is fixed */ UINT8 pin_code_len; /* Bonding information */ @@ -949,8 +959,8 @@ typedef struct { UINT8 acl_disc_reason; UINT8 trace_level; UINT8 busy_level; /* the current busy level */ - BOOLEAN is_paging; /* TRUE, if paging is in progess */ - BOOLEAN is_inquiry; /* TRUE, if inquiry is in progess */ + BOOLEAN is_paging; /* TRUE, if paging is in progress */ + BOOLEAN is_inquiry; /* TRUE, if inquiry is in progress */ fixed_queue_t *page_queue; BOOLEAN paging; BOOLEAN discing; @@ -963,9 +973,11 @@ typedef struct { typedef struct{ //connection parameters update callback tBTM_UPDATE_CONN_PARAM_CBACK *update_conn_param_cb; + // setting packet data length callback + tBTM_SET_PKT_DATA_LENGTH_CBACK *set_pkt_data_length_cb; }tBTM_CallbackFunc; -extern tBTM_CallbackFunc conn_param_update_cb; +extern tBTM_CallbackFunc conn_callback_func; /* security action for L2CAP COC channels */ #define BTM_SEC_OK 1 #define BTM_SEC_ENCRYPT 2 /* encrypt the link with current key */ @@ -1148,6 +1160,9 @@ void btm_delete_stored_link_key_complete (UINT8 *p); void btm_report_device_status (tBTM_DEV_STATUS status); void btm_set_afh_channels_complete (UINT8 *p); void btm_ble_set_channels_complete (UINT8 *p); +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +void btm_set_min_enc_key_size_complete(const UINT8 *p); +#endif void btm_set_page_timeout_complete (const UINT8 *p); void btm_page_to_setup_timeout (void *p_tle); diff --git a/lib/bt/host/bluedroid/stack/btu/btu_hcif.c b/lib/bt/host/bluedroid/stack/btu/btu_hcif.c index 1b841154..30e76125 100644 --- a/lib/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/lib/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -998,6 +998,16 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l case HCI_WRITE_PAGE_TOUT: btm_set_page_timeout_complete(p); break; +#if (ENC_KEY_SIZE_CTRL_MODE == ENC_KEY_SIZE_CTRL_MODE_STD) + case HCI_SET_MIN_ENC_KEY_SIZE: + btm_set_min_enc_key_size_complete(p); + break; +#endif +#if (ENC_KEY_SIZE_CTRL_MODE == ENC_KEY_SIZE_CTRL_MODE_VSC) + case HCI_VENDOR_BT_SET_MIN_ENC_KEY_SIZE: + btm_set_min_enc_key_size_complete(p); + break; +#endif #endif #if (BLE_INCLUDED == TRUE) @@ -1088,7 +1098,12 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l btm_ble_set_addr_resolution_enable_complete(p, evt_len); break; case HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT: + btm_ble_set_rpa_timeout_complete(p, evt_len); break; + case HCI_BLE_SET_PRIVACY_MODE: + btm_ble_set_privacy_mode_complete(p, evt_len); + break; +#endif // #if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) #if (BLE_50_FEATURE_SUPPORT == TRUE) case HCI_BLE_SET_EXT_ADV_PARAM: case HCI_BLE_SET_EXT_ADV_DATA: @@ -1128,7 +1143,6 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l break; } #endif // #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) -#endif #endif /* (BLE_INCLUDED == TRUE) */ default: { @@ -1241,6 +1255,9 @@ static void btu_hcif_command_complete_evt(BT_HDR *response, void *context) static void btu_hcif_hdl_command_status (UINT16 opcode, UINT8 status, UINT8 *p_cmd, void *p_vsc_status_cback) { + if (status != HCI_SUCCESS){ + HCI_TRACE_WARNING("%s,opcode:0x%04x,status:0x%02x", __func__, opcode,status); + } BD_ADDR bd_addr; UINT16 handle; #if BTM_SCO_INCLUDED == TRUE @@ -1454,7 +1471,6 @@ static void btu_hcif_command_status_evt(uint8_t status, BT_HDR *command, void *c hack->context = context; event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK; - if (btu_task_post(SIG_BTU_HCI_MSG, event, OSI_THREAD_MAX_TIMEOUT) == false) { osi_free(event); } diff --git a/lib/bt/host/bluedroid/stack/btu/btu_init.c b/lib/bt/host/bluedroid/stack/btu/btu_init.c index 615fbf80..9ede9c2d 100644 --- a/lib/bt/host/bluedroid/stack/btu/btu_init.c +++ b/lib/bt/host/bluedroid/stack/btu/btu_init.c @@ -98,11 +98,11 @@ void btu_init_core(void) #endif #if BLE_INCLUDED == TRUE -#if (defined(GATT_INCLUDED) && GATT_INCLUDED == true) - gatt_init(); -#endif #if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE) SMP_Init(); +#endif +#if (defined(GATT_INCLUDED) && GATT_INCLUDED == true) + gatt_init(); #endif btm_ble_init(); #endif diff --git a/lib/bt/host/bluedroid/stack/gap/gap_ble.c b/lib/bt/host/bluedroid/stack/gap/gap_ble.c index 5bac86f0..e3215129 100644 --- a/lib/bt/host/bluedroid/stack/gap/gap_ble.c +++ b/lib/bt/host/bluedroid/stack/gap/gap_ble.c @@ -65,7 +65,7 @@ static const tGATT_CBACK gap_cback = { ** ** Function gap_find_clcb_by_bd_addr ** -** Description The function searches all LCB with macthing bd address +** Description The function searches all LCB with matching bd address ** ** Returns total number of clcb found. ** @@ -88,7 +88,7 @@ tGAP_CLCB *gap_find_clcb_by_bd_addr(BD_ADDR bda) ** ** Function gap_ble_find_clcb_by_conn_id ** -** Description The function searches all LCB with macthing connection ID +** Description The function searches all LCB with matching connection ID ** ** Returns total number of clcb found. ** @@ -163,7 +163,7 @@ void gap_ble_dealloc_clcb(tGAP_CLCB *p_clcb) ** ** Description The function enqueue a GAP client request ** -** Returns TRUE is successul; FALSE otherwise +** Returns TRUE is successful; FALSE otherwise ** *******************************************************************************/ BOOLEAN gap_ble_enqueue_request (tGAP_CLCB *p_clcb, UINT16 uuid, tGAP_BLE_CMPL_CBACK *p_cback) @@ -185,7 +185,7 @@ BOOLEAN gap_ble_enqueue_request (tGAP_CLCB *p_clcb, UINT16 uuid, tGAP_BLE_CMPL_C ** ** Description The function dequeue a GAP client request if any ** -** Returns TRUE is successul; FALSE otherwise +** Returns TRUE is successful; FALSE otherwise ** *******************************************************************************/ BOOLEAN gap_ble_dequeue_request (tGAP_CLCB *p_clcb, UINT16 *p_uuid, tGAP_BLE_CMPL_CBACK **p_cback) @@ -221,7 +221,7 @@ tGATT_STATUS gap_read_attr_value (UINT16 handle, tGATT_VALUE *p_value, BOOLEAN i switch (p_db_attr->uuid) { case GATT_UUID_GAP_DEVICE_NAME: - BTM_ReadLocalDeviceName((char **)&p_dev_name); + BTM_ReadLocalDeviceName((char **)&p_dev_name, BT_DEVICE_TYPE_BLE); if (strlen ((char *)p_dev_name) > GATT_MAX_ATTR_LEN) { p_value->len = GATT_MAX_ATTR_LEN; } else { @@ -304,7 +304,7 @@ UINT8 gap_proc_write_req( tGATTS_REQ_TYPE type, tGATT_WRITE_REQ *p_data) case GATT_UUID_GAP_DEVICE_NAME: { UINT8 *p_val = p_data->value; p_val[p_data->len] = '\0'; - BTM_SetLocalDeviceName((char *)p_val); + BTM_SetLocalDeviceName((char *)p_val, BT_DEVICE_TYPE_BLE); return GATT_SUCCESS; } #endif @@ -385,7 +385,7 @@ void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id, ** ** Function btm_ble_att_db_init ** -** Description GAP ATT database initalization. +** Description GAP ATT database initialization. ** ** Returns void. ** @@ -510,7 +510,7 @@ void GAP_BleAttrDBUpdate(UINT16 attr_uuid, tGAP_BLE_ATTR_VALUE *p_value) break; case GATT_UUID_GAP_DEVICE_NAME: - BTM_SetLocalDeviceName((char *)p_value->p_dev_name); + BTM_SetLocalDeviceName((char *)p_value->p_dev_name, BT_DEVICE_TYPE_BLE); break; case GATT_UUID_GAP_CENTRAL_ADDR_RESOL: @@ -529,7 +529,7 @@ void GAP_BleAttrDBUpdate(UINT16 attr_uuid, tGAP_BLE_ATTR_VALUE *p_value) ** ** Function gap_ble_send_cl_read_request ** -** Description utility function to send a read request for a GAP charactersitic +** Description utility function to send a read request for a GAP characteristic ** ** Returns TRUE if read started, else FALSE if GAP is busy ** diff --git a/lib/bt/host/bluedroid/stack/gatt/gatt_db.c b/lib/bt/host/bluedroid/stack/gatt/gatt_db.c index e84580bc..efae6413 100644 --- a/lib/bt/host/bluedroid/stack/gatt/gatt_db.c +++ b/lib/bt/host/bluedroid/stack/gatt/gatt_db.c @@ -1242,7 +1242,7 @@ tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code, else if ( (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) && (p_attr->uuid == GATT_UUID_CHAR_CLIENT_CONFIG || p_attr->uuid == GATT_UUID_CHAR_SRVR_CONFIG || - p_attr->uuid == GATT_UUID_CLIENT_SUP_FEAT || + p_attr->uuid == GATT_UUID_CLIENT_SUP_FEAT || p_attr->uuid == GATT_UUID_GAP_ICON ) ) // btla-specific -- diff --git a/lib/bt/host/bluedroid/stack/hcic/hciblecmds.c b/lib/bt/host/bluedroid/stack/hcic/hciblecmds.c index 0f6408f0..52a2b2dc 100644 --- a/lib/bt/host/bluedroid/stack/hcic/hciblecmds.c +++ b/lib/bt/host/bluedroid/stack/hcic/hciblecmds.c @@ -1909,4 +1909,28 @@ UINT8 btsnd_hcic_ble_set_default_periodic_adv_sync_trans_params(UINT8 mode, UINT return btu_hcif_send_cmd_sync(LOCAL_BR_EDR_CONTROLLER_ID, p); } #endif // #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) + +UINT8 btsnd_hcic_ble_set_privacy_mode(UINT8 addr_type, BD_ADDR addr, UINT8 privacy_mode) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_SET_PRIVACY_MODE)) == NULL) { + return (FALSE); + } + + pp = (UINT8 *)(p + 1); + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_PRIVACY_MODE; + p->offset = 0; + + UINT16_TO_STREAM(pp, HCI_BLE_SET_PRIVACY_MODE); + UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_SET_PRIVACY_MODE); + + UINT8_TO_STREAM(pp, addr_type); + BDADDR_TO_STREAM(pp, addr); + UINT8_TO_STREAM(pp, privacy_mode); + + btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} #endif diff --git a/lib/bt/host/bluedroid/stack/hcic/hcicmds.c b/lib/bt/host/bluedroid/stack/hcic/hcicmds.c index 89995eba..3a176a58 100644 --- a/lib/bt/host/bluedroid/stack/hcic/hcicmds.c +++ b/lib/bt/host/bluedroid/stack/hcic/hcicmds.c @@ -1910,4 +1910,30 @@ BOOLEAN btsnd_hcic_set_afh_channels (AFH_CHANNELS channels) btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); return (TRUE); } + +#if (ENC_KEY_SIZE_CTRL_MODE == ENC_KEY_SIZE_CTRL_MODE_STD) +BOOLEAN btsnd_hcic_set_min_enc_key_size (UINT8 size) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_MIN_ENC_KEY_SIZE)) == NULL) { + return (FALSE); + } + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_MIN_ENC_KEY_SIZE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_SET_MIN_ENC_KEY_SIZE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SET_MIN_ENC_KEY_SIZE); + + UINT8_TO_STREAM (pp, size); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} +#endif + #endif /// CLASSIC_BT_INCLUDED == TRUE diff --git a/lib/bt/host/bluedroid/stack/hid/hidd_conn.c b/lib/bt/host/bluedroid/stack/hid/hidd_conn.c index 3b44402e..5a8e36ee 100644 --- a/lib/bt/host/bluedroid/stack/hid/hidd_conn.c +++ b/lib/bt/host/bluedroid/stack/hid/hidd_conn.c @@ -231,7 +231,7 @@ static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) tHID_CONN *p_hcon = &hd_cb.device.conn; HIDD_TRACE_EVENT("%s: cid=%04x result=%d, conn_state=%d", __func__, cid, result, p_hcon->conn_state); if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } if (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) || @@ -243,10 +243,12 @@ static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) } if (result != L2CAP_CONN_OK) { HIDD_TRACE_WARNING("%s: connection failed, now disconnect", __func__); - if (cid == p_hcon->ctrl_cid) + if (cid == p_hcon->ctrl_cid) { p_hcon->ctrl_cid = 0; - else + } else { p_hcon->intr_cid = 0; + } + hidd_conn_disconnect(); hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_L2CAP_CONN_FAIL | (uint32_t)result, NULL); return; @@ -278,7 +280,7 @@ static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO *p_cfg) HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid); p_hcon = &hd_cb.device.conn; if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE)) @@ -297,7 +299,8 @@ static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO *p_cfg) // update flags if (cid == p_hcon->ctrl_cid) { p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE; - if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) { + if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE) && + (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)) { p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) { p_hcon->conn_state = HID_CONN_STATE_UNUSED; @@ -330,7 +333,7 @@ static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO *p_cfg) HIDD_TRACE_EVENT("%s: cid=%04x pcfg->result=%d", __func__, cid, p_cfg->result); p_hcon = &hd_cb.device.conn; if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } if (p_hcon->intr_cid == cid && p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS && p_cfg->qos_present) { @@ -357,7 +360,8 @@ static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO *p_cfg) // update flags if (cid == p_hcon->ctrl_cid) { p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE; - if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) { + if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE) && + (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)) { p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) { p_hcon->conn_state = HID_CONN_STATE_UNUSED; @@ -389,11 +393,14 @@ static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed); p_hcon = &hd_cb.device.conn; if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } - if (ack_needed) + + if (ack_needed) { L2CA_DisconnectRsp(cid); + } + if (cid == p_hcon->ctrl_cid) { p_hcon->ctrl_cid = 0; p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL; @@ -417,7 +424,7 @@ static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) * * Function hidd_l2cif_disconnect_cfm * - * Description Handles L2CAP disconection response + * Description Handles L2CAP disconnection response * * Returns void * @@ -428,7 +435,7 @@ static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result) HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result); p_hcon = &hd_cb.device.conn; if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } if (cid == p_hcon->ctrl_cid) { @@ -465,7 +472,7 @@ static void hidd_l2cif_cong_ind(uint16_t cid, bool congested) HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested); p_hcon = &hd_cb.device.conn; if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } if (congested) { @@ -492,7 +499,7 @@ static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR *p_msg) HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid); p_hcon = &hd_cb.device.conn; if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); osi_free(p_msg); return; } @@ -645,7 +652,7 @@ tHID_STATUS hidd_conn_initiate(void) p_dev->conn.ctrl_cid = 0; p_dev->conn.intr_cid = 0; p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL; - p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG; + p_dev->conn.conn_flags |= HID_CONN_FLAGS_IS_ORIG; BTM_SetOutService(p_dev->addr, BTM_SEC_SERVICE_HIDD_SEC_CTRL, HIDD_SEC_CHN); /* Check if L2CAP started the connection process */ if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr)) == 0) { diff --git a/lib/bt/host/bluedroid/stack/hid/hidh_api.c b/lib/bt/host/bluedroid/stack/hid/hidh_api.c index ea8e73a7..ec072845 100644 --- a/lib/bt/host/bluedroid/stack/hid/hidh_api.c +++ b/lib/bt/host/bluedroid/stack/hid/hidh_api.c @@ -651,4 +651,23 @@ BOOLEAN hid_known_hid_device (BD_ADDR bd_addr) return FALSE; } +BOOLEAN HID_HostConnectOrig(UINT8 dev_handle) +{ + BOOLEAN ret = FALSE; + + do { + if (!hh_cb.reg_flag) { + break; + } + + if ((dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use)) { + break; + } + + ret = hidh_conn_is_orig(dev_handle); + } while (0); + + return ret; +} + #endif //HID_HOST_INCLUDED diff --git a/lib/bt/host/bluedroid/stack/hid/hidh_conn.c b/lib/bt/host/bluedroid/stack/hid/hidh_conn.c index 801f087c..f9d4a47b 100644 --- a/lib/bt/host/bluedroid/stack/hid/hidh_conn.c +++ b/lib/bt/host/bluedroid/stack/hid/hidh_conn.c @@ -457,8 +457,8 @@ static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) if (l2cap_cid == p_hcon->ctrl_cid) { p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE; - if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && - (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) { + if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE) && + (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)) { /* Connect interrupt channel */ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */ if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0) { @@ -528,8 +528,8 @@ static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) if (l2cap_cid == p_hcon->ctrl_cid) { p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE; - if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && - (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) { + if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE) && + (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)) { /* Connect interrupt channel */ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */ if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0) { @@ -968,7 +968,7 @@ tHID_STATUS hidh_conn_initiate (UINT8 dhandle) p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */ /* We are the originator of this connection */ - p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG; + p_dev->conn.conn_flags |= HID_CONN_FLAGS_IS_ORIG; if (p_dev->attr_mask & HID_SEC_REQUIRED) { service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL; @@ -989,6 +989,20 @@ tHID_STATUS hidh_conn_initiate (UINT8 dhandle) return ( HID_SUCCESS ); } +/******************************************************************************* +** +** Function hidh_conn_is_orig +** +** Description This function check if we are the originator of this connection +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN hidh_conn_is_orig(UINT8 dhandle) +{ + tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle]; + return (p_dev->conn.conn_flags & HID_CONN_FLAGS_IS_ORIG); +} /******************************************************************************* ** diff --git a/lib/bt/host/bluedroid/stack/hid/include/hid_int.h b/lib/bt/host/bluedroid/stack/hid/include/hid_int.h index b4208966..beaca21e 100644 --- a/lib/bt/host/bluedroid/stack/hid/include/hid_int.h +++ b/lib/bt/host/bluedroid/stack/hid/include/hid_int.h @@ -39,7 +39,6 @@ typedef struct per_device_ctb { UINT16 attr_mask; /* 0x01- virtual_cable; 0x02- normally_connectable; 0x03- reconn_initiate; 0x04- sdp_disable; */ UINT8 state; /* Device state if in HOST-KNOWN mode */ - UINT8 conn_substate; UINT8 conn_tries; /* Remembers to the number of connection attempts while CONNECTING */ tHID_CONN conn; /* L2CAP channel info */ @@ -66,6 +65,7 @@ extern tHID_STATUS hidh_conn_reg (void); extern void hidh_conn_dereg( void ); extern tHID_STATUS hidh_conn_disconnect (UINT8 dhandle); extern tHID_STATUS hidh_conn_initiate (UINT8 dhandle); +extern BOOLEAN hidh_conn_is_orig(UINT8 dhandle); extern void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle); #ifdef __cplusplus extern "C" { diff --git a/lib/bt/host/bluedroid/stack/include/stack/bt_types.h b/lib/bt/host/bluedroid/stack/include/stack/bt_types.h index be803d50..5d817632 100644 --- a/lib/bt/host/bluedroid/stack/include/stack/bt_types.h +++ b/lib/bt/host/bluedroid/stack/include/stack/bt_types.h @@ -33,6 +33,8 @@ typedef int32_t INT32; #define BCM_STRCPY_S(x1,x2) strcpy((x1),(x2)) #define BCM_STRNCPY_S(x1,x2,x3) strncpy((x1),(x2),(x3)) +#define BCM_STRCMP_S(x1,x2) strcmp((x1),(x2)) +#define BCM_STRNCMP_S(x1,x2,x3) strncmp((x1),(x2),(x3)) /* READ WELL !! ** @@ -676,6 +678,11 @@ typedef void (BT_LOG_FUNC) (int trace_type, const char *fmt_str, ...); typedef uint8_t BD_ADDR[BD_ADDR_LEN]; #endif +/* peer irk */ +#ifndef PEER_IRK_LEN +#define PEER_IRK_LEN 16 +typedef uint8_t PEER_IRK[PEER_IRK_LEN]; +#endif // From bd.c /***************************************************************************** diff --git a/lib/bt/host/bluedroid/stack/include/stack/btm_api.h b/lib/bt/host/bluedroid/stack/include/stack/btm_api.h index 24024505..32420f75 100644 --- a/lib/bt/host/bluedroid/stack/include/stack/btm_api.h +++ b/lib/bt/host/bluedroid/stack/include/stack/btm_api.h @@ -197,6 +197,9 @@ typedef void (tBTM_UPDATE_WHITELIST_CBACK) (UINT8 status, tBTM_WL_OPERATION wl_o typedef void (tBTM_SET_LOCAL_PRIVACY_CBACK) (UINT8 status); +typedef void (tBTM_SET_RPA_TIMEOUT_CMPL_CBACK) (UINT8 status); + +typedef void (tBTM_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK) (UINT8 status); /******************************* ** Device Coexist status ********************************/ @@ -330,7 +333,7 @@ typedef enum { #define BTM_COD_MINOR_CELLULAR 0x04 #define BTM_COD_MINOR_CORDLESS 0x08 #define BTM_COD_MINOR_SMART_PHONE 0x0C -#define BTM_COD_MINOR_WIRED_MDM_V_GTWY 0x10 /* wired modem or voice gatway */ +#define BTM_COD_MINOR_WIRED_MDM_V_GTWY 0x10 /* wired modem or voice gateway */ #define BTM_COD_MINOR_ISDN_ACCESS 0x14 /* minor device class field for LAN Access Point Major Class */ @@ -470,7 +473,6 @@ typedef enum { #define BTM_COD_SERVICE_CLASS_LO_B 0x00E0 #define BTM_COD_SERVICE_CLASS_MASK 0xFFE0 - /* BTM service definitions ** Used for storing EIR data to bit mask */ @@ -860,6 +862,15 @@ typedef struct { UINT16 pkt_types; } tBTM_SET_ACL_PKT_TYPES_RESULTS; +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +/* Structure returned with set minimal encryption key size event (in tBTM_CMPL_CB callback function) +** in response to BTM_SetMinEncKeySize call. +*/ +typedef struct { + UINT8 hci_status; +} tBTM_SET_MIN_ENC_KEY_SIZE_RESULTS; +#endif + /* Structure returned with set BLE channels event (in tBTM_CMPL_CB callback function) ** in response to BTM_BleSetChannels call. */ @@ -1594,7 +1605,7 @@ typedef struct { tBTM_AUTH_REQ loc_auth_req; /* Authentication required for local device */ tBTM_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */ tBTM_IO_CAP loc_io_caps; /* IO Capabilities of the local device */ - tBTM_IO_CAP rmt_io_caps; /* IO Capabilities of the remot device */ + tBTM_IO_CAP rmt_io_caps; /* IO Capabilities of the remote device */ } tBTM_SP_CFM_REQ; /* data type for BTM_SP_KEY_REQ_EVT */ @@ -2067,7 +2078,7 @@ BOOLEAN BTM_IsDeviceUp (void); ** *******************************************************************************/ //extern -tBTM_STATUS BTM_SetLocalDeviceName (char *p_name); +tBTM_STATUS BTM_SetLocalDeviceName (char *p_name, tBT_DEVICE_TYPE name_type); /******************************************************************************* ** @@ -2096,7 +2107,7 @@ tBTM_STATUS BTM_SetDeviceClass (DEV_CLASS dev_class); ** *******************************************************************************/ //extern -tBTM_STATUS BTM_ReadLocalDeviceName (char **p_name); +tBTM_STATUS BTM_ReadLocalDeviceName (char **p_name, tBT_DEVICE_TYPE name_type); /******************************************************************************* ** @@ -2267,7 +2278,7 @@ UINT8 BTM_SetTraceLevel (UINT8 new_level); ** ** Function BTM_WritePageTimeout ** -** Description Send HCI Wite Page Timeout. +** Description Send HCI Write Page Timeout. ** ** Returns ** BTM_SUCCESS Command sent. @@ -2305,6 +2316,22 @@ tBTM_STATUS BTM_ReadPageTimeout(tBTM_CMPL_CB *p_cb); //extern tBTM_STATUS BTM_SetAclPktTypes(BD_ADDR remote_bda, UINT16 pkt_types, tBTM_CMPL_CB *p_cb); +/******************************************************************************* +** +** Function BTM_SetMinEncKeySize +** +** Description Send HCI Set Minimum Encryption Key Size +** +** Returns +** BTM_SUCCESS Command sent. +** BTM_NO_RESOURCES If out of resources to send the command. +** +*******************************************************************************/ +//extern +#if (ENC_KEY_SIZE_CTRL_MODE != ENC_KEY_SIZE_CTRL_MODE_NONE) +tBTM_STATUS BTM_SetMinEncKeySize(UINT8 key_size, tBTM_CMPL_CB *p_cb); +#endif + /******************************************************************************* ** ** Function BTM_WriteVoiceSettings @@ -2459,7 +2486,7 @@ tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, ** Description This function returns a bit mask of the current inquiry state ** ** Returns BTM_INQUIRY_INACTIVE if inactive (0) -** BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active +** BTM_LIMITED_INQUIRY_ACTIVE if a limited inquiry is active ** BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active ** BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active ** @@ -3599,7 +3626,7 @@ BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, ** ** Description Free resources associated with the device. ** -** Returns TRUE if rmoved OK, FALSE if not found +** Returns TRUE if removed OK, FALSE if not found ** *******************************************************************************/ //extern @@ -4245,7 +4272,7 @@ UINT8 BTM_GetEirUuidList( UINT8 *p_eir, UINT8 uuid_size, UINT8 *p_num_uuid, ** pointer is used, PCM parameter maintained in ** the control block will be used; otherwise update ** control block value. -** err_data_rpt: Lisbon feature to enable the erronous data report +** err_data_rpt: Lisbon feature to enable the erroneous data report ** or not. ** ** Returns BTM_SUCCESS if the successful. diff --git a/lib/bt/host/bluedroid/stack/include/stack/btm_ble_api.h b/lib/bt/host/bluedroid/stack/include/stack/btm_ble_api.h index a3085361..1bea9908 100644 --- a/lib/bt/host/bluedroid/stack/include/stack/btm_ble_api.h +++ b/lib/bt/host/bluedroid/stack/include/stack/btm_ble_api.h @@ -144,12 +144,12 @@ typedef UINT8 tBTM_BLE_SFP; #ifndef BTM_BLE_SCAN_FAST_INT #define BTM_BLE_SCAN_FAST_INT 96 /* 30 ~ 60 ms (use 60) = 96 *0.625 */ #endif -/* default scan window for background connection, applicable for auto connection or selective conenction */ +/* default scan window for background connection, applicable for auto connection or selective connection */ #ifndef BTM_BLE_SCAN_FAST_WIN #define BTM_BLE_SCAN_FAST_WIN 48 /* 30 ms = 48 *0.625 */ #endif -/* default scan paramter used in reduced power cycle (background scanning) */ +/* default scan parameter used in reduced power cycle (background scanning) */ #ifndef BTM_BLE_SCAN_SLOW_INT_1 #define BTM_BLE_SCAN_SLOW_INT_1 2048 /* 1.28 s = 2048 *0.625 */ #endif @@ -157,7 +157,7 @@ typedef UINT8 tBTM_BLE_SFP; #define BTM_BLE_SCAN_SLOW_WIN_1 48 /* 30 ms = 48 *0.625 */ #endif -/* default scan paramter used in reduced power cycle (background scanning) */ +/* default scan parameter used in reduced power cycle (background scanning) */ #ifndef BTM_BLE_SCAN_SLOW_INT_2 #define BTM_BLE_SCAN_SLOW_INT_2 4096 /* 2.56 s = 4096 *0.625 */ #endif @@ -254,6 +254,7 @@ typedef UINT8 BLE_SIGNATURE[BTM_BLE_AUTH_SIGN_LEN]; /* Device address */ #define BTM_BLE_APPEARANCE_CYCLING_CADENCE 0x0483 #define BTM_BLE_APPEARANCE_CYCLING_POWER 0x0484 #define BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485 +#define BTM_BLE_APPEARANCE_STANDALONE_SPEAKER 0x0841 #define BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40 #define BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41 #define BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42 @@ -459,7 +460,7 @@ typedef struct { } tBTM_BLE_PROPRIETARY; typedef struct { - tBTM_BLE_INT_RANGE int_range; /* slave prefered conn interval range */ + tBTM_BLE_INT_RANGE int_range; /* slave preferred conn interval range */ tBTM_BLE_MANU *p_manu; /* manufacturer data */ tBTM_BLE_SERVICE *p_services; /* services */ tBTM_BLE_128SERVICE *p_services_128b; /* 128 bits service */ @@ -1005,6 +1006,8 @@ typedef void (tBTM_START_STOP_ADV_CMPL_CBACK) (UINT8 status); typedef void (tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK) (tBTM_STATUS status, uint8_t subcode, uint32_t length, uint8_t *device_info); typedef void (tBTM_CLEAR_ADV_CMPL_CBACK) (UINT8 status); +typedef void (tBTM_SET_PRIVACY_MODE_CMPL_CBACK) (tBTM_STATUS status); + #if (BLE_50_FEATURE_SUPPORT == TRUE) #define BTM_BLE_5_GAP_READ_PHY_COMPLETE_EVT 1 #define BTM_BLE_5_GAP_SET_PREFERED_DEFAULT_PHY_COMPLETE_EVT 2 @@ -1047,7 +1050,8 @@ typedef void (tBTM_CLEAR_ADV_CMPL_CBACK) (UINT8 status); #define BTM_BLE_GAP_SET_PAST_PARAMS_COMPLETE_EVT 38 #define BTM_BLE_GAP_PERIODIC_ADV_SYNC_TRANS_RECV_EVT 39 #endif // #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) -#define BTM_BLE_5_GAP_UNKNOWN_EVT 40 +#define BTM_BLE_GAP_SET_PRIVACY_MODE_COMPLETE_EVT 40 +#define BTM_BLE_5_GAP_UNKNOWN_EVT 41 typedef UINT8 tBTM_BLE_5_GAP_EVENT; #define BTM_BLE_EXT_ADV_DATA_COMPLETE 0x00 @@ -1365,6 +1369,7 @@ extern "C" { ** *******************************************************************************/ void BTM_BleRegiseterConnParamCallback(tBTM_UPDATE_CONN_PARAM_CBACK *update_conn_param_cb); +void BTM_BleRegiseterPktLengthChangeCallback(tBTM_SET_PKT_DATA_LENGTH_CBACK *ptk_len_chane_cb); /******************************************************************************* ** @@ -1894,7 +1899,7 @@ void BTM_BleSecureConnectionCreateOobData(void); ** Function BTM_BleDataSignature ** ** Description This function is called to sign the data using AES128 CMAC -** algorith. +** algorithm. ** ** Parameter bd_addr: target device the data to be signed for. ** p_text: singing data @@ -1902,7 +1907,7 @@ void BTM_BleSecureConnectionCreateOobData(void); ** signature: output parameter where data signature is going to ** be stored. ** -** Returns TRUE if signing sucessul, otherwise FALSE. +** Returns TRUE if signing successful, otherwise FALSE. ** *******************************************************************************/ //extern @@ -2392,7 +2397,7 @@ BOOLEAN BTM_UseLeLink (BD_ADDR bd_addr); ** ** Function BTM_BleStackEnable ** -** Description Enable/Disable BLE functionality on stack regarless controller +** Description Enable/Disable BLE functionality on stack regardless controller ** capability. ** ** Parameters: enable: TRUE to enable, FALSE to disable. @@ -2436,7 +2441,7 @@ BOOLEAN BTM_BleSecurityProcedureIsRunning (BD_ADDR bd_addr); ** Function BTM_BleGetSupportedKeySize ** ** Description This function gets the maximum encryption key size in bytes -** the local device can suport. +** the local device can support. ** record. ** ** Returns the key size or 0 if the size can't be retrieved. @@ -2471,7 +2476,7 @@ tBTM_STATUS BTM_BleEnableAdvInstance (tBTM_BLE_ADV_PARAMS *p_params, ** ** Function BTM_BleUpdateAdvInstParam ** -** Description This function update a Multi-ADV instance with the specififed +** Description This function update a Multi-ADV instance with the specified ** adv parameters. ** ** Parameters inst_id: adv instance ID @@ -2547,7 +2552,7 @@ tBTM_STATUS BTM_BleAdvFilterParamSetup(int action, ** ** Parameters action: to read/write/clear ** cond_type: filter condition type. -** p_cond: filter condition paramter +** p_cond: filter condition parameter ** ** Returns tBTM_STATUS ** @@ -2654,6 +2659,59 @@ BOOLEAN BTM_Ble_Authorization(BD_ADDR bd_addr, BOOLEAN authorize); ** *******************************************************************************/ BOOLEAN BTM_BleClearAdv(tBTM_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cback); + +/******************************************************************************* +** +** Function BTM_BleSetRpaTimeout +** +** Description This function is called to set the Resolvable Private Address +** (RPA) timeout. +** +** Parameter rpa_timeout - The timeout value for RPA, typically in seconds. +** +*******************************************************************************/ +BOOLEAN BTM_BleSetRpaTimeout(uint16_t rpa_timeout, tBTM_SET_RPA_TIMEOUT_CMPL_CBACK *p_set_rpa_timeout_cback); + +/******************************************************************************* +** +** Function BTM_BleAddDevToResolvingList +** +** Description This function is called to add a device to the resolving list +** used to generate and resolve Resolvable Private Addresses (RPAs) +** in the Bluetooth Controller. +** +** Parameters addr - The address of the device to be added to the resolving list. +** addr_type - The address type of the device (public or random). +** irk - The Identity Resolving Key (IRK) of the device. +** p_add_dev_to_resolving_list_callback - Callback function to be called when the operation is completed. +** +** Returns TRUE if the operation was successful, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_BleAddDevToResolvingList(BD_ADDR addr, + uint8_t addr_type, + uint8_t irk[], + tBTM_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK *p_add_dev_to_resolving_list_callback); + +/******************************************************************************* +** +** Function BTM_BleSetPrivacyMode +** +** Description This function is called to set the privacy mode of device in resolving list +** +** Parameters addr_type - The address type of the device in resolving list (public or random). +** addr - The address of the device in resolving list. +** privacy_mode - The privacy mode (network or device) of the device. +** p_callback - Callback function to be called when the operation is completed. +** +** Returns TRUE if the operation was successful, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_BleSetPrivacyMode(UINT8 addr_type, + BD_ADDR bd_addr, + UINT8 privacy_mode, + tBTM_SET_PRIVACY_MODE_CMPL_CBACK *p_callback); + /* #ifdef __cplusplus } diff --git a/lib/bt/host/bluedroid/stack/include/stack/gatt_api.h b/lib/bt/host/bluedroid/stack/include/stack/gatt_api.h index 7872e139..fed2ea9a 100644 --- a/lib/bt/host/bluedroid/stack/include/stack/gatt_api.h +++ b/lib/bt/host/bluedroid/stack/include/stack/gatt_api.h @@ -139,7 +139,7 @@ typedef UINT16 tGATT_DISCONN_REASON; /* max length of an attribute value */ #ifndef GATT_MAX_ATTR_LEN -#define GATT_MAX_ATTR_LEN 600 +#define GATT_MAX_ATTR_LEN 512 #endif /* default GATT MTU size over LE link @@ -701,7 +701,7 @@ extern UINT8 GATT_SetTraceLevel (UINT8 new_level); ** ** Function GATTS_AddHandleRange ** -** Description This function add the allocated handles range for the specifed +** Description This function add the allocated handles range for the specified ** application UUID, service UUID and service instance ** ** Parameter p_hndl_range: pointer to allocated handles information @@ -720,7 +720,7 @@ extern BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range); ** NV save callback function. There can be one and only one ** NV save callback function. ** -** Parameter p_cb_info : callback informaiton +** Parameter p_cb_info : callback information ** ** Returns TRUE if registered OK, else FALSE ** @@ -1143,7 +1143,7 @@ extern BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, tBLE_ADDR_TYPE b ** ** Function GATT_CancelConnect ** -** Description This function terminate the connection initaition to a remote +** Description This function terminate the connection initiation to a remote ** device on GATT channel. ** ** Parameters gatt_if: client interface. If 0 used as unconditionally disconnect, diff --git a/lib/bt/host/bluedroid/stack/include/stack/hcidefs.h b/lib/bt/host/bluedroid/stack/include/stack/hcidefs.h index 8c5ba3f2..21b14881 100644 --- a/lib/bt/host/bluedroid/stack/include/stack/hcidefs.h +++ b/lib/bt/host/bluedroid/stack/include/stack/hcidefs.h @@ -212,6 +212,7 @@ #define HCI_WRITE_ERRONEOUS_DATA_RPT (0x005B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) #define HCI_ENHANCED_FLUSH (0x005F | HCI_GRP_HOST_CONT_BASEBAND_CMDS) #define HCI_SEND_KEYPRESS_NOTIF (0x0060 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_MIN_ENC_KEY_SIZE (0x0084 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) /* AMP HCI */ @@ -383,8 +384,8 @@ #define HCI_BLE_RD_TRANSMIT_POWER (0x004B | HCI_GRP_BLE_CMDS) #define HCI_BLE_RD_RF_PATH_COMPENSATION (0x004C | HCI_GRP_BLE_CMDS) #define HCI_BLE_WR_RF_PATH_COMPENSATION (0x004D | HCI_GRP_BLE_CMDS) -#define HCI_BLE_SET_PRIVACY_MODE (0x004E | HCI_GRP_BLE_CMDS) #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) +#define HCI_BLE_SET_PRIVACY_MODE (0x004E | HCI_GRP_BLE_CMDS) #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) #define HCI_BLE_SET_PERIOD_ADV_RECV_ENABLE (0x0059 | HCI_GRP_BLE_CMDS) #define HCI_BLE_PERIOD_ADV_SYNC_TRANS (0x005A | HCI_GRP_BLE_CMDS) @@ -424,8 +425,9 @@ #define HCI_SUBCODE_BLE_MAX 0x7F //ESP BT subcode define -#define HCI_SUBCODE_BT_INIT 0x00 -#define HCI_SUBCODE_BT_MAX 0x7F +#define HCI_SUBCODE_BT_INIT 0x00 +#define HCI_SUBCODE_BT_SET_MIN_ENC_KEY_SIZE 0x02 +#define HCI_SUBCODE_BT_MAX 0x7F #define HCI_ESP_VENDOR_OPCODE_BUILD(ogf, group, subcode) ((ogf << 10) | (group <<7) | (subcode << 0)) /* @@ -467,6 +469,7 @@ /* BLE clear legacy advertising */ #define HCI_VENDOR_BLE_CLEAR_ADV HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_CLEAR_ADV) //ESP BT HCI CMD +#define HCI_VENDOR_BT_SET_MIN_ENC_KEY_SIZE HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BT, HCI_SUBCODE_BT_SET_MIN_ENC_KEY_SIZE) /* subcode for multi adv feature */ #define BTM_BLE_MULTI_ADV_SET_PARAM 0x01 @@ -1131,18 +1134,18 @@ typedef UINT8 tHCI_STATUS; #define HCI_MIN_INQ_LAP 0x9E8B00 #define HCI_MAX_INQ_LAP 0x9E8B3F -/* HCI role defenitions */ +/* HCI role definitions */ #define HCI_ROLE_MASTER 0x00 #define HCI_ROLE_SLAVE 0x01 #define HCI_ROLE_UNKNOWN 0xff -/* HCI mode defenitions */ +/* HCI mode definitions */ #define HCI_MODE_ACTIVE 0x00 #define HCI_MODE_HOLD 0x01 #define HCI_MODE_SNIFF 0x02 #define HCI_MODE_PARK 0x03 -/* HCI Flow Control Mode defenitions */ +/* HCI Flow Control Mode definitions */ #define HCI_PACKET_BASED_FC_MODE 0x00 #define HCI_BLOCK_BASED_FC_MODE 0x01 @@ -1411,7 +1414,7 @@ typedef UINT8 tHCI_STATUS; /* Define an invalid value for a handle */ #define HCI_INVALID_HANDLE 0xFFFF -/* Define max ammount of data in the HCI command */ +/* Define max amount of data in the HCI command */ #define HCI_COMMAND_SIZE 255 /* Define the preamble length for all HCI Commands. diff --git a/lib/bt/host/bluedroid/stack/include/stack/hcimsgs.h b/lib/bt/host/bluedroid/stack/include/stack/hcimsgs.h index bd328fab..951e5b70 100644 --- a/lib/bt/host/bluedroid/stack/include/stack/hcimsgs.h +++ b/lib/bt/host/bluedroid/stack/include/stack/hcimsgs.h @@ -583,6 +583,10 @@ BOOLEAN btsnd_hcic_set_afh_channels (AFH_CHANNELS channels); BOOLEAN btsnd_hcic_ble_set_channels (BLE_CHANNELS channels); #define HCIC_PARAM_SIZE_BLE_SET_CHANNELS 5 +/* set minimum encryption key size */ +BOOLEAN btsnd_hcic_set_min_enc_key_size (UINT8 size); +#define HCIC_PARAM_SIZE_SET_MIN_ENC_KEY_SIZE 1 + BOOLEAN btsnd_hcic_write_pin_type(UINT8 type); /* Write PIN Type */ BOOLEAN btsnd_hcic_write_auto_accept(UINT8 flag); /* Write Auto Accept */ BOOLEAN btsnd_hcic_read_name (void); /* Read Local Name */ @@ -621,7 +625,7 @@ BOOLEAN btsnd_hcic_write_voice_settings(UINT16 flags); /* Write Voice BOOLEAN btsnd_hcic_write_auto_flush_tout(UINT16 handle, - UINT16 timeout); /* Write Retransmit Timout */ + UINT16 timeout); /* Write Retransmit Timeout */ #define HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT 4 @@ -754,6 +758,7 @@ void btsnd_hcic_vendor_spec_cmd (BT_HDR *buffer, UINT16 opcode, #define HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM 11 #define HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL 2 #define HCIC_PARAM_SIZE_BLE_CLEAR_ADV 0 +#define HCIC_PARAM_SIZE_SET_PRIVACY_MODE 8 #if (BLE_50_FEATURE_SUPPORT == TRUE) #define HCIC_PARAM_SIZE_BLE_READ_PHY 2 #define HCIC_PARAM_SIZE_BLE_SET_DEF_PHY 3 @@ -1037,6 +1042,8 @@ UINT8 btsnd_hcic_ble_write_rf_path_compensation(UINT16 rf_tx_path, UINT16 rf_rx_ #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) +UINT8 btsnd_hcic_ble_set_privacy_mode(UINT8 addr_type, BD_ADDR addr, UINT8 privacy_mode); + #define HCIC_PARAM_SIZE_WRITE_AUTHENT_PAYLOAD_TOUT 4 #define HCI__WRITE_AUTHENT_PAYLOAD_TOUT_HANDLE_OFF 0 diff --git a/lib/bt/host/bluedroid/stack/include/stack/hidh_api.h b/lib/bt/host/bluedroid/stack/include/stack/hidh_api.h index 2ddaf1c5..2445163d 100644 --- a/lib/bt/host/bluedroid/stack/include/stack/hidh_api.h +++ b/lib/bt/host/bluedroid/stack/include/stack/hidh_api.h @@ -249,6 +249,17 @@ BOOLEAN hid_known_hid_device (BD_ADDR bd_addr); *******************************************************************************/ extern UINT8 HID_HostSetTraceLevel (UINT8 new_level); +/******************************************************************************* +** +** Function HID_HostConnectOrig +** +** Description Check if the HID Host initiates the connection +** +** Returns TRUE if the HID Host initiates the connection else FALSE +** +*******************************************************************************/ +extern BOOLEAN HID_HostConnectOrig(UINT8 dev_handle); + #ifdef __cplusplus } #endif diff --git a/lib/bt/host/bluedroid/stack/l2cap/l2c_ble.c b/lib/bt/host/bluedroid/stack/l2cap/l2c_ble.c index 4e6c8534..956a4b7f 100644 --- a/lib/bt/host/bluedroid/stack/l2cap/l2c_ble.c +++ b/lib/bt/host/bluedroid/stack/l2cap/l2c_ble.c @@ -175,14 +175,14 @@ BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bda, UINT16 min_int, UINT16 max_in L2CAP_TRACE_ERROR("There are two connection parameter requests that are being updated, please try later "); } - if ((need_cb == TRUE) && (conn_param_update_cb.update_conn_param_cb != NULL)) { + if ((need_cb == TRUE) && (conn_callback_func.update_conn_param_cb != NULL)) { tBTM_LE_UPDATE_CONN_PRAMS update_param; update_param.max_conn_int = max_int; update_param.min_conn_int = min_int; update_param.conn_int = p_lcb->current_used_conn_interval; update_param.slave_latency = p_lcb->current_used_conn_latency; update_param.supervision_tout = p_lcb->current_used_conn_timeout; - (conn_param_update_cb.update_conn_param_cb)(status, p_lcb->remote_bd_addr, &update_param); + (conn_callback_func.update_conn_param_cb)(status, p_lcb->remote_bd_addr, &update_param); return (status == HCI_SUCCESS); } @@ -287,7 +287,7 @@ UINT8 L2CA_GetBleConnRole (BD_ADDR bd_addr) ** ** Function l2cble_notify_le_connection ** -** Description This function notifiy the l2cap connection to the app layer +** Description This function notify the l2cap connection to the app layer ** ** Returns none ** @@ -647,7 +647,7 @@ void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status, UINT16 conn_in p_lcb->conn_update_mask &= ~L2C_BLE_UPDATE_PARAM_FULL; btu_stop_timer(&p_lcb->upda_con_timer); - if (conn_param_update_cb.update_conn_param_cb != NULL) { + if (conn_callback_func.update_conn_param_cb != NULL) { l2c_send_update_conn_params_cb(p_lcb, status); } @@ -686,7 +686,7 @@ void l2cble_get_conn_param_format_err_from_contoller (UINT8 status, UINT16 handl btu_stop_timer (&p_lcb->upda_con_timer); - if (conn_param_update_cb.update_conn_param_cb != NULL) { + if (conn_callback_func.update_conn_param_cb != NULL) { l2c_send_update_conn_params_cb(p_lcb, status); } if ((p_lcb->conn_update_mask & L2C_BLE_UPDATE_PARAM_FULL) != 0){ @@ -868,7 +868,7 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) ** ** Function l2cble_init_direct_conn ** -** Description This function is to initate a direct connection +** Description This function is to initiate a direct connection ** ** Returns TRUE connection initiated, FALSE otherwise. ** @@ -894,7 +894,7 @@ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) /* There can be only one BLE connection request outstanding at a time */ if (p_dev_rec == NULL) { - L2CAP_TRACE_WARNING ("unknown device, can not initate connection"); + L2CAP_TRACE_WARNING ("unknown device, can not initiate connection"); return (FALSE); } @@ -947,7 +947,7 @@ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) if (!btm_ble_topology_check(BTM_BLE_STATE_INIT)) { l2cu_release_lcb (p_lcb); - L2CAP_TRACE_ERROR("initate direct connection fail, topology limitation"); + L2CAP_TRACE_ERROR("initiate direct connection fail, topology limitation"); return FALSE; } uint32_t link_timeout = L2CAP_BLE_LINK_CONNECT_TOUT; @@ -981,7 +981,7 @@ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) BLE_CE_LEN_MIN, /* UINT16 min_len */ BLE_CE_LEN_MIN)) { /* UINT16 max_len */ l2cu_release_lcb (p_lcb); - L2CAP_TRACE_ERROR("initate direct connection fail, no resources"); + L2CAP_TRACE_ERROR("initiate direct connection fail, no resources"); return (FALSE); } else { p_lcb->link_state = LST_CONNECTING; @@ -1033,7 +1033,7 @@ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) btm_ble_set_conn_st (BLE_DIR_CONN); if(!btsnd_hcic_ble_create_ext_conn(&aux_conn)) { l2cu_release_lcb (p_lcb); - L2CAP_TRACE_ERROR("initate Aux connection failed, no resources"); + L2CAP_TRACE_ERROR("initiate Aux connection failed, no resources"); } #else L2CAP_TRACE_ERROR("BLE 5.0 not support!\n"); @@ -1324,15 +1324,18 @@ void l2cble_process_data_length_change_event(UINT16 handle, UINT16 tx_data_len, if(p_acl) { p_acl->data_length_params = data_length_params; if (p_acl->p_set_pkt_data_cback) { + // Only when the corresponding API is called will the callback be registered (*p_acl->p_set_pkt_data_cback)(BTM_SUCCESS, &data_length_params); + } else { + // If the callback is not registered,using global callback + (*conn_callback_func.set_pkt_data_length_cb)(BTM_SUCCESS, &data_length_params); } - p_acl->data_len_updating = false; if(p_acl->data_len_waiting) { p_acl->data_len_waiting = false; p_acl->p_set_pkt_data_cback = p_acl->p_set_data_len_cback_waiting; p_acl->p_set_data_len_cback_waiting = NULL; - // if value is same, triger callback directly + // if value is same, trigger callback directly if(p_acl->tx_len_waiting == p_acl->data_length_params.tx_len) { if(p_acl->p_set_pkt_data_cback) { (*p_acl->p_set_pkt_data_cback)(BTM_SUCCESS, &p_acl->data_length_params); @@ -1396,7 +1399,7 @@ void l2cble_set_fixed_channel_tx_data_length(BD_ADDR remote_bda, UINT16 fix_cid, *******************************************************************************/ void l2c_send_update_conn_params_cb(tL2C_LCB *p_lcb, UINT8 status) { - if(conn_param_update_cb.update_conn_param_cb != NULL){ + if(conn_callback_func.update_conn_param_cb != NULL){ tBTM_LE_UPDATE_CONN_PRAMS update_param; //if myself update the connection parameters if (p_lcb->updating_param_flag){ @@ -1412,7 +1415,7 @@ void l2c_send_update_conn_params_cb(tL2C_LCB *p_lcb, UINT8 status) update_param.slave_latency = p_lcb->current_used_conn_latency; update_param.supervision_tout = p_lcb->current_used_conn_timeout; - (conn_param_update_cb.update_conn_param_cb)(status, p_lcb->remote_bd_addr, &update_param); + (conn_callback_func.update_conn_param_cb)(status, p_lcb->remote_bd_addr, &update_param); } } diff --git a/lib/bt/host/bluedroid/stack/l2cap/l2c_link.c b/lib/bt/host/bluedroid/stack/l2cap/l2c_link.c index 4b81b4b3..c3118fdd 100644 --- a/lib/bt/host/bluedroid/stack/l2cap/l2c_link.c +++ b/lib/bt/host/bluedroid/stack/l2cap/l2c_link.c @@ -367,6 +367,11 @@ BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason) if (reason != HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT) { BTM_Recovery_Pre_State(); } + #if (BLE_50_FEATURE_SUPPORT == TRUE) + if(btm_ble_inter_get() && reason == HCI_ERR_CONN_FAILED_ESTABLISHMENT) { + BTM_BleStartExtAdvRestart(handle); + } + #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) #endif ///BLE_INCLUDED == TRUE status = FALSE; } else { @@ -438,7 +443,7 @@ BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason) #endif { #if (L2CAP_NUM_FIXED_CHNLS > 0) - /* If we are going to re-use the LCB without dropping it, release all fixed channels + /* If we are going to reuse the LCB without dropping it, release all fixed channels here */ int xx; for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) { @@ -463,9 +468,9 @@ BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason) } p_lcb->p_pending_ccb = NULL; -#if (BLE_INCLUDED == TRUE && GATTC_CONNECT_RETRY_EN == TRUE) +#if (BLE_INCLUDED == TRUE) if(reason == HCI_ERR_CONN_FAILED_ESTABLISHMENT && p_lcb->transport == BT_TRANSPORT_LE) { - + #if (GATTC_CONNECT_RETRY_EN == TRUE) if(p_lcb->link_role == HCI_ROLE_MASTER && p_lcb->retry_create_con < GATTC_CONNECT_RETRY_COUNT) { L2CAP_TRACE_DEBUG("master retry connect, retry count %d reason 0x%x\n", p_lcb->retry_create_con, reason); p_lcb->retry_create_con ++; @@ -475,9 +480,10 @@ BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason) lcb_is_free = FALSE; /* still using this lcb */ } } + #endif // (GATTC_CONNECT_RETRY_EN == TRUE) #if (BLE_50_FEATURE_SUPPORT == TRUE) - if(btm_ble_inter_get() && p_lcb->link_role == HCI_ROLE_SLAVE && p_lcb->retry_create_con < GATTC_CONNECT_RETRY_COUNT) { + if(btm_ble_inter_get() && p_lcb->link_role == HCI_ROLE_SLAVE) { p_lcb->retry_create_con ++; L2CAP_TRACE_DEBUG("slave restart extend adv, retry count %d reason 0x%x\n", p_lcb->retry_create_con, reason); BTM_BleStartExtAdvRestart(handle); @@ -485,7 +491,7 @@ BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason) #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) #if (BLE_42_FEATURE_SUPPORT == TRUE) - if(!btm_ble_inter_get() && p_lcb->link_role == HCI_ROLE_SLAVE && p_lcb->retry_create_con < GATTC_CONNECT_RETRY_COUNT) { + if(!btm_ble_inter_get() && p_lcb->link_role == HCI_ROLE_SLAVE) { p_lcb->retry_create_con ++; L2CAP_TRACE_DEBUG("slave resatrt adv, retry count %d reason 0x%x\n", p_lcb->retry_create_con, reason); btm_ble_start_adv(); @@ -909,7 +915,7 @@ UINT8 l2c_link_pkts_rcvd (UINT16 *num_pkts, UINT16 *handles) ** ** Function l2c_link_role_changed ** -** Description This function is called whan a link's master/slave role change +** Description This function is called when a link's master/slave role change ** event is received. It simply updates the link control block. ** ** Returns void @@ -947,7 +953,7 @@ void l2c_link_role_changed (BD_ADDR bd_addr, UINT8 new_role, UINT8 hci_status) ** ** Function l2c_pin_code_request ** -** Description This function is called whan a pin-code request is received +** Description This function is called when a pin-code request is received ** on a connection. If there are no channels active yet on the ** link, it extends the link first connection timer. Make sure ** that inactivity timer is not extended if PIN code happens diff --git a/lib/bt/host/nimble/Kconfig.in b/lib/bt/host/nimble/Kconfig.in index eec575c3..d02293a8 100644 --- a/lib/bt/host/nimble/Kconfig.in +++ b/lib/bt/host/nimble/Kconfig.in @@ -201,7 +201,7 @@ config BT_NIMBLE_LL_CFG_FEAT_LE_ENCRYPTION help Enable encryption connection -config BT_NIMBLE_SM_SC_LVL +config BT_NIMBLE_SM_LVL int "Security level" depends on BT_NIMBLE_SECURITY_ENABLE default 0 @@ -341,6 +341,13 @@ menu "Memory Settings" low-priority event buffers, then an incoming advertising report will get dropped + config BT_NIMBLE_L2CAP_COC_SDU_BUFF_COUNT + int "L2cap coc Service Data Unit Buffer count" + depends on BT_NIMBLE_ENABLED + default 1 + help + This is the service data unit buffer count for l2cap coc. + endmenu config BT_NIMBLE_GATT_MAX_PROCS @@ -388,8 +395,7 @@ config BT_NIMBLE_RPA_TIMEOUT depends on BT_NIMBLE_ENABLED default 900 help - Time interval between RPA address change. This is applicable in case of - Host based RPA + Time interval between RPA address change. menuconfig BT_NIMBLE_MESH bool "Enable BLE mesh functionality" @@ -492,7 +498,6 @@ config BT_NIMBLE_CRYPTO_STACK_MBEDTLS bool "Override TinyCrypt with mbedTLS for crypto computations" default y depends on BT_NIMBLE_ENABLED - select MBEDTLS_ECP_RESTARTABLE select MBEDTLS_CMAC_C help Enable this option to choose mbedTLS instead of TinyCrypt for crypto @@ -523,7 +528,7 @@ config BT_NIMBLE_ENABLE_CONN_REATTEMPT config BT_NIMBLE_MAX_CONN_REATTEMPT int "Maximum number connection reattempts" - range 1 7 + range 1 255 default 3 depends on BT_NIMBLE_ENABLED && BT_NIMBLE_ENABLE_CONN_REATTEMPT help @@ -591,7 +596,7 @@ if BT_NIMBLE_EXT_ADV Enable this option to start periodic advertisement. config BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER - bool "Enable Transer Sync Events" + bool "Enable Transfer Sync Events" depends on BT_NIMBLE_ENABLE_PERIODIC_ADV default y help @@ -634,8 +639,9 @@ config BT_NIMBLE_PERIODIC_ADV_ENH menuconfig BT_NIMBLE_GATT_CACHING bool "Enable GATT caching" depends on BT_NIMBLE_ENABLED && BT_NIMBLE_50_FEATURE_SUPPORT + select BT_NIMBLE_DYNAMIC_SERVICE help - Enable GATT caching + Enable GATT caching config BT_NIMBLE_GATT_CACHING_MAX_CONNS int "Maximum connections to be cached" depends on BT_NIMBLE_GATT_CACHING @@ -659,7 +665,7 @@ config BT_NIMBLE_GATT_CACHING_MAX_DSCS depends on BT_NIMBLE_GATT_CACHING default 64 help - Set this option to set the upper limit on number of discriptors per connection to be cached. + Set this option to set the upper limit on number of descriptors per connection to be cached. config BT_NIMBLE_WHITELIST_SIZE int "BLE white list size" @@ -900,7 +906,6 @@ config BT_NIMBLE_OPTIMIZE_MULTI_CONN config BT_NIMBLE_ENC_ADV_DATA bool "Encrypted Advertising Data" - depends on SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV help This option is used to enable encrypted advertising data. @@ -942,9 +947,35 @@ menu "Host-controller Transport" help Uart port + choice BT_NIMBLE_HCI_USE_UART_BAUDRATE + prompt "Uart Hci Baud Rate" + default UART_BAUDRATE_921600 + depends on BT_CONTROLLER_DISABLED && BT_NIMBLE_TRANSPORT_UART + help + Uart Baud Rate + + config UART_BAUDRATE_115200 + bool "115200" + config UART_BAUDRATE_230400 + bool "230400" + config UART_BAUDRATE_460800 + bool "460800" + config UART_BAUDRATE_921600 + bool "921600" + endchoice + + config BT_NIMBLE_HCI_UART_BAUDRATE + depends on BT_CONTROLLER_DISABLED && BT_NIMBLE_TRANSPORT_UART + int + default 115200 if UART_BAUDRATE_115200 + default 230400 if UART_BAUDRATE_230400 + default 460800 if UART_BAUDRATE_460800 + default 921600 if UART_BAUDRATE_921600 + choice BT_NIMBLE_USE_HCI_UART_PARITY prompt "Uart PARITY" default UART_PARITY_NONE + depends on BT_CONTROLLER_DISABLED && BT_NIMBLE_TRANSPORT_UART help Uart Parity @@ -960,16 +991,19 @@ menu "Host-controller Transport" int default 0 if !UART_PARITY_NONE default 1 if UART_PARITY_NONE + depends on BT_CONTROLLER_DISABLED && BT_NIMBLE_TRANSPORT_UART config BT_NIMBLE_TRANSPORT_UART_PARITY_ODD int default 0 if !UART_PARITY_ODD default 1 if UART_PARITY_ODD + depends on BT_CONTROLLER_DISABLED && BT_NIMBLE_TRANSPORT_UART config BT_NIMBLE_TRANSPORT_UART_PARITY_EVEN int default 0 if !UART_PARITY_EVEN default 1 if UART_PARITY_EVEN + depends on BT_CONTROLLER_DISABLED && BT_NIMBLE_TRANSPORT_UART config BT_NIMBLE_UART_RX_PIN int "UART Rx pin" diff --git a/lib/bt/host/nimble/esp-hci/src/esp_nimble_hci.c b/lib/bt/host/nimble/esp-hci/src/esp_nimble_hci.c index 9d997389..605b8312 100644 --- a/lib/bt/host/nimble/esp-hci/src/esp_nimble_hci.c +++ b/lib/bt/host/nimble/esp-hci/src/esp_nimble_hci.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -170,7 +170,6 @@ static void ble_hci_rx_acl(uint8_t *data, uint16_t len) OS_EXIT_CRITICAL(sr); } - /* * @brief: BT controller callback function, used to notify the upper layer that * controller is ready to receive command diff --git a/lib/bt/host/nimble/nimble/.mailmap b/lib/bt/host/nimble/nimble/.mailmap index c1458fc5..61be657c 100644 --- a/lib/bt/host/nimble/nimble/.mailmap +++ b/lib/bt/host/nimble/nimble/.mailmap @@ -1,8 +1,20 @@ +Brian Giori Christopher Collins +Christopher Collins +Jakub Rotkiewicz +Jakub Rotkiewicz +Magdalena Kasenberg +Magdalena Kasenberg <–magdalena.kasenberg@codecoup.pl> Marko Kiiskila +Michał Narajowski +Sterling Hughes +Sterling Hughes +Szymon Czapracki +Szymon Janc Vipul Rahane Vipul Rahane Vipul Rahane +Will San Filippo Will San Filippo Will San Filippo diff --git a/lib/bt/host/nimble/nimble/.rat-excludes b/lib/bt/host/nimble/nimble/.rat-excludes index a4bcb91b..f29a97eb 100644 --- a/lib/bt/host/nimble/nimble/.rat-excludes +++ b/lib/bt/host/nimble/nimble/.rat-excludes @@ -17,21 +17,19 @@ pts-sm.txt uncrustify.cfg .style_ignored_dirs .mailmap +requirements.txt # tinycrypt - BSD License. tinycrypt -# Bluetooth Mesh - Apache 2.0 License -mesh - # Queue implementation - BSD License queue.h # mbuf implementation - BSD License os_mbuf.c -# Bluetooth Mesh badge sample - Apache 2.0 License -mesh_badge +# Nordic nRF5 SDK - BSD License +system_nrf52.c -#BabbleSim and EDDT - Apache 2.0 License -babblesim +# CMSIS-CORE - BSD License. +cmsis_nvic.h diff --git a/lib/bt/host/nimble/nimble/LICENSE b/lib/bt/host/nimble/nimble/LICENSE index 08b9b218..960e8257 100644 --- a/lib/bt/host/nimble/nimble/LICENSE +++ b/lib/bt/host/nimble/nimble/LICENSE @@ -215,3 +215,13 @@ under the following license: This product bundles tinycrypt, which is available under the "3-clause BSD" license. For details, and bundled files see: * ext/tinycrypt/LICENSE + +This product bundles and partly derives from parts of the Nordic nRF52 SDK, +which are available under a BSD style license. Relevant files are: + * babblesim/hw/mcu/nordic/nrf52_bsim/src/system_nrf52.c + +This product bundles additional files from CMSIS-CORE, but these files are +missing licensing information. The BSD license was subsequently added to +these files in later releases. These files are: + * babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cmsis_nvic.h + diff --git a/lib/bt/host/nimble/nimble/README.md b/lib/bt/host/nimble/nimble/README.md index 07a893aa..00cb27c6 100644 --- a/lib/bt/host/nimble/nimble/README.md +++ b/lib/bt/host/nimble/nimble/README.md @@ -25,7 +25,21 @@ ## Overview -Apache NimBLE is an open-source Bluetooth 5.1 stack (both Host & Controller) + + + + + + + + + + + + +

+ +Apache NimBLE is an open-source Bluetooth 5.4 stack (both Host & Controller) that completely replaces the proprietary SoftDevice on Nordic chipsets. It is part of [Apache Mynewt project](https://github.com/apache/mynewt-core). @@ -41,9 +55,9 @@ Feature highlight: ## Supported hardware -Controller supports Nordic nRF51 and nRF52 chipsets. Host runs on any board -and architecture [supported](https://github.com/apache/mynewt-core#overview) -by Apache Mynewt OS. +Controller supports Nordic nRF51, nRF52 and nRF5340 chipsets as well as DA1469x (cmac) +from Renesas. Host runs on any board and architecture +[supported](https://github.com/apache/mynewt-core#overview) by Apache Mynewt OS. ## Browsing @@ -105,6 +119,16 @@ Implements a simple BLE peripheral that supports the Nordic UART / Serial Port Emulation service (https://developer.nordicsemi.com/nRF5_SDK/nRF51_SDK_v8.x.x/doc/8.0.0/s110/html/a00072.html). +## External projects using NimBLE + +Several other projects provide support for using NimBLE either by [NPL port](https://github.com/apache/mynewt-nimble/tree/master/porting) or forking: + + * [The Espressif ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/bluetooth/nimble/index.html) contains a NimBLE port for ESP-32 devices. + * [The RIOT](https://doc.riot-os.org/group__pkg__nimble.html) operating system contains a package for using NimBLE. + * [The Open IOT SDK](https://gitlab.arm.com/iot/open-iot-sdk/sdk) contains a NimBLE [port](https://gitlab.arm.com/iot/open-iot-sdk/sdk/-/tree/main/components/bluetooth) based on [CMSIS RTOSv2](https://www.keil.com/pack/doc/CMSIS/RTOS2/html/index.html), which is an RTOS interface implemented by either Amazon Freertos, CMSIS RTX or Azure ThreadX. + + If you publish a NimBLE port, please let us know to include it here! + # Getting Help If you are having trouble using or contributing to Apache Mynewt NimBLE, or just @@ -114,7 +138,7 @@ want to talk to a human about what you're working on, you can contact us via the Although not a formal channel, you can also find a number of core developers on the #mynewt channel on Freenode IRC or #general channel on [Mynewt Slack](https://mynewt.slack.com/join/shared_invite/enQtNjA1MTg0NzgyNzg3LTcyMmZiOGQzOGMxM2U4ODFmMTIwNjNmYTE5Y2UwYjQwZWIxNTE0MTUzY2JmMTEzOWFjYWZkNGM0YmM4MzAxNWQ) -Also, be sure to checkout the [Frequently Asked Questions](https://mynewt.apache.org/faq/answers) +Also, be sure to checkout the [Frequently Asked Questions](https://mynewt.apache.org/latest/mynewt_faq) for some help troubleshooting first. # Contributing diff --git a/lib/bt/host/nimble/nimble/RELEASE_NOTES.md b/lib/bt/host/nimble/nimble/RELEASE_NOTES.md index cde2ce27..afd5e92a 100644 --- a/lib/bt/host/nimble/nimble/RELEASE_NOTES.md +++ b/lib/bt/host/nimble/nimble/RELEASE_NOTES.md @@ -1,24 +1,20 @@ # RELEASE NOTES -20 April 2022 - Apache NimBLE v1.5.0 +09 August 2023 - Apache NimBLE v1.6.0 For full release notes, please visit the [Apache Mynewt Wiki](https://cwiki.apache.org/confluence/display/MYNEWT/Release+Notes). -Apache NimBLE is an open-source Bluetooth 5.3 stack (both Host & Controller) that completely +Apache NimBLE is an open-source Bluetooth 5.4 stack (both Host & Controller) that completely replaces the proprietary SoftDevice on Nordic chipsets. New features in this version of NimBLE include: -* Fake dual-mode option for controller -* LLCP tracing via HCI events -* Code size optimization for disabled GAP roles -* Support for PA/LNA -* LE Secure Connections Only mode -* Support for Bluetooth Core Specification 5.3 -* Connection subrating -* BabbleSim support -* Various bugfixes and improvements +* Initial support for ISO broacaster +* Support for Bluetooth Core Specification 5.4 +* FEM antenna control +* nRF PHY driver unification +* IPC HCI transport improvements If working on next-generation RTOS and Bluetooth protocol stack sounds exciting to you, get in touch, by sending a mail to the Apache Mynewt diff --git a/lib/bt/host/nimble/nimble/apps/advertiser/pkg.yml b/lib/bt/host/nimble/nimble/apps/advertiser/pkg.yml index ad6f133d..2693cdad 100644 --- a/lib/bt/host/nimble/nimble/apps/advertiser/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/advertiser/pkg.yml @@ -24,9 +24,9 @@ pkg.author: "Krzysztof Kopyściński " pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util" diff --git a/lib/bt/host/nimble/nimble/apps/advertiser/syscfg.yml b/lib/bt/host/nimble/nimble/apps/advertiser/syscfg.yml index 963839fc..63b136be 100644 --- a/lib/bt/host/nimble/nimble/apps/advertiser/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/advertiser/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + BLE_ROLE_BROADCASTER: 1 BLE_ROLE_CENTRAL: 0 BLE_ROLE_OBSERVER: 0 diff --git a/lib/bt/host/nimble/nimble/apps/blecent/pkg.yml b/lib/bt/host/nimble/nimble/apps/blecent/pkg.yml index 86e3f016..7b06e627 100644 --- a/lib/bt/host/nimble/nimble/apps/blecent/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/blecent/pkg.yml @@ -24,10 +24,10 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - nimble/host - nimble/host/util - nimble/host/services/gap diff --git a/lib/bt/host/nimble/nimble/apps/blecent/src/main.c b/lib/bt/host/nimble/nimble/apps/blecent/src/main.c index 7f1c5f15..f794937e 100644 --- a/lib/bt/host/nimble/nimble/apps/blecent/src/main.c +++ b/lib/bt/host/nimble/nimble/apps/blecent/src/main.c @@ -272,7 +272,7 @@ blecent_should_connect(const struct ble_gap_disc_desc *disc) rc = ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data); if (rc != 0) { - return rc; + return 0; } /* The device has to advertise support for the Alert Notification diff --git a/lib/bt/host/nimble/nimble/apps/blecent/syscfg.yml b/lib/bt/host/nimble/nimble/apps/blecent/syscfg.yml index e1863839..30c0febb 100644 --- a/lib/bt/host/nimble/nimble/apps/blecent/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/blecent/syscfg.yml @@ -17,6 +17,10 @@ # syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # DEBUG logging is a bit noisy; use INFO. LOG_LEVEL: 1 diff --git a/lib/bt/host/nimble/nimble/apps/blecsc/pkg.yml b/lib/bt/host/nimble/nimble/apps/blecsc/pkg.yml index d3768fc7..3f862f38 100644 --- a/lib/bt/host/nimble/nimble/apps/blecsc/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/blecsc/pkg.yml @@ -26,10 +26,10 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/sysinit" - "@apache-mynewt-core/sys/id" - nimble/host diff --git a/lib/bt/host/nimble/nimble/apps/blecsc/syscfg.yml b/lib/bt/host/nimble/nimble/apps/blecsc/syscfg.yml index abf89969..8234ae8a 100644 --- a/lib/bt/host/nimble/nimble/apps/blecsc/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/blecsc/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Disable central and observer roles. BLE_ROLE_BROADCASTER: 1 BLE_ROLE_CENTRAL: 0 diff --git a/lib/bt/host/nimble/nimble/apps/blehci/pkg.yml b/lib/bt/host/nimble/nimble/apps/blehci/pkg.yml index e385d7da..915ae5b6 100644 --- a/lib/bt/host/nimble/nimble/apps/blehci/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/blehci/pkg.yml @@ -24,8 +24,8 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/sys/console" - - "@apache-mynewt-core/sys/log/stub" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/kernel/os" - nimble/transport diff --git a/lib/bt/host/nimble/nimble/apps/blehci/syscfg.yml b/lib/bt/host/nimble/nimble/apps/blehci/syscfg.yml index ec20e689..3a8f53f7 100644 --- a/lib/bt/host/nimble/nimble/apps/blehci/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/blehci/syscfg.yml @@ -20,7 +20,9 @@ syscfg.vals: # Default task settings OS_MAIN_STACK_SIZE: 64 # Stub console - CONSOLE_MODE: stub + CONSOLE_IMPLEMENTATION: stub + LOG_IMPLEMENTATION: stub + STATS_IMPLEMENTATION: full syscfg.vals.'!BLE_TRANSPORT_NETCORE': # Use UART by default if not built on netcore diff --git a/lib/bt/host/nimble/nimble/apps/blehr/pkg.yml b/lib/bt/host/nimble/nimble/apps/blehr/pkg.yml index ace633b1..43c84ce3 100644 --- a/lib/bt/host/nimble/nimble/apps/blehr/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/blehr/pkg.yml @@ -26,10 +26,10 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/sysinit" - "@apache-mynewt-core/sys/id" - nimble/host diff --git a/lib/bt/host/nimble/nimble/apps/blehr/src/main.c b/lib/bt/host/nimble/nimble/apps/blehr/src/main.c index e09349fa..e6dac7ce 100644 --- a/lib/bt/host/nimble/nimble/apps/blehr/src/main.c +++ b/lib/bt/host/nimble/nimble/apps/blehr/src/main.c @@ -111,7 +111,7 @@ blehr_tx_hrate_stop(void) os_callout_stop(&blehr_tx_timer); } -/* Reset heartrate measurment */ +/* Reset heartrate measurement */ static void blehr_tx_hrate_reset(void) { @@ -193,9 +193,6 @@ blehr_gap_event(struct ble_gap_event *event, void *arg) if (event->subscribe.attr_handle == hrs_hrm_handle) { notify_state = event->subscribe.cur_notify; blehr_tx_hrate_reset(); - } else if (event->subscribe.attr_handle != hrs_hrm_handle) { - notify_state = event->subscribe.cur_notify; - blehr_tx_hrate_stop(); } break; diff --git a/lib/bt/host/nimble/nimble/apps/blehr/syscfg.yml b/lib/bt/host/nimble/nimble/apps/blehr/syscfg.yml index 98cf2554..a34080ed 100644 --- a/lib/bt/host/nimble/nimble/apps/blehr/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/blehr/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Disable central and observer roles. BLE_ROLE_BROADCASTER: 1 BLE_ROLE_CENTRAL: 0 diff --git a/lib/bt/host/nimble/nimble/apps/blemesh/pkg.yml b/lib/bt/host/nimble/nimble/apps/blemesh/pkg.yml index 19fb4782..fb4c4941 100644 --- a/lib/bt/host/nimble/nimble/apps/blemesh/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/blemesh/pkg.yml @@ -24,10 +24,10 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/shell" - nimble/host - nimble/host/services/gap diff --git a/lib/bt/host/nimble/nimble/apps/blemesh/syscfg.yml b/lib/bt/host/nimble/nimble/apps/blemesh/syscfg.yml index 4424b14d..e6e961bf 100644 --- a/lib/bt/host/nimble/nimble/apps/blemesh/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/blemesh/syscfg.yml @@ -17,6 +17,10 @@ # syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Enable the shell task. SHELL_TASK: 1 diff --git a/lib/bt/host/nimble/nimble/apps/blemesh_light/pkg.yml b/lib/bt/host/nimble/nimble/apps/blemesh_light/pkg.yml index bb37ffb5..f261a6f4 100644 --- a/lib/bt/host/nimble/nimble/apps/blemesh_light/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/blemesh_light/pkg.yml @@ -24,10 +24,10 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/shell" - nimble/host - nimble/host/services/gap diff --git a/lib/bt/host/nimble/nimble/apps/blemesh_light/syscfg.yml b/lib/bt/host/nimble/nimble/apps/blemesh_light/syscfg.yml index 826d9d5f..0443549f 100644 --- a/lib/bt/host/nimble/nimble/apps/blemesh_light/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/blemesh_light/syscfg.yml @@ -21,6 +21,10 @@ syscfg.defs: value: 0 syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Enable the shell task. SHELL_TASK: 1 diff --git a/lib/bt/host/nimble/nimble/apps/blemesh_models_example_1/pkg.yml b/lib/bt/host/nimble/nimble/apps/blemesh_models_example_1/pkg.yml index 44e2d79c..3cf9cd81 100644 --- a/lib/bt/host/nimble/nimble/apps/blemesh_models_example_1/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/blemesh_models_example_1/pkg.yml @@ -24,9 +24,9 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - nimble/host - nimble/host/services/gap - nimble/host/services/gatt diff --git a/lib/bt/host/nimble/nimble/apps/blemesh_models_example_1/syscfg.yml b/lib/bt/host/nimble/nimble/apps/blemesh_models_example_1/syscfg.yml index 969753fe..26e178b0 100644 --- a/lib/bt/host/nimble/nimble/apps/blemesh_models_example_1/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/blemesh_models_example_1/syscfg.yml @@ -17,6 +17,10 @@ # syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Set log level to info (disable debug logging). LOG_LEVEL: 1 diff --git a/lib/bt/host/nimble/nimble/apps/blemesh_models_example_2/pkg.yml b/lib/bt/host/nimble/nimble/apps/blemesh_models_example_2/pkg.yml index 194b5546..f4ceacbc 100644 --- a/lib/bt/host/nimble/nimble/apps/blemesh_models_example_2/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/blemesh_models_example_2/pkg.yml @@ -24,9 +24,9 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/encoding/base64" - "@apache-mynewt-core/sys/config" - nimble/host diff --git a/lib/bt/host/nimble/nimble/apps/blemesh_models_example_2/syscfg.yml b/lib/bt/host/nimble/nimble/apps/blemesh_models_example_2/syscfg.yml index b56e9d2d..4ba0e1b7 100644 --- a/lib/bt/host/nimble/nimble/apps/blemesh_models_example_2/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/blemesh_models_example_2/syscfg.yml @@ -17,6 +17,10 @@ # syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Set log level to info (disable debug logging). LOG_LEVEL: 1 diff --git a/lib/bt/host/nimble/nimble/apps/blemesh_shell/pkg.yml b/lib/bt/host/nimble/nimble/apps/blemesh_shell/pkg.yml index a7e457ed..df3a45d4 100644 --- a/lib/bt/host/nimble/nimble/apps/blemesh_shell/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/blemesh_shell/pkg.yml @@ -24,10 +24,10 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/shell" - nimble/host - nimble/host/services/gap diff --git a/lib/bt/host/nimble/nimble/apps/blemesh_shell/syscfg.yml b/lib/bt/host/nimble/nimble/apps/blemesh_shell/syscfg.yml index 0756e46f..a450ae4b 100644 --- a/lib/bt/host/nimble/nimble/apps/blemesh_shell/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/blemesh_shell/syscfg.yml @@ -17,6 +17,10 @@ # syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Enable the shell task. SHELL_TASK: 1 diff --git a/lib/bt/host/nimble/nimble/apps/bleprph/pkg.yml b/lib/bt/host/nimble/nimble/apps/bleprph/pkg.yml index 0bb0d9d0..6a7a354c 100644 --- a/lib/bt/host/nimble/nimble/apps/bleprph/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/bleprph/pkg.yml @@ -29,10 +29,10 @@ pkg.deps: - "@apache-mynewt-core/mgmt/imgmgr" - "@apache-mynewt-core/mgmt/smp" - "@apache-mynewt-core/mgmt/smp/transport/ble" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/sysinit" - "@apache-mynewt-core/sys/id" - nimble/host diff --git a/lib/bt/host/nimble/nimble/apps/bleprph/syscfg.yml b/lib/bt/host/nimble/nimble/apps/bleprph/syscfg.yml index e00eb3b8..0800f213 100644 --- a/lib/bt/host/nimble/nimble/apps/bleprph/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/bleprph/syscfg.yml @@ -38,6 +38,10 @@ syscfg.defs: value: "(int[]){ LED_1, LED_2, LED_3 }" syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Disable central and observer roles. BLE_ROLE_BROADCASTER: 1 BLE_ROLE_CENTRAL: 0 diff --git a/lib/bt/host/nimble/nimble/apps/blestress/pkg.yml b/lib/bt/host/nimble/nimble/apps/blestress/pkg.yml index 21013eb5..e56cdd64 100644 --- a/lib/bt/host/nimble/nimble/apps/blestress/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/blestress/pkg.yml @@ -26,9 +26,9 @@ pkg.deps: - "@mcuboot/boot/bootutil" - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/id" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util" diff --git a/lib/bt/host/nimble/nimble/apps/blestress/src/rx_stress.h b/lib/bt/host/nimble/nimble/apps/blestress/src/rx_stress.h index 62f84117..b2f89719 100644 --- a/lib/bt/host/nimble/nimble/apps/blestress/src/rx_stress.h +++ b/lib/bt/host/nimble/nimble/apps/blestress/src/rx_stress.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include /* BLE */ #include "nimble/ble.h" diff --git a/lib/bt/host/nimble/nimble/apps/blestress/src/stress.c b/lib/bt/host/nimble/nimble/apps/blestress/src/stress.c index 1bdbafa9..1a9cb0c0 100644 --- a/lib/bt/host/nimble/nimble/apps/blestress/src/stress.c +++ b/lib/bt/host/nimble/nimble/apps/blestress/src/stress.c @@ -167,11 +167,13 @@ stress_l2cap_coc_accept(uint16_t peer_mtu, struct ble_l2cap_chan *chan) console_printf("LE CoC accepting, chan: 0x%08lx, peer_mtu %d\n", (uint32_t) chan, peer_mtu); - sdu_rx = os_msys_get_pkthdr(STRESS_COC_MTU, 0); - assert(sdu_rx != NULL); + for (int i = 0; i < MYNEWT_VAL(BLE_L2CAP_COC_SDU_BUFF_COUNT); i++) { + sdu_rx = os_msys_get_pkthdr(STRESS_COC_MTU, 0); + assert(sdu_rx != NULL); - rc = ble_l2cap_recv_ready(chan, sdu_rx); - assert(rc == 0); + rc = ble_l2cap_recv_ready(chan, sdu_rx); + assert(rc == 0); + } } void diff --git a/lib/bt/host/nimble/nimble/apps/blestress/syscfg.yml b/lib/bt/host/nimble/nimble/apps/blestress/syscfg.yml index 3acf280b..5e16ed1f 100644 --- a/lib/bt/host/nimble/nimble/apps/blestress/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/blestress/syscfg.yml @@ -35,6 +35,10 @@ syscfg.defs: # Settings this app overrides. syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Change these settings: # Set 0 to print all debug logs, but keep in mind that plenty of @@ -67,6 +71,9 @@ syscfg.vals: # BLE_L2CAP_COC_MAX_NUM: 2 + # L2CAP COC SDU buffers in RX endpoint + BLE_L2CAP_COC_SDU_BUFF_COUNT: 1 + # Enable 2M PHY BLE_LL_CFG_FEAT_LE_2M_PHY: 1 diff --git a/lib/bt/host/nimble/nimble/apps/btshell/pkg.yml b/lib/bt/host/nimble/nimble/apps/btshell/pkg.yml index abbee73c..b50b371c 100644 --- a/lib/bt/host/nimble/nimble/apps/btshell/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/btshell/pkg.yml @@ -24,10 +24,10 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" - - "@apache-mynewt-core/sys/console/full" + - "@apache-mynewt-core/sys/stats" + - "@apache-mynewt-core/sys/console" - "@apache-mynewt-core/sys/shell" - nimble/host - nimble/host/services/gap diff --git a/lib/bt/host/nimble/nimble/apps/btshell/src/btshell.h b/lib/bt/host/nimble/nimble/apps/btshell/src/btshell.h index f52d65f5..134eb016 100644 --- a/lib/bt/host/nimble/nimble/apps/btshell/src/btshell.h +++ b/lib/bt/host/nimble/nimble/apps/btshell/src/btshell.h @@ -184,7 +184,7 @@ int btshell_l2cap_reconfig(uint16_t conn_handle, uint16_t mtu, int btshell_gap_event(struct ble_gap_event *event, void *arg); void btshell_sync_stats(uint16_t handle); - +uint8_t btshell_get_default_own_addr_type(void); /** GATT server. */ #define GATT_SVR_SVC_ALERT_UUID 0x1811 #define GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47 diff --git a/lib/bt/host/nimble/nimble/apps/btshell/src/cmd.c b/lib/bt/host/nimble/nimble/apps/btshell/src/cmd.c index ddb76c82..4148b8e8 100644 --- a/lib/bt/host/nimble/nimble/apps/btshell/src/cmd.c +++ b/lib/bt/host/nimble/nimble/apps/btshell/src/cmd.c @@ -260,7 +260,7 @@ cmd_advertise_configure(int argc, char **argv) params.own_addr_type = parse_arg_kv_dflt("own_addr_type", cmd_own_addr_types, - BLE_OWN_ADDR_PUBLIC, &rc); + btshell_get_default_own_addr_type(), &rc); if (rc != 0) { console_printf("invalid 'own_addr_type' parameter\n"); return rc; @@ -473,7 +473,7 @@ static const struct shell_param advertise_configure_params[] = { {"directed", "directed advertising, usage: =[0-1], default: 0"}, {"peer_addr_type", "usage: =[public|random|public_id|random_id], default: public"}, {"peer_addr", "usage: =[XX:XX:XX:XX:XX:XX]"}, - {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"}, + {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public if available, otherwise random"}, {"channel_map", "usage: =[0x00-0xff], default: 0"}, {"filter", "usage: =[none|scan|conn|both], default: none"}, {"interval_min", "usage: =[0-UINT32_MAX], default: 0"}, @@ -615,7 +615,7 @@ cmd_advertise(int argc, char **argv) } own_addr_type = parse_arg_kv_dflt("own_addr_type", cmd_own_addr_types, - BLE_OWN_ADDR_PUBLIC, &rc); + btshell_get_default_own_addr_type(), &rc); if (rc != 0) { console_printf("invalid 'own_addr_type' parameter\n"); return rc; @@ -676,7 +676,7 @@ static const struct shell_param advertise_params[] = { {"discov", "discoverable mode, usage: =[non|ltd|gen], default: gen"}, {"peer_addr_type", "usage: =[public|random|public_id|random_id], default: public"}, {"peer_addr", "usage: =[XX:XX:XX:XX:XX:XX]"}, - {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"}, + {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public if available, otherwise random"}, {"channel_map", "usage: =[0x00-0xff], default: 0"}, {"filter", "usage: =[none|scan|conn|both], default: none"}, {"interval_min", "usage: =[0-UINT16_MAX], default: 0"}, @@ -752,7 +752,7 @@ cmd_connect(int argc, char **argv) } own_addr_type = parse_arg_kv_dflt("own_addr_type", cmd_own_addr_types, - BLE_OWN_ADDR_PUBLIC, &rc); + btshell_get_default_own_addr_type(), &rc); if (rc != 0) { console_printf("invalid 'own_addr_type' parameter\n"); return rc; @@ -969,7 +969,7 @@ static const struct shell_param connect_params[] = { {"extended", "usage: =[none|1M|coded|both|all], default: none"}, {"peer_addr_type", "usage: =[public|random|public_id|random_id], default: public"}, {"peer_addr", "usage: =[XX:XX:XX:XX:XX:XX]"}, - {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"}, + {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public if available, otherwise random"}, {"duration", "usage: =[1-INT32_MAX], default: 0"}, {"scan_interval", "usage: =[0-UINT16_MAX], default: 0x0010"}, {"scan_window", "usage: =[0-UINT16_MAX], default: 0x0010"}, @@ -1209,7 +1209,7 @@ cmd_scan(int argc, char **argv) return rc; } - if (argc > 1 && strcmp(argv[1], "cancel") == 0) { + if (argc > 1 && (strcmp(argv[1], "cancel") == 0 || strcmp(argv[1], "off") == 0)) { rc = btshell_scan_cancel(); if (rc != 0) { console_printf("scan cancel fail: %d\n", rc); @@ -1268,7 +1268,7 @@ cmd_scan(int argc, char **argv) } own_addr_type = parse_arg_kv_dflt("own_addr_type", cmd_own_addr_types, - BLE_OWN_ADDR_PUBLIC, &rc); + btshell_get_default_own_addr_type(), &rc); if (rc != 0) { console_printf("invalid 'own_addr_type' parameter\n"); return rc; @@ -1353,6 +1353,7 @@ cmd_scan(int argc, char **argv) #if MYNEWT_VAL(SHELL_CMD_HELP) static const struct shell_param scan_params[] = { {"cancel", "cancel scan procedure"}, + {"off", "\"cancel\" param substitute"}, {"extended", "usage: =[none|1M|coded|both], default: none"}, {"duration", "usage: =[1-INT32_MAX], default: INT32_MAX"}, {"limited", "usage: =[0-1], default: 0"}, @@ -1361,7 +1362,7 @@ static const struct shell_param scan_params[] = { {"window", "usage: =[0-UINT16_MAX], default: 0"}, {"filter", "usage: =[no_wl|use_wl|no_wl_inita|use_wl_inita], default: no_wl"}, {"nodups", "usage: =[0-1], default: 0"}, - {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"}, + {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public if available, otherwise random"}, {"extended_duration", "usage: =[0-UINT16_MAX], default: 0"}, {"extended_period", "usage: =[0-UINT16_MAX], default: 0"}, {"longrange_interval", "usage: =[0-UINT16_MAX], default: 0"}, @@ -2257,17 +2258,6 @@ cmd_keystore_parse_keydata(int argc, char **argv, union ble_store_key *out, return rc; } - out->sec.ediv = parse_arg_uint16("ediv", &rc); - if (rc != 0) { - console_printf("invalid 'ediv' parameter\n"); - return rc; - } - - out->sec.rand_num = parse_arg_uint64("rand", &rc); - if (rc != 0) { - console_printf("invalid 'rand' parameter\n"); - return rc; - } return 0; default: @@ -2316,8 +2306,6 @@ cmd_keystore_parse_valuedata(int argc, char **argv, return rc; } out->sec.peer_addr = key->sec.peer_addr; - out->sec.ediv = key->sec.ediv; - out->sec.rand_num = key->sec.rand_num; break; } diff --git a/lib/bt/host/nimble/nimble/apps/btshell/src/main.c b/lib/bt/host/nimble/nimble/apps/btshell/src/main.c index cc69e5d1..2df37191 100644 --- a/lib/bt/host/nimble/nimble/apps/btshell/src/main.c +++ b/lib/bt/host/nimble/nimble/apps/btshell/src/main.c @@ -76,6 +76,8 @@ bssnz_t struct btshell_conn btshell_conns[MYNEWT_VAL(BLE_MAX_CONNECTIONS)]; int btshell_num_conns; +static uint8_t default_own_addr_type; + static os_membuf_t btshell_svc_mem[ OS_MEMPOOL_SIZE(BTSHELL_MAX_SVCS, sizeof(struct btshell_svc)) ]; @@ -2131,6 +2133,8 @@ btshell_on_sync(void) console_printf("Failed to set identity address\n"); } + ble_hs_id_infer_auto(0, &default_own_addr_type); + #if MYNEWT_VAL(BLE_SM_SC) int rc; @@ -2220,19 +2224,25 @@ btshell_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu) static int btshell_l2cap_coc_accept(uint16_t conn_handle, uint16_t peer_mtu, - struct ble_l2cap_chan *chan) + struct ble_l2cap_chan *chan) { struct os_mbuf *sdu_rx; + int rc; console_printf("LE CoC accepting, chan: 0x%08lx, peer_mtu %d\n", (uint32_t) chan, peer_mtu); - sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); - if (!sdu_rx) { - return BLE_HS_ENOMEM; + for (int i = 0; i < MYNEWT_VAL(BLE_L2CAP_COC_SDU_BUFF_COUNT); i++) { + sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + if (!sdu_rx) { + return BLE_HS_ENOMEM; + } + + rc = ble_l2cap_recv_ready(chan, sdu_rx); + assert(rc == 0); } - return ble_l2cap_recv_ready(chan, sdu_rx); + return rc; } static void @@ -2569,6 +2579,12 @@ btshell_init_ext_adv_restart(void) #endif } +uint8_t +btshell_get_default_own_addr_type(void) +{ + return default_own_addr_type; +} + /** * main * diff --git a/lib/bt/host/nimble/nimble/apps/btshell/syscfg.yml b/lib/bt/host/nimble/nimble/apps/btshell/syscfg.yml index 1535b336..091a2df0 100644 --- a/lib/bt/host/nimble/nimble/apps/btshell/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/btshell/syscfg.yml @@ -22,6 +22,10 @@ syscfg.defs: value: 1 syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Enable the shell task. SHELL_TASK: 1 @@ -41,5 +45,8 @@ syscfg.vals: # Whether to save data to sys/config, or just keep it in RAM. BLE_STORE_CONFIG_PERSIST: 0 + # L2CAP COC SDU buffers in RX endpoint + BLE_L2CAP_COC_SDU_BUFF_COUNT: 1 + syscfg.vals.BLE_MESH: MSYS_1_BLOCK_COUNT: 16 diff --git a/lib/bt/host/nimble/nimble/apps/bttester/pkg.yml b/lib/bt/host/nimble/nimble/apps/bttester/pkg.yml index 219e5298..e763185f 100644 --- a/lib/bt/host/nimble/nimble/apps/bttester/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/bttester/pkg.yml @@ -26,10 +26,10 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/shell" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util" diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp.h b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp.h new file mode 100644 index 00000000..5e1a172e --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp.h @@ -0,0 +1,86 @@ +/* + * 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. + */ + +/* btp.h - Bluetooth tester btp headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bttester.h" +#include "btp_core.h" +#include "btp_gap.h" +#include "btp_gatt.h" +#include "btp_gattc.h" +#include "btp_l2cap.h" +#include "btp_mesh.h" + +#define BTP_MTU MYNEWT_VAL(BTTESTER_BTP_DATA_SIZE_MAX) +#define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr)) + +#define BTP_INDEX_NONE 0xff +#define BTP_INDEX 0x00 + +#define BTP_SERVICE_ID_CORE 0 +#define BTP_SERVICE_ID_GAP 1 +#define BTP_SERVICE_ID_GATT 2 +#define BTP_SERVICE_ID_L2CAP 3 +#define BTP_SERVICE_ID_MESH 4 +#define BTP_SERVICE_ID_GATTC 6 + +#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_GATTC + +#define BTP_STATUS_SUCCESS 0x00 +#define BTP_STATUS_FAILED 0x01 +#define BTP_STATUS_UNKNOWN_CMD 0x02 +#define BTP_STATUS_NOT_READY 0x03 + +/* TODO indicate delay response, should be removed when all commands are + * converted to cmd+status+ev pattern + */ +#define BTP_STATUS_DELAY_REPLY 0xFF + +#define SYS_LOG_DBG(fmt, ...) \ + if (MYNEWT_VAL(BTTESTER_DEBUG)) { \ + console_printf("[DBG] %s: " fmt "\n", \ + __func__, ## __VA_ARGS__); \ + } +#define SYS_LOG_INF(fmt, ...) console_printf("[INF] %s: " fmt "\n", \ + __func__, ## __VA_ARGS__); +#define SYS_LOG_ERR(fmt, ...) console_printf("[WRN] %s: " fmt "\n", \ + __func__, ## __VA_ARGS__); + +#define SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG +#define SYS_LOG_DOMAIN "bttester" + +struct btp_hdr { + uint8_t service; + uint8_t opcode; + uint8_t index; + uint16_t len; + uint8_t data[0]; +} __packed; + +#define BTP_STATUS 0x00 +struct btp_status { + uint8_t code; +} __packed; diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_core.h b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_core.h new file mode 100644 index 00000000..cbf309ce --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_core.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +/* btp_core.h - Bluetooth tester Core service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Core Service */ +#define BTP_CORE_READ_SUPPORTED_COMMANDS 0x01 +struct btp_core_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_CORE_READ_SUPPORTED_SERVICES 0x02 +struct btp_core_read_supported_services_rp { + uint8_t data[0]; +} __packed; + +#define BTP_CORE_REGISTER_SERVICE 0x03 +struct btp_core_register_service_cmd { + uint8_t id; +} __packed; + +#define BTP_CORE_UNREGISTER_SERVICE 0x04 +struct btp_core_unregister_service_cmd { + uint8_t id; +} __packed; + +/* events */ +#define BTP_CORE_EV_IUT_READY 0x80 \ No newline at end of file diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_gap.h b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_gap.h new file mode 100644 index 00000000..93b62c48 --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_gap.h @@ -0,0 +1,344 @@ +/* + * 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. + */ + +/* btp_gap.h - Bluetooth tester GAP service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nimble/ble.h" + +struct adv_data { + uint8_t type; + uint8_t data_len; + const uint8_t *data; +}; + +#define ADV_DATA(_type, _data, _data_len) \ + { \ + .type = (_type), \ + .data_len = (_data_len), \ + .data = (const uint8_t *)(_data), \ + } + +/* GAP Service */ +/* commands */ +#define BTP_GAP_READ_SUPPORTED_COMMANDS 0x01 +struct btp_gap_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_GAP_READ_CONTROLLER_INDEX_LIST 0x02 +struct btp_gap_read_controller_index_list_rp { + uint8_t num; + uint8_t index[0]; +} __packed; + +#define BTP_GAP_SETTINGS_POWERED 0 +#define BTP_GAP_SETTINGS_CONNECTABLE 1 +#define BTP_GAP_SETTINGS_FAST_CONNECTABLE 2 +#define BTP_GAP_SETTINGS_DISCOVERABLE 3 +#define BTP_GAP_SETTINGS_BONDABLE 4 +#define BTP_GAP_SETTINGS_LINK_SEC_3 5 +#define BTP_GAP_SETTINGS_SSP 6 +#define BTP_GAP_SETTINGS_BREDR 7 +#define BTP_GAP_SETTINGS_HS 8 +#define BTP_GAP_SETTINGS_LE 9 +#define BTP_GAP_SETTINGS_ADVERTISING 10 +#define BTP_GAP_SETTINGS_SC 11 +#define BTP_GAP_SETTINGS_DEBUG_KEYS 12 +#define BTP_GAP_SETTINGS_PRIVACY 13 +#define BTP_GAP_SETTINGS_CONTROLLER_CONFIG 14 +#define BTP_GAP_SETTINGS_STATIC_ADDRESS 15 + +#define BTP_GAP_READ_CONTROLLER_INFO 0x03 +struct btp_gap_read_controller_info_rp { + uint8_t address[6]; + uint32_t supported_settings; + uint32_t current_settings; + uint8_t cod[3]; + uint8_t name[249]; + uint8_t short_name[11]; +} __packed; + +#define BTP_GAP_RESET 0x04 +struct btp_gap_reset_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_SET_POWERED 0x05 +struct btp_gap_set_powered_cmd { + uint8_t powered; +} __packed; +struct btp_gap_set_powered_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_SET_CONNECTABLE 0x06 +struct btp_gap_set_connectable_cmd { + uint8_t connectable; +} __packed; +struct btp_gap_set_connectable_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_SET_FAST_CONNECTABLE 0x07 +struct btp_gap_set_fast_connectable_cmd { + uint8_t fast_connectable; +} __packed; +struct btp_gap_set_fast_connectable_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_NON_DISCOVERABLE 0x00 +#define BTP_GAP_GENERAL_DISCOVERABLE 0x01 +#define BTP_GAP_LIMITED_DISCOVERABLE 0x02 + +#define BTP_GAP_SET_DISCOVERABLE 0x08 +struct btp_gap_set_discoverable_cmd { + uint8_t discoverable; +} __packed; +struct btp_gap_set_discoverable_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_SET_BONDABLE 0x09 +struct btp_gap_set_bondable_cmd { + uint8_t bondable; +} __packed; +struct btp_gap_set_bondable_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_START_ADVERTISING 0x0a +struct btp_gap_start_advertising_cmd { + uint8_t adv_data_len; + uint8_t scan_rsp_len; + uint8_t adv_data[0]; + uint8_t scan_rsp[0]; +/* + * This command is very unfortunate because it has two fields after variable + * data. Those needs to be handled explicitly by handler. + * uint32_t duration; + * uint8_t own_addr_type; + */ +} __packed; +struct btp_gap_start_advertising_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_STOP_ADVERTISING 0x0b +struct btp_gap_stop_advertising_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_DISCOVERY_FLAG_LE 0x01 +#define BTP_GAP_DISCOVERY_FLAG_BREDR 0x02 +#define BTP_GAP_DISCOVERY_FLAG_LIMITED 0x04 +#define BTP_GAP_DISCOVERY_FLAG_LE_ACTIVE_SCAN 0x08 +#define BTP_GAP_DISCOVERY_FLAG_LE_OBSERVE 0x10 + +#define BTP_GAP_START_DISCOVERY 0x0c +struct btp_gap_start_discovery_cmd { + uint8_t flags; +} __packed; + +#define BTP_GAP_STOP_DISCOVERY 0x0d + +#define BTP_GAP_CONNECT 0x0e +struct btp_gap_connect_cmd { + ble_addr_t address; + uint8_t own_addr_type; +} __packed; + +#define BTP_GAP_DISCONNECT 0x0f +struct btp_gap_disconnect_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GAP_IO_CAP_DISPLAY_ONLY 0 +#define BTP_GAP_IO_CAP_DISPLAY_YESNO 1 +#define BTP_GAP_IO_CAP_KEYBOARD_ONLY 2 +#define BTP_GAP_IO_CAP_NO_INPUT_OUTPUT 3 +#define BTP_GAP_IO_CAP_KEYBOARD_DISPLAY 4 + +#define BTP_GAP_SET_IO_CAP 0x10 +struct btp_gap_set_io_cap_cmd { + uint8_t io_cap; +} __packed; + +#define BTP_GAP_PAIR 0x11 +struct btp_gap_pair_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GAP_UNPAIR 0x12 +struct btp_gap_unpair_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GAP_PASSKEY_ENTRY 0x13 +struct btp_gap_passkey_entry_cmd { + ble_addr_t address; + uint32_t passkey; +} __packed; + +#define BTP_GAP_PASSKEY_CONFIRM 0x14 +struct btp_gap_passkey_confirm_cmd { + ble_addr_t address; + uint8_t match; +} __packed; + +#define BTP_GAP_START_DIRECT_ADV 0x15 +struct btp_gap_start_direct_adv_cmd { + ble_addr_t address; + uint16_t options; +} __packed; + +#define BTP_GAP_CONN_PARAM_UPDATE 0x16 +struct btp_gap_conn_param_update_cmd { + ble_addr_t address; + uint16_t conn_itvl_min; + uint16_t conn_itvl_max; + uint16_t conn_latency; + uint16_t supervision_timeout; +} __packed; + +#define BTP_GAP_PAIRING_CONSENT_RSP 0x17 +struct btp_gap_pairing_consent_rsp_cmd { + ble_addr_t address; + uint8_t consent; +} __packed; + +#define BTP_GAP_OOB_LEGACY_SET_DATA 0x18 +struct btp_gap_oob_legacy_set_data_cmd { + uint8_t oob_data[16]; +} __packed; + +#define BTP_GAP_OOB_SC_GET_LOCAL_DATA 0x19 +struct btp_gap_oob_sc_get_local_data_rp { + uint8_t r[16]; + uint8_t c[16]; +} __packed; + +#define BTP_GAP_OOB_SC_SET_REMOTE_DATA 0x1a +struct btp_gap_oob_sc_set_remote_data_cmd { + uint8_t r[16]; + uint8_t c[16]; +} __packed; + +#define BTP_GAP_SET_MITM 0x1b +struct btp_gap_set_mitm_cmd { + uint8_t mitm; +} __packed; + +#define BTP_GAP_SET_FILTER_ACCEPT_LIST 0x1c +struct btp_gap_set_filter_accept_list_cmd { + uint8_t list_len; + ble_addr_t addrs[]; +} __packed; +/* events */ +#define BTP_GAP_EV_NEW_SETTINGS 0x80 +struct btp_gap_new_settings_ev { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_DEVICE_FOUND_FLAG_RSSI 0x01 +#define BTP_GAP_DEVICE_FOUND_FLAG_AD 0x02 +#define BTP_GAP_DEVICE_FOUND_FLAG_SD 0x04 + +#define BTP_GAP_EV_DEVICE_FOUND 0x81 +struct btp_gap_device_found_ev { + ble_addr_t address; + int8_t rssi; + uint8_t flags; + uint16_t eir_data_len; + uint8_t eir_data[0]; +} __packed; + +#define BTP_GAP_EV_DEVICE_CONNECTED 0x82 +struct btp_gap_device_connected_ev { + ble_addr_t address; + uint16_t conn_itvl; + uint16_t conn_latency; + uint16_t supervision_timeout; +} __packed; + +#define BTP_GAP_EV_DEVICE_DISCONNECTED 0x83 +struct btp_gap_device_disconnected_ev { + ble_addr_t address; +} __packed; + +#define BTP_GAP_EV_PASSKEY_DISPLAY 0x84 +struct btp_gap_passkey_display_ev { + ble_addr_t address; + uint32_t passkey; +} __packed; + +#define BTP_GAP_EV_PASSKEY_ENTRY_REQ 0x85 +struct btp_gap_passkey_entry_req_ev { + ble_addr_t address; +} __packed; + +#define BTP_GAP_EV_PASSKEY_CONFIRM_REQ 0x86 +struct btp_gap_passkey_confirm_req_ev { + ble_addr_t address; + uint32_t passkey; +} __packed; + +#define BTP_GAP_EV_IDENTITY_RESOLVED 0x87 +struct btp_gap_identity_resolved_ev { + ble_addr_t address; + uint8_t identity_address_type; + uint8_t identity_address; +} __packed; + +#define BTP_GAP_EV_CONN_PARAM_UPDATE 0x88 +struct btp_gap_conn_param_update_ev { + ble_addr_t address; + uint16_t conn_itvl; + uint16_t conn_latency; + uint16_t supervision_timeout; +} __packed; + +#define BTP_GAP_EV_SEC_LEVEL_CHANGED 0x89 +struct btp_gap_sec_level_changed_ev { + ble_addr_t address; + uint8_t level; +} __packed; + +#define BTP_GAP_EV_PAIRING_CONSENT_REQ 0x8a +struct btp_gap_pairing_consent_req_ev { + ble_addr_t address; +} __packed; + +#define BTP_GAP_EV_BOND_LOST 0x8b +struct btp_gap_bond_lost_ev { + ble_addr_t address; +} __packed; + +#define BTP_GAP_EV_SEC_PAIRING_FAILED 0x8c +struct btp_gap_sec_pairing_failed_ev { + ble_addr_t address; + uint8_t reason; +} __packed; diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_gatt.h b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_gatt.h new file mode 100644 index 00000000..88f2e62a --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_gatt.h @@ -0,0 +1,332 @@ +/* + * 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. + */ + +/* btp_gatt.h - Bluetooth tester GATT service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* GATT Service */ +/* commands */ +#define BTP_GATT_READ_SUPPORTED_COMMANDS 0x01 +struct btp_gatt_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_GATT_SERVICE_PRIMARY 0x00 +#define BTP_GATT_SERVICE_SECONDARY 0x01 + +#define BTP_GATT_ADD_SERVICE 0x02 +struct btp_gatt_add_service_cmd { + uint8_t type; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; +struct btp_gatt_add_service_rp { + uint16_t svc_id; +} __packed; + +#define BTP_GATT_ADD_CHARACTERISTIC 0x03 +struct btp_gatt_add_characteristic_cmd { + uint16_t svc_id; + uint8_t properties; + uint8_t permissions; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; +struct btp_gatt_add_characteristic_rp { + uint16_t char_id; +} __packed; + +#define BTP_GATT_ADD_DESCRIPTOR 0x04 +struct btp_gatt_add_descriptor_cmd { + uint16_t char_id; + uint8_t permissions; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; +struct btp_gatt_add_descriptor_rp { + uint16_t desc_id; +} __packed; + +#define BTP_GATT_ADD_INCLUDED_SERVICE 0x05 +struct btp_gatt_add_included_service_cmd { + uint16_t svc_id; +} __packed; +struct btp_gatt_add_included_service_rp { + uint16_t included_service_id; +} __packed; + +#define BTP_GATT_SET_VALUE 0x06 +struct btp_gatt_set_value_cmd { + uint16_t attr_id; + uint16_t len; + uint8_t value[0]; +} __packed; + +#define BTP_GATT_START_SERVER 0x07 +struct btp_gatt_start_server_rp { + uint16_t db_attr_off; + uint8_t db_attr_cnt; +} __packed; + +#define BTP_GATT_SET_ENC_KEY_SIZE 0x09 +struct btp_gatt_set_enc_key_size_cmd { + uint16_t attr_id; + uint8_t key_size; +} __packed; + +struct btp_gatt_service { + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +struct btp_gatt_included { + uint16_t included_handle; + struct btp_gatt_service service; +} __packed; + +struct btp_gatt_read_uuid_chr { + uint16_t handle; + uint8_t data[0]; +} __packed; + +struct btp_gatt_characteristic { + uint16_t characteristic_handle; + uint16_t value_handle; + uint8_t properties; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +struct btp_gatt_descriptor { + uint16_t descriptor_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +#define BTP_GATT_EXCHANGE_MTU 0x0a +struct btp_gatt_exchange_mtu_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GATT_DISC_ALL_PRIM_SVCS 0x0b +struct btp_gatt_disc_all_prim_svcs_cmd { + ble_addr_t address; +} __packed; +struct btp_gatt_disc_all_prim_svcs_rp { + uint8_t services_count; + struct btp_gatt_service services[0]; +} __packed; + +#define BTP_GATT_DISC_PRIM_UUID 0x0c +struct btp_gatt_disc_prim_uuid_cmd { + ble_addr_t address; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; +struct btp_gatt_disc_prim_uuid_rp { + uint8_t services_count; + struct btp_gatt_service services[0]; +} __packed; + +#define BTP_GATT_FIND_INCLUDED 0x0d +struct btp_gatt_find_included_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; +struct btp_gatt_find_included_rp { + uint8_t services_count; + struct btp_gatt_included included[0]; +} __packed; + +#define BTP_GATT_DISC_ALL_CHRC 0x0e +struct btp_gatt_disc_all_chrc_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; +struct btp_gatt_disc_chrc_rp { + uint8_t characteristics_count; + struct btp_gatt_characteristic characteristics[0]; +} __packed; + +#define BTP_GATT_DISC_CHRC_UUID 0x0f +struct btp_gatt_disc_chrc_uuid_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +#define BTP_GATT_DISC_ALL_DESC 0x10 +struct btp_gatt_disc_all_desc_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; +struct btp_gatt_disc_all_desc_rp { + uint8_t descriptors_count; + struct btp_gatt_descriptor descriptors[0]; +} __packed; + +#define BTP_GATT_READ 0x11 +struct btp_gatt_read_cmd { + ble_addr_t address; + uint16_t handle; +} __packed; +struct btp_gatt_read_rp { + uint8_t att_response; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_READ_UUID 0x12 +struct btp_gatt_read_uuid_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +#define BTP_GATT_READ_LONG 0x13 +struct btp_gatt_read_long_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; +} __packed; + +#define BTP_GATT_READ_MULTIPLE 0x14 +struct btp_gatt_read_multiple_cmd { + ble_addr_t address; + uint8_t handles_count; + uint16_t handles[0]; +} __packed; + +#define BTP_GATT_WRITE_WITHOUT_RSP 0x15 +struct btp_gatt_write_without_rsp_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_SIGNED_WRITE_WITHOUT_RSP 0x16 +struct btp_gatt_signed_write_without_rsp_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_WRITE 0x17 +struct btp_gatt_write_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_WRITE_LONG 0x18 +struct btp_gatt_write_long_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_RELIABLE_WRITE 0x19 +struct btp_gatt_reliable_write_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_CFG_NOTIFY 0x1a +#define BTP_GATT_CFG_INDICATE 0x1b +struct btp_gatt_cfg_notify_cmd { + ble_addr_t address; + uint8_t enable; + uint16_t ccc_handle; +} __packed; + +#define BTP_GATT_GET_ATTRIBUTES 0x1c +struct btp_gatt_get_attributes_cmd { + uint16_t start_handle; + uint16_t end_handle; + uint8_t type_length; + uint8_t type[0]; +} __packed; +struct btp_gatt_get_attributes_rp { + uint8_t attrs_count; + uint8_t attrs[0]; +} __packed; +struct btp_gatt_attr { + uint16_t handle; + uint8_t permission; + uint8_t type_length; + uint8_t type[0]; +} __packed; + +#define BTP_GATT_GET_ATTRIBUTE_VALUE 0x1d +struct btp_gatt_get_attribute_value_cmd { + ble_addr_t address; + uint16_t handle; +} __packed; +struct btp_gatt_get_attribute_value_rp { + uint8_t att_response; + uint16_t value_length; + uint8_t value[0]; +} __packed; + +#define BTP_GATT_CHANGE_DATABASE 0x1e +struct btp_gatt_change_database_cmd { + uint16_t start_handle; + uint16_t end_handle; + uint8_t visibility; +} __packed; + +/* GATT events */ +#define BTP_GATT_EV_NOTIFICATION 0x80 +struct btp_gatt_notification_ev { + ble_addr_t address; + uint8_t type; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_EV_ATTR_VALUE_CHANGED 0x81 +struct btp_gatt_attr_value_changed_ev { + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_gattc.h b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_gattc.h new file mode 100644 index 00000000..76510b47 --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_gattc.h @@ -0,0 +1,243 @@ +/* + * 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. + */ + +/* btp_gattc.h - Bluetooth tester GATT Client service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* GATT Client Service */ +/* commands */ +#define BTP_GATTC_READ_SUPPORTED_COMMANDS 0x01 +struct btp_gattc_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_EXCHANGE_MTU 0x02 +struct btp_gattc_exchange_mtu_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GATTC_DISC_ALL_PRIM_SVCS 0x03 +struct btp_gattc_disc_all_prim_svcs_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GATTC_DISC_PRIM_UUID 0x04 +struct btp_gattc_disc_prim_uuid_cmd { + ble_addr_t address; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +#define BTP_GATTC_FIND_INCLUDED 0x05 +struct btp_gattc_find_included_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; + +#define BTP_GATTC_DISC_ALL_CHRC 0x06 +struct btp_gattc_disc_all_chrc_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; + +#define BTP_GATTC_DISC_CHRC_UUID 0x07 +struct btp_gattc_disc_chrc_uuid_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +#define BTP_GATTC_DISC_ALL_DESC 0x08 +struct btp_gattc_disc_all_desc_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; + +#define BTP_GATTC_READ 0x09 +struct btp_gattc_read_cmd { + ble_addr_t address; + uint16_t handle; +} __packed; + +#define BTP_GATTC_READ_UUID 0x0a +struct btp_gattc_read_uuid_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; +struct btp_gattc_read_uuid_rp { + ble_addr_t address; + uint8_t status; + uint16_t data_length; + uint8_t value_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_READ_LONG 0x0b +struct btp_gattc_read_long_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; +} __packed; + +#define BTP_GATTC_READ_MULTIPLE 0x0c +struct btp_gattc_read_multiple_cmd { + ble_addr_t address; + uint8_t handles_count; + uint16_t handles[0]; +} __packed; + +#define BTP_GATTC_WRITE_WITHOUT_RSP 0x0d +struct btp_gattc_write_without_rsp_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_SIGNED_WRITE_WITHOUT_RSP 0x0e +struct btp_gattc_signed_write_without_rsp_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_WRITE 0x0f +struct btp_gattc_write_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_WRITE_LONG 0x10 +struct btp_gattc_write_long_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_RELIABLE_WRITE 0x11 +struct btp_gattc_reliable_write_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_CFG_NOTIFY 0x12 +#define BTP_GATTC_CFG_INDICATE 0x13 +struct btp_gattc_cfg_notify_cmd { + ble_addr_t address; + uint8_t enable; + uint16_t ccc_handle; +} __packed; + +/* events */ +#define BTP_GATTC_EV_MTU_EXCHANGED 0x80 +struct btp_gattc_exchange_mtu_ev { + ble_addr_t address; + uint16_t mtu; +} __packed; + +#define BTP_GATTC_DISC_ALL_PRIM_RP 0x81 +struct btp_gattc_disc_prim_svcs_rp { + ble_addr_t address; + uint8_t status; + uint8_t services_count; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_DISC_PRIM_UUID_RP 0x82 + +#define BTP_GATTC_FIND_INCLUDED_RP 0x83 +struct btp_gattc_find_included_rp { + ble_addr_t address; + uint8_t status; + uint8_t services_count; + struct btp_gatt_included included[0]; +} __packed; + +#define BTP_GATTC_DISC_ALL_CHRC_RP 0x84 +#define BTP_GATTC_DISC_CHRC_UUID_RP 0x85 +struct btp_gattc_disc_chrc_rp { + ble_addr_t address; + uint8_t status; + uint8_t characteristics_count; + struct btp_gatt_characteristic characteristics[0]; +} __packed; + +#define BTP_GATTC_DISC_ALL_DESC_RP 0x86 +struct btp_gattc_disc_all_desc_rp { + ble_addr_t address; + uint8_t status; + uint8_t descriptors_count; + struct btp_gatt_descriptor descriptors[0]; +} __packed; + +#define BTP_GATTC_READ_RP 0x87 +#define BTP_GATTC_READ_UUID_RP 0x88 +#define BTP_GATTC_READ_LONG_RP 0x89 +#define BTP_GATTC_READ_MULTIPLE_RP 0x8a +struct btp_gattc_read_rp { + ble_addr_t address; + uint8_t status; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_WRITE_RP 0x8b +struct btp_gattc_write_rp { + ble_addr_t address; + uint8_t status; +} __packed; +#define BTP_GATTC_WRITE_LONG_RP 0x8c +#define BTP_GATTC_RELIABLE_WRITE_RP 0x8d +#define BTP_GATTC_CFG_NOTIFY_RP 0x8e +#define BTP_GATTC_CFG_INDICATE_RP 0x8f +struct btp_subscribe_rp { + ble_addr_t address; + uint8_t status; +} __packed; + +#define BTP_GATTC_EV_NOTIFICATION_RXED 0x90 +struct btp_gattc_notification_ev { + ble_addr_t address; + uint8_t type; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_l2cap.h b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_l2cap.h new file mode 100644 index 00000000..7d2adcae --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_l2cap.h @@ -0,0 +1,136 @@ +/* + * 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. + */ + +/* btp_l2cap.h - Bluetooth tester L2CAP service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* L2CAP Service */ +/* commands */ +#define BTP_L2CAP_READ_SUPPORTED_COMMANDS 0x01 +struct btp_l2cap_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_L2CAP_CONNECT_OPT_ECFC 0x01 +#define BTP_L2CAP_CONNECT_OPT_HOLD_CREDIT 0x02 + +#define BTP_L2CAP_CONNECT 0x02 +struct btp_l2cap_connect_cmd { + ble_addr_t address; + uint16_t psm; + uint16_t mtu; + uint8_t num; + uint8_t options; +} __packed; + +struct btp_l2cap_connect_rp { + uint8_t num; + uint8_t chan_ids[0]; +} __packed; + +#define BTP_L2CAP_DISCONNECT 0x03 +struct btp_l2cap_disconnect_cmd { + uint8_t chan_id; +} __packed; + +#define BTP_L2CAP_SEND_DATA 0x04 +struct btp_l2cap_send_data_cmd { + uint8_t chan_id; + uint16_t data_len; + uint8_t data[]; +} __packed; + +#define BTP_L2CAP_TRANSPORT_BREDR 0x00 +#define BTP_L2CAP_TRANSPORT_LE 0x01 + +#define BTP_L2CAP_LISTEN 0x05 +struct btp_l2cap_listen_cmd { + uint16_t psm; + uint8_t transport; + uint16_t mtu; + uint16_t response; +} __packed; + +#define BTP_L2CAP_ACCEPT_CONNECTION 0x06 +struct l2cap_accept_connection_cmd { + uint8_t chan_id; + uint16_t result; +} __packed; + +#define BTP_L2CAP_RECONFIGURE 0x07 +struct btp_l2cap_reconfigure_cmd { + ble_addr_t address; + uint16_t mtu; + uint8_t num; + uint8_t idxs[]; +} __packed; + +#define BTP_L2CAP_CREDITS 0x08 +struct btp_l2cap_credits_cmd { + uint8_t chan_id; +} __packed; + +/* events */ +#define BTP_L2CAP_EV_CONNECTION_REQ 0x80 +struct btp_l2cap_connection_req_ev { + uint8_t chan_id; + uint16_t psm; + ble_addr_t address; +} __packed; + +#define BTP_L2CAP_EV_CONNECTED 0x81 +struct btp_l2cap_connected_ev { + uint8_t chan_id; + uint16_t psm; + uint16_t peer_mtu; + uint16_t peer_mps; + uint16_t our_mtu; + uint16_t our_mps; + ble_addr_t address; +} __packed; + +#define BTP_L2CAP_EV_DISCONNECTED 0x82 +struct btp_l2cap_disconnected_ev { + uint16_t result; + uint8_t chan_id; + uint16_t psm; + ble_addr_t address; +} __packed; + +#define BTP_L2CAP_EV_DATA_RECEIVED 0x83 +struct btp_l2cap_data_received_ev { + uint8_t chan_id; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_L2CAP_EV_RECONFIGURED 0x84 +struct btp_l2cap_reconfigured_ev { + uint8_t chan_id; + uint16_t peer_mtu; + uint16_t peer_mps; + uint16_t our_mtu; + uint16_t our_mps; +} __packed; diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_mesh.h b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_mesh.h new file mode 100644 index 00000000..0a356e40 --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/btp_mesh.h @@ -0,0 +1,205 @@ +/* + * 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. + */ + +/* btp_mesh.h - Bluetooth tester MESH service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* MESH Service */ +/* commands */ +#define BTP_MESH_READ_SUPPORTED_COMMANDS 0x01 +struct btp_mesh_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_MESH_OUT_BLINK BIT(0) +#define BTP_MESH_OUT_BEEP BIT(1) +#define BTP_MESH_OUT_VIBRATE BIT(2) +#define BTP_MESH_OUT_DISPLAY_NUMBER BIT(3) +#define BTP_MESH_OUT_DISPLAY_STRING BIT(4) + +#define BTP_MESH_IN_PUSH BIT(0) +#define BTP_MESH_IN_TWIST BIT(1) +#define BTP_MESH_IN_ENTER_NUMBER BIT(2) +#define BTP_MESH_IN_ENTER_STRING BIT(3) + +#define BTP_MESH_CONFIG_PROVISIONING 0x02 +struct btp_mesh_config_provisioning_cmd { + uint8_t uuid[16]; + uint8_t static_auth[16]; + uint8_t out_size; + uint16_t out_actions; + uint8_t in_size; + uint16_t in_actions; +} __packed; + +#define BTP_MESH_PROVISION_NODE 0x03 +struct btp_mesh_provision_node_cmd { + uint8_t net_key[16]; + uint16_t net_key_idx; + uint8_t flags; + uint32_t iv_index; + uint32_t seq_num; + uint16_t addr; + uint8_t dev_key[16]; +} __packed; + +#define BTP_MESH_INIT 0x04 +#define BTP_MESH_RESET 0x05 +#define BTP_MESH_INPUT_NUMBER 0x06 +struct btp_mesh_input_number_cmd { + uint32_t number; +} __packed; + +#define BTP_MESH_INPUT_STRING 0x07 +struct btp_mesh_input_string_cmd { + uint8_t string_len; + uint8_t string[0]; +} __packed; + +#define BTP_MESH_IVU_TEST_MODE 0x08 +struct btp_mesh_ivu_test_mode_cmd { + uint8_t enable; +} __packed; + +#define BTP_MESH_IVU_TOGGLE_STATE 0x09 + +#define BTP_MESH_NET_SEND 0x0a +struct btp_mesh_net_send_cmd { + uint8_t ttl; + uint16_t src; + uint16_t dst; + uint8_t payload_len; + uint8_t payload[0]; +} __packed; + +#define BTP_MESH_HEALTH_GENERATE_FAULTS 0x0b +struct btp_mesh_health_generate_faults_rp { + uint8_t test_id; + uint8_t cur_faults_count; + uint8_t reg_faults_count; + uint8_t current_faults[0]; + uint8_t registered_faults[0]; +} __packed; + +#define BTP_MESH_HEALTH_CLEAR_FAULTS 0x0c + +#define BTP_MESH_LPN 0x0d +struct btp_mesh_lpn_set_cmd { + uint8_t enable; +} __packed; + +#define BTP_MESH_LPN_POLL 0x0e + +#define BTP_MESH_MODEL_SEND 0x0f +struct btp_mesh_model_send_cmd { + uint16_t src; + uint16_t dst; + uint8_t payload_len; + uint8_t payload[0]; +} __packed; + +#define BTP_MESH_LPN_SUBSCRIBE 0x10 +struct btp_mesh_lpn_subscribe_cmd { + uint16_t address; +} __packed; + +#define BTP_MESH_LPN_UNSUBSCRIBE 0x11 +struct btp_mesh_lpn_unsubscribe_cmd { + uint16_t address; +} __packed; + +#define BTP_MESH_RPL_CLEAR 0x12 +#define BTP_MESH_PROXY_IDENTITY 0x13 + +/* events */ +#define BTP_MESH_EV_OUT_NUMBER_ACTION 0x80 +struct btp_mesh_out_number_action_ev { + uint16_t action; + uint32_t number; +} __packed; + +#define BTP_MESH_EV_OUT_STRING_ACTION 0x81 +struct btp_mesh_out_string_action_ev { + uint8_t string_len; + uint8_t string[0]; +} __packed; + +#define BTP_MESH_EV_IN_ACTION 0x82 +struct btp_mesh_in_action_ev { + uint16_t action; + uint8_t size; +} __packed; + +#define BTP_MESH_EV_PROVISIONED 0x83 + +#define BTP_MESH_PROV_BEARER_PB_ADV 0x00 +#define BTP_MESH_PROV_BEARER_PB_GATT 0x01 +#define BTP_MESH_EV_PROV_LINK_OPEN 0x84 +struct btp_mesh_prov_link_open_ev { + uint8_t bearer; +} __packed; + +#define BTP_MESH_EV_PROV_LINK_CLOSED 0x85 +struct btp_mesh_prov_link_closed_ev { + uint8_t bearer; +} __packed; + +#define BTP_MESH_EV_NET_RECV 0x86 +struct btp_mesh_net_recv_ev { + uint8_t ttl; + uint8_t ctl; + uint16_t src; + uint16_t dst; + uint8_t payload_len; + uint8_t payload[0]; +} __packed; + +#define BTP_MESH_EV_INVALID_BEARER 0x87 +struct btp_mesh_invalid_bearer_ev { + uint8_t opcode; +} __packed; + +#define BTP_MESH_EV_INCOMP_TIMER_EXP 0x88 + +#define BTP_MESH_EV_LPN_ESTABLISHED 0x8b +struct btp_mesh_lpn_established_ev { + uint16_t net_idx; + uint16_t friend_addr; + uint8_t queue_size; + uint8_t recv_win; +} __packed; + +#define BTP_MESH_EV_LPN_TERMINATED 0x8c +struct btp_mesh_lpn_terminated_ev { + uint16_t net_idx; + uint16_t friend_addr; +} __packed; + +#define BTP_MESH_EV_LPN_POLLED 0x8d +struct btp_mesh_lpn_polled_ev { + uint16_t net_idx; + uint16_t friend_addr; + uint8_t retry; +} __packed; diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp/bttester.h b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/bttester.h new file mode 100644 index 00000000..8e8b98b5 --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp/bttester.h @@ -0,0 +1,144 @@ +/* + * 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. + */ + +/* bttester.h - Bluetooth tester headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __BTTESTER_H__ +#define __BTTESTER_H__ + +#include "syscfg/syscfg.h" +#include "host/ble_gatt.h" +#include "os/os_mbuf.h" +#include + +#define BIT(n) (1UL << (n)) + +/* Reset os_mbuf to reusable state */ +void +tester_mbuf_reset(struct os_mbuf *buf); + +const char * +string_from_bytes(const void *buf, size_t len); + +static inline void +tester_set_bit(uint8_t *addr, unsigned int bit) +{ + uint8_t *p = addr + (bit / 8); + + *p |= BIT(bit % 8); +} + +static inline uint8_t +tester_test_bit(const uint8_t *addr, unsigned int bit) +{ + const uint8_t *p = addr + (bit / 8); + + return *p & BIT(bit % 8); +} + +static inline void +tester_clear_bit(uint8_t *addr, unsigned int bit) +{ + uint8_t *p = addr + (bit / 8); + + *p &= ~BIT(bit % 8); +} + + +void +tester_init(void); +void +tester_rsp(uint8_t service, uint8_t opcode, uint8_t status); +void +tester_rsp_full(uint8_t service, uint8_t opcode, const void *rsp, size_t len); +void +tester_event(uint8_t service, uint8_t opcode, const void *data, size_t len); + +/* Used to indicate that command length is variable and that validation will + * be done in handler. + */ +#define BTP_HANDLER_LENGTH_VARIABLE (-1) + +struct btp_handler { + uint8_t opcode; + uint8_t index; + ssize_t expect_len; + uint8_t (*func)(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +}; + +void tester_register_command_handlers(uint8_t service, + const struct btp_handler *handlers, + size_t num); +void +tester_send_buf(uint8_t service, uint8_t opcode, uint8_t index, + struct os_mbuf *buf); + +uint8_t +tester_init_gap(void); +uint8_t +tester_unregister_gap(void); +void +tester_init_core(void); +uint8_t +tester_init_gatt(void); +uint8_t +tester_unregister_gatt(void); +int +tester_gattc_notify_rx_ev(uint16_t conn_handle, uint16_t attr_handle, + uint8_t indication, struct os_mbuf *om); +int +tester_gatt_subscribe_ev(uint16_t conn_handle, + uint16_t attr_handle, + uint8_t reason, + uint8_t prev_notify, + uint8_t cur_notify, + uint8_t prev_indicate, + uint8_t cur_indicate); + +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) +uint8_t +tester_init_l2cap(void); +uint8_t +tester_unregister_l2cap(void); +#endif + +#if MYNEWT_VAL(BLE_MESH) +uint8_t +tester_init_mesh(void); +uint8_t +tester_unregister_mesh(void); +#endif /* MYNEWT_VAL(BLE_MESH) */ +uint8_t +tester_init_gatt_cl(void); +uint8_t +tester_unregister_gatt_cl(void); +void +gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); + +int +gatt_svr_init(void); +#endif /* __BTTESTER_H__ */ \ No newline at end of file diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp_core.c b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_core.c new file mode 100644 index 00000000..5ab290d9 --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_core.c @@ -0,0 +1,202 @@ +/* + * 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. + */ + +/* btp_core.c - Bluetooth BTP Core service */ + +/* + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "btp/btp.h" + +static uint8_t registered_services[((BTP_SERVICE_ID_MAX - 1) / 8) + 1]; + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_core_read_supported_commands_rp *rp = rsp; + + tester_set_bit(rp->data, BTP_CORE_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_CORE_READ_SUPPORTED_SERVICES); + tester_set_bit(rp->data, BTP_CORE_REGISTER_SERVICE); + tester_set_bit(rp->data, BTP_CORE_UNREGISTER_SERVICE); + + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +supported_services(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_core_read_supported_services_rp *rp = rsp; + + /* octet 0 */ + tester_set_bit(rp->data, BTP_SERVICE_ID_CORE); + tester_set_bit(rp->data, BTP_SERVICE_ID_GAP); + tester_set_bit(rp->data, BTP_SERVICE_ID_GATT); +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) + tester_set_bit(rp->data, BTP_SERVICE_ID_L2CAP); +#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ +#if MYNEWT_VAL(BLE_MESH) + tester_set_bit(rp->data, BTP_SERVICE_ID_MESH); +#endif /* MYNEWT_VAL(BLE_MESH) */ + tester_set_bit(rp->data, BTP_SERVICE_ID_GATTC); + + *rsp_len = sizeof(*rp) + 2; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +register_service(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_core_register_service_cmd *cp = cmd; + uint8_t status; + + /* invalid service */ + if ((cp->id == BTP_SERVICE_ID_CORE) || (cp->id > BTP_SERVICE_ID_MAX)) { + return BTP_STATUS_FAILED; + } + + /* already registered */ + if (tester_test_bit(registered_services, cp->id)) { + return BTP_STATUS_FAILED; + } + + switch (cp->id) { + case BTP_SERVICE_ID_GAP: + status = tester_init_gap(); + break; + case BTP_SERVICE_ID_GATT: + status = tester_init_gatt(); + break; +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) + case BTP_SERVICE_ID_L2CAP: + status = tester_init_l2cap(); + break; +#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ +#if MYNEWT_VAL(BLE_MESH) + case BTP_SERVICE_ID_MESH: + status = tester_init_mesh(); + break; +#endif /* MYNEWT_VAL(BLE_MESH) */ + case BTP_SERVICE_ID_GATTC: + status = tester_init_gatt_cl(); + break; + default: + status = BTP_STATUS_FAILED; + break; + } + + if (status == BTP_STATUS_SUCCESS) { + tester_set_bit(registered_services, cp->id); + } + + return status; +} + +static uint8_t +unregister_service(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_core_unregister_service_cmd *cp = cmd; + uint8_t status; + + /* invalid service ID */ + if ((cp->id == BTP_SERVICE_ID_CORE) || (cp->id > BTP_SERVICE_ID_MAX)) { + return BTP_STATUS_FAILED; + } + + /* not registered */ + if (!tester_test_bit(registered_services, cp->id)) { + return BTP_STATUS_FAILED; + } + + switch (cp->id) { + case BTP_SERVICE_ID_GAP: + status = tester_unregister_gap(); + break; + case BTP_SERVICE_ID_GATT: + status = tester_unregister_gatt(); + break; +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) + case BTP_SERVICE_ID_L2CAP: + status = tester_unregister_l2cap(); + break; +#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ +#if MYNEWT_VAL(BLE_MESH) + case BTP_SERVICE_ID_MESH: + status = tester_unregister_mesh(); + break; +#endif /* MYNEWT_VAL(BLE_MESH) */ + case BTP_SERVICE_ID_GATTC: + status = tester_unregister_gatt_cl(); + break; + default: + status = BTP_STATUS_FAILED; + break; + } + + if (status == BTP_STATUS_SUCCESS) { + tester_clear_bit(registered_services, cp->id); + } + + return status; +} + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_CORE_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_CORE_READ_SUPPORTED_SERVICES, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_services, + }, + { + .opcode = BTP_CORE_REGISTER_SERVICE, + .index = BTP_INDEX_NONE, + .expect_len = sizeof(struct btp_core_register_service_cmd), + .func = register_service, + }, + { + .opcode = BTP_CORE_UNREGISTER_SERVICE, + .index = BTP_INDEX_NONE, + .expect_len = sizeof(struct btp_core_unregister_service_cmd), + .func = unregister_service, + }, +}; + +void +tester_init_core(void) +{ + tester_register_command_handlers(BTP_SERVICE_ID_CORE, handlers, + ARRAY_SIZE(handlers)); + tester_set_bit(registered_services, BTP_SERVICE_ID_CORE); +} diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp_gap.c b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_gap.c new file mode 100644 index 00000000..715ff447 --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_gap.c @@ -0,0 +1,1939 @@ +/* + * 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. + */ + +/* gap.c - Bluetooth GAP Tester */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "host/ble_gap.h" +#include "host/util/util.h" +#include "console/console.h" + +#include "../../../nimble/host/src/ble_hs_pvcy_priv.h" +#include "../../../nimble/host/src/ble_hs_hci_priv.h" +#include "../../../nimble/host/src/ble_sm_priv.h" + +#include "btp/btp.h" + +#include + +#define CONTROLLER_INDEX 0 +#define CONTROLLER_NAME "btp_tester" + +#define BLE_AD_DISCOV_MASK (BLE_HS_ADV_F_DISC_LTD | BLE_HS_ADV_F_DISC_GEN) +#define ADV_BUF_LEN (sizeof(struct btp_gap_device_found_ev) + 2 * 31) + +/* parameter values to reject in CPUP if all match the pattern */ +#define REJECT_INTERVAL_MIN 0x0C80 +#define REJECT_INTERVAL_MAX 0x0C80 +#define REJECT_LATENCY 0x0000 +#define REJECT_SUPERVISION_TIMEOUT 0x0C80 + +const uint8_t irk[16] = { + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, +}; + +static uint8_t oob[16]; +static struct ble_sm_sc_oob_data oob_data_local; +static struct ble_sm_sc_oob_data oob_data_remote; + +static uint16_t current_settings; +uint8_t own_addr_type; +static ble_addr_t peer_id_addr; +static ble_addr_t peer_ota_addr; +static bool encrypted = false; + +static struct os_callout update_params_co; +static struct btp_gap_conn_param_update_cmd update_params; + +static struct os_callout connected_ev_co; +static struct btp_gap_device_connected_ev connected_ev; +#define CONNECTED_EV_DELAY_MS(itvl) 8 * BLE_HCI_CONN_ITVL * itvl / 1000 +static int connection_attempts; +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) +static int64_t advertising_start; +static struct os_callout bttester_nrpa_rotate_timer; +#endif + +static const struct ble_gap_conn_params dflt_conn_params = { + .scan_itvl = 0x0010, + .scan_window = 0x0010, + .itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN, + .itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX, + .latency = 0, + .supervision_timeout = 0x0100, + .min_ce_len = 0x0010, + .max_ce_len = 0x0300, +}; + +static int +gap_conn_find_by_addr(const ble_addr_t *dev_addr, + struct ble_gap_conn_desc *out_desc) +{ + ble_addr_t addr = *dev_addr; + + if (memcmp(BLE_ADDR_ANY, &peer_id_addr, 6) == 0) { + return ble_gap_conn_find_by_addr(&addr, out_desc); + } + + if (BLE_ADDR_IS_RPA(&addr)) { + if (ble_addr_cmp(&peer_ota_addr, &addr) != 0) { + return -1; + } + + return ble_gap_conn_find_by_addr(&addr, out_desc); + } else { + if (ble_addr_cmp(&peer_id_addr, &addr) != 0) { + return -1; + } + + if (BLE_ADDR_IS_RPA(&peer_ota_addr)) { + /* Change addr type to ID addr */ + addr.type |= 2; + } + + return ble_gap_conn_find_by_addr(&addr, out_desc); + } +} + +static int +gap_event_cb(struct ble_gap_event *event, void *arg); + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gap_read_supported_commands_rp *rp = rsp; + + /* octet 0 */ + tester_set_bit(rp->data, BTP_GAP_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_GAP_READ_CONTROLLER_INDEX_LIST); + tester_set_bit(rp->data, BTP_GAP_READ_CONTROLLER_INFO); + tester_set_bit(rp->data, BTP_GAP_SET_CONNECTABLE); + + /* octet 1 */ + tester_set_bit(rp->data, BTP_GAP_SET_DISCOVERABLE); + tester_set_bit(rp->data, BTP_GAP_SET_BONDABLE); + tester_set_bit(rp->data, BTP_GAP_START_ADVERTISING); + tester_set_bit(rp->data, BTP_GAP_STOP_ADVERTISING); + tester_set_bit(rp->data, BTP_GAP_START_DISCOVERY); + tester_set_bit(rp->data, BTP_GAP_STOP_DISCOVERY); + tester_set_bit(rp->data, BTP_GAP_CONNECT); + tester_set_bit(rp->data, BTP_GAP_DISCONNECT); + + /* octet 2 */ + tester_set_bit(rp->data, BTP_GAP_SET_IO_CAP); + tester_set_bit(rp->data, BTP_GAP_PAIR); + tester_set_bit(rp->data, BTP_GAP_UNPAIR); + tester_set_bit(rp->data, BTP_GAP_PASSKEY_ENTRY); + tester_set_bit(rp->data, BTP_GAP_PASSKEY_CONFIRM); + tester_set_bit(rp->data, BTP_GAP_START_DIRECT_ADV); + tester_set_bit(rp->data, BTP_GAP_CONN_PARAM_UPDATE); + + /* octet 3 */ + tester_set_bit(rp->data, BTP_GAP_OOB_LEGACY_SET_DATA); + tester_set_bit(rp->data, BTP_GAP_OOB_SC_GET_LOCAL_DATA); + tester_set_bit(rp->data, BTP_GAP_OOB_SC_SET_REMOTE_DATA); + tester_set_bit(rp->data, BTP_GAP_SET_MITM); + + *rsp_len = sizeof(*rp) + 4; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +controller_index_list(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gap_read_controller_index_list_rp *rp = rsp; + + SYS_LOG_DBG(""); + + rp->num = 1; + rp->index[0] = CONTROLLER_INDEX; + + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +controller_info(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gap_read_controller_info_rp *rp = rsp; + uint32_t supported_settings = 0; + ble_addr_t addr; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_hs_pvcy_set_our_irk(irk); + assert(rc == 0); + + /* Make sure we have proper identity address set (public preferred) */ + rc = ble_hs_util_ensure_addr(1); + assert(rc == 0); + rc = ble_hs_id_copy_addr(BLE_ADDR_RANDOM, addr.val, NULL); + assert(rc == 0); + + if (MYNEWT_VAL(BTTESTER_PRIVACY_MODE)) { + if (MYNEWT_VAL(BTTESTER_USE_NRPA)) { + own_addr_type = BLE_OWN_ADDR_RANDOM; + rc = ble_hs_id_gen_rnd(1, &addr); + assert(rc == 0); + rc = ble_hs_id_set_rnd(addr.val); + assert(rc == 0); + } else { + own_addr_type = BLE_OWN_ADDR_RPA_RANDOM_DEFAULT; + } + current_settings |= BIT(BTP_GAP_SETTINGS_PRIVACY); + supported_settings |= BIT(BTP_GAP_SETTINGS_PRIVACY); + memcpy(&rp->address, &addr, sizeof(rp->address)); + } else { + rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, rp->address, NULL); + if (rc) { + own_addr_type = BLE_OWN_ADDR_RANDOM; + memcpy(rp->address, addr.val, sizeof(rp->address)); + supported_settings |= BIT(BTP_GAP_SETTINGS_STATIC_ADDRESS); + current_settings |= BIT(BTP_GAP_SETTINGS_STATIC_ADDRESS); + } else { + own_addr_type = BLE_OWN_ADDR_PUBLIC; + } + } + + supported_settings |= BIT(BTP_GAP_SETTINGS_POWERED); + supported_settings |= BIT(BTP_GAP_SETTINGS_CONNECTABLE); + supported_settings |= BIT(BTP_GAP_SETTINGS_BONDABLE); + supported_settings |= BIT(BTP_GAP_SETTINGS_LE); + supported_settings |= BIT(BTP_GAP_SETTINGS_ADVERTISING); + supported_settings |= BIT(BTP_GAP_SETTINGS_SC); + + if (ble_hs_cfg.sm_bonding) { + current_settings |= BIT(BTP_GAP_SETTINGS_BONDABLE); + } + if (ble_hs_cfg.sm_sc) { + current_settings |= BIT(BTP_GAP_SETTINGS_SC); + } + + rp->supported_settings = htole32(supported_settings); + rp->current_settings = htole32(current_settings); + + memcpy(rp->name, CONTROLLER_NAME, sizeof(CONTROLLER_NAME)); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static struct ble_gap_adv_params adv_params = { + .conn_mode = BLE_GAP_CONN_MODE_NON, + .disc_mode = BLE_GAP_DISC_MODE_NON, +}; + +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) +static void rotate_nrpa_cb(struct os_event *ev) +{ + int rc; + ble_addr_t addr; + int32_t duration_ms = BLE_HS_FOREVER; + int32_t remaining_time; + os_time_t remaining_ticks; + + if (adv_params.disc_mode == BLE_GAP_DISC_MODE_LTD) { + duration_ms = MYNEWT_VAL(BTTESTER_LTD_ADV_TIMEOUT); + } + + ble_gap_adv_stop(); + rc = ble_hs_id_gen_rnd(1, &addr); + assert(rc == 0); + rc = ble_hs_id_set_rnd(addr.val); + assert(rc == 0); + + ble_gap_adv_start(own_addr_type, NULL, duration_ms, + &adv_params, gap_event_cb, NULL); + + remaining_time = os_get_uptime_usec() - advertising_start; + if (remaining_time > 0) { + advertising_start = os_get_uptime_usec(); + os_time_ms_to_ticks(remaining_time, &remaining_ticks); + os_callout_reset(&bttester_nrpa_rotate_timer, + remaining_ticks); + } +} +#endif + +static uint8_t +set_connectable(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_connectable_cmd *cp = cmd; + struct btp_gap_set_connectable_rp *rp = rsp; + + SYS_LOG_DBG(""); + + if (cp->connectable) { + current_settings |= BIT(BTP_GAP_SETTINGS_CONNECTABLE); + adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; + } else { + current_settings &= ~BIT(BTP_GAP_SETTINGS_CONNECTABLE); + adv_params.conn_mode = BLE_GAP_CONN_MODE_NON; + } + + rp->current_settings = htole32(current_settings); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t ad_flags = BLE_HS_ADV_F_BREDR_UNSUP; + +static uint8_t +set_discoverable(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_discoverable_cmd *cp = cmd; + struct btp_gap_set_discoverable_rp *rp = rsp; + + SYS_LOG_DBG(""); + + switch (cp->discoverable) { + case BTP_GAP_NON_DISCOVERABLE: + ad_flags &= ~(BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_DISC_LTD); + adv_params.disc_mode = BLE_GAP_DISC_MODE_NON; + current_settings &= ~BIT(BTP_GAP_SETTINGS_DISCOVERABLE); + break; + case BTP_GAP_GENERAL_DISCOVERABLE: + ad_flags &= ~BLE_HS_ADV_F_DISC_LTD; + ad_flags |= BLE_HS_ADV_F_DISC_GEN; + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + current_settings |= BIT(BTP_GAP_SETTINGS_DISCOVERABLE); + break; + case BTP_GAP_LIMITED_DISCOVERABLE: + ad_flags &= ~BLE_HS_ADV_F_DISC_GEN; + ad_flags |= BLE_HS_ADV_F_DISC_LTD; + adv_params.disc_mode = BLE_GAP_DISC_MODE_LTD; + current_settings |= BIT(BTP_GAP_SETTINGS_DISCOVERABLE); + break; + default: + return BTP_STATUS_FAILED; + } + + rp->current_settings = htole32(current_settings); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_bondable(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_bondable_cmd *cp = cmd; + struct btp_gap_set_bondable_rp *rp = rsp; + + SYS_LOG_DBG("bondable: %d", cp->bondable); + + ble_hs_cfg.sm_bonding = cp->bondable; + if (ble_hs_cfg.sm_bonding) { + current_settings |= BIT(BTP_GAP_SETTINGS_BONDABLE); + } else { + current_settings &= ~BIT(BTP_GAP_SETTINGS_BONDABLE); + } + + rp->current_settings = htole32(current_settings); + *rsp_len = sizeof(*rp); + return BTP_STATUS_SUCCESS; +} + +static struct adv_data ad[10] = { + ADV_DATA(BLE_HS_ADV_TYPE_FLAGS, &ad_flags, sizeof(ad_flags)), +}; +static struct adv_data sd[10]; + +static int +set_ad(const struct adv_data *ad_data, size_t ad_len, + uint8_t *buf, uint8_t *buf_len) +{ + int i; + + for (i = 0; i < ad_len; i++) { + buf[(*buf_len)++] = ad_data[i].data_len + 1; + buf[(*buf_len)++] = ad_data[i].type; + + memcpy(&buf[*buf_len], ad_data[i].data, + ad_data[i].data_len); + *buf_len += ad_data[i].data_len; + } + + return 0; +} + +static uint8_t +start_advertising(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_start_advertising_cmd *cp = cmd; + struct btp_gap_start_advertising_rp *rp = rsp; + int32_t duration_ms = BLE_HS_FOREVER; + uint8_t buf[BLE_HS_ADV_MAX_SZ]; + uint8_t buf_len = 0; + uint8_t adv_len, sd_len; + uint8_t addr_type; + uint32_t duration; + + int err; + + int i; + + SYS_LOG_DBG(""); + + /* This command is very unfortunate since after variable data there is + * additional 5 bytes (4 bytes for duration, 1 byte for own address + * type. + */ + if ((cmd_len < sizeof(*cp)) || + (cmd_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len + + sizeof(duration) + sizeof(own_addr_type))) { + return BTP_STATUS_FAILED; + } + + /* currently ignored */ + duration = get_le32(cp->adv_data + cp->adv_data_len + cp->scan_rsp_len); + (void)duration; + addr_type = cp->adv_data[cp->adv_data_len + + cp->scan_rsp_len + + sizeof(duration)]; + + for (i = 0, adv_len = 1U; i < cp->adv_data_len; adv_len++) { + if (adv_len >= ARRAY_SIZE(ad)) { + SYS_LOG_ERR("ad[] Out of memory"); + return BTP_STATUS_FAILED; + } + + ad[adv_len].type = cp->scan_rsp[i++]; + ad[adv_len].data_len = cp->scan_rsp[i++]; + ad[adv_len].data = &cp->scan_rsp[i]; + i += ad[adv_len].data_len; + } + + for (sd_len = 0U; i < cp->scan_rsp_len; sd_len++) { + if (sd_len >= ARRAY_SIZE(sd)) { + SYS_LOG_ERR("sd[] Out of memory"); + return BTP_STATUS_FAILED; + } + + sd[sd_len].type = cp->scan_rsp[i++]; + sd[sd_len].data_len = cp->scan_rsp[i++]; + sd[sd_len].data = &cp->scan_rsp[i]; + i += sd[sd_len].data_len; + } + + err = set_ad(ad, adv_len, buf, &buf_len); + if (err) { + return BTP_STATUS_FAILED; + } + + err = ble_gap_adv_set_data(buf, buf_len); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + if (sd_len) { + buf_len = 0; + + err = set_ad(sd, sd_len, buf, &buf_len); + if (err) { + SYS_LOG_ERR("Advertising failed: err %d", err); + return BTP_STATUS_FAILED; + } + + err = ble_gap_adv_rsp_set_data(buf, buf_len); + if (err != 0) { + SYS_LOG_ERR("Advertising failed: err %d", err); + return BTP_STATUS_FAILED; + } + } + + if (adv_params.disc_mode == BLE_GAP_DISC_MODE_LTD) { + duration_ms = MYNEWT_VAL(BTTESTER_LTD_ADV_TIMEOUT); + } + + /* In NimBLE, own_addr_type is configured in `controller_info` function. + * Let's just verify restrictions for Privacy options. + */ + switch (addr_type) { + case 0x00: + break; +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) + case 0x01: + /* RPA usage is is controlled via privacy settings */ + if (!(current_settings & BIT(BTP_GAP_SETTINGS_PRIVACY))) { + return BTP_STATUS_FAILED; + } + break; + case 0x02: + /* NRPA is used only for non-connectable advertising */ + if (!(current_settings & BIT(BTP_GAP_SETTINGS_CONNECTABLE))) { + return BTP_STATUS_FAILED; + } + break; +#endif + default: + return BTP_STATUS_FAILED; + } + +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) + if (MYNEWT_VAL(BTTESTER_NRPA_TIMEOUT) < duration_ms / 1000) { + advertising_start = os_get_uptime_usec(); + os_callout_reset(&bttester_nrpa_rotate_timer, + OS_TICKS_PER_SEC * MYNEWT_VAL(BTTESTER_NRPA_TIMEOUT)); + } +#endif + err = ble_gap_adv_start(own_addr_type, NULL, duration_ms, + &adv_params, gap_event_cb, NULL); + if (err) { + SYS_LOG_ERR("Advertising failed: err %d", err); + return BTP_STATUS_FAILED; + } + + current_settings |= BIT(BTP_GAP_SETTINGS_ADVERTISING); + rp->current_settings = htole32(current_settings); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +stop_advertising(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gap_stop_advertising_rp *rp = rsp; + int err; + + SYS_LOG_DBG(""); + + err = ble_gap_adv_stop(); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + current_settings &= ~BIT(BTP_GAP_SETTINGS_ADVERTISING); + rp->current_settings = htole32(current_settings); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +get_ad_flags(const uint8_t *data, uint8_t data_len) +{ + uint8_t len, i; + + /* Parse advertisement to get flags */ + for (i = 0; i < data_len; i += len - 1) { + len = data[i++]; + if (!len) { + break; + } + + /* Check if field length is correct */ + if (len > (data_len - i) || (data_len - i) < 1) { + break; + } + + switch (data[i++]) { + case BLE_HS_ADV_TYPE_FLAGS: + return data[i]; + default: + break; + } + } + + return 0; +} + +static uint8_t discovery_flags; +static struct os_mbuf *adv_buf; + +static void +store_adv(const ble_addr_t *addr, int8_t rssi, + const uint8_t *data, uint8_t len) +{ + struct btp_gap_device_found_ev *ev; + void *adv_data; + /* cleanup */ + tester_mbuf_reset(adv_buf); + + ev = os_mbuf_extend(adv_buf, sizeof(*ev)); + if (!ev) { + return; + } + + memcpy(&ev->address, addr, sizeof(ev->address)); + ev->rssi = rssi; + ev->flags = BTP_GAP_DEVICE_FOUND_FLAG_AD | BTP_GAP_DEVICE_FOUND_FLAG_RSSI; + ev->eir_data_len = len; + + adv_data = os_mbuf_extend(adv_buf, len); + if (!adv_data) { + return; + } + + memcpy(adv_data, data, len); +} + +static void +device_found(ble_addr_t *addr, int8_t rssi, uint8_t evtype, + const uint8_t *data, uint8_t len) +{ + struct btp_gap_device_found_ev *ev; + void *adv_data; + ble_addr_t a; + + /* if General/Limited Discovery - parse Advertising data to get flags */ + if (!(discovery_flags & BTP_GAP_DISCOVERY_FLAG_LE_OBSERVE) && + (evtype != BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP)) { + uint8_t flags = get_ad_flags(data, len); + + /* ignore non-discoverable devices */ + if (!(flags & BLE_AD_DISCOV_MASK)) { + SYS_LOG_DBG("Non discoverable, skipping"); + return; + } + + /* if Limited Discovery - ignore general discoverable devices */ + if ((discovery_flags & BTP_GAP_DISCOVERY_FLAG_LIMITED) && + !(flags & BLE_HS_ADV_F_DISC_LTD)) { + SYS_LOG_DBG("General discoverable, skipping"); + return; + } + } + + /* attach Scan Response data */ + if (evtype == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) { + /* skip if there is no pending advertisement */ + if (!adv_buf->om_len) { + SYS_LOG_INF("No pending advertisement, skipping"); + return; + } + + ev = (void *) adv_buf->om_data; + memcpy(&a, &ev->address, sizeof(a)); + + /* + * in general, the Scan Response comes right after the + * Advertisement, but if not if send stored event and ignore + * this one + */ + if (ble_addr_cmp(addr, &a)) { + SYS_LOG_INF("Address does not match, skipping"); + goto done; + } + + ev->eir_data_len += len; + ev->flags |= BTP_GAP_DEVICE_FOUND_FLAG_SD; + + adv_data = os_mbuf_extend(adv_buf, len); + if (!adv_data) { + return; + } + + memcpy(adv_data, data, len); + + goto done; + } + + /* + * if there is another pending advertisement, send it and store the + * current one + */ + if (adv_buf->om_len) { + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_FOUND, + adv_buf->om_data, adv_buf->om_len); + } + + store_adv(addr, rssi, data, len); + + /* if Active Scan and scannable event - wait for Scan Response */ + if ((discovery_flags & BTP_GAP_DISCOVERY_FLAG_LE_ACTIVE_SCAN) && + (evtype == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND || + evtype == BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND)) { + SYS_LOG_DBG("Waiting for scan response"); + return; + } +done: + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_FOUND, + adv_buf->om_data, adv_buf->om_len); +} + +static int +discovery_cb(struct ble_gap_event *event, void *arg) +{ + if (event->type == BLE_GAP_EVENT_DISC) { + device_found(&event->disc.addr, event->disc.rssi, + event->disc.event_type, event->disc.data, + event->disc.length_data); + } + + return 0; +} + +static uint8_t +start_discovery(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_start_discovery_cmd *cp = cmd; + struct ble_gap_disc_params params = {0}; + + SYS_LOG_DBG(""); + + /* only LE scan is supported */ + if (cp->flags & BTP_GAP_DISCOVERY_FLAG_BREDR) { + return BTP_STATUS_FAILED; + } + + params.passive = (cp->flags & BTP_GAP_DISCOVERY_FLAG_LE_ACTIVE_SCAN) == 0; + params.limited = (cp->flags & BTP_GAP_DISCOVERY_FLAG_LIMITED) > 0; + params.filter_duplicates = 1; + + if (ble_gap_disc(own_addr_type, BLE_HS_FOREVER, + ¶ms, discovery_cb, NULL) != 0) { + return BTP_STATUS_FAILED; + } + + tester_mbuf_reset(adv_buf); + discovery_flags = cp->flags; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +stop_discovery(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + SYS_LOG_DBG(""); + + if (ble_gap_disc_cancel() != 0) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +/* Bluetooth Core Spec v5.1 | Section 10.7.1 + * If a privacy-enabled Peripheral, that has a stored bond, + * receives a resolvable private address, the Host may resolve + * the resolvable private address [...] + * If the resolution is successful, the Host may accept the connection. + * If the resolution procedure fails, then the Host shall disconnect + * with the error code "Authentication failure" [...] + */ +static void +periph_privacy(struct ble_gap_conn_desc desc) +{ +#if !MYNEWT_VAL(BTTESTER_PRIVACY_MODE) + return; +#endif + int count; + + SYS_LOG_DBG(""); + + ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC, &count); + if (count > 0 && BLE_ADDR_IS_RPA(&desc.peer_id_addr)) { + SYS_LOG_DBG("Authentication failure, disconnecting"); + ble_gap_terminate(desc.conn_handle, BLE_ERR_AUTH_FAIL); + } +} + +static void +device_connected_ev_send(struct os_event *ev) +{ + struct ble_gap_conn_desc desc; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr((ble_addr_t *) &connected_ev, &desc); + if (rc) { + tester_rsp(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_CONNECTED, + BTP_STATUS_FAILED); + return; + } + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_CONNECTED, + (uint8_t *) &connected_ev, sizeof(connected_ev)); + + periph_privacy(desc); +} + +static void +le_connected(uint16_t conn_handle, int status) +{ + struct ble_gap_conn_desc desc; + ble_addr_t *addr; + int rc; + + SYS_LOG_DBG(""); + + if (status != 0) { + return; + } + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + peer_id_addr = desc.peer_id_addr; + peer_ota_addr = desc.peer_ota_addr; + + addr = &desc.peer_id_addr; + + memcpy(&connected_ev.address, addr, sizeof(connected_ev.address)); + connected_ev.conn_itvl = desc.conn_itvl; + connected_ev.conn_latency = desc.conn_latency; + connected_ev.supervision_timeout = desc.supervision_timeout; + +#if MYNEWT_VAL(BTTESTER_CONN_RETRY) + os_callout_reset(&connected_ev_co, + os_time_ms_to_ticks32( + CONNECTED_EV_DELAY_MS(desc.conn_itvl))); +#else + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_CONNECTED, + (uint8_t *) &connected_ev, + sizeof(connected_ev)); +#endif +} + +static void +le_disconnected(struct ble_gap_conn_desc *conn, int reason) +{ + struct btp_gap_device_disconnected_ev ev; + ble_addr_t *addr = &conn->peer_ota_addr; + + SYS_LOG_DBG(""); + +#if MYNEWT_VAL(BTTESTER_CONN_RETRY) + int rc; + + if ((reason == BLE_HS_HCI_ERR(BLE_ERR_CONN_ESTABLISHMENT)) && + os_callout_queued(&connected_ev_co)) { + if (connection_attempts < MYNEWT_VAL(BTTESTER_CONN_RETRY)) { + os_callout_stop(&connected_ev_co); + + /* try connecting again */ + rc = ble_gap_connect(own_addr_type, addr, 0, + &dflt_conn_params, gap_event_cb, + NULL); + + if (rc == 0) { + connection_attempts++; + return; + } + } + } else if (os_callout_queued(&connected_ev_co)) { + os_callout_stop(&connected_ev_co); + return; + } +#endif + + connection_attempts = 0; + memset(&connected_ev, 0, sizeof(connected_ev)); + + memcpy(&ev.address, addr, sizeof(ev.address)); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_DISCONNECTED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +auth_passkey_oob(uint16_t conn_handle) +{ + struct ble_gap_conn_desc desc; + struct ble_sm_io pk; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + memcpy(pk.oob, oob, sizeof(oob)); + pk.action = BLE_SM_IOACT_OOB; + + rc = ble_sm_inject_io(conn_handle, &pk); + assert(rc == 0); +} + +static void +auth_passkey_display(uint16_t conn_handle, unsigned int passkey) +{ + struct ble_gap_conn_desc desc; + struct btp_gap_passkey_display_ev ev; + ble_addr_t *addr; + struct ble_sm_io pk; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + rc = ble_hs_hci_util_rand(&pk.passkey, sizeof(pk.passkey)); + assert(rc == 0); + /* Max value is 999999 */ + pk.passkey %= 1000000; + pk.action = BLE_SM_IOACT_DISP; + + rc = ble_sm_inject_io(conn_handle, &pk); + assert(rc == 0); + + addr = &desc.peer_ota_addr; + + memcpy(&ev.address, addr, sizeof(ev.address)); + ev.passkey = htole32(pk.passkey); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_PASSKEY_DISPLAY, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +auth_passkey_entry(uint16_t conn_handle) +{ + struct ble_gap_conn_desc desc; + struct btp_gap_passkey_entry_req_ev ev; + ble_addr_t *addr; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + addr = &desc.peer_ota_addr; + + memcpy(&ev.address, addr, sizeof(ev.address)); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_PASSKEY_ENTRY_REQ, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +auth_passkey_numcmp(uint16_t conn_handle, unsigned int passkey) +{ + struct ble_gap_conn_desc desc; + struct btp_gap_passkey_confirm_req_ev ev; + ble_addr_t *addr; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + addr = &desc.peer_ota_addr; + + memcpy(&ev.address, addr, sizeof(ev.address)); + ev.passkey = htole32(passkey); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_PASSKEY_CONFIRM_REQ, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +auth_passkey_oob_sc(uint16_t conn_handle) +{ + int rc; + struct ble_sm_io pk; + + SYS_LOG_DBG(""); + + memset(&pk, 0, sizeof(pk)); + + pk.oob_sc_data.local = &oob_data_local; + + if (ble_hs_cfg.sm_oob_data_flag) { + pk.oob_sc_data.remote = &oob_data_remote; + } + + pk.action = BLE_SM_IOACT_OOB_SC; + rc = ble_sm_inject_io(conn_handle, &pk); + if (rc != 0) { + console_printf("error providing oob; rc=%d\n", rc); + } +} + +static void +le_passkey_action(uint16_t conn_handle, + struct ble_gap_passkey_params *params) +{ + SYS_LOG_DBG(""); + + switch (params->action) { + case BLE_SM_IOACT_NONE: + break; + case BLE_SM_IOACT_OOB: + auth_passkey_oob(conn_handle); + break; + case BLE_SM_IOACT_INPUT: + auth_passkey_entry(conn_handle); + break; + case BLE_SM_IOACT_DISP: + auth_passkey_display(conn_handle, + params->numcmp); + break; + case BLE_SM_IOACT_NUMCMP: + auth_passkey_numcmp(conn_handle, + params->numcmp); + break; + case BLE_SM_IOACT_OOB_SC: + auth_passkey_oob_sc(conn_handle); + break; + default: + assert(0); + } +} + +static void +le_identity_resolved(uint16_t conn_handle) +{ + struct ble_gap_conn_desc desc; + struct btp_gap_identity_resolved_ev ev; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + peer_id_addr = desc.peer_id_addr; + peer_ota_addr = desc.peer_ota_addr; + + memcpy(&ev.address, &desc.peer_ota_addr, sizeof(ev.address)); + + memcpy(&ev.identity_address, &desc.peer_id_addr, + sizeof(ev.identity_address)); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_IDENTITY_RESOLVED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +le_pairing_failed(uint16_t conn_handle, int reason) +{ + struct ble_gap_conn_desc desc; + struct btp_gap_sec_pairing_failed_ev ev; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + peer_id_addr = desc.peer_id_addr; + peer_ota_addr = desc.peer_ota_addr; + + memcpy(&ev.address, &desc.peer_ota_addr, sizeof(ev.address)); + + ev.reason = reason; + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_SEC_PAIRING_FAILED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +le_conn_param_update(struct ble_gap_conn_desc *desc) +{ + struct btp_gap_conn_param_update_ev ev; + + SYS_LOG_DBG(""); + + memcpy(&ev.address, &desc->peer_ota_addr, sizeof(ev.address)); + + ev.conn_itvl = desc->conn_itvl; + ev.conn_latency = desc->conn_latency; + ev.supervision_timeout = desc->supervision_timeout; + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_CONN_PARAM_UPDATE, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +le_encryption_changed(struct ble_gap_conn_desc *desc) +{ + struct btp_gap_sec_level_changed_ev ev; + + SYS_LOG_DBG(""); + + encrypted = (bool) desc->sec_state.encrypted; + + memcpy(&ev.address, &desc->peer_ota_addr, sizeof(ev.address)); + ev.level = 0; + + if (desc->sec_state.encrypted) { + if (desc->sec_state.authenticated) { + if (desc->sec_state.key_size == 16) { + ev.level = 3; + } else { + ev.level = 2; + } + } else { + ev.level = 1; + } + } + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_SEC_LEVEL_CHANGED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +bond_lost(uint16_t conn_handle) +{ + struct btp_gap_bond_lost_ev ev; + struct ble_gap_conn_desc desc; + int rc; + + rc = ble_gap_conn_find(conn_handle, &desc); + assert(rc == 0); + + memcpy(&ev.address, &desc.peer_id_addr, sizeof(ev.address)); + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_BOND_LOST, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +print_bytes(const uint8_t *bytes, int len) +{ + int i; + + for (i = 0; i < len; i++) { + console_printf("%s0x%02x", i != 0 ? ":" : "", bytes[i]); + } +} + +static void +print_mbuf(const struct os_mbuf *om) +{ + int colon; + + colon = 0; + while (om != NULL) { + if (colon) { + console_printf(":"); + } else { + colon = 1; + } + print_bytes(om->om_data, om->om_len); + om = SLIST_NEXT(om, om_next); + } +} + +static void +print_addr(const void *addr) +{ + const uint8_t *u8p; + + u8p = addr; + console_printf("%02x:%02x:%02x:%02x:%02x:%02x", + u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); +} + +static void +print_conn_desc(const struct ble_gap_conn_desc *desc) +{ + console_printf("handle=%d our_ota_addr_type=%d our_ota_addr=", + desc->conn_handle, desc->our_ota_addr.type); + print_addr(desc->our_ota_addr.val); + console_printf(" our_id_addr_type=%d our_id_addr=", + desc->our_id_addr.type); + print_addr(desc->our_id_addr.val); + console_printf(" peer_ota_addr_type=%d peer_ota_addr=", + desc->peer_ota_addr.type); + print_addr(desc->peer_ota_addr.val); + console_printf(" peer_id_addr_type=%d peer_id_addr=", + desc->peer_id_addr.type); + print_addr(desc->peer_id_addr.val); + console_printf(" conn_itvl=%d conn_latency=%d supervision_timeout=%d " + "key_sz=%d encrypted=%d authenticated=%d bonded=%d\n", + desc->conn_itvl, desc->conn_latency, + desc->supervision_timeout, + desc->sec_state.key_size, + desc->sec_state.encrypted, + desc->sec_state.authenticated, + desc->sec_state.bonded); +} + +static void +adv_complete(void) +{ + struct btp_gap_new_settings_ev ev; + + current_settings &= ~BIT(BTP_GAP_SETTINGS_ADVERTISING); + ev.current_settings = htole32(current_settings); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_NEW_SETTINGS, + (uint8_t *) &ev, sizeof(ev)); +} + +static int +gap_event_cb(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_ADV_COMPLETE: + console_printf("advertising complete; reason=%d\n", + event->adv_complete.reason); + break; + case BLE_GAP_EVENT_CONNECT: + console_printf("connection %s; status=%d ", + event->connect.status == 0 ? "established" + : "failed", + event->connect.status); + if (event->connect.status == 0) { + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + } + + if (desc.role == BLE_GAP_ROLE_SLAVE) { + adv_complete(); + } + + le_connected(event->connect.conn_handle, + event->connect.status); + break; + case BLE_GAP_EVENT_DISCONNECT: + console_printf("disconnect; reason=%d ", + event->disconnect.reason); + print_conn_desc(&event->disconnect.conn); + le_disconnected(&event->disconnect.conn, + event->disconnect.reason); + break; + case BLE_GAP_EVENT_ENC_CHANGE: + console_printf("encryption change event; status=%d ", + event->enc_change.status); + rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + le_encryption_changed(&desc); + if (event->enc_change.status + == BLE_HS_HCI_ERR(BLE_ERR_PINKEY_MISSING)) { + bond_lost(event->enc_change.conn_handle); + } + break; + case BLE_GAP_EVENT_PASSKEY_ACTION: + console_printf("passkey action event; action=%d", + event->passkey.params.action); + if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) { + console_printf(" numcmp=%lu", + (unsigned long) event->passkey.params.numcmp); + } + console_printf("\n"); + le_passkey_action(event->passkey.conn_handle, + &event->passkey.params); + break; + case BLE_GAP_EVENT_IDENTITY_RESOLVED: + console_printf("identity resolved "); + rc = ble_gap_conn_find(event->identity_resolved.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + le_identity_resolved(event->identity_resolved.conn_handle); + break; + case BLE_GAP_EVENT_NOTIFY_RX: + console_printf( + "notification rx event; attr_handle=%d indication=%d " + "len=%d data=", + event->notify_rx.attr_handle, + event->notify_rx.indication, + OS_MBUF_PKTLEN(event->notify_rx.om)); + + print_mbuf(event->notify_rx.om); + console_printf("\n"); + tester_gattc_notify_rx_ev(event->notify_rx.conn_handle, + event->notify_rx.attr_handle, + event->notify_rx.indication, + event->notify_rx.om); + break; + case BLE_GAP_EVENT_SUBSCRIBE: + console_printf("subscribe event; conn_handle=%d attr_handle=%d " + "reason=%d prevn=%d curn=%d previ=%d curi=%d\n", + event->subscribe.conn_handle, + event->subscribe.attr_handle, + event->subscribe.reason, + event->subscribe.prev_notify, + event->subscribe.cur_notify, + event->subscribe.prev_indicate, + event->subscribe.cur_indicate); + tester_gatt_subscribe_ev(event->subscribe.conn_handle, + event->subscribe.attr_handle, + event->subscribe.reason, + event->subscribe.prev_notify, + event->subscribe.cur_notify, + event->subscribe.prev_indicate, + event->subscribe.cur_indicate); + break; + case BLE_GAP_EVENT_REPEAT_PAIRING: + console_printf("repeat pairing event; conn_handle=%d " + "cur_key_sz=%d cur_auth=%d cur_sc=%d " + "new_key_sz=%d new_auth=%d new_sc=%d " + "new_bonding=%d\n", + event->repeat_pairing.conn_handle, + event->repeat_pairing.cur_key_size, + event->repeat_pairing.cur_authenticated, + event->repeat_pairing.cur_sc, + event->repeat_pairing.new_key_size, + event->repeat_pairing.new_authenticated, + event->repeat_pairing.new_sc, + event->repeat_pairing.new_bonding); + rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); + assert(rc == 0); + rc = ble_store_util_delete_peer(&desc.peer_id_addr); + assert(rc == 0); + bond_lost(event->repeat_pairing.conn_handle); + return BLE_GAP_REPEAT_PAIRING_RETRY; + case BLE_GAP_EVENT_CONN_UPDATE: + console_printf("connection update event; status=%d ", + event->conn_update.status); + rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + le_conn_param_update(&desc); + break; + case BLE_GAP_EVENT_CONN_UPDATE_REQ: + console_printf("connection update request event; " + "conn_handle=%d itvl_min=%d itvl_max=%d " + "latency=%d supervision_timoeut=%d " + "min_ce_len=%d max_ce_len=%d\n", + event->conn_update_req.conn_handle, + event->conn_update_req.peer_params->itvl_min, + event->conn_update_req.peer_params->itvl_max, + event->conn_update_req.peer_params->latency, + event->conn_update_req.peer_params->supervision_timeout, + event->conn_update_req.peer_params->min_ce_len, + event->conn_update_req.peer_params->max_ce_len); + + *event->conn_update_req.self_params = *event->conn_update_req.peer_params; + break; + case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: + console_printf("connection update request event; " + "conn_handle=%d itvl_min=%d itvl_max=%d " + "latency=%d supervision_timoeut=%d " + "min_ce_len=%d max_ce_len=%d\n", + event->conn_update_req.conn_handle, + event->conn_update_req.peer_params->itvl_min, + event->conn_update_req.peer_params->itvl_max, + event->conn_update_req.peer_params->latency, + event->conn_update_req.peer_params->supervision_timeout, + event->conn_update_req.peer_params->min_ce_len, + event->conn_update_req.peer_params->max_ce_len); + if (event->conn_update_req.peer_params->itvl_min + == REJECT_INTERVAL_MIN && + event->conn_update_req.peer_params->itvl_max + == REJECT_INTERVAL_MAX && + event->conn_update_req.peer_params->latency == REJECT_LATENCY + && + event->conn_update_req.peer_params->supervision_timeout + == REJECT_SUPERVISION_TIMEOUT) { + return EINVAL; + } + case BLE_GAP_EVENT_PARING_COMPLETE: + console_printf("received pairing complete: " + "conn_handle=%d status=%d\n", + event->pairing_complete.conn_handle, + event->pairing_complete.status); + if (event->pairing_complete.status != BLE_SM_ERR_SUCCESS) { + le_pairing_failed(event->pairing_complete.conn_handle, + event->pairing_complete.status); + } + break; + default: + break; + } + + return 0; +} + +static uint8_t +connect(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_connect_cmd *cp = cmd; + + ble_addr_t *addr = (ble_addr_t *)&cp->address; + + SYS_LOG_DBG(""); + + if (ble_addr_cmp(BLE_ADDR_ANY, addr) == 0) { + addr = NULL; + } + + if (ble_gap_connect(own_addr_type, addr, 0, + &dflt_conn_params, gap_event_cb, NULL)) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +disconnect(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_disconnect_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr(&cp->address, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gap_terminate(desc.conn_handle, BLE_ERR_REM_USER_CONN_TERM)) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_io_cap(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_io_cap_cmd *cp = cmd; + + SYS_LOG_DBG(""); + + switch (cp->io_cap) { + case BTP_GAP_IO_CAP_DISPLAY_ONLY: + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_ONLY; + ble_hs_cfg.sm_mitm = 1; + break; + case BTP_GAP_IO_CAP_KEYBOARD_DISPLAY: + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_KEYBOARD_DISP; + ble_hs_cfg.sm_mitm = 1; + break; + case BTP_GAP_IO_CAP_NO_INPUT_OUTPUT: + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO; + ble_hs_cfg.sm_mitm = 0; + break; + case BTP_GAP_IO_CAP_KEYBOARD_ONLY: + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_KEYBOARD_ONLY; + ble_hs_cfg.sm_mitm = 1; + break; + case BTP_GAP_IO_CAP_DISPLAY_YESNO: + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_YES_NO; + ble_hs_cfg.sm_mitm = 1; + break; + default: + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +pair(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_pair_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr(&cp->address, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_security_initiate(desc.conn_handle); + if (rc != 0 && rc != BLE_HS_EALREADY) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +unpair(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_unpair_cmd *cp = cmd; + int err; + + SYS_LOG_DBG(""); + + err = ble_gap_unpair(&cp->address); + return err != 0 ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; +} + +static uint8_t +passkey_entry(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_passkey_entry_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + struct ble_sm_io pk; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr(&cp->address, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + pk.action = BLE_SM_IOACT_INPUT; + pk.passkey = le32toh(cp->passkey); + + rc = ble_sm_inject_io(desc.conn_handle, &pk); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +passkey_confirm(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_passkey_confirm_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + struct ble_sm_io pk; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr(&cp->address, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + pk.action = BLE_SM_IOACT_NUMCMP; + pk.numcmp_accept = cp->match; + + rc = ble_sm_inject_io(desc.conn_handle, &pk); + if (rc) { + console_printf("sm inject io failed"); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +start_direct_adv(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_start_direct_adv_cmd *cp = cmd; + struct btp_gap_start_advertising_rp *rp = rsp; + static struct ble_gap_adv_params adv_params = { + .conn_mode = BLE_GAP_CONN_MODE_DIR, + }; + int err; + + SYS_LOG_DBG(""); + + adv_params.high_duty_cycle = cp->options & BIT(1); + + err = ble_gap_adv_start(own_addr_type, &cp->address, + BLE_HS_FOREVER, &adv_params, + gap_event_cb, NULL); + if (err) { + SYS_LOG_ERR("Advertising failed: err %d", err); + return BTP_STATUS_FAILED; + } + + current_settings |= BIT(BTP_GAP_SETTINGS_ADVERTISING); + rp->current_settings = htole32(current_settings); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static void +conn_param_update_cb(uint16_t conn_handle, int status, void *arg) +{ + console_printf("conn param update complete; conn_handle=%d status=%d\n", + conn_handle, status); +} + +static int +conn_param_update_slave(uint16_t conn_handle, + const struct btp_gap_conn_param_update_cmd *cmd) +{ + int rc; + struct ble_l2cap_sig_update_params params; + + params.itvl_min = cmd->conn_itvl_min; + params.itvl_max = cmd->conn_itvl_max; + params.slave_latency = cmd->conn_latency; + params.timeout_multiplier = cmd->supervision_timeout; + + rc = ble_l2cap_sig_update(conn_handle, ¶ms, + conn_param_update_cb, NULL); + if (rc) { + SYS_LOG_ERR("Failed to send update params: rc=%d", rc); + } + + return 0; +} + +static int +conn_param_update_master(uint16_t conn_handle, + const struct btp_gap_conn_param_update_cmd *cmd) +{ + int rc; + struct ble_gap_upd_params params; + + params.itvl_min = cmd->conn_itvl_min; + params.itvl_max = cmd->conn_itvl_max; + params.latency = cmd->conn_latency; + params.supervision_timeout = cmd->supervision_timeout; + params.min_ce_len = 0; + params.max_ce_len = 0; + rc = ble_gap_update_params(conn_handle, ¶ms); + if (rc) { + SYS_LOG_ERR("Failed to send update params: rc=%d", rc); + } + + return rc; +} + +static void +conn_param_update(struct os_event *ev) +{ + struct ble_gap_conn_desc desc; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr((ble_addr_t *) &update_params, &desc); + if (rc) { + goto rsp; + } + + if ((desc.conn_itvl >= update_params.conn_itvl_min) && + (desc.conn_itvl <= update_params.conn_itvl_max) && + (desc.conn_latency == update_params.conn_latency) && + (desc.supervision_timeout == update_params.supervision_timeout)) { + goto rsp; + } + + if (desc.role == BLE_GAP_ROLE_MASTER) { + rc = conn_param_update_master(desc.conn_handle, &update_params); + } else { + rc = conn_param_update_slave(desc.conn_handle, &update_params); + } + + if (rc == 0) { + return; + } + +rsp: + SYS_LOG_ERR("Conn param update fail; rc=%d", rc); +} + +static uint8_t +conn_param_update_async(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_conn_param_update_cmd *cp = cmd; + update_params = *cp; + + os_callout_reset(&update_params_co, 0); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_oob_legacy_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_oob_legacy_set_data_cmd *cp = cmd; + + ble_hs_cfg.sm_oob_data_flag = 1; + memcpy(oob, cp->oob_data, sizeof(oob)); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +get_oob_sc_local_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gap_oob_sc_get_local_data_rp *rp = rsp; + + memcpy(rp->r, oob_data_local.r, 16); + memcpy(rp->c, oob_data_local.c, 16); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_oob_sc_remote_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_oob_sc_set_remote_data_cmd *cp = cmd; + + ble_hs_cfg.sm_oob_data_flag = 1; + memcpy(oob_data_remote.r, cp->r, 16); + memcpy(oob_data_remote.c, cp->c, 16); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_mitm(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_mitm_cmd *cp = cmd; + + ble_hs_cfg.sm_mitm = cp->mitm; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_filter_accept_list(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_filter_accept_list_cmd *cp = cmd; + int err; + + SYS_LOG_DBG(""); + + /* + * Check if the nb of bytes received matches the len of addrs list. + * Then set the filter accept list. + */ + if ((cmd_len < sizeof(*cp)) || + (cmd_len != sizeof(*cp) + (cp->list_len * sizeof(cp->addrs[0])))) { + return BTP_STATUS_FAILED; + } + + err = ble_gap_wl_set(cp->addrs, cp->list_len); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_GAP_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_GAP_READ_CONTROLLER_INDEX_LIST, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = controller_index_list, + }, + { + .opcode = BTP_GAP_READ_CONTROLLER_INFO, + .expect_len = 0, + .func = controller_info, + }, + { + .opcode = BTP_GAP_SET_CONNECTABLE, + .expect_len = sizeof(struct btp_gap_set_connectable_cmd), + .func = set_connectable, + }, + { + .opcode = BTP_GAP_SET_DISCOVERABLE, + .expect_len = sizeof(struct btp_gap_set_discoverable_cmd), + .func = set_discoverable, + }, + { + .opcode = BTP_GAP_SET_BONDABLE, + .expect_len = sizeof(struct btp_gap_set_bondable_cmd), + .func = set_bondable, + }, + { + .opcode = BTP_GAP_START_ADVERTISING, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = start_advertising, + }, + { + .opcode = BTP_GAP_START_DIRECT_ADV, + .expect_len = sizeof(struct btp_gap_start_direct_adv_cmd), + .func = start_direct_adv, + }, + { + .opcode = BTP_GAP_STOP_ADVERTISING, + .expect_len = 0, + .func = stop_advertising, + }, + { + .opcode = BTP_GAP_START_DISCOVERY, + .expect_len = sizeof(struct btp_gap_start_discovery_cmd), + .func = start_discovery, + }, + { + .opcode = BTP_GAP_STOP_DISCOVERY, + .expect_len = 0, + .func = stop_discovery, + }, + { + .opcode = BTP_GAP_CONNECT, + .expect_len = sizeof(struct btp_gap_connect_cmd), + .func = connect, + }, + { + .opcode = BTP_GAP_DISCONNECT, + .expect_len = sizeof(struct btp_gap_disconnect_cmd), + .func = disconnect, + }, + { + .opcode = BTP_GAP_SET_IO_CAP, + .expect_len = sizeof(struct btp_gap_set_io_cap_cmd), + .func = set_io_cap, + }, + { + .opcode = BTP_GAP_PAIR, + .expect_len = sizeof(struct btp_gap_pair_cmd), + .func = pair, + }, + { + .opcode = BTP_GAP_UNPAIR, + .expect_len = sizeof(struct btp_gap_unpair_cmd), + .func = unpair, + }, + { + .opcode = BTP_GAP_PASSKEY_ENTRY, + .expect_len = sizeof(struct btp_gap_passkey_entry_cmd), + .func = passkey_entry, + }, + { + .opcode = BTP_GAP_PASSKEY_CONFIRM, + .expect_len = sizeof(struct btp_gap_passkey_confirm_cmd), + .func = passkey_confirm, + }, + { + .opcode = BTP_GAP_CONN_PARAM_UPDATE, + .expect_len = sizeof(struct btp_gap_conn_param_update_cmd), + .func = conn_param_update_async, + }, + { + .opcode = BTP_GAP_OOB_LEGACY_SET_DATA, + .expect_len = sizeof(struct btp_gap_oob_legacy_set_data_cmd), + .func = set_oob_legacy_data, + }, + { + .opcode = BTP_GAP_OOB_SC_GET_LOCAL_DATA, + .expect_len = 0, + .func = get_oob_sc_local_data, + }, + { + .opcode = BTP_GAP_OOB_SC_SET_REMOTE_DATA, + .expect_len = sizeof(struct btp_gap_oob_sc_set_remote_data_cmd), + .func = set_oob_sc_remote_data, + }, + { + .opcode = BTP_GAP_SET_MITM, + .expect_len = sizeof(struct btp_gap_set_mitm_cmd), + .func = set_mitm, + }, + { + .opcode = BTP_GAP_SET_FILTER_ACCEPT_LIST, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = set_filter_accept_list, + }, +}; + +static void +tester_init_gap_cb() +{ + current_settings = 0; + current_settings |= BIT(BTP_GAP_SETTINGS_POWERED); + current_settings |= BIT(BTP_GAP_SETTINGS_LE); + + os_callout_init(&update_params_co, os_eventq_dflt_get(), + conn_param_update, NULL); + + os_callout_init(&connected_ev_co, os_eventq_dflt_get(), + device_connected_ev_send, NULL); +} + +uint8_t +tester_init_gap(void) +{ +#if MYNEWT_VAL(BLE_SM_SC) + int rc; + + rc = ble_sm_sc_oob_generate_data(&oob_data_local); + if (rc) { + console_printf("Error: generating oob data; reason=%d\n", rc); + return BTP_STATUS_FAILED; + } +#endif +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) + os_callout_init(&bttester_nrpa_rotate_timer, os_eventq_dflt_get(), + rotate_nrpa_cb, NULL); +#endif + adv_buf = os_msys_get(ADV_BUF_LEN, 0); + assert(adv_buf); + + tester_init_gap_cb(); + + tester_register_command_handlers(BTP_SERVICE_ID_GAP, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_gap(void) +{ + return BTP_STATUS_SUCCESS; +} diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp_gatt.c b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_gatt.c new file mode 100644 index 00000000..863d06ac --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_gatt.c @@ -0,0 +1,2237 @@ +/* + * 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. + */ + +/* gatt.c - Bluetooth GATT Server Tester */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "host/ble_gap.h" +#include "host/ble_gatt.h" +#include "console/console.h" +#include "services/gatt/ble_svc_gatt.h" +#include "../../../nimble/host/src/ble_att_priv.h" +#include "../../../nimble/host/src/ble_gatt_priv.h" + +#include "btp/btp.h" + +#define CONTROLLER_INDEX 0 +#define MAX_BUFFER_SIZE 2048 + +/* 0000xxxx-8c26-476f-89a7-a108033a69c7 */ +#define PTS_UUID_DECLARE(uuid16) \ + ((const ble_uuid_t *) (&(ble_uuid128_t) BLE_UUID128_INIT( \ + 0xc7, 0x69, 0x3a, 0x03, 0x08, 0xa1, 0xa7, 0x89, \ + 0x6f, 0x47, 0x26, 0x8c, uuid16, uuid16 >> 8, 0x00, 0x00 \ + ))) + +/* 0000xxxx-8c26-476f-89a7-a108033a69c6 */ +#define PTS_UUID_DECLARE_ALT(uuid16) \ + ((const ble_uuid_t *) (&(ble_uuid128_t) BLE_UUID128_INIT( \ + 0xc6, 0x69, 0x3a, 0x03, 0x08, 0xa1, 0xa7, 0x89, \ + 0x6f, 0x47, 0x26, 0x8c, uuid16, uuid16 >> 8, 0x00, 0x00 \ + ))) + +#define PTS_SVC 0x0001 +#define PTS_CHR_READ 0x0002 +#define PTS_CHR_WRITE 0x0003 +#define PTS_CHR_RELIABLE_WRITE 0x0004 +#define PTS_CHR_WRITE_NO_RSP 0x0005 +#define PTS_CHR_READ_WRITE 0x0006 +#define PTS_CHR_READ_WRITE_ENC 0x0007 +#define PTS_CHR_READ_WRITE_AUTHEN 0x0008 +#define PTS_DSC_READ 0x0009 +#define PTS_DSC_WRITE 0x000a +#define PTS_DSC_READ_WRITE 0x000b +#define PTS_CHR_NOTIFY 0x0025 +#define PTS_LONG_CHR_READ_WRITE 0x0015 +#define PTS_LONG_CHR_READ_WRITE_ALT 0x0016 +#define PTS_LONG_DSC_READ_WRITE 0x001b +#define PTS_INC_SVC 0x001e +#define PTS_CHR_READ_WRITE_ALT 0x001f + +static uint8_t gatt_svr_pts_static_long_val[300]; +static uint8_t gatt_svr_pts_static_val[30]; +static uint8_t gatt_svr_pts_static_short_val; +static uint8_t notify_state; +static uint8_t indicate_state; +static uint16_t myconn_handle; +static struct os_callout notify_tx_timer; +uint16_t notify_handle; +uint8_t notify_value = 90; + +struct find_attr_data { + ble_uuid_any_t *uuid; + int attr_type; + void *ptr; + uint16_t handle; +}; + +static int +gatt_svr_read_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_read_write_auth_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_read_write_enc_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_dsc_read_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_write_no_rsp_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_rel_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_dsc_read_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_dsc_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static const struct ble_gatt_svc_def gatt_svr_inc_svcs[] = { + { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(PTS_INC_SVC), + .characteristics = (struct ble_gatt_chr_def[]) {{ + .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_ALT), + .access_cb = gatt_svr_read_write_test, + .flags = BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_READ, + }, { + 0, + }}, + + }, + + { + 0, /* No more services. */ + }, +}; + +static const struct ble_gatt_svc_def *inc_svcs[] = { + &gatt_svr_inc_svcs[0], + NULL, +}; + +static const struct ble_gatt_svc_def gatt_svr_svcs[] = { + { + /*** Service: PTS test. */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = PTS_UUID_DECLARE(PTS_SVC), + .includes = inc_svcs, + .characteristics = (struct ble_gatt_chr_def[]) { + { + .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE), + .access_cb = gatt_svr_read_write_test, + .flags = BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE, + .descriptors = (struct ble_gatt_dsc_def[]) {{ + .uuid = PTS_UUID_DECLARE(PTS_DSC_READ_WRITE), + .access_cb = gatt_svr_dsc_read_write_test, + .att_flags = BLE_ATT_F_READ | + BLE_ATT_F_WRITE, + }, { + .uuid = PTS_UUID_DECLARE(PTS_LONG_DSC_READ_WRITE), + .access_cb = gatt_svr_dsc_read_write_long_test, + .att_flags = BLE_ATT_F_READ | + BLE_ATT_F_WRITE, + }, { + .uuid = PTS_UUID_DECLARE(PTS_DSC_READ), + .access_cb = gatt_svr_dsc_read_test, + .att_flags = BLE_ATT_F_READ, + }, { + 0, /* No more descriptors in this characteristic */ + }} + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_WRITE_NO_RSP), + .access_cb = gatt_svr_write_no_rsp_test, + .flags = BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_WRITE_NO_RSP, + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_AUTHEN), + .access_cb = gatt_svr_read_write_auth_test, + .flags = BLE_GATT_CHR_F_READ_AUTHEN | + BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE_AUTHEN | + BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_WRITE_AUTHEN, + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_RELIABLE_WRITE), + .access_cb = gatt_svr_rel_write_test, + .flags = BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_RELIABLE_WRITE, + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_ENC), + .access_cb = gatt_svr_read_write_enc_test, + .flags = BLE_GATT_CHR_F_READ_ENC | + BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + }, { + .uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE), + .access_cb = gatt_svr_read_write_long_test, + .flags = BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_READ, + }, { + .uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE_ALT), + .access_cb = gatt_svr_read_write_long_test, + .flags = BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_READ, + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_NOTIFY), + .access_cb = gatt_svr_read_write_test, + .val_handle = ¬ify_handle, + .flags = BLE_GATT_CHR_F_NOTIFY | + BLE_GATT_CHR_F_INDICATE, + }, { + 0, /* No more characteristics in this service. */ + } + }, + }, { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = PTS_UUID_DECLARE_ALT(PTS_SVC), + .characteristics = (struct ble_gatt_chr_def[]) {{ + .uuid = PTS_UUID_DECLARE_ALT(PTS_CHR_READ_WRITE), + .access_cb = gatt_svr_read_write_test, + .flags = BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_READ, + }, { + 0, /* No more characteristics in this service */ + }}, + }, { + 0, /* No more services. */ + }, +}; + +static void +attr_value_changed_ev(uint16_t handle, struct os_mbuf *data) +{ + struct btp_gatt_attr_value_changed_ev *ev; + struct os_mbuf *buf = os_msys_get(0, 0); + + SYS_LOG_DBG(""); + + ev = os_mbuf_extend(buf, sizeof(*ev)); + if (!ev) { + return; + } + + ev->handle = htole16(handle); + ev->data_length = htole16(os_mbuf_len(data)); + os_mbuf_appendfrom(buf, data, 0, os_mbuf_len(data)); + + tester_event(BTP_SERVICE_ID_GATT, BTP_GATT_EV_ATTR_VALUE_CHANGED, + buf->om_data, buf->om_len); +} + +static int +gatt_svr_chr_write(uint16_t conn_handle, uint16_t attr_handle, + struct os_mbuf *om, uint16_t min_len, uint16_t max_len, + void *dst, uint16_t *len) +{ + uint16_t om_len; + int rc; + + om_len = OS_MBUF_PKTLEN(om); + if (om_len < min_len || om_len > max_len) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + rc = ble_hs_mbuf_to_flat(om, dst, max_len, len); + if (rc != 0) { + return BLE_ATT_ERR_UNLIKELY; + } + + attr_value_changed_ev(attr_handle, om); + + return 0; +} + +static uint16_t +extract_uuid16_from_pts_uuid128(const ble_uuid_t *uuid) +{ + const uint8_t *u8ptr; + uint16_t uuid16; + + u8ptr = BLE_UUID128(uuid)->value; + uuid16 = u8ptr[12]; + uuid16 |= (uint16_t) u8ptr[13] << 8; + return uuid16; +} + +static int +gatt_svr_read_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_CHR_READ_WRITE: + case PTS_CHR_READ_WRITE_ALT: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, + ctxt->om, 0, + sizeof gatt_svr_pts_static_short_val, + &gatt_svr_pts_static_short_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_short_val, + sizeof gatt_svr_pts_static_short_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_LONG_CHR_READ_WRITE: + case PTS_LONG_CHR_READ_WRITE_ALT: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, + ctxt->om, 0, + sizeof gatt_svr_pts_static_long_val, + &gatt_svr_pts_static_long_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val, + sizeof gatt_svr_pts_static_long_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_read_write_auth_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_CHR_READ_WRITE_AUTHEN: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, + ctxt->om, 0, + sizeof gatt_svr_pts_static_val, + &gatt_svr_pts_static_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_val, + sizeof gatt_svr_pts_static_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_read_write_enc_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_CHR_READ_WRITE_ENC: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_val, + sizeof gatt_svr_pts_static_val); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, + ctxt->om, 0, + sizeof gatt_svr_pts_static_val, + &gatt_svr_pts_static_val, NULL); + return rc; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_dsc_read_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_DSC_READ_WRITE: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_DSC) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, + ctxt->om, 0, + sizeof gatt_svr_pts_static_short_val, + &gatt_svr_pts_static_short_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_short_val, + sizeof gatt_svr_pts_static_short_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_dsc_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_LONG_DSC_READ_WRITE: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_DSC) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, + ctxt->om, 0, + sizeof gatt_svr_pts_static_long_val, + &gatt_svr_pts_static_long_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val, + sizeof gatt_svr_pts_static_long_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_dsc_read_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_DSC_READ: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val, + sizeof gatt_svr_pts_static_long_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_write_no_rsp_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_CHR_WRITE_NO_RSP: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, + ctxt->om, 0, + sizeof gatt_svr_pts_static_short_val, + &gatt_svr_pts_static_short_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_short_val, + sizeof gatt_svr_pts_static_short_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_rel_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_CHR_RELIABLE_WRITE: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, + ctxt->om, 0, + sizeof gatt_svr_pts_static_val, + &gatt_svr_pts_static_val, NULL); + return rc; + } + + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static uint8_t +start_server(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gatt_start_server_rp *rp = rsp; + + SYS_LOG_DBG(""); + + ble_gatts_show_local(); + + ble_svc_gatt_changed(0x0001, 0xffff); + + rp->db_attr_off = 0; + rp->db_attr_cnt = 0; + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +/* Convert UUID from BTP command to bt_uuid */ +static uint8_t +btp2bt_uuid(const uint8_t *uuid, uint8_t len, + ble_uuid_any_t *bt_uuid) +{ + uint16_t le16; + + switch (len) { + case 0x02: /* UUID 16 */ + bt_uuid->u.type = BLE_UUID_TYPE_16; + memcpy(&le16, uuid, sizeof(le16)); + BLE_UUID16(bt_uuid)->value = le16toh(le16); + break; + case 0x10: /* UUID 128*/ + bt_uuid->u.type = BLE_UUID_TYPE_128; + memcpy(BLE_UUID128(bt_uuid)->value, uuid, 16); + break; + default: + return BTP_STATUS_FAILED; + } + return BTP_STATUS_SUCCESS; +} + +/* + * gatt_buf - cache used by a gatt client (to cache data read/discovered) + * and gatt server (to store attribute user_data). + * It is not intended to be used by client and server at the same time. + */ +static struct { + uint16_t len; + uint8_t buf[MAX_BUFFER_SIZE]; +} gatt_buf; + +static void * +gatt_buf_add(const void *data, size_t len) +{ + void *ptr = gatt_buf.buf + gatt_buf.len; + + if ((len + gatt_buf.len) > MAX_BUFFER_SIZE) { + return NULL; + } + + if (data) { + memcpy(ptr, data, len); + } else { + (void) memset(ptr, 0, len); + } + + gatt_buf.len += len; + + SYS_LOG_DBG("%d/%d used", gatt_buf.len, MAX_BUFFER_SIZE); + + return ptr; +} + +static void * +gatt_buf_reserve(size_t len) +{ + return gatt_buf_add(NULL, len); +} + +static void +gatt_buf_clear(void) +{ + (void) memset(&gatt_buf, 0, sizeof(gatt_buf)); +} + +static void +discover_destroy(void) +{ + gatt_buf_clear(); +} + +static void +read_destroy(void) +{ + gatt_buf_clear(); +} + +static int +read_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gatt_read_rp *rp = (void *) gatt_buf.buf; + uint8_t btp_opcode = (uint8_t) (int) arg; + + SYS_LOG_DBG("status=%d", error->status); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->att_response = (uint8_t) BLE_HS_ATT_ERR(error->status); + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + gatt_buf.buf, gatt_buf.len); + read_destroy(); + return 0; + } + + if (!gatt_buf_add(attr->om->om_data, attr->om->om_len)) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + BTP_STATUS_FAILED); + read_destroy(); + return 0; + } + + rp->data_length += attr->om->om_len; + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + gatt_buf.buf, gatt_buf.len); + read_destroy(); + + return 0; +} + +static uint8_t +read_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_read_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_read_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_read(conn.conn_handle, le16toh(cp->handle), + read_cb, (void *) BTP_GATT_READ)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +read_long_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gatt_read_rp *rp = (void *) gatt_buf.buf; + uint8_t btp_opcode = (uint8_t) (int) arg; + + SYS_LOG_DBG("status=%d", error->status); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->att_response = (uint8_t) BLE_HS_ATT_ERR(error->status); + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + gatt_buf.buf, gatt_buf.len); + read_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + gatt_buf.buf, gatt_buf.len); + read_destroy(); + return 0; + } + + if (gatt_buf_add(attr->om->om_data, attr->om->om_len) == NULL) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + BTP_STATUS_FAILED); + read_destroy(); + return BLE_HS_ENOMEM; + } + + rp->data_length += attr->om->om_len; + + return 0; +} + +static uint8_t +read_long(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_read_long_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_read_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_read_long(conn.conn_handle, + le16toh(cp->handle), + le16toh(cp->offset), + read_long_cb, (void *) BTP_GATT_READ_LONG)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +read_multiple(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_read_multiple_cmd *cp = cmd; + uint16_t handles[cp->handles_count]; + struct ble_gap_conn_desc conn; + int rc, i; + + SYS_LOG_DBG(""); + + for (i = 0; i < ARRAY_SIZE(handles); i++) { + handles[i] = le16toh(cp->handles[i]); + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_read_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_read_mult(conn.conn_handle, handles, + cp->handles_count, read_cb, + (void *) BTP_GATT_READ_MULTIPLE)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +write_without_rsp(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_write_without_rsp_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_write_no_rsp_flat(conn.conn_handle, + le16toh(cp->handle), cp->data, + le16toh(cp->data_length))) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +write_rsp(uint16_t conn_handle, const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + uint8_t err = (uint8_t) error->status; + uint8_t btp_opcode = (uint8_t) (int) arg; + + SYS_LOG_DBG(""); + + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + &err, sizeof(err)); + return 0; +} + +static uint8_t +write_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_write_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_write_flat(conn.conn_handle, le16toh(cp->handle), + cp->data, le16toh(cp->data_length), + write_rsp, (void *) BTP_GATT_WRITE)) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static uint8_t +write_long(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_write_long_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + struct os_mbuf *om = NULL; + int rc = 0; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + goto fail; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + goto fail; + } + + om = ble_hs_mbuf_from_flat(cp->data, le16toh(cp->data_length)); + if (!om) { + SYS_LOG_ERR("Insufficient resources"); + goto fail; + } + + rc = ble_gattc_write_long(conn.conn_handle, + le16toh(cp->handle), + le16toh(cp->offset), + om, write_rsp, + (void *) BTP_GATT_WRITE_LONG); + if (!rc) { + return BTP_STATUS_DELAY_REPLY; + } + +fail: + SYS_LOG_ERR("Failed to send Write Long request, rc=%d", rc); + os_mbuf_free_chain(om); + return BTP_STATUS_FAILED; +} + +static int +reliable_write_rsp(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + uint8_t num_attrs, + void *arg) +{ + uint8_t err = (uint8_t) error->status; + + SYS_LOG_DBG("Reliable write status %d", err); + + tester_rsp_full(BTP_SERVICE_ID_GATT, BTP_GATT_RELIABLE_WRITE, + &err, sizeof(err)); + return 0; +} + +static uint8_t +reliable_write(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_reliable_write_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + struct ble_gatt_attr attr; + struct os_mbuf *om = NULL; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + goto fail; + } + + om = ble_hs_mbuf_from_flat(cp->data, le16toh(cp->data_length)); + /* This is required, because Nimble checks if + * the data is longer than offset + */ + if (os_mbuf_extend(om, le16toh(cp->offset) + 1) == NULL) { + goto fail; + } + + attr.handle = le16toh(cp->handle); + attr.offset = le16toh(cp->offset); + attr.om = om; + + if (ble_gattc_write_reliable(conn.conn_handle, &attr, 1, + reliable_write_rsp, NULL)) { + goto fail; + } + + return BTP_STATUS_SUCCESS; + +fail: + os_mbuf_free_chain(om); + + return BTP_STATUS_FAILED; +} + +static struct bt_gatt_subscribe_params { + uint16_t ccc_handle; + uint16_t value; + uint16_t value_handle; +} subscribe_params; + +static uint8_t +read_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_read_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_read_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_read_by_uuid(conn.conn_handle, + le16toh(cp->start_handle), + le16toh(cp->end_handle), &uuid.u, + read_long_cb, (void *) BTP_GATT_READ_UUID)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +disc_prim_uuid_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *gatt_svc, void *arg) +{ + struct btp_gatt_disc_prim_uuid_rp *rp = (void *) gatt_buf.buf; + struct btp_gatt_service *service; + const ble_uuid_any_t *uuid; + uint8_t uuid_length; + uint8_t opcode = (uint8_t) (int) arg; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, opcode, + BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_rsp_full(BTP_SERVICE_ID_GATT, opcode, + gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_svc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + service = gatt_buf_reserve(sizeof(*service) + uuid_length); + if (!service) { + tester_rsp(BTP_SERVICE_ID_GATT, opcode, + BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + service->start_handle = htole16(gatt_svc->start_handle); + service->end_handle = htole16(gatt_svc->end_handle); + service->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(service->uuid, &u16, uuid_length); + } else { + memcpy(service->uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + rp->services_count++; + + return 0; +} + +static int +disc_all_desc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *gatt_dsc, + void *arg) +{ + struct btp_gatt_disc_all_desc_rp *rp = (void *) gatt_buf.buf; + struct btp_gatt_descriptor *dsc; + const ble_uuid_any_t *uuid; + uint8_t uuid_length; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, BTP_GATT_DISC_ALL_DESC, + BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_rsp_full(BTP_SERVICE_ID_GATT, BTP_GATT_DISC_ALL_DESC, + gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_dsc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + dsc = gatt_buf_reserve(sizeof(*dsc) + uuid_length); + if (!dsc) { + tester_rsp(BTP_SERVICE_ID_GATT, BTP_GATT_DISC_ALL_DESC, + BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + dsc->descriptor_handle = htole16(gatt_dsc->handle); + dsc->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(dsc->uuid, &u16, uuid_length); + } else { + memcpy(dsc->uuid, BLE_UUID128(uuid)->value, uuid_length); + } + + rp->descriptors_count++; + + return 0; +} + +static uint8_t +disc_all_prim_svcs(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_disc_all_prim_svcs_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_disc_all_prim_svcs_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_disc_all_svcs(conn.conn_handle, disc_prim_uuid_cb, + (void *) BTP_GATT_DISC_ALL_PRIM_SVCS)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static uint8_t +disc_all_desc(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_disc_all_desc_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_disc_all_desc_rp))) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle) - 1; + end_handle = le16toh(cp->end_handle); + + rc = ble_gattc_disc_all_dscs(conn.conn_handle, start_handle, end_handle, + disc_all_desc_cb, NULL); + + SYS_LOG_DBG("rc=%d", rc); + + if (rc) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static int +find_included_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *gatt_svc, void *arg) +{ + struct btp_gatt_find_included_rp *rp = (void *) gatt_buf.buf; + struct btp_gatt_included *included; + const ble_uuid_any_t *uuid; + int service_handle = (int) arg; + uint8_t uuid_length; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, BTP_GATT_FIND_INCLUDED, + BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_rsp_full(BTP_SERVICE_ID_GATT, BTP_GATT_FIND_INCLUDED, + gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_svc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + included = gatt_buf_reserve(sizeof(*included) + uuid_length); + if (!included) { + tester_rsp(BTP_SERVICE_ID_GATT, BTP_GATT_FIND_INCLUDED, + BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + included->included_handle = htole16(service_handle + 1 + + rp->services_count); + included->service.start_handle = htole16(gatt_svc->start_handle); + included->service.end_handle = htole16(gatt_svc->end_handle); + included->service.uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(included->service.uuid, &u16, uuid_length); + } else { + memcpy(included->service.uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + rp->services_count++; + + return 0; +} + +static int +disc_chrc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *gatt_chr, void *arg) +{ + struct btp_gatt_disc_chrc_rp *rp = (void *) gatt_buf.buf; + struct btp_gatt_characteristic *chrc; + const ble_uuid_any_t *uuid; + uint8_t btp_opcode = (uint8_t) (int) arg; + uint8_t uuid_length; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_chr->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + chrc = gatt_buf_reserve(sizeof(*chrc) + uuid_length); + if (!chrc) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + chrc->characteristic_handle = htole16(gatt_chr->def_handle); + chrc->properties = gatt_chr->properties; + chrc->value_handle = htole16(gatt_chr->val_handle); + chrc->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(chrc->uuid, &u16, uuid_length); + } else { + memcpy(chrc->uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + rp->characteristics_count++; + + return 0; +} + +static uint8_t +disc_chrc_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_disc_chrc_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_disc_chrc_rp))) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + + if (ble_gattc_disc_chrs_by_uuid(conn.conn_handle, start_handle, + end_handle, &uuid.u, disc_chrc_cb, + (void *) BTP_GATT_DISC_CHRC_UUID)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static uint8_t +disc_prim_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_disc_prim_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + if ((cmd_len < sizeof(*cp)) || + (cmd_len != sizeof(*cp) + cp->uuid_length)) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_disc_prim_uuid_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_disc_svc_by_uuid(conn.conn_handle, + &uuid.u, disc_prim_uuid_cb, + (void *) BTP_GATT_DISC_PRIM_UUID)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static uint8_t +disc_all_chrc(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_disc_all_chrc_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + SYS_LOG_DBG("Conn find failed"); + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_disc_chrc_rp))) { + SYS_LOG_DBG("Buf reserve failed"); + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + + rc = ble_gattc_disc_all_chrs(conn.conn_handle, start_handle, end_handle, + disc_chrc_cb, (void *) BTP_GATT_DISC_ALL_CHRC); + if (rc) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static uint8_t +find_included(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_find_included_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int service_handle_arg; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_find_included_rp))) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + service_handle_arg = start_handle; + + if (ble_gattc_find_inc_svcs(conn.conn_handle, start_handle, end_handle, + find_included_cb, + (void *) service_handle_arg)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static int +exchange_func(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t mtu, void *arg) +{ + SYS_LOG_DBG(""); + + if (error->status) { + SYS_LOG_DBG("MTU exchange failed"); + + return 0; + } + + SYS_LOG_DBG("MTU exchange succeed"); + + return 0; +} + +static uint8_t +exchange_mtu(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_exchange_mtu_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_exchange_mtu(conn.conn_handle, exchange_func, NULL)) { + return BTP_STATUS_FAILED; + } + + /* this BTP command is about initiating MTU exchange, no need to wait + * for procedure to complete. + */ + return BTP_STATUS_SUCCESS; +} + +static int +enable_subscription(uint16_t conn_handle, uint16_t ccc_handle, + uint16_t value) +{ + uint8_t op; + + SYS_LOG_DBG(""); + + op = (uint8_t) (value == 0x0001 ? BTP_GATT_CFG_NOTIFY : BTP_GATT_CFG_INDICATE); + + if (ble_gattc_write_flat(conn_handle, ccc_handle, + &value, sizeof(value), NULL, NULL)) { + return -EINVAL; + } + + subscribe_params.ccc_handle = value; + + tester_rsp(BTP_SERVICE_ID_GATT, op, BTP_STATUS_SUCCESS); + return 0; +} + +static int +disable_subscription(uint16_t conn_handle, uint16_t ccc_handle) +{ + uint16_t value = 0x00; + + SYS_LOG_DBG(""); + + /* Fail if CCC handle doesn't match */ + if (ccc_handle != subscribe_params.ccc_handle) { + SYS_LOG_ERR("CCC handle doesn't match"); + return -EINVAL; + } + + if (ble_gattc_write_no_rsp_flat(conn_handle, ccc_handle, + &value, sizeof(value))) { + return -EINVAL; + } + + subscribe_params.ccc_handle = 0; + return 0; +} + +static uint8_t +config_subscription_notif(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_cfg_notify_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t ccc_handle = le16toh(cp->ccc_handle); + uint8_t status; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (cp->enable) { + /* on success response will be sent from callback */ + if (enable_subscription(conn.conn_handle, + ccc_handle, 0x0001) == 0) { + return BTP_STATUS_DELAY_REPLY; + } + + status = BTP_STATUS_FAILED; + } else { + if (disable_subscription(conn.conn_handle, ccc_handle) < 0) { + status = BTP_STATUS_FAILED; + } else { + status = BTP_STATUS_SUCCESS; + } + } + + return status; +} + +static uint8_t +config_subscription_ind(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_cfg_notify_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t ccc_handle = le16toh(cp->ccc_handle); + uint8_t status; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (cp->enable) { + /* on success response will be sent from callback */ + if (enable_subscription(conn.conn_handle, + ccc_handle, 0x0002) == 0) { + return BTP_STATUS_DELAY_REPLY; + } + + status = BTP_STATUS_FAILED; + } else { + if (disable_subscription(conn.conn_handle, ccc_handle) < 0) { + status = BTP_STATUS_FAILED; + } else { + status = BTP_STATUS_SUCCESS; + } + } + + return status; +} + +#define BTP_PERM_F_READ 0x01 +#define BTP_PERM_F_WRITE 0x02 +#define BTP_PERM_F_READ_ENC 0x04 +#define BTP_PERM_F_WRITE_ENC 0x08 +#define BTP_PERM_F_READ_AUTHEN 0x10 +#define BTP_PERM_F_WRITE_AUTHEN 0x20 +#define BTP_PERM_F_READ_AUTHOR 0x40 +#define BTP_PERM_F_WRITE_AUTHOR 0x80 + +static int flags_hs2btp_map[] = { + BTP_PERM_F_READ, + BTP_PERM_F_WRITE, + BTP_PERM_F_READ_ENC, + BTP_PERM_F_READ_AUTHEN, + BTP_PERM_F_READ_AUTHOR, + BTP_PERM_F_WRITE_ENC, + BTP_PERM_F_WRITE_AUTHEN, + BTP_PERM_F_WRITE_AUTHOR, +}; + +static uint8_t +flags_hs2btp(uint8_t flags) +{ + int i; + uint8_t ret = 0; + + for (i = 0; i < 8; ++i) { + if (flags & BIT(i)) { + ret |= flags_hs2btp_map[i]; + } + } + + return ret; +} + +static uint8_t +get_attrs(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_get_attributes_cmd *cp = cmd; + struct btp_gatt_get_attributes_rp *rp = rsp; + struct btp_gatt_attr *gatt_attr; + struct os_mbuf *buf = os_msys_get(0, 0); + uint16_t start_handle, end_handle; + struct ble_att_svr_entry *entry = NULL; + ble_uuid_any_t uuid; + ble_uuid_t *uuid_ptr = NULL; + uint8_t count = 0; + char str[BLE_UUID_STR_LEN]; + uint8_t status = BTP_STATUS_SUCCESS; + + SYS_LOG_DBG(""); + + if (!buf) { + return BTP_STATUS_FAILED; + } + + memset(str, 0, sizeof(str)); + memset(&uuid, 0, sizeof(uuid)); + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + + if (cp->type_length) { + if (btp2bt_uuid(cp->type, cp->type_length, &uuid)) { + status = BTP_STATUS_FAILED; + goto done; + } + + ble_uuid_to_str(&uuid.u, str); + SYS_LOG_DBG("start 0x%04x end 0x%04x, uuid %s", start_handle, + end_handle, str); + + uuid_ptr = &uuid.u; + } else { + SYS_LOG_DBG("start 0x%04x end 0x%04x", start_handle, end_handle); + } + + entry = ble_att_svr_find_by_uuid(entry, uuid_ptr, end_handle); + while (entry) { + + if (entry->ha_handle_id < start_handle) { + entry = ble_att_svr_find_by_uuid(entry, + uuid_ptr, end_handle); + continue; + } + + gatt_attr = os_mbuf_extend(buf, sizeof(*gatt_attr)); + if (!gatt_attr) { + status = BTP_STATUS_FAILED; + goto done; + } + gatt_attr->handle = htole16(entry->ha_handle_id); + gatt_attr->permission = flags_hs2btp(entry->ha_flags); + + if (entry->ha_uuid->type == BLE_UUID_TYPE_16) { + uint16_t uuid_val; + + gatt_attr->type_length = 2; + uuid_val = htole16(BLE_UUID16(entry->ha_uuid)->value); + if (os_mbuf_append(buf, &uuid_val, sizeof(uuid_val))) { + status = BTP_STATUS_FAILED; + goto done; + } + } else { + gatt_attr->type_length = 16; + if (os_mbuf_append(buf, BLE_UUID128(entry->ha_uuid)->value, + gatt_attr->type_length)) { + status = BTP_STATUS_FAILED; + goto done; + } + } + + count++; + + entry = ble_att_svr_find_by_uuid(entry, uuid_ptr, end_handle); + } + + rp->attrs_count = count; + os_mbuf_copydata(buf, 0, os_mbuf_len(buf), rp->attrs); + + *rsp_len = sizeof(*rp) + os_mbuf_len(buf); + +done: + os_mbuf_free_chain(buf); + return status; +} + +static uint8_t +get_attr_val(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_get_attribute_value_cmd *cp = cmd; + struct btp_gatt_get_attribute_value_rp *rp; + struct ble_gap_conn_desc conn; + struct os_mbuf *buf = os_msys_get(0, 0); + uint16_t handle = le16toh(cp->handle); + uint8_t out_att_err = 0; + int conn_status; + uint8_t status = BTP_STATUS_SUCCESS; + + conn_status = ble_gap_conn_find_by_addr(&cp->address, &conn); + + if (conn_status) { + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + status = BTP_STATUS_FAILED; + goto free; + } + + ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, + handle, 0, buf, + &out_att_err); + + rp->att_response = out_att_err; + rp->value_length = os_mbuf_len(buf) - sizeof(*rp); + + os_mbuf_copydata(buf, 0, os_mbuf_len(buf), rsp); + *rsp_len = os_mbuf_len(buf); + + goto free; + } else { + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + status = BTP_STATUS_FAILED; + goto free; + } + + ble_att_svr_read_handle(conn.conn_handle, + handle, 0, buf, + &out_att_err); + + rp->att_response = out_att_err; + rp->value_length = os_mbuf_len(buf) - sizeof(*rp); + + os_mbuf_copydata(buf, 0, os_mbuf_len(buf), rsp); + *rsp_len = os_mbuf_len(buf); + + goto free; + } + +free: + os_mbuf_free_chain(buf); + return status; +} + +static uint8_t +change_database(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_change_database_cmd *cp = cmd; + + SYS_LOG_DBG("") + + ble_gatts_show_local(); + + ble_svc_gatt_changed(cp->start_handle, cp->end_handle); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gatt_read_supported_commands_rp *rp = rsp; + + /* octet 0 */ + tester_set_bit(rp->data, BTP_GATT_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_GATT_START_SERVER); + + /* octet 1 */ + tester_set_bit(rp->data, BTP_GATT_EXCHANGE_MTU); + tester_set_bit(rp->data, BTP_GATT_DISC_ALL_PRIM_SVCS); + tester_set_bit(rp->data, BTP_GATT_DISC_PRIM_UUID); + tester_set_bit(rp->data, BTP_GATT_FIND_INCLUDED); + tester_set_bit(rp->data, BTP_GATT_DISC_ALL_CHRC); + tester_set_bit(rp->data, BTP_GATT_DISC_CHRC_UUID); + + /* octet 2 */ + tester_set_bit(rp->data, BTP_GATT_DISC_ALL_DESC); + tester_set_bit(rp->data, BTP_GATT_READ); + tester_set_bit(rp->data, BTP_GATT_READ_LONG); + tester_set_bit(rp->data, BTP_GATT_READ_MULTIPLE); + tester_set_bit(rp->data, BTP_GATT_WRITE_WITHOUT_RSP); +#if 0 + tester_set_bit(rp->data, BTP_GATT_SIGNED_WRITE_WITHOUT_RSP); +#endif + tester_set_bit(rp->data, BTP_GATT_WRITE); + + /* octet 3 */ + tester_set_bit(rp->data, BTP_GATT_WRITE_LONG); + tester_set_bit(rp->data, BTP_GATT_CFG_NOTIFY); + tester_set_bit(rp->data, BTP_GATT_CFG_INDICATE); + tester_set_bit(rp->data, BTP_GATT_GET_ATTRIBUTES); + tester_set_bit(rp->data, BTP_GATT_GET_ATTRIBUTE_VALUE); + tester_set_bit(rp->data, BTP_GATT_CHANGE_DATABASE); + + *rsp_len = sizeof(*rp) + 4; + + return BTP_STATUS_SUCCESS; +} + +enum attr_type { + BLE_GATT_ATTR_SVC = 0, + BLE_GATT_ATTR_CHR, + BLE_GATT_ATTR_DSC, +}; + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_GATT_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_GATT_START_SERVER, + .expect_len = 0, + .func = start_server, + }, + { + .opcode = BTP_GATT_EXCHANGE_MTU, + .expect_len = sizeof(struct btp_gatt_exchange_mtu_cmd), + .func = exchange_mtu, + }, + { + .opcode = BTP_GATT_DISC_ALL_PRIM_SVCS, + .expect_len = sizeof(struct btp_gatt_disc_all_prim_svcs_cmd), + .func = disc_all_prim_svcs, + }, + { + .opcode = BTP_GATT_DISC_PRIM_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = disc_prim_uuid, + }, + { + .opcode = BTP_GATT_FIND_INCLUDED, + .expect_len = sizeof(struct btp_gatt_find_included_cmd), + .func = find_included, + }, + { + .opcode = BTP_GATT_DISC_ALL_CHRC, + .expect_len = sizeof(struct btp_gatt_disc_all_chrc_cmd), + .func = disc_all_chrc, + }, + { + .opcode = BTP_GATT_DISC_CHRC_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = disc_chrc_uuid, + }, + { + .opcode = BTP_GATT_DISC_ALL_DESC, + .expect_len = sizeof(struct btp_gatt_disc_all_desc_cmd), + .func = disc_all_desc, + }, + { + .opcode = BTP_GATT_CHANGE_DATABASE, + .expect_len = sizeof(struct btp_gatt_change_database_cmd), + .func = change_database, + }, + { + .opcode = BTP_GATT_READ, + .expect_len = sizeof(struct btp_gatt_read_cmd), + .func = read_data, + }, + { + .opcode = BTP_GATT_READ_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = read_uuid, + }, + { + .opcode = BTP_GATT_READ_LONG, + .expect_len = sizeof(struct btp_gatt_read_long_cmd), + .func = read_long, + }, + { + .opcode = BTP_GATT_READ_MULTIPLE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = read_multiple, + }, + { + .opcode = BTP_GATT_WRITE_WITHOUT_RSP, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_without_rsp, + }, +#if 0 + { + .opcode = BTP_GATT_SIGNED_WRITE_WITHOUT_RSP, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_signed_without_rsp, + }, +#endif + { + .opcode = BTP_GATT_WRITE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_data, + }, + { + .opcode = BTP_GATT_WRITE_LONG, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_long, + }, + { + .opcode = BTP_GATT_RELIABLE_WRITE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = reliable_write, + }, + { + .opcode = BTP_GATT_CFG_NOTIFY, + .expect_len = sizeof(struct btp_gatt_cfg_notify_cmd), + .func = config_subscription_notif, + }, + { + .opcode = BTP_GATT_CFG_INDICATE, + .expect_len = sizeof(struct btp_gatt_cfg_notify_cmd), + .func = config_subscription_ind, + }, + { + .opcode = BTP_GATT_GET_ATTRIBUTES, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = get_attrs, + }, + { + .opcode = BTP_GATT_GET_ATTRIBUTE_VALUE, + .expect_len = sizeof(struct btp_gatt_get_attribute_value_cmd), + .func = get_attr_val, + }, +}; + +int +tester_gatt_notify_rx_ev(uint16_t conn_handle, uint16_t attr_handle, + uint8_t indication, struct os_mbuf *om) +{ + struct btp_gatt_notification_ev *ev; + struct ble_gap_conn_desc conn; + struct os_mbuf *buf = os_msys_get(0, 0); + const ble_addr_t *addr; + + SYS_LOG_DBG(""); + + if (!subscribe_params.ccc_handle) { + goto fail; + } + + if (ble_gap_conn_find(conn_handle, &conn)) { + goto fail; + } + + ev = os_mbuf_extend(buf, sizeof(*ev)); + if (!ev) { + goto fail; + } + + addr = &conn.peer_ota_addr; + + memcpy(&ev->address, addr, sizeof(ev->address)); + ev->type = (uint8_t) (indication ? 0x02 : 0x01); + ev->handle = htole16(attr_handle); + ev->data_length = htole16(os_mbuf_len(om)); + os_mbuf_appendfrom(buf, om, 0, os_mbuf_len(om)); + + tester_event(BTP_SERVICE_ID_GATT, BTP_GATT_EV_NOTIFICATION, + buf->om_data, buf->om_len); + +fail: + os_mbuf_free_chain(buf); + return 0; +} + +void +notify_test_stop(void) +{ + os_callout_stop(¬ify_tx_timer); +} + +void +notify_test_reset(void) +{ + int rc; + + rc = os_callout_reset(¬ify_tx_timer, OS_TICKS_PER_SEC); + assert(rc == 0); +} + +void +notify_test(struct os_event *ev) +{ + static uint8_t ntf[1]; + struct os_mbuf *om; + int rc; + + if (!notify_state && !indicate_state) { + notify_test_stop(); + notify_value = 90; + return; + } + + ntf[0] = notify_value; + + notify_value++; + if (notify_value == 160) { + notify_value = 90; + } + + om = ble_hs_mbuf_from_flat(ntf, sizeof(ntf)); + + if (notify_state) { + rc = ble_gatts_notify_custom(myconn_handle, notify_handle, om); + assert(rc == 0); + } + + if (indicate_state) { + rc = ble_gatts_indicate_custom(myconn_handle, notify_handle, om); + assert(rc == 0); + } +} + +int +tester_gatt_subscribe_ev(uint16_t conn_handle, + uint16_t attr_handle, + uint8_t reason, + uint8_t prev_notify, + uint8_t cur_notify, + uint8_t prev_indicate, + uint8_t cur_indicate) +{ + SYS_LOG_DBG(""); + myconn_handle = conn_handle; + + if (cur_notify == 0 && cur_indicate == 0) { + SYS_LOG_INF("Unsubscribed"); + memset(&subscribe_params, 0, sizeof(subscribe_params)); + return 0; + } + + if (cur_notify) { + SYS_LOG_INF("Subscribed to notifications"); + if (attr_handle == notify_handle) { + notify_state = cur_notify; + } + } + + if (cur_indicate) { + SYS_LOG_INF("Subscribed to indications"); + if (attr_handle == notify_handle) { + indicate_state = cur_indicate; + } + } + + if (notify_state || indicate_state) { + notify_test_reset(); + } else { + notify_test_stop(); + } + + return 0; +} + +void +gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) +{ + char buf[BLE_UUID_STR_LEN]; + + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + MODLOG_DFLT(DEBUG, + "registered service %s with handle=%d\n", + ble_uuid_to_str( + ctxt->svc.svc_def->uuid, + buf), + ctxt->svc.handle); + break; + + case BLE_GATT_REGISTER_OP_CHR: + MODLOG_DFLT(DEBUG, + "registering characteristic %s with " + "def_handle=%d val_handle=%d\n", + ble_uuid_to_str( + ctxt->chr.chr_def->uuid, + buf), + ctxt->chr.def_handle, + ctxt->chr.val_handle); + break; + + case BLE_GATT_REGISTER_OP_DSC: + MODLOG_DFLT(DEBUG, + "registering descriptor %s with handle=%d\n", + ble_uuid_to_str( + ctxt->dsc.dsc_def->uuid, + buf), + ctxt->dsc.handle); + break; + + default: + assert(0); + break; + } +} + +int +gatt_svr_init(void) +{ + int rc; + + rc = ble_gatts_count_cfg(gatt_svr_inc_svcs); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svr_inc_svcs); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_count_cfg(gatt_svr_svcs); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svr_svcs); + if (rc != 0) { + return rc; + } + + return 0; +} + +uint8_t +tester_init_gatt(void) +{ + os_callout_init(¬ify_tx_timer, os_eventq_dflt_get(), + notify_test, NULL); + + tester_register_command_handlers(BTP_SERVICE_ID_GATT, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_gatt(void) +{ + return BTP_STATUS_SUCCESS; +} diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp_gatt_cl.c b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_gatt_cl.c new file mode 100644 index 00000000..ff76d7dd --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_gatt_cl.c @@ -0,0 +1,1557 @@ +/* + * 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 +#include +#include + +#include "host/ble_gap.h" +#include "host/ble_gatt.h" +#include "console/console.h" +#include "services/gatt/ble_svc_gatt.h" +#include "../../../nimble/host/src/ble_att_priv.h" +#include "../../../nimble/host/src/ble_gatt_priv.h" + +#include "btp/btp.h" + +#define CONTROLLER_INDEX 0 +#define MAX_BUFFER_SIZE 2048 + +/* Convert UUID from BTP command to bt_uuid */ +static uint8_t +btp2bt_uuid(const uint8_t *uuid, uint8_t len, + ble_uuid_any_t *bt_uuid) +{ + uint16_t le16; + + switch (len) { + case 0x02: /* UUID 16 */ + bt_uuid->u.type = BLE_UUID_TYPE_16; + memcpy(&le16, uuid, sizeof(le16)); + BLE_UUID16(bt_uuid)->value = le16toh(le16); + break; + case 0x10: /* UUID 128*/ + bt_uuid->u.type = BLE_UUID_TYPE_128; + memcpy(BLE_UUID128(bt_uuid)->value, uuid, 16); + break; + default: + return BTP_STATUS_FAILED; + } + return BTP_STATUS_SUCCESS; +} + +/* + * gatt_buf - cache used by a gatt client (to cache data read/discovered) + * and gatt server (to store attribute user_data). + * It is not intended to be used by client and server at the same time. + */ +static struct { + uint16_t len; + uint8_t buf[MAX_BUFFER_SIZE]; + uint16_t cnt; +} gatt_buf; +static struct bt_gatt_subscribe_params { + uint16_t ccc_handle; + uint16_t value; + uint16_t value_handle; +} subscribe_params; + +static void * +gatt_buf_add(const void *data, size_t len) +{ + void *ptr = gatt_buf.buf + gatt_buf.len; + + if ((len + gatt_buf.len) > MAX_BUFFER_SIZE) { + return NULL; + } + + if (data) { + memcpy(ptr, data, len); + } else { + (void) memset(ptr, 0, len); + } + + gatt_buf.len += len; + + SYS_LOG_DBG("%d/%d used", gatt_buf.len, MAX_BUFFER_SIZE); + + return ptr; +} + +static void * +gatt_buf_reserve(size_t len) +{ + return gatt_buf_add(NULL, len); +} + +static void +gatt_buf_clear(void) +{ + (void) memset(&gatt_buf, 0, sizeof(gatt_buf)); +} + +static void +discover_destroy(void) +{ + gatt_buf_clear(); +} + +static void +read_destroy() +{ + gatt_buf_clear(); +} + +static int +tester_mtu_exchanged_ev(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t mtu, void *arg) +{ + struct btp_gattc_exchange_mtu_ev *ev; + struct ble_gap_conn_desc conn; + struct os_mbuf *buf = os_msys_get(0, 0); + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + goto fail; + } + + ev = os_mbuf_extend(buf, sizeof(*ev)); + if (!ev) { + return 0; + } + + memcpy(&ev->address, &conn.peer_ota_addr, sizeof(ev->address)); + + ev->mtu = mtu; + + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_EV_MTU_EXCHANGED, + buf->om_data, buf->om_len); +fail: + os_mbuf_free_chain(buf); + return 0; +} + +static uint8_t +exchange_mtu(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_exchange_mtu_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_exchange_mtu(conn.conn_handle, + tester_mtu_exchanged_ev, + NULL)) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +disc_prim_svcs_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *gatt_svc, void *arg) +{ + struct btp_gattc_disc_prim_svcs_rp *rp; + struct ble_gap_conn_desc conn; + struct btp_gatt_service *service; + const ble_uuid_any_t *uuid; + uint8_t uuid_length; + struct os_mbuf *buf = os_msys_get(0, 0); + uint8_t opcode = (uint8_t) (int) arg; + uint8_t err = (uint8_t) error->status; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->services_count = 0; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->status = 0; + rp->services_count = gatt_buf.cnt; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + uuid = &gatt_svc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + service = gatt_buf_reserve(sizeof(*service) + uuid_length); + if (!service) { + discover_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + service->start_handle = htole16(gatt_svc->start_handle); + service->end_handle = htole16(gatt_svc->end_handle); + service->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(service->uuid, &u16, uuid_length); + } else { + memcpy(service->uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + gatt_buf.cnt++; + +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +disc_all_prim_svcs(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_disc_all_prim_svcs_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_disc_all_svcs(conn.conn_handle, disc_prim_svcs_cb, + (void *) BTP_GATTC_DISC_ALL_PRIM_RP)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +disc_prim_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_disc_prim_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_disc_svc_by_uuid(conn.conn_handle, + &uuid.u, disc_prim_svcs_cb, + (void *) BTP_GATTC_DISC_PRIM_UUID_RP)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +find_included_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *gatt_svc, void *arg) +{ + struct btp_gattc_find_included_rp *rp; + struct btp_gatt_included *included; + const ble_uuid_any_t *uuid; + int service_handle = (int) arg; + uint8_t uuid_length; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + + SYS_LOG_DBG(""); + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->services_count = 0; + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_FIND_INCLUDED_RP, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->status = 0; + rp->services_count = gatt_buf.cnt; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_FIND_INCLUDED_RP, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + uuid = &gatt_svc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + included = gatt_buf_reserve(sizeof(*included) + uuid_length); + if (!included) { + discover_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + included->included_handle = htole16(service_handle + 1 + + rp->services_count); + included->service.start_handle = htole16(gatt_svc->start_handle); + included->service.end_handle = htole16(gatt_svc->end_handle); + included->service.uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(included->service.uuid, &u16, uuid_length); + } else { + memcpy(included->service.uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + gatt_buf.cnt++; + +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +find_included(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_find_included_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int service_handle_arg; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + service_handle_arg = start_handle; + + if (ble_gattc_find_inc_svcs(conn.conn_handle, start_handle, end_handle, + find_included_cb, + (void *) service_handle_arg)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +disc_chrc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *gatt_chr, void *arg) +{ + struct btp_gattc_disc_chrc_rp *rp; + struct btp_gatt_characteristic *chrc; + const ble_uuid_any_t *uuid; + uint8_t uuid_length; + uint8_t opcode = (uint8_t) (int) arg; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + if (ble_gap_conn_find(conn_handle, &conn)) { + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->characteristics_count = 0; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->status = 0; + rp->characteristics_count = gatt_buf.cnt; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + uuid = &gatt_chr->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + chrc = gatt_buf_reserve(sizeof(*chrc) + uuid_length); + if (!chrc) { + discover_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + chrc->characteristic_handle = htole16(gatt_chr->def_handle); + chrc->properties = gatt_chr->properties; + chrc->value_handle = htole16(gatt_chr->val_handle); + chrc->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(chrc->uuid, &u16, uuid_length); + } else { + memcpy(chrc->uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + gatt_buf.cnt++; +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +disc_all_chrc(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_disc_all_chrc_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + SYS_LOG_DBG("Conn find rsped"); + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + + rc = ble_gattc_disc_all_chrs(conn.conn_handle, + start_handle, + end_handle, + disc_chrc_cb, + (void *) BTP_GATTC_DISC_ALL_CHRC_RP); + if (rc) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +disc_chrc_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_disc_chrc_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + + rc = ble_gattc_disc_chrs_by_uuid(conn.conn_handle, start_handle, + end_handle, &uuid.u, disc_chrc_cb, + (void *) BTP_GATTC_DISC_CHRC_UUID_RP); + if (rc) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +disc_all_desc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *gatt_dsc, + void *arg) +{ + struct btp_gattc_disc_all_desc_rp *rp; + struct btp_gatt_descriptor *dsc; + const ble_uuid_any_t *uuid; + uint8_t uuid_length; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->descriptors_count = 0; + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_DISC_ALL_DESC_RP, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->status = 0; + rp->descriptors_count = gatt_buf.cnt; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_DISC_ALL_DESC_RP, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + uuid = &gatt_dsc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + dsc = gatt_buf_reserve(sizeof(*dsc) + uuid_length); + if (!dsc) { + discover_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + dsc->descriptor_handle = htole16(gatt_dsc->handle); + dsc->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(dsc->uuid, &u16, uuid_length); + } else { + memcpy(dsc->uuid, BLE_UUID128(uuid)->value, uuid_length); + } + + gatt_buf.cnt++; + +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +disc_all_desc(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_disc_all_desc_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle) - 1; + end_handle = le16toh(cp->end_handle); + + rc = ble_gattc_disc_all_dscs(conn.conn_handle, + start_handle, + end_handle, + disc_all_desc_cb, + (void *) BTP_GATTC_DISC_ALL_DESC); + + SYS_LOG_DBG("rc=%d", rc); + + if (rc) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +read_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gattc_read_rp *rp; + uint8_t opcode = (uint8_t) (int) arg; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + SYS_LOG_DBG("status=%d", error->status); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->status = (uint8_t) BLE_HS_ATT_ERR(error->status); + rp->data_length = 0; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); + goto free; + } + + if (!gatt_buf_add(attr->om->om_data, attr->om->om_len)) { + read_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + rp->status = 0; + rp->data_length = attr->om->om_len; + os_mbuf_appendfrom(buf, attr->om, 0, os_mbuf_len(attr->om)); + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +read(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_read_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (ble_gattc_read(conn.conn_handle, le16toh(cp->handle), + read_cb, (void *) BTP_GATTC_READ_RP)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +read_uuid_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gattc_read_uuid_rp *rp; + struct btp_gatt_read_uuid_chr *chr; + uint8_t opcode = (uint8_t) (int) arg; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + static uint16_t attr_len; + + SYS_LOG_DBG("status=%d", error->status); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->data_length = 0; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->data_length = gatt_buf.len; + rp->value_length = attr_len; + rp->status = 0; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); + goto free; + } + + if (error->status == 0) { + attr_len = attr->om->om_len; + } + + chr = gatt_buf_reserve(sizeof(*chr) + attr->om->om_len); + if (!chr) { + read_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + chr->handle = htobe16(attr->handle); + memcpy(chr->data, attr->om->om_data, attr->om->om_len); + +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +read_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_read_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (ble_gattc_read_by_uuid(conn.conn_handle, + le16toh(cp->start_handle), + le16toh(cp->end_handle), &uuid.u, + read_uuid_cb, (void *) BTP_GATTC_READ_UUID_RP)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +read_long_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gattc_read_rp *rp;; + uint8_t opcode = (uint8_t) (int) arg; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG("status=%d", error->status); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->data_length = 0; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->status = 0; + rp->data_length = gatt_buf.len; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); + goto free; + } + + if (gatt_buf_add(attr->om->om_data, attr->om->om_len) == NULL) { + read_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + rp->data_length += attr->om->om_len; + +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +read_long(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_read_long_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (ble_gattc_read_long(conn.conn_handle, + le16toh(cp->handle), + le16toh(cp->offset), + read_long_cb, (void *) BTP_GATTC_READ_LONG_RP)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +read_multiple(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_read_multiple_cmd *cp = cmd; + uint16_t handles[cp->handles_count]; + struct ble_gap_conn_desc conn; + int rc, i; + + SYS_LOG_DBG(""); + + for (i = 0; i < ARRAY_SIZE(handles); i++) { + handles[i] = le16toh(cp->handles[i]); + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (ble_gattc_read_mult(conn.conn_handle, + handles, + cp->handles_count, + read_cb, + (void *) BTP_GATTC_READ_MULTIPLE_RP)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +write_without_rsp(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_write_without_rsp_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_write_no_rsp_flat(conn.conn_handle, + le16toh(cp->handle), cp->data, + le16toh(cp->data_length))) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +write_cb(uint16_t conn_handle, const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gattc_write_rp *rp; + uint8_t err = (uint8_t) error->status; + uint8_t opcode = (uint8_t) (int) arg; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +write(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_write_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_write_flat(conn.conn_handle, le16toh(cp->handle), + cp->data, le16toh(cp->data_length), + write_cb, (void *) BTP_GATTC_WRITE_RP)) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +write_long(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_write_long_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + struct os_mbuf *om = NULL; + int rc = 0; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + goto fail; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + goto fail; + } + + om = ble_hs_mbuf_from_flat(cp->data, le16toh(cp->data_length)); + if (!om) { + SYS_LOG_ERR("Insufficient resources"); + goto fail; + } + + rc = ble_gattc_write_long(conn.conn_handle, + le16toh(cp->handle), + le16toh(cp->offset), + om, write_cb, + (void *) BTP_GATTC_WRITE_LONG_RP); + if (!rc) { + return BTP_STATUS_SUCCESS; + } + +fail: + SYS_LOG_ERR("Failed to send Write Long request, rc=%d", rc); + os_mbuf_free_chain(om); + return BTP_STATUS_FAILED; +} + +static int +reliable_write_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + uint8_t num_attrs, + void *arg) +{ + struct btp_gattc_write_rp *rp; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_RELIABLE_WRITE_RP, + buf->om_data, buf->om_len); +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +reliable_write(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_reliable_write_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + struct ble_gatt_attr attr; + struct os_mbuf *om = NULL; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_SUCCESS; + } + + om = ble_hs_mbuf_from_flat(cp->data, le16toh(cp->data_length)); + /* This is required, because Nimble checks if + * the data is longer than offset + */ + if (os_mbuf_extend(om, le16toh(cp->offset) + 1) == NULL) { + return BTP_STATUS_SUCCESS; + } + + attr.handle = le16toh(cp->handle); + attr.offset = le16toh(cp->offset); + attr.om = om; + + if (ble_gattc_write_reliable(conn.conn_handle, &attr, 1, + reliable_write_cb, NULL)) { + goto fail; + } + + return BTP_STATUS_SUCCESS; + +fail: + os_mbuf_free_chain(om); + + return BTP_STATUS_FAILED; +} + +static int +subscribe_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + void *arg) +{ + struct btp_subscribe_rp *rp; + uint8_t err = (uint8_t) error->status; + uint8_t opcode = (uint8_t) (int) arg; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); +free: + os_mbuf_free_chain(buf); + return rc; +} + +static int +enable_subscription(uint16_t conn_handle, uint16_t ccc_handle, + uint16_t value) +{ + uint32_t opcode; + + SYS_LOG_DBG(""); + + opcode = (uint32_t) (value == 0x0001 ? BTP_GATTC_CFG_NOTIFY_RP + : BTP_GATTC_CFG_INDICATE_RP); + + if (ble_gattc_write_flat(conn_handle, + ccc_handle, + &value, + sizeof(value), + subscribe_cb, + (void *) opcode)) { + return -EINVAL; + } + + subscribe_params.ccc_handle = value; + + return 0; +} + +static int +disable_subscription(uint16_t conn_handle, uint16_t ccc_handle) +{ + uint16_t value = 0x00; + uint32_t opcode; + + SYS_LOG_DBG(""); + + opcode = (uint32_t) (value == 0x0001 ? BTP_GATTC_CFG_NOTIFY_RP + : BTP_GATTC_CFG_INDICATE_RP); + + /* Fail if CCC handle doesn't match */ + if (ccc_handle != subscribe_params.ccc_handle) { + SYS_LOG_ERR("CCC handle doesn't match"); + return -EINVAL; + } + + if (ble_gattc_write_flat(conn_handle, + ccc_handle, + &value, + sizeof(value), + subscribe_cb, + (void *) opcode)) { + return -EINVAL; + } + + subscribe_params.ccc_handle = 0; + return 0; +} + +static uint8_t +config_subscription_notif(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_cfg_notify_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t ccc_handle = le16toh(cp->ccc_handle); + uint8_t status; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (cp->enable) { + if (enable_subscription(conn.conn_handle, + ccc_handle, 0x0001) == 0) { + return BTP_STATUS_SUCCESS; + } + + status = BTP_STATUS_FAILED; + } else { + if (disable_subscription(conn.conn_handle, ccc_handle) < 0) { + status = BTP_STATUS_FAILED; + } else { + status = BTP_STATUS_SUCCESS; + } + } + + return status; +} + +static uint8_t +config_subscription_ind(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_cfg_notify_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t ccc_handle = le16toh(cp->ccc_handle); + uint8_t status; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (cp->enable) { + if (enable_subscription(conn.conn_handle, + ccc_handle, 0x0002) == 0) { + return BTP_STATUS_SUCCESS; + } + + status = BTP_STATUS_FAILED; + } else { + if (disable_subscription(conn.conn_handle, ccc_handle) < 0) { + status = BTP_STATUS_FAILED; + } else { + status = BTP_STATUS_SUCCESS; + } + } + + return status; +} + +int +tester_gattc_notify_rx_ev(uint16_t conn_handle, uint16_t attr_handle, + uint8_t indication, struct os_mbuf *om) +{ + struct btp_gattc_notification_ev *ev; + struct ble_gap_conn_desc conn; + struct os_mbuf *buf = os_msys_get(0, 0); + + SYS_LOG_DBG(""); + + if (!subscribe_params.ccc_handle) { + goto fail; + } + + if (ble_gap_conn_find(conn_handle, &conn)) { + goto fail; + } + + ev = os_mbuf_extend(buf, sizeof(*ev)); + if (!ev) { + return 0; + } + + memcpy(&ev->address, &conn.peer_ota_addr, sizeof(ev->address)); + ev->type = (uint8_t) (indication ? 0x02 : 0x01); + ev->handle = htole16(attr_handle); + ev->data_length = htole16(os_mbuf_len(om)); + os_mbuf_appendfrom(buf, om, 0, os_mbuf_len(om)); + + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_EV_NOTIFICATION_RXED, + buf->om_data, buf->om_len); + +fail: + os_mbuf_free_chain(buf); + return 0; +} + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gattc_read_supported_commands_rp *rp = rsp; + + SYS_LOG_DBG(""); + + /* octet 0 */ + tester_set_bit(rp->data, BTP_GATTC_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_GATTC_EXCHANGE_MTU); + tester_set_bit(rp->data, BTP_GATTC_DISC_ALL_PRIM_SVCS); + tester_set_bit(rp->data, BTP_GATTC_DISC_PRIM_UUID); + tester_set_bit(rp->data, BTP_GATTC_FIND_INCLUDED); + tester_set_bit(rp->data, BTP_GATTC_DISC_ALL_CHRC); + tester_set_bit(rp->data, BTP_GATTC_DISC_CHRC_UUID); + /* octet 1 */ + tester_set_bit(rp->data, BTP_GATTC_DISC_ALL_DESC); + tester_set_bit(rp->data, BTP_GATTC_READ); + tester_set_bit(rp->data, BTP_GATTC_READ_UUID); + tester_set_bit(rp->data, BTP_GATTC_READ_LONG); + tester_set_bit(rp->data, BTP_GATTC_READ_MULTIPLE); + tester_set_bit(rp->data, BTP_GATTC_WRITE_WITHOUT_RSP); +#if 0 + tester_set_bit(rp->data, BTP_GATTC_SIGNED_WRITE_WITHOUT_RSP); +#endif + tester_set_bit(rp->data, BTP_GATTC_WRITE); + /* octet 2 */ + tester_set_bit(rp->data, BTP_GATTC_WRITE_LONG); + tester_set_bit(rp->data, BTP_GATTC_RELIABLE_WRITE); + tester_set_bit(rp->data, BTP_GATTC_CFG_NOTIFY); + tester_set_bit(rp->data, BTP_GATTC_CFG_INDICATE); + + *rsp_len = sizeof(*rp) + 3; + + return BTP_STATUS_SUCCESS; +} + + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_GATTC_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_GATTC_EXCHANGE_MTU, + .expect_len = sizeof(struct btp_gattc_exchange_mtu_cmd), + .func = exchange_mtu, + }, + { + .opcode = BTP_GATTC_DISC_ALL_PRIM_SVCS, + .expect_len = sizeof(struct btp_gattc_disc_all_prim_svcs_cmd), + .func = disc_all_prim_svcs, + }, + { + .opcode = BTP_GATTC_DISC_PRIM_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = disc_prim_uuid, + }, + { + .opcode = BTP_GATTC_FIND_INCLUDED, + .expect_len = sizeof(struct btp_gattc_find_included_cmd), + .func = find_included, + }, + { + .opcode = BTP_GATTC_DISC_ALL_CHRC, + .expect_len = sizeof(struct btp_gattc_disc_all_chrc_cmd), + .func = disc_all_chrc, + }, + { + .opcode = BTP_GATTC_DISC_CHRC_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = disc_chrc_uuid, + }, + { + .opcode = BTP_GATTC_DISC_ALL_DESC, + .expect_len = sizeof(struct btp_gattc_disc_all_desc_cmd), + .func = disc_all_desc, + }, + { + .opcode = BTP_GATTC_READ, + .expect_len = sizeof(struct btp_gattc_read_cmd), + .func = read, + }, + { + .opcode = BTP_GATTC_READ_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = read_uuid, + }, + { + .opcode = BTP_GATTC_READ_LONG, + .expect_len = sizeof(struct btp_gattc_read_long_cmd), + .func = read_long, + }, + { + .opcode = BTP_GATTC_READ_MULTIPLE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = read_multiple, + }, + { + .opcode = BTP_GATTC_WRITE_WITHOUT_RSP, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_without_rsp, + }, +#if 0 + { + .opcode = BTP_GATTC_SIGNED_WRITE_WITHOUT_RSP, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_signed_without_rsp, + }, +#endif + { + .opcode = BTP_GATTC_WRITE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write, + }, + { + .opcode = BTP_GATTC_WRITE_LONG, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_long, + }, + { + .opcode = BTP_GATTC_RELIABLE_WRITE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = reliable_write, + }, + { + .opcode = BTP_GATTC_CFG_NOTIFY, + .expect_len = sizeof(struct btp_gattc_cfg_notify_cmd), + .func = config_subscription_notif, + }, + { + .opcode = BTP_GATTC_CFG_INDICATE, + .expect_len = sizeof(struct btp_gattc_cfg_notify_cmd), + .func = config_subscription_ind, + }, +}; + +uint8_t +tester_init_gatt_cl(void) +{ + tester_register_command_handlers(BTP_SERVICE_ID_GATTC, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_gatt_cl(void) +{ + return BTP_STATUS_SUCCESS; +} diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp_l2cap.c b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_l2cap.c new file mode 100644 index 00000000..916e714e --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_l2cap.c @@ -0,0 +1,760 @@ +/* + * 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. + */ + +/* l2cap.c - Bluetooth L2CAP Tester */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) + +#include "console/console.h" +#include "host/ble_gap.h" +#include "host/ble_l2cap.h" + +#include "../../../nimble/host/src/ble_l2cap_priv.h" + +#include "btp/btp.h" + +#define CONTROLLER_INDEX 0 +#define CHANNELS MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) +#define TESTER_COC_MTU MYNEWT_VAL(BTTESTER_L2CAP_COC_MTU) +#define TESTER_COC_BUF_COUNT (3 * MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)) + +static os_membuf_t tester_sdu_coc_mem[ + OS_MEMPOOL_SIZE(TESTER_COC_BUF_COUNT, TESTER_COC_MTU) +]; + +struct os_mbuf_pool sdu_os_mbuf_pool; +static struct os_mempool sdu_coc_mbuf_mempool; +static bool hold_credit = false; + +static struct channel { + uint8_t chan_id; /* Internal number that identifies L2CAP channel. */ + uint8_t state; + struct ble_l2cap_chan *chan; +} channels[CHANNELS]; + +static uint8_t + recv_cb_buf[TESTER_COC_MTU + sizeof(struct btp_l2cap_data_received_ev)]; + +static struct channel * +get_free_channel(void) +{ + uint8_t i; + struct channel *chan; + + for (i = 0; i < CHANNELS; i++) { + if (channels[i].state) { + continue; + } + + chan = &channels[i]; + chan->chan_id = i; + return chan; + } + + return NULL; +} + +struct channel * +find_channel(struct ble_l2cap_chan *chan) +{ + int i; + + for (i = 0; i < CHANNELS; ++i) { + if (channels[i].chan == chan) { + return &channels[i]; + } + } + + return NULL; +} + +struct channel * +get_channel(uint8_t chan_id) +{ + if (chan_id >= CHANNELS) { + return NULL; + } + + return &channels[chan_id]; +} + +static void +tester_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu) +{ + SYS_LOG_DBG("LE CoC SDU received, chan: 0x%08lx, data len %d", + (uint32_t) chan, OS_MBUF_PKTLEN(sdu)); + + os_mbuf_free_chain(sdu); + if (!hold_credit) { + sdu = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + assert(sdu != NULL); + + ble_l2cap_recv_ready(chan, sdu); + } +} + +static void +recv_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan, + struct os_mbuf *buf, void *arg) +{ + struct btp_l2cap_data_received_ev *ev = (void *) recv_cb_buf; + struct channel *channel = find_channel(chan); + assert(channel != NULL); + + ev->chan_id = channel->chan_id; + ev->data_length = OS_MBUF_PKTLEN(buf); + + if (ev->data_length > TESTER_COC_MTU) { + SYS_LOG_ERR("Too large sdu received, truncating data"); + ev->data_length = TESTER_COC_MTU; + } + os_mbuf_copydata(buf, 0, ev->data_length, ev->data); + + tester_event(BTP_SERVICE_ID_L2CAP, BTP_L2CAP_EV_DATA_RECEIVED, + recv_cb_buf, sizeof(*ev) + ev->data_length); + + tester_l2cap_coc_recv(chan, buf); +} + +static void +reconfigured_ev(uint16_t conn_handle, struct ble_l2cap_chan *chan, + struct ble_l2cap_chan_info *chan_info, + int status) +{ + struct btp_l2cap_reconfigured_ev ev; + struct channel *channel; + + if (status != 0) { + return; + } + + channel = find_channel(chan); + assert(channel != NULL); + + ev.chan_id = channel->chan_id; + ev.peer_mtu = chan_info->peer_coc_mtu; + ev.peer_mps = chan_info->peer_l2cap_mtu; + ev.our_mtu = chan_info->our_coc_mtu; + ev.our_mps = chan_info->our_l2cap_mtu; + + tester_event(BTP_SERVICE_ID_L2CAP, BTP_L2CAP_EV_RECONFIGURED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +connected_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan, + struct ble_l2cap_chan_info *chan_info, void *arg) +{ + struct btp_l2cap_connected_ev ev; + struct ble_gap_conn_desc desc; + struct channel *channel = find_channel(chan); + + if (channel == NULL) { + channel = get_free_channel(); + } + + ev.chan_id = channel->chan_id; + ev.psm = chan_info->psm; + ev.peer_mtu = chan_info->peer_coc_mtu; + ev.peer_mps = chan_info->peer_l2cap_mtu; + ev.our_mtu = chan_info->our_coc_mtu; + ev.our_mps = chan_info->our_l2cap_mtu; + channel->state = 1; + channel->chan = chan; + + if (!ble_gap_conn_find(conn_handle, &desc)) { + memcpy(&ev.address, &desc.peer_ota_addr, sizeof(ev.address)); + } + + tester_event(BTP_SERVICE_ID_L2CAP, BTP_L2CAP_EV_CONNECTED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +disconnected_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan, + struct ble_l2cap_chan_info *chan_info, void *arg) +{ + struct btp_l2cap_disconnected_ev ev; + struct ble_gap_conn_desc desc; + struct channel *channel; + + memset(&ev, 0, sizeof(struct btp_l2cap_disconnected_ev)); + + channel = find_channel(chan); + assert(channel != NULL); + + channel->state = 0; + channel->chan = chan; + ev.chan_id = channel->chan_id; + ev.psm = chan_info->psm; + + if (!ble_gap_conn_find(conn_handle, &desc)) { + memcpy(&ev.address, &desc.peer_ota_addr, sizeof(ev.address)); + } + + tester_event(BTP_SERVICE_ID_L2CAP, BTP_L2CAP_EV_DISCONNECTED, + (uint8_t *) &ev, sizeof(ev)); +} + +static int +accept_cb(uint16_t conn_handle, uint16_t peer_mtu, + struct ble_l2cap_chan *chan) +{ + struct os_mbuf *sdu_rx; + + SYS_LOG_DBG("LE CoC accepting, chan: 0x%08lx, peer_mtu %d", + (uint32_t) chan, peer_mtu); + + sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + if (!sdu_rx) { + return BLE_HS_ENOMEM; + } + + ble_l2cap_recv_ready(chan, sdu_rx); + + return 0; +} + +static int +tester_l2cap_event(struct ble_l2cap_event *event, void *arg) +{ + struct ble_l2cap_chan_info chan_info; + struct ble_gap_conn_desc conn; + + switch (event->type) { + case BLE_L2CAP_EVENT_COC_CONNECTED: + if (ble_l2cap_get_chan_info(event->connect.chan, &chan_info)) { + assert(0); + } + + if (event->connect.status) { + console_printf("LE COC error: %d\n", event->connect.status); + return 0; + } + + console_printf("LE COC connected, conn: %d, chan: 0x%08lx, " + "psm: 0x%02x, scid: 0x%04x, dcid: 0x%04x, " + "our_mps: %d, our_mtu: %d, peer_mps: %d, " + "peer_mtu: %d\n", event->connect.conn_handle, + (uint32_t) event->connect.chan, chan_info.psm, + chan_info.scid, chan_info.dcid, + chan_info.our_l2cap_mtu, chan_info.our_coc_mtu, + chan_info.peer_l2cap_mtu, chan_info.peer_coc_mtu); + + connected_cb(event->connect.conn_handle, + event->connect.chan, &chan_info, arg); + + return 0; + case BLE_L2CAP_EVENT_COC_DISCONNECTED: + if (ble_l2cap_get_chan_info(event->disconnect.chan, + &chan_info)) { + assert(0); + } + console_printf("LE CoC disconnected, chan: 0x%08lx\n", + (uint32_t) event->disconnect.chan); + + disconnected_cb(event->disconnect.conn_handle, + event->disconnect.chan, &chan_info, arg); + return 0; + case BLE_L2CAP_EVENT_COC_ACCEPT: + ble_l2cap_get_chan_info(event->accept.chan, + &chan_info); + if (chan_info.psm == 0x00F2) { + /* TSPX_psm_authentication_required */ + ble_gap_conn_find(event->accept.conn_handle, &conn); + if (!conn.sec_state.authenticated) { + return BLE_HS_EAUTHEN; + } + } else if (chan_info.psm == 0x00F3) { + /* TSPX_psm_authorization_required */ + ble_gap_conn_find(event->accept.conn_handle, &conn); + if (!conn.sec_state.encrypted) { + return BLE_HS_EAUTHOR; + } + return BLE_HS_EAUTHOR; + } else if (chan_info.psm == 0x00F4) { + /* TSPX_psm_encryption_key_size_required */ + ble_gap_conn_find(event->accept.conn_handle, &conn); + if (conn.sec_state.key_size < 16) { + return BLE_HS_EENCRYPT_KEY_SZ; + } + } else if (chan_info.psm == 0x00F5) { + /* TSPX_psm_encryption_required */ + ble_gap_conn_find(event->accept.conn_handle, &conn); + if (conn.sec_state.key_size == 0) { + return BLE_HS_EENCRYPT; + } + } + + console_printf( + "LE CoC accept, chan: 0x%08lx, handle: %u, sdu_size: %u\n", + (uint32_t) event->accept.chan, + event->accept.conn_handle, + event->accept.peer_sdu_size); + + return accept_cb(event->accept.conn_handle, + event->accept.peer_sdu_size, + event->accept.chan); + + case BLE_L2CAP_EVENT_COC_DATA_RECEIVED: + console_printf( + "LE CoC data received, chan: 0x%08lx, handle: %u, sdu_len: %u\n", + (uint32_t) event->receive.chan, + event->receive.conn_handle, + OS_MBUF_PKTLEN(event->receive.sdu_rx)); + + recv_cb(event->receive.conn_handle, event->receive.chan, + event->receive.sdu_rx, arg); + return 0; + case BLE_L2CAP_EVENT_COC_TX_UNSTALLED: + console_printf( + "LE CoC tx unstalled, chan: 0x%08lx, handle: %u, status: %d\n", + (uint32_t) event->tx_unstalled.chan, + event->tx_unstalled.conn_handle, + event->tx_unstalled.status); + return 0; + case BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED: + if (ble_l2cap_get_chan_info(event->reconfigured.chan, + &chan_info)) { + assert(0); + } + console_printf("LE CoC reconfigure completed status 0x%02x, " + "chan: 0x%08lx\n", event->reconfigured.status, + (uint32_t) event->reconfigured.chan); + + if (event->reconfigured.status == 0) { + console_printf("\t our_mps: %d our_mtu %d\n", + chan_info.our_l2cap_mtu, chan_info.our_coc_mtu); + } + + reconfigured_ev(event->reconfigured.conn_handle, + event->reconfigured.chan, + &chan_info, + event->reconfigured.status); + return 0; + case BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED: + if (ble_l2cap_get_chan_info(event->reconfigured.chan, + &chan_info)) { + assert(0); + } + console_printf("LE CoC peer reconfigured status 0x%02x, " + "chan: 0x%08lx\n", event->reconfigured.status, + (uint32_t) event->reconfigured.chan); + + if (event->reconfigured.status == 0) { + console_printf("\t peer_mps: %d peer_mtu %d\n", + chan_info.peer_l2cap_mtu, + chan_info.peer_coc_mtu); + } + + reconfigured_ev(event->reconfigured.conn_handle, + event->reconfigured.chan, + &chan_info, + event->reconfigured.status); + return 0; + default: + return 0; + } +} + +static uint8_t +connect(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_connect_cmd *cp = cmd; + struct btp_l2cap_connect_rp *rp = rsp; + struct ble_gap_conn_desc desc; + struct channel *chan; + struct os_mbuf *sdu_rx[cp->num]; + ble_addr_t *addr = (void *)&cp->address; + uint16_t mtu = le16toh(cp->mtu); + uint16_t psm = le16toh(cp->psm); + int rc; + int i, j; + uint8_t status = BTP_STATUS_SUCCESS; + bool ecfc = cp->options & BTP_L2CAP_CONNECT_OPT_ECFC; + hold_credit = cp->options & BTP_L2CAP_CONNECT_OPT_HOLD_CREDIT; + + SYS_LOG_DBG("connect: type: %d addr: %s", + addr->type, + string_from_bytes(addr->val, 6)); + + rc = ble_gap_conn_find_by_addr(addr, &desc); + if (cp->num == 0 || cp->num > CHANNELS || + mtu > TESTER_COC_MTU || mtu == 0) { + return BTP_STATUS_FAILED; + } + + if (rc) { + SYS_LOG_ERR("GAP conn find failed"); + return BTP_STATUS_FAILED; + } + + for (i = 0; i < cp->num; i++) { + chan = get_free_channel(); + if (!chan) { + SYS_LOG_ERR("No free channels"); + status = BTP_STATUS_FAILED; + goto done; + } + /* temporarily mark channel as used to select next one */ + chan->state = 1; + + rp->chan_ids[i] = chan->chan_id; + + sdu_rx[i] = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + if (sdu_rx[i] == NULL) { + SYS_LOG_ERR("Failed to alloc buf"); + status = BTP_STATUS_FAILED; + goto done; + } + } + + if (cp->num == 1 && !ecfc) { + rc = ble_l2cap_connect(desc.conn_handle, psm, + mtu, sdu_rx[0], + tester_l2cap_event, NULL); + } else if (ecfc) { + rc = ble_l2cap_enhanced_connect(desc.conn_handle, + psm, mtu, + cp->num, sdu_rx, + tester_l2cap_event, NULL); + } else { + SYS_LOG_ERR("Invalid 'num' parameter value"); + status = BTP_STATUS_FAILED; + goto done; + } + + if (rc) { + SYS_LOG_ERR("L2CAP connect failed\n"); + status = BTP_STATUS_FAILED; + goto done; + } + + rp->num = cp->num; + + *rsp_len = sizeof(*rp) + (rp->num * sizeof(rp->chan_ids[0])); +done: + /* mark selected channels as unused again */ + for (i = 0; i < cp->num; i++) { + for (j = 0; j < CHANNELS; j++) { + if (rp->chan_ids[i] == channels[j].chan_id) { + channels[j].state = 0; + } + } + } + + return status; +} + +static uint8_t +disconnect(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_disconnect_cmd *cp = cmd; + struct channel *chan; + int err; + + SYS_LOG_DBG(""); + + if (cp->chan_id >= CHANNELS) { + return BTP_STATUS_FAILED; + } + + chan = get_channel(cp->chan_id); + assert(chan != NULL); + + err = ble_l2cap_disconnect(chan->chan); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +send_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_send_data_cmd *cp = cmd; + struct channel *chan; + struct os_mbuf *sdu_tx = NULL; + int rc; + uint16_t data_len; + + SYS_LOG_DBG("cmd->chan_id=%d", cp->chan_id); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_len)) { + return BTP_STATUS_FAILED; + } + + if (cp->chan_id >= CHANNELS) { + return BTP_STATUS_FAILED; + } + + chan = get_channel(cp->chan_id); + data_len = le16toh(cp->data_len); + + if (!chan) { + SYS_LOG_ERR("Invalid channel\n"); + return BTP_STATUS_FAILED; + } + + /* FIXME: For now, fail if data length exceeds buffer length */ + if (data_len > TESTER_COC_MTU) { + SYS_LOG_ERR("Data length exceeds buffer length"); + return BTP_STATUS_FAILED; + } + + sdu_tx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + if (sdu_tx == NULL) { + SYS_LOG_ERR("No memory in the test sdu pool\n"); + rc = BLE_HS_ENOMEM; + goto fail; + } + + os_mbuf_append(sdu_tx, cp->data, data_len); + + /* ble_l2cap_send takes ownership of the sdu */ + rc = ble_l2cap_send(chan->chan, sdu_tx); + if (rc == 0 || rc == BLE_HS_ESTALLED) { + return BTP_STATUS_SUCCESS; + } + +fail: + SYS_LOG_ERR("Unable to send data: %d", rc); + os_mbuf_free_chain(sdu_tx); + + return BTP_STATUS_FAILED; +} + +static uint8_t +listen(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_listen_cmd *cp = cmd; + uint16_t mtu = htole16(cp->mtu); + uint16_t psm = htole16(cp->psm); + int rc; + + SYS_LOG_DBG(""); + + if (psm == 0) { + return BTP_STATUS_FAILED; + } + + if (mtu == 0 || mtu > TESTER_COC_MTU) { + mtu = TESTER_COC_MTU; + } + + /* We do not support BR/EDR transport */ + if (cp->transport == 0) { + return BTP_STATUS_FAILED; + } + + rc = ble_l2cap_create_server(psm, mtu, tester_l2cap_event, NULL); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +credits(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_credits_cmd *cp = cmd; + struct channel *chan; + struct os_mbuf *sdu; + int rc; + + if (cp->chan_id >= CHANNELS) { + return BTP_STATUS_FAILED; + } + + chan = get_channel(cp->chan_id); + if (chan == NULL) { + return BTP_STATUS_FAILED; + } + + sdu = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + if (sdu == NULL) { + os_mbuf_free_chain(sdu); + return BTP_STATUS_FAILED; + } + + rc = ble_l2cap_recv_ready(chan->chan, sdu); + if (rc != 0) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +reconfigure(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_reconfigure_cmd *cp = cmd; + uint16_t mtu = le16toh(cp->mtu); + struct ble_gap_conn_desc desc; + ble_addr_t *addr = (ble_addr_t *)&cp->address; + struct ble_l2cap_chan *chans[cp->num]; + struct channel *channel; + int rc; + int i; + + SYS_LOG_DBG(""); + + if (mtu == 0 || mtu > TESTER_COC_MTU) { + mtu = TESTER_COC_MTU; + } + + rc = ble_gap_conn_find_by_addr(addr, &desc); + if (rc) { + SYS_LOG_ERR("GAP conn find failed"); + return BTP_STATUS_FAILED; + } + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + cp->num) { + return BTP_STATUS_FAILED; + } + + if (cp->num > CHANNELS) { + return BTP_STATUS_FAILED; + } + + mtu = le16toh(cp->mtu); + if (mtu > TESTER_COC_MTU) { + return BTP_STATUS_FAILED; + } + + for (i = 0; i < cp->num; ++i) { + channel = get_channel(cp->idxs[i]); + if (channel == NULL) { + return BTP_STATUS_FAILED; + } + chans[i] = channel->chan; + } + + rc = ble_l2cap_reconfig(chans, cp->num, mtu); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_l2cap_read_supported_commands_rp *rp = rsp; + + /* octet 0 */ + tester_set_bit(rp->data, BTP_L2CAP_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_L2CAP_CONNECT); + tester_set_bit(rp->data, BTP_L2CAP_DISCONNECT); + tester_set_bit(rp->data, BTP_L2CAP_SEND_DATA); + tester_set_bit(rp->data, BTP_L2CAP_LISTEN); + /* octet 1 */ + tester_set_bit(rp->data, BTP_L2CAP_CREDITS); + *rsp_len = sizeof(*rp) + 2; + + return BTP_STATUS_SUCCESS; +} + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_L2CAP_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_L2CAP_CONNECT, + .expect_len = sizeof(struct btp_l2cap_connect_cmd), + .func = connect, + }, + { + .opcode = BTP_L2CAP_DISCONNECT, + .expect_len = sizeof(struct btp_l2cap_disconnect_cmd), + .func = disconnect, + }, + { + .opcode = BTP_L2CAP_SEND_DATA, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = send_data, + }, + { + .opcode = BTP_L2CAP_LISTEN, + .expect_len = sizeof(struct btp_l2cap_listen_cmd), + .func = listen, + }, + { + .opcode = BTP_L2CAP_RECONFIGURE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = reconfigure, + }, + { + .opcode = BTP_L2CAP_CREDITS, + .expect_len = sizeof(struct btp_l2cap_credits_cmd), + .func = credits, + }, +}; + +uint8_t +tester_init_l2cap(void) +{ + int rc; + + /* For testing we want to support all the available channels */ + rc = os_mempool_init(&sdu_coc_mbuf_mempool, TESTER_COC_BUF_COUNT, + TESTER_COC_MTU, tester_sdu_coc_mem, + "tester_coc_sdu_pool"); + assert(rc == 0); + + rc = os_mbuf_pool_init(&sdu_os_mbuf_pool, &sdu_coc_mbuf_mempool, + TESTER_COC_MTU, TESTER_COC_BUF_COUNT); + assert(rc == 0); + + tester_register_command_handlers(BTP_SERVICE_ID_L2CAP, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_l2cap(void) +{ + return BTP_STATUS_SUCCESS; +} + +#endif diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/btp_mesh.c b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_mesh.c new file mode 100644 index 00000000..96eaaf81 --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/btp_mesh.c @@ -0,0 +1,1098 @@ +/* + * 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. + */ + +/* mesh.c - Bluetooth Mesh Tester */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_MESH) + +#include + +#include "mesh/mesh.h" +#include "mesh/glue.h" +#include "mesh/testing.h" +#include "console/console.h" + +#include "btp/btp.h" + +extern uint8_t own_addr_type; + +#define CONTROLLER_INDEX 0 +#define CID_LOCAL 0x0002 + +/* Health server data */ +#define CUR_FAULTS_MAX 4 +#define HEALTH_TEST_ID 0x00 + +static uint8_t cur_faults[CUR_FAULTS_MAX]; +static uint8_t reg_faults[CUR_FAULTS_MAX * 2]; + +/* Provision node data */ +static uint8_t net_key[16]; +static uint16_t net_key_idx; +static uint8_t flags; +static uint32_t iv_index; +static uint16_t addr; +static uint8_t dev_key[16]; +static uint8_t input_size; + +/* Configured provisioning data */ +static uint8_t dev_uuid[16]; +static uint8_t static_auth[16]; + +/* Vendor Model data */ +#define VND_MODEL_ID_1 0x1234 + +/* Model send data */ +#define MODEL_BOUNDS_MAX 2 + +static struct model_data { + struct bt_mesh_model *model; + uint16_t addr; + uint16_t appkey_idx; +} model_bound[MODEL_BOUNDS_MAX]; + +static struct { + uint16_t local; + uint16_t dst; + uint16_t net_idx; +} net = { + .local = BT_MESH_ADDR_UNASSIGNED, + .dst = BT_MESH_ADDR_UNASSIGNED, +}; + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_mesh_read_supported_commands_rp *rp = rsp; + + /* octet 0 */ + tester_set_bit(rp->data, BTP_MESH_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_MESH_CONFIG_PROVISIONING); + tester_set_bit(rp->data, BTP_MESH_PROVISION_NODE); + tester_set_bit(rp->data, BTP_MESH_INIT); + tester_set_bit(rp->data, BTP_MESH_RESET); + tester_set_bit(rp->data, BTP_MESH_INPUT_NUMBER); + tester_set_bit(rp->data, BTP_MESH_INPUT_STRING); + /* octet 1 */ + tester_set_bit(rp->data, BTP_MESH_IVU_TEST_MODE); + tester_set_bit(rp->data, BTP_MESH_IVU_TOGGLE_STATE); + tester_set_bit(rp->data, BTP_MESH_NET_SEND); + tester_set_bit(rp->data, BTP_MESH_HEALTH_GENERATE_FAULTS); + tester_set_bit(rp->data, BTP_MESH_HEALTH_CLEAR_FAULTS); + tester_set_bit(rp->data, BTP_MESH_LPN); + tester_set_bit(rp->data, BTP_MESH_LPN_POLL); + tester_set_bit(rp->data, BTP_MESH_MODEL_SEND); + /* octet 2 */ +#if MYNEWT_VAL(BLE_MESH_TESTING) + tester_set_bit(rp->data, BTP_MESH_LPN_SUBSCRIBE); + tester_set_bit(rp->data, BTP_MESH_LPN_UNSUBSCRIBE); + tester_set_bit(rp->data, BTP_MESH_RPL_CLEAR); +#endif /* CONFIG_BT_TESTING */ + tester_set_bit(rp->data, BTP_MESH_PROXY_IDENTITY); + + *rsp_len = sizeof(*rp) + 3; + + return BTP_STATUS_SUCCESS; +} + +static void +get_faults(uint8_t *faults, uint8_t faults_size, uint8_t *dst, uint8_t *count) +{ + uint8_t i, limit = *count; + + for (i = 0, *count = 0; i < faults_size && *count < limit; i++) { + if (faults[i]) { + *dst++ = faults[i]; + (*count)++; + } + } +} + +static int +fault_get_cur(struct bt_mesh_model *model, uint8_t *test_id, + uint16_t *company_id, uint8_t *faults, uint8_t *fault_count) +{ + SYS_LOG_DBG(""); + + *test_id = HEALTH_TEST_ID; + *company_id = CID_LOCAL; + + get_faults(cur_faults, sizeof(cur_faults), faults, fault_count); + + return 0; +} + +static int +fault_get_reg(struct bt_mesh_model *model, uint16_t company_id, + uint8_t *test_id, uint8_t *faults, uint8_t *fault_count) +{ + SYS_LOG_DBG("company_id 0x%04x", company_id); + + if (company_id != CID_LOCAL) { + return -EINVAL; + } + + *test_id = HEALTH_TEST_ID; + + get_faults(reg_faults, sizeof(reg_faults), faults, fault_count); + + return 0; +} + +static int +fault_clear(struct bt_mesh_model *model, uint16_t company_id) +{ + SYS_LOG_DBG("company_id 0x%04x", company_id); + + if (company_id != CID_LOCAL) { + return -EINVAL; + } + + memset(reg_faults, 0, sizeof(reg_faults)); + + return 0; +} + +static int +fault_test(struct bt_mesh_model *model, uint8_t test_id, + uint16_t company_id) +{ + SYS_LOG_DBG("test_id 0x%02x company_id 0x%04x", test_id, company_id); + + if (company_id != CID_LOCAL || test_id != HEALTH_TEST_ID) { + return -EINVAL; + } + + return 0; +} + +static const struct bt_mesh_health_srv_cb health_srv_cb = { + .fault_get_cur = fault_get_cur, + .fault_get_reg = fault_get_reg, + .fault_clear = fault_clear, + .fault_test = fault_test, +}; + +static struct bt_mesh_health_srv health_srv = { + .cb = &health_srv_cb, +}; + +static struct bt_mesh_model_pub health_pub; + +static void +health_pub_init(void) +{ + health_pub.msg = BT_MESH_HEALTH_FAULT_MSG(CUR_FAULTS_MAX); +} + +static struct bt_mesh_cfg_cli cfg_cli = { +}; + +void +show_faults(uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count) +{ + size_t i; + + if (!fault_count) { + SYS_LOG_DBG("Health Test ID 0x%02x Company ID 0x%04x: " + "no faults", test_id, cid); + return; + } + + SYS_LOG_DBG("Health Test ID 0x%02x Company ID 0x%04x Fault Count %zu: ", + test_id, cid, fault_count); + + for (i = 0; i < fault_count; i++) { + SYS_LOG_DBG("0x%02x", faults[i]); + } +} + +static void +health_current_status(struct bt_mesh_health_cli *cli, uint16_t addr, + uint8_t test_id, uint16_t cid, uint8_t *faults, + size_t fault_count) +{ + SYS_LOG_DBG("Health Current Status from 0x%04x", addr); + show_faults(test_id, cid, faults, fault_count); +} + +static struct bt_mesh_health_cli health_cli = { + .current_status = health_current_status, +}; + +static struct bt_mesh_model root_models[] = { + BT_MESH_MODEL_CFG_SRV, + BT_MESH_MODEL_CFG_CLI(&cfg_cli), + BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), + BT_MESH_MODEL_HEALTH_CLI(&health_cli), +}; + +static struct bt_mesh_model vnd_models[] = { + BT_MESH_MODEL_VND(CID_LOCAL, VND_MODEL_ID_1, BT_MESH_MODEL_NO_OPS, NULL, + NULL), +}; + +static struct bt_mesh_elem elements[] = { + BT_MESH_ELEM(0, root_models, vnd_models), +}; + +static void +link_open(bt_mesh_prov_bearer_t bearer) +{ + struct btp_mesh_prov_link_open_ev ev; + + SYS_LOG_DBG("bearer 0x%02x", bearer); + + switch (bearer) { + case BT_MESH_PROV_ADV: + ev.bearer = BTP_MESH_PROV_BEARER_PB_ADV; + break; + case BT_MESH_PROV_GATT: + ev.bearer = BTP_MESH_PROV_BEARER_PB_GATT; + break; + default: + SYS_LOG_ERR("Invalid bearer"); + + return; + } + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_PROV_LINK_OPEN, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +link_close(bt_mesh_prov_bearer_t bearer) +{ + struct btp_mesh_prov_link_closed_ev ev; + + SYS_LOG_DBG("bearer 0x%02x", bearer); + + switch (bearer) { + case BT_MESH_PROV_ADV: + ev.bearer = BTP_MESH_PROV_BEARER_PB_ADV; + break; + case BT_MESH_PROV_GATT: + ev.bearer = BTP_MESH_PROV_BEARER_PB_GATT; + break; + default: + SYS_LOG_ERR("Invalid bearer"); + + return; + } + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_PROV_LINK_CLOSED, + (uint8_t *) &ev, sizeof(ev)); +} + +static int +output_number(bt_mesh_output_action_t action, uint32_t number) +{ + struct btp_mesh_out_number_action_ev ev; + + SYS_LOG_DBG("action 0x%04x number 0x%08lx", action, number); + + ev.action = htole16(action); + ev.number = htole32(number); + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_OUT_NUMBER_ACTION, + (uint8_t *) &ev, sizeof(ev)); + + return 0; +} + +static int +output_string(const char *str) +{ + struct btp_mesh_out_string_action_ev *ev; + struct os_mbuf *buf = NET_BUF_SIMPLE(BTP_DATA_MAX_SIZE); + + SYS_LOG_DBG("str %s", str); + + net_buf_simple_init(buf, 0); + + ev = net_buf_simple_add(buf, sizeof(*ev)); + ev->string_len = strlen(str); + + net_buf_simple_add_mem(buf, str, ev->string_len); + + tester_send_buf(BTP_SERVICE_ID_MESH, BTP_MESH_EV_OUT_STRING_ACTION, + CONTROLLER_INDEX, buf); + + os_mbuf_free_chain(buf); + return 0; +} + +static int +input(bt_mesh_input_action_t action, uint8_t size) +{ + struct btp_mesh_in_action_ev ev; + + SYS_LOG_DBG("action 0x%04x number 0x%02x", action, size); + + input_size = size; + + ev.action = htole16(action); + ev.size = size; + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_IN_ACTION, + (uint8_t *) &ev, sizeof(ev)); + + return 0; +} + +static uint8_t vnd_app_key[16]; +static uint16_t vnd_app_key_idx = 0x000f; + +static void +prov_complete(uint16_t net_idx, uint16_t addr) +{ + SYS_LOG_DBG("net_idx 0x%04x addr 0x%04x", net_idx, addr); + + net.net_idx = net_idx, + net.local = addr; + net.dst = addr; + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_PROVISIONED, + NULL, 0); +} + +static void +prov_reset(void) +{ + SYS_LOG_DBG(""); + + bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT); +} + +static const struct bt_mesh_comp comp = { + .cid = CID_LOCAL, + .elem = elements, + .elem_count = ARRAY_SIZE(elements), +}; + +static struct bt_mesh_prov prov = { + .uuid = dev_uuid, + .static_val = static_auth, + .static_val_len = sizeof(static_auth), + .output_number = output_number, + .output_string = output_string, + .input = input, + .link_open = link_open, + .link_close = link_close, + .complete = prov_complete, + .reset = prov_reset, +}; + +static uint8_t +config_prov(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_config_provisioning_cmd *cp = cmd; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp)) { + return BTP_STATUS_FAILED; + } + + memcpy(dev_uuid, cp->uuid, sizeof(dev_uuid)); + memcpy(static_auth, cp->static_auth, sizeof(static_auth)); + + prov.output_size = cp->out_size; + prov.output_actions = sys_le16_to_cpu(cp->out_actions); + prov.input_size = cp->in_size; + prov.input_actions = sys_le16_to_cpu(cp->in_actions); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +provision_node(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_provision_node_cmd *cp = cmd; + + SYS_LOG_DBG(""); + + if (cmd_len != sizeof(*cp)) { + return BTP_STATUS_FAILED; + } + + memcpy(dev_key, cp->dev_key, sizeof(dev_key)); + memcpy(net_key, cp->net_key, sizeof(net_key)); + + addr = sys_le16_to_cpu(cp->addr); + flags = cp->flags; + iv_index = le32toh(cp->iv_index); + net_key_idx = sys_le16_to_cpu(cp->net_key_idx); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +init(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + SYS_LOG_DBG(""); + + err = bt_mesh_init(own_addr_type, &prov, &comp); + if (err) { + return BTP_STATUS_FAILED; + } + + if (addr) { + err = bt_mesh_provision(net_key, net_key_idx, flags, iv_index, + addr, dev_key); + if (err) { + return BTP_STATUS_FAILED; + } + } else { + err = bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT); + if (err) { + return BTP_STATUS_FAILED; + } + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +reset(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + SYS_LOG_DBG(""); + + bt_mesh_reset(); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +input_number(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_input_number_cmd *cp = cmd; + uint32_t number; + int err; + + number = le32toh(cp->number); + + SYS_LOG_DBG("number 0x%04lx", number); + + err = bt_mesh_input_number(number); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +input_string(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_input_string_cmd *cp = cmd; + int err; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) && + cmd_len != (sizeof(*cp) + cp->string_len)) { + return BTP_STATUS_FAILED; + } + + /* for historical reasons this commands must send NULL terminated + * string + */ + if (cp->string[cp->string_len] != '\0') { + return BTP_STATUS_FAILED; + } + + if (strlen((char *)cp->string) < input_size) { + SYS_LOG_ERR("Too short input (%u chars required)", input_size); + return BTP_STATUS_FAILED; + } + err = bt_mesh_input_string((char *)cp->string); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +ivu_test_mode(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_ivu_test_mode_cmd *cp = cmd; + + SYS_LOG_DBG("enable 0x%02x", cp->enable); + + bt_mesh_iv_update_test(cp->enable ? true : false); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +ivu_toggle_state(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + bool result; + + SYS_LOG_DBG(""); + + result = bt_mesh_iv_update(); + if (!result) { + SYS_LOG_ERR("Failed to toggle the IV Update state"); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +lpn(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_lpn_set_cmd *cp = cmd; + bool enable; + int err; + + SYS_LOG_DBG("enable 0x%02x", cp->enable); + + enable = cp->enable ? true : false; + err = bt_mesh_lpn_set(enable); + if (err) { + SYS_LOG_ERR("Failed to toggle LPN (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +lpn_poll(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + SYS_LOG_DBG(""); + + err = bt_mesh_lpn_poll(); + if (err) { + SYS_LOG_ERR("Failed to send poll msg (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +net_send(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_net_send_cmd *cp = cmd; + struct os_mbuf *msg = NET_BUF_SIMPLE(UINT8_MAX); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net.net_idx, + .app_idx = vnd_app_key_idx, + .addr = sys_le16_to_cpu(cp->dst), + .send_ttl = cp->ttl, + }; + int err; + int status = BTP_STATUS_SUCCESS; + + if (cmd_len < sizeof(*cp) && + cmd_len != (sizeof(*cp) + cp->payload_len)) { + return BTP_STATUS_FAILED; + } + + SYS_LOG_DBG("ttl 0x%02x dst 0x%04x payload_len %d", ctx.send_ttl, + ctx.addr, cp->payload_len); + + if (!bt_mesh_app_key_exists(vnd_app_key_idx)) { + (void) bt_mesh_app_key_add(vnd_app_key_idx, net.net_idx, + vnd_app_key); + vnd_models[0].keys[0] = vnd_app_key_idx; + } + + net_buf_simple_add_mem(msg, cp->payload, cp->payload_len); + + err = bt_mesh_model_send(&vnd_models[0], &ctx, msg, NULL, NULL); + if (err) { + SYS_LOG_ERR("Failed to send (err %d)", err); + status = BTP_STATUS_FAILED; + } + + os_mbuf_free_chain(msg); + + return status; +} + +static uint8_t +health_generate_faults(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_mesh_health_generate_faults_rp *rp = rsp; + uint8_t some_faults[] = {0x01, 0x02, 0x03, 0xff, 0x06}; + uint8_t cur_faults_count, reg_faults_count; + + cur_faults_count = min(sizeof(cur_faults), sizeof(some_faults)); + memcpy(cur_faults, some_faults, cur_faults_count); + memcpy(rp->current_faults, cur_faults, cur_faults_count); + rp->cur_faults_count = cur_faults_count; + + reg_faults_count = min(sizeof(reg_faults), sizeof(some_faults)); + memcpy(reg_faults, some_faults, reg_faults_count); + memcpy(rp->registered_faults + cur_faults_count, reg_faults, reg_faults_count); + rp->reg_faults_count = reg_faults_count; + + bt_mesh_fault_update(&elements[0]); + + *rsp_len = sizeof(*rp) + cur_faults_count + reg_faults_count; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +health_clear_faults(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + SYS_LOG_DBG(""); + + memset(cur_faults, 0, sizeof(cur_faults)); + memset(reg_faults, 0, sizeof(reg_faults)); + + bt_mesh_fault_update(&elements[0]); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +model_send(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_model_send_cmd *cp = cmd; + struct os_mbuf *msg = NET_BUF_SIMPLE(UINT8_MAX); + struct bt_mesh_model *model = NULL; + int err, i; + uint16_t src; + int status = BTP_STATUS_SUCCESS; + + if (cmd_len < sizeof(*cp) && + cmd_len != (sizeof(*cp) + cp->payload_len)) { + return BTP_STATUS_FAILED; + } + + struct bt_mesh_msg_ctx ctx = { + .net_idx = net.net_idx, + .app_idx = BT_MESH_KEY_DEV, + .addr = sys_le16_to_cpu(cp->dst), + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + + src = sys_le16_to_cpu(cp->src); + + /* Lookup source address */ + for (i = 0; i < ARRAY_SIZE(model_bound); i++) { + if (bt_mesh_model_elem(model_bound[i].model)->addr == src) { + model = model_bound[i].model; + ctx.app_idx = model_bound[i].appkey_idx; + + break; + } + } + + if (!model) { + SYS_LOG_ERR("Model not found"); + status = BTP_STATUS_FAILED; + + goto rsp; + } + + SYS_LOG_DBG("src 0x%04x dst 0x%04x model %p payload_len %d", src, + ctx.addr, model, cp->payload_len); + + net_buf_simple_add_mem(msg, cp->payload, cp->payload_len); + + err = bt_mesh_model_send(model, &ctx, msg, NULL, NULL); + if (err) { + SYS_LOG_ERR("Failed to send (err %d)", err); + status = BTP_STATUS_FAILED; + } + +rsp: + os_mbuf_free_chain(msg); + return status; +} + +#if MYNEWT_VAL(BLE_MESH_TESTING) + +static uint8_t +lpn_subscribe(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_lpn_subscribe_cmd *cp = cmd; + uint16_t address = sys_le16_to_cpu(cp->address); + int err; + + SYS_LOG_DBG("address 0x%04x", address); + + err = bt_test_mesh_lpn_group_add(address); + if (err) { + SYS_LOG_ERR("Failed to subscribe (err %d)", err); + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +lpn_unsubscribe(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_lpn_unsubscribe_cmd *cp = cmd; + uint16_t address = sys_le16_to_cpu(cp->address); + int err; + + SYS_LOG_DBG("address 0x%04x", address); + + err = bt_test_mesh_lpn_group_remove(&address, 1); + if (err) { + SYS_LOG_ERR("Failed to unsubscribe (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +rpl_clear(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + SYS_LOG_DBG(""); + + err = bt_test_mesh_rpl_clear(); + if (err) { + SYS_LOG_ERR("Failed to clear RPL (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +#endif /* MYNEWT_VAL(BLE_MESH_TESTING) */ + +static uint8_t +proxy_identity_enable(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + SYS_LOG_DBG(""); + + err = bt_mesh_proxy_identity_enable(); + if (err) { + SYS_LOG_ERR("Failed to enable proxy identity (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_MESH_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_MESH_CONFIG_PROVISIONING, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = config_prov, + }, + { + .opcode = BTP_MESH_PROVISION_NODE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = provision_node, + }, + { + .opcode = BTP_MESH_INIT, + .expect_len = 0, + .func = init, + }, + { + .opcode = BTP_MESH_RESET, + .expect_len = 0, + .func = reset, + }, + { + .opcode = BTP_MESH_INPUT_NUMBER, + .expect_len = sizeof(struct btp_mesh_input_number_cmd), + .func = input_number, + }, + { + .opcode = BTP_MESH_INPUT_STRING, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = input_string, + }, + { + .opcode = BTP_MESH_IVU_TEST_MODE, + .expect_len = sizeof(struct btp_mesh_ivu_test_mode_cmd), + .func = ivu_test_mode, + }, + { + .opcode = BTP_MESH_IVU_TOGGLE_STATE, + .expect_len = 0, + .func = ivu_toggle_state, + }, + { + .opcode = BTP_MESH_LPN, + .expect_len = sizeof(struct btp_mesh_lpn_set_cmd), + .func = lpn, + }, + { + .opcode = BTP_MESH_LPN_POLL, + .expect_len = 0, + .func = lpn_poll, + }, + { + .opcode = BTP_MESH_NET_SEND, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = net_send, + }, + { + .opcode = BTP_MESH_HEALTH_GENERATE_FAULTS, + .expect_len = 0, + .func = health_generate_faults, + }, + { + .opcode = BTP_MESH_HEALTH_CLEAR_FAULTS, + .expect_len = 0, + .func = health_clear_faults, + }, + { + .opcode = BTP_MESH_MODEL_SEND, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = model_send, + }, + { + .opcode = BTP_MESH_LPN_SUBSCRIBE, + .expect_len = sizeof(struct btp_mesh_lpn_subscribe_cmd), + .func = lpn_subscribe, + }, + { + .opcode = BTP_MESH_LPN_UNSUBSCRIBE, + .expect_len = sizeof(struct btp_mesh_lpn_unsubscribe_cmd), + .func = lpn_unsubscribe, + }, + { + .opcode = BTP_MESH_RPL_CLEAR, + .expect_len = 0, + .func = rpl_clear, + }, + { + .opcode = BTP_MESH_PROXY_IDENTITY, + .expect_len = 0, + .func = proxy_identity_enable, + }, +}; + +void +net_recv_ev(uint8_t ttl, + uint8_t ctl, + uint16_t src, + uint16_t dst, + const void *payload, + size_t payload_len) +{ + struct os_mbuf *buf = NET_BUF_SIMPLE(UINT8_MAX); + struct btp_mesh_net_recv_ev *ev; + + SYS_LOG_DBG("ttl 0x%02x ctl 0x%02x src 0x%04x dst 0x%04x " + "payload_len %d", ttl, ctl, src, dst, payload_len); + + if (payload_len > net_buf_simple_tailroom(buf)) { + SYS_LOG_ERR("Payload size exceeds buffer size"); + + goto done; + } + + ev = net_buf_simple_add(buf, sizeof(*ev)); + ev->ttl = ttl; + ev->ctl = ctl; + ev->src = htole16(src); + ev->dst = htole16(dst); + ev->payload_len = payload_len; + net_buf_simple_add_mem(buf, payload, payload_len); + + tester_send_buf(BTP_SERVICE_ID_MESH, BTP_MESH_EV_NET_RECV, CONTROLLER_INDEX, + buf); +done: + os_mbuf_free_chain(buf); +} + +static void +model_bound_cb(uint16_t addr, struct bt_mesh_model *model, + uint16_t key_idx) +{ + int i; + + SYS_LOG_DBG("remote addr 0x%04x key_idx 0x%04x model %p", + addr, key_idx, model); + + for (i = 0; i < ARRAY_SIZE(model_bound); i++) { + if (!model_bound[i].model) { + model_bound[i].model = model; + model_bound[i].addr = addr; + model_bound[i].appkey_idx = key_idx; + + return; + } + } + + SYS_LOG_ERR("model_bound is full"); +} + +static void +model_unbound_cb(uint16_t addr, struct bt_mesh_model *model, + uint16_t key_idx) +{ + int i; + + SYS_LOG_DBG("remote addr 0x%04x key_idx 0x%04x model %p", + addr, key_idx, model); + + for (i = 0; i < ARRAY_SIZE(model_bound); i++) { + if (model_bound[i].model == model) { + model_bound[i].model = NULL; + model_bound[i].addr = 0x0000; + model_bound[i].appkey_idx = BT_MESH_KEY_UNUSED; + + return; + } + } + + SYS_LOG_INF("model not found"); +} + +static void +invalid_bearer_cb(uint8_t opcode) +{ + struct btp_mesh_invalid_bearer_ev ev = { + .opcode = opcode, + }; + + SYS_LOG_DBG("opcode 0x%02x", opcode); + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_INVALID_BEARER, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +incomp_timer_exp_cb(void) +{ + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_INCOMP_TIMER_EXP, + NULL, 0); +} + +static struct bt_test_cb bt_test_cb = { + .mesh_net_recv = net_recv_ev, + .mesh_model_bound = model_bound_cb, + .mesh_model_unbound = model_unbound_cb, + .mesh_prov_invalid_bearer = invalid_bearer_cb, + .mesh_trans_incomp_timer_exp = incomp_timer_exp_cb, +}; + +static void +lpn_established(uint16_t friend_addr) +{ + + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + struct btp_mesh_lpn_established_ev + ev = {lpn->sub->net_idx, friend_addr, lpn->queue_size, + lpn->recv_win}; + + SYS_LOG_DBG("Friendship (as LPN) established with " + "Friend 0x%04x Queue Size %d Receive Window %d", + friend_addr, lpn->queue_size, lpn->recv_win); + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_LPN_ESTABLISHED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +lpn_terminated(uint16_t friend_addr) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + struct btp_mesh_lpn_terminated_ev ev = {lpn->sub->net_idx, friend_addr}; + + SYS_LOG_DBG("Friendship (as LPN) lost with Friend " + "0x%04x", friend_addr); + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_LPN_TERMINATED, + (uint8_t *) &ev, sizeof(ev)); +} + +void +lpn_cb(uint16_t friend_addr, bool established) +{ + if (established) { + lpn_established(friend_addr); + } else { + lpn_terminated(friend_addr); + } +} + +uint8_t +tester_init_mesh(void) +{ + health_pub_init(); + + if (IS_ENABLED(CONFIG_BT_TESTING)) { + bt_mesh_lpn_set_cb(lpn_cb); + bt_test_cb_register(&bt_test_cb); + } + + tester_register_command_handlers(BTP_SERVICE_ID_MESH, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_mesh(void) +{ + return BTP_STATUS_SUCCESS; +} + +#endif /* MYNEWT_VAL(BLE_MESH) */ diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/bttester.c b/lib/bt/host/nimble/nimble/apps/bttester/src/bttester.c index 76aebbf1..d5e0399a 100644 --- a/lib/bt/host/nimble/nimble/apps/bttester/src/bttester.c +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/bttester.c @@ -33,347 +33,343 @@ #include "console/console.h" #include "bttester_pipe.h" -#include "bttester.h" +#include "btp/btp.h" #define CMD_QUEUED 2 static struct os_eventq avail_queue; static struct os_eventq *cmds_queue; static struct os_event bttester_ev[CMD_QUEUED]; +static struct btp_buf *delayed_cmd; struct btp_buf { - struct os_event *ev; - union { - uint8_t data[BTP_MTU]; - struct btp_hdr hdr; - }; + struct os_event *ev; + union { + uint8_t data[BTP_MTU]; + struct btp_hdr hdr; + }; + uint8_t rsp[BTP_MTU]; }; static struct btp_buf cmd_buf[CMD_QUEUED]; -static void supported_commands(uint8_t *data, uint16_t len) -{ - uint8_t buf[1]; - struct core_read_supported_commands_rp *rp = (void *) buf; +static struct { + const struct btp_handler *handlers; + uint8_t num; +} service_handler[BTP_SERVICE_ID_MAX + 1]; + - memset(buf, 0, sizeof(buf)); +void +tester_mbuf_reset(struct os_mbuf *buf) +{ + buf->om_data = &buf->om_databuf[buf->om_pkthdr_len]; + buf->om_len = 0; +} - tester_set_bit(buf, CORE_READ_SUPPORTED_COMMANDS); - tester_set_bit(buf, CORE_READ_SUPPORTED_SERVICES); - tester_set_bit(buf, CORE_REGISTER_SERVICE); - tester_set_bit(buf, CORE_UNREGISTER_SERVICE); +static void +tester_send_with_index(uint8_t service, uint8_t opcode, uint8_t index, + const uint8_t *data, size_t len); +static void +tester_rsp_with_index(uint8_t service, uint8_t opcode, uint8_t index, + uint8_t status); + +void +tester_register_command_handlers(uint8_t service, + const struct btp_handler *handlers, + size_t num) +{ + assert(service <= BTP_SERVICE_ID_MAX); + assert(service_handler[service].handlers == NULL); - tester_send(BTP_SERVICE_ID_CORE, CORE_READ_SUPPORTED_COMMANDS, - BTP_INDEX_NONE, (uint8_t *) rp, sizeof(buf)); + service_handler[service].handlers = handlers; + service_handler[service].num = num; } -static void supported_services(uint8_t *data, uint16_t len) +const char * +string_from_bytes(const void *buf, size_t len) { - uint8_t buf[1]; - struct core_read_supported_services_rp *rp = (void *) buf; - - memset(buf, 0, sizeof(buf)); - - tester_set_bit(buf, BTP_SERVICE_ID_CORE); - tester_set_bit(buf, BTP_SERVICE_ID_GAP); - tester_set_bit(buf, BTP_SERVICE_ID_GATT); -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) - tester_set_bit(buf, BTP_SERVICE_ID_L2CAP); -#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ -#if MYNEWT_VAL(BLE_MESH) - tester_set_bit(buf, BTP_SERVICE_ID_MESH); -#endif /* MYNEWT_VAL(BLE_MESH) */ - tester_set_bit(buf, BTP_SERVICE_ID_GATTC); - - tester_send(BTP_SERVICE_ID_CORE, CORE_READ_SUPPORTED_SERVICES, - BTP_INDEX_NONE, (uint8_t *) rp, sizeof(buf)); + static const char hex[] = "0123456789abcdef"; + static char hexbufs[4][137]; + static uint8_t curbuf; + const uint8_t *b = buf; + char *str; + int i; + + str = hexbufs[curbuf++]; + curbuf %= ARRAY_SIZE(hexbufs); + + len = min(len, (sizeof(hexbufs[0]) - 1) / 2); + + for (i = 0; i < len; i++) { + str[i * 2] = hex[b[i] >> 4]; + str[i * 2 + 1] = hex[b[i] & 0xf]; + } + + str[i * 2] = '\0'; + + return str; } -static void register_service(uint8_t *data, uint16_t len) +static const struct btp_handler * +find_btp_handler(uint8_t service, uint8_t opcode) { - struct core_register_service_cmd *cmd = (void *) data; - uint8_t status; - - switch (cmd->id) { - case BTP_SERVICE_ID_GAP: - status = tester_init_gap(); - /* Rsp with success status will be handled by bt enable cb */ - if (status == BTP_STATUS_FAILED) { - goto rsp; - } - return; - case BTP_SERVICE_ID_GATT: - status = tester_init_gatt(); - break; -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) - case BTP_SERVICE_ID_L2CAP: - status = tester_init_l2cap(); - break; -#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ -#if MYNEWT_VAL(BLE_MESH) - case BTP_SERVICE_ID_MESH: - status = tester_init_mesh(); - break; -#endif /* MYNEWT_VAL(BLE_MESH) */ - default: - status = BTP_STATUS_FAILED; - break; - } - -rsp: - tester_rsp(BTP_SERVICE_ID_CORE, CORE_REGISTER_SERVICE, BTP_INDEX_NONE, - status); + if ((service > BTP_SERVICE_ID_MAX) || + (service_handler[service].handlers == NULL)) { + return NULL; + } + + for (uint8_t i = 0; i < service_handler[service].num; i++) { + if (service_handler[service].handlers[i].opcode == opcode) { + return &service_handler[service].handlers[i]; + } + } + + return NULL; } -static void unregister_service(uint8_t *data, uint16_t len) +static void +cmd_handler(struct os_event *ev) { - struct core_unregister_service_cmd *cmd = (void *) data; - uint8_t status; - - switch (cmd->id) { - case BTP_SERVICE_ID_GAP: - status = tester_unregister_gap(); - break; - case BTP_SERVICE_ID_GATT: - status = tester_unregister_gatt(); - break; -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) - case BTP_SERVICE_ID_L2CAP: - status = tester_unregister_l2cap(); - break; -#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ -#if MYNEWT_VAL(BLE_MESH) - case BTP_SERVICE_ID_MESH: - status = tester_unregister_mesh(); - break; -#endif /* MYNEWT_VAL(BLE_MESH) */ - default: - status = BTP_STATUS_FAILED; - break; - } - - tester_rsp(BTP_SERVICE_ID_CORE, CORE_UNREGISTER_SERVICE, BTP_INDEX_NONE, - status); + const struct btp_handler *btp; + uint16_t len; + struct btp_buf *cmd; + uint8_t status; + uint16_t rsp_len = 0; + + if (!ev || !ev->ev_arg) { + return; + } + + cmd = ev->ev_arg; + + len = le16toh(cmd->hdr.len); + if (MYNEWT_VAL(BTTESTER_BTP_LOG)) { + console_printf("[DBG] received %d bytes: %s\n", + sizeof(cmd->hdr) + len, + string_from_bytes(cmd->data, + sizeof(cmd->hdr) + len)); + } + + btp = find_btp_handler(cmd->hdr.service, cmd->hdr.opcode); + if (btp) { + if (btp->index != cmd->hdr.index) { + status = BTP_STATUS_FAILED; + } else if ((btp->expect_len >= 0) && (btp->expect_len != len)) { + status = BTP_STATUS_FAILED; + } else { + status = btp->func(cmd->hdr.data, len, + cmd->rsp, &rsp_len); + } + + assert((rsp_len + sizeof(struct btp_hdr)) <= BTP_MTU); + } else { + status = BTP_STATUS_UNKNOWN_CMD; + } + + /* Allow to delay only 1 command. This is for convenience only + * of using cmd data without need of copying those in async + * functions. Should be not needed eventually. + */ + if (status == BTP_STATUS_DELAY_REPLY) { + assert(delayed_cmd == NULL); + delayed_cmd = cmd; + return; + } + + if ((status == BTP_STATUS_SUCCESS) && rsp_len > 0) { + tester_send_with_index(cmd->hdr.service, cmd->hdr.opcode, + cmd->hdr.index, cmd->rsp, rsp_len); + } else { + tester_rsp_with_index(cmd->hdr.service, cmd->hdr.opcode, + cmd->hdr.index, status); + } + + os_eventq_put(&avail_queue, ev); } -static void handle_core(uint8_t opcode, uint8_t index, uint8_t *data, - uint16_t len) +static uint8_t * +recv_cb(uint8_t *buf, size_t *off) { - if (index != BTP_INDEX_NONE) { - tester_rsp(BTP_SERVICE_ID_CORE, opcode, index, - BTP_STATUS_FAILED); - return; - } - - switch (opcode) { - case CORE_READ_SUPPORTED_COMMANDS: - supported_commands(data, len); - return; - case CORE_READ_SUPPORTED_SERVICES: - supported_services(data, len); - return; - case CORE_REGISTER_SERVICE: - register_service(data, len); - return; - case CORE_UNREGISTER_SERVICE: - unregister_service(data, len); - return; - default: - tester_rsp(BTP_SERVICE_ID_CORE, opcode, BTP_INDEX_NONE, - BTP_STATUS_UNKNOWN_CMD); - return; - } + struct btp_hdr *cmd = (void *) buf; + struct os_event *new_ev; + struct btp_buf *new_buf, *old_buf; + uint16_t len; + + if (*off < sizeof(*cmd)) { + return buf; + } + + len = le16toh(cmd->len); + if (len > BTP_MTU - sizeof(*cmd)) { + *off = 0; + return buf; + } + + if (*off < sizeof(*cmd) + len) { + return buf; + } + + new_ev = os_eventq_get_no_wait(&avail_queue); + if (!new_ev) { + SYS_LOG_ERR("BT tester: RX overflow"); + *off = 0; + return buf; + } + + old_buf = CONTAINER_OF(buf, struct btp_buf, data); + os_eventq_put(cmds_queue, old_buf->ev); + + new_buf = new_ev->ev_arg; + *off = 0; + return new_buf->data; } -static void cmd_handler(struct os_event *ev) +static void +avail_queue_init(void) { - uint16_t len; - struct btp_buf *cmd; - - if (!ev || !ev->ev_arg) { - return; - } - - cmd = ev->ev_arg; - - len = sys_le16_to_cpu(cmd->hdr.len); - if (MYNEWT_VAL(BTTESTER_BTP_LOG)) { - console_printf("[DBG] received %d bytes: %s\n", - sizeof(cmd->hdr) + len, - bt_hex(cmd->data, - sizeof(cmd->hdr) + len)); - } - - /* TODO - * verify if service is registered before calling handler - */ - - switch (cmd->hdr.service) { - case BTP_SERVICE_ID_CORE: - handle_core(cmd->hdr.opcode, cmd->hdr.index, - cmd->hdr.data, len); - break; - case BTP_SERVICE_ID_GAP: - tester_handle_gap(cmd->hdr.opcode, cmd->hdr.index, - cmd->hdr.data, len); - break; - case BTP_SERVICE_ID_GATT: - tester_handle_gatt(cmd->hdr.opcode, cmd->hdr.index, - cmd->hdr.data, len); - break; -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) - case BTP_SERVICE_ID_L2CAP: - tester_handle_l2cap(cmd->hdr.opcode, cmd->hdr.index, - cmd->hdr.data, len); - break; -#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ -#if MYNEWT_VAL(BLE_MESH) - case BTP_SERVICE_ID_MESH: - tester_handle_mesh(cmd->hdr.opcode, cmd->hdr.index, - cmd->hdr.data, len); - break; -#endif /* MYNEWT_VAL(BLE_MESH) */ - case BTP_SERVICE_ID_GATTC: - tester_handle_gattc(cmd->hdr.opcode, cmd->hdr.index, - cmd->hdr.data, len); - break; - default: - tester_rsp(cmd->hdr.service, cmd->hdr.opcode, - cmd->hdr.index, BTP_STATUS_FAILED); - break; - } - - os_eventq_put(&avail_queue, ev); + int i; + + os_eventq_init(&avail_queue); + + for (i = 0; i < CMD_QUEUED; i++) { + cmd_buf[i].ev = &bttester_ev[i]; + bttester_ev[i].ev_cb = cmd_handler; + bttester_ev[i].ev_arg = &cmd_buf[i]; + + os_eventq_put(&avail_queue, &bttester_ev[i]); + } } -static uint8_t *recv_cb(uint8_t *buf, size_t *off) +void +bttester_evq_set(struct os_eventq *evq) { - struct btp_hdr *cmd = (void *) buf; - struct os_event *new_ev; - struct btp_buf *new_buf, *old_buf; - uint16_t len; - - if (*off < sizeof(*cmd)) { - return buf; - } - - len = sys_le16_to_cpu(cmd->len); - if (len > BTP_MTU - sizeof(*cmd)) { - *off = 0; - return buf; - } - - if (*off < sizeof(*cmd) + len) { - return buf; - } - - new_ev = os_eventq_get_no_wait(&avail_queue); - if (!new_ev) { - SYS_LOG_ERR("BT tester: RX overflow"); - *off = 0; - return buf; - } - - old_buf = CONTAINER_OF(buf, struct btp_buf, data); - os_eventq_put(cmds_queue, old_buf->ev); - - new_buf = new_ev->ev_arg; - *off = 0; - return new_buf->data; + cmds_queue = evq; } -static void avail_queue_init(void) +void +tester_init(void) { - int i; + struct os_event *ev; + struct btp_buf *buf; + + avail_queue_init(); + bttester_evq_set(os_eventq_dflt_get()); + + ev = os_eventq_get(&avail_queue); + buf = ev->ev_arg; - os_eventq_init(&avail_queue); + if (bttester_pipe_init()) { + SYS_LOG_ERR("Failed to initialize pipe"); + return; + } - for (i = 0; i < CMD_QUEUED; i++) { - cmd_buf[i].ev = &bttester_ev[i]; - bttester_ev[i].ev_cb = cmd_handler; - bttester_ev[i].ev_arg = &cmd_buf[i]; + bttester_pipe_register(buf->data, BTP_MTU, recv_cb); - os_eventq_put(&avail_queue, &bttester_ev[i]); - } + /* core service is always available */ + tester_init_core(); + + tester_send_with_index(BTP_SERVICE_ID_CORE, BTP_CORE_EV_IUT_READY, + BTP_INDEX_NONE, NULL, 0); } -void bttester_evq_set(struct os_eventq *evq) +static void +tester_send_with_index(uint8_t service, uint8_t opcode, uint8_t index, + const uint8_t *data, size_t len) { - cmds_queue = evq; + struct btp_hdr msg; + + msg.service = service; + msg.opcode = opcode; + msg.index = index; + msg.len = htole16(len); + + bttester_pipe_send((uint8_t *) &msg, sizeof(msg)); + if (data && len) { + bttester_pipe_send(data, len); + } + + if (MYNEWT_VAL(BTTESTER_BTP_LOG)) { + console_printf("[DBG] send %d bytes hdr: %s\n", sizeof(msg), + string_from_bytes((char *) &msg, sizeof(msg))); + if (data && len) { + console_printf("[DBG] send %d bytes data: %s\n", len, + string_from_bytes((char *) data, len)); + } + } } -void tester_init(void) +void +tester_send_buf(uint8_t service, uint8_t opcode, uint8_t index, + struct os_mbuf *data) { - struct os_event *ev; - struct btp_buf *buf; + struct btp_hdr msg; - avail_queue_init(); - bttester_evq_set(os_eventq_dflt_get()); + msg.service = service; + msg.opcode = opcode; + msg.index = index; + msg.len = os_mbuf_len(data); - ev = os_eventq_get(&avail_queue); - buf = ev->ev_arg; + bttester_pipe_send((uint8_t *) &msg, sizeof(msg)); + if (data && msg.len) { + bttester_pipe_send_buf(data); + } +} - if (bttester_pipe_init()) { - SYS_LOG_ERR("Failed to initialize pipe"); - return; - } +static void +tester_rsp_with_index(uint8_t service, uint8_t opcode, uint8_t index, + uint8_t status) +{ + struct btp_status s; - bttester_pipe_register(buf->data, BTP_MTU, recv_cb); + if (status == BTP_STATUS_SUCCESS) { + tester_send_with_index(service, opcode, index, NULL, 0); + return; + } - tester_send(BTP_SERVICE_ID_CORE, CORE_EV_IUT_READY, BTP_INDEX_NONE, - NULL, 0); + s.code = status; + tester_send_with_index(service, BTP_STATUS, index, (uint8_t *) &s, sizeof(s)); } -void tester_send(uint8_t service, uint8_t opcode, uint8_t index, uint8_t *data, - size_t len) +void +tester_event(uint8_t service, uint8_t opcode, const void *data, size_t len) { - struct btp_hdr msg; - - msg.service = service; - msg.opcode = opcode; - msg.index = index; - msg.len = len; - - bttester_pipe_send((uint8_t *)&msg, sizeof(msg)); - if (data && len) { - bttester_pipe_send(data, len); - } - - if (MYNEWT_VAL(BTTESTER_BTP_LOG)) { - console_printf("[DBG] send %d bytes hdr: %s\n", sizeof(msg), - bt_hex((char *) &msg, sizeof(msg))); - if (data && len) { - console_printf("[DBG] send %d bytes data: %s\n", len, - bt_hex((char *) data, len)); - } - } + assert(opcode >= 0x80); + tester_send_with_index(service, opcode, BTP_INDEX, data, len); } -void tester_send_buf(uint8_t service, uint8_t opcode, uint8_t index, - struct os_mbuf *data) +void +tester_rsp_full(uint8_t service, uint8_t opcode, const void *rsp, size_t len) { - struct btp_hdr msg; + struct btp_buf *cmd; - msg.service = service; - msg.opcode = opcode; - msg.index = index; - msg.len = os_mbuf_len(data); + assert(opcode < 0x80); + assert(delayed_cmd != NULL); - bttester_pipe_send((uint8_t *)&msg, sizeof(msg)); - if (data && msg.len) { - bttester_pipe_send_buf(data); - } + tester_send_with_index(service, opcode, BTP_INDEX, rsp, len); + + cmd = delayed_cmd; + delayed_cmd = NULL; + + (void)memset(cmd, 0, sizeof(*cmd)); + + os_eventq_put(&avail_queue, + CONTAINER_OF(cmd, struct btp_buf, data)->ev); } -void tester_rsp(uint8_t service, uint8_t opcode, uint8_t index, uint8_t status) +void +tester_rsp(uint8_t service, uint8_t opcode, uint8_t status) { - struct btp_status s; + struct btp_buf *cmd; + + assert(opcode < 0x80); + assert(delayed_cmd != NULL); + + tester_rsp_with_index(service, opcode, BTP_INDEX, status); - if (status == BTP_STATUS_SUCCESS) { - tester_send(service, opcode, index, NULL, 0); - return; - } + cmd = delayed_cmd; + delayed_cmd = NULL; - s.code = status; - tester_send(service, BTP_STATUS, index, (uint8_t *) &s, sizeof(s)); + (void)memset(cmd, 0, sizeof(*cmd)); + os_eventq_put(&avail_queue, + CONTAINER_OF(cmd, struct btp_buf, data)->ev); } diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/bttester_pipe.h b/lib/bt/host/nimble/nimble/apps/bttester/src/bttester_pipe.h index 64b63cd6..ac56c575 100644 --- a/lib/bt/host/nimble/nimble/apps/bttester/src/bttester_pipe.h +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/bttester_pipe.h @@ -21,17 +21,21 @@ #define __BTTESTER_PIPE_H__ #include -#include "bttester.h" +#include "btp/bttester.h" #ifdef __cplusplus extern "C" { #endif typedef uint8_t *(*bttester_pipe_recv_cb)(uint8_t *buf, size_t *off); -void bttester_pipe_register(uint8_t *buf, size_t len, bttester_pipe_recv_cb cb); -int bttester_pipe_send(const uint8_t *data, int len); -int bttester_pipe_send_buf(struct os_mbuf *buf); -int bttester_pipe_init(void); +void +bttester_pipe_register(uint8_t *buf, size_t len, bttester_pipe_recv_cb cb); +int +bttester_pipe_send(const uint8_t *data, int len); +int +bttester_pipe_send_buf(struct os_mbuf *buf); +int +bttester_pipe_init(void); #ifdef __cplusplus } diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/main.c b/lib/bt/host/nimble/nimble/apps/bttester/src/main.c index ea130805..99dff7e3 100644 --- a/lib/bt/host/nimble/nimble/apps/bttester/src/main.c +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/main.c @@ -31,42 +31,45 @@ #include "host/ble_uuid.h" #include "host/ble_hs.h" -#include "bttester.h" +#include "btp/btp.h" -static void on_reset(int reason) +static void +on_reset(int reason) { - MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason); + MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason); } -static void on_sync(void) +static void +on_sync(void) { - MODLOG_DFLT(INFO, "Bluetooth initialized\n"); + MODLOG_DFLT(INFO, "Bluetooth initialized\n"); - tester_init(); + tester_init(); } -int main(int argc, char **argv) +int +main(int argc, char **argv) { - int rc; + int rc; #ifdef ARCH_sim - mcu_sim_parse_args(argc, argv); + mcu_sim_parse_args(argc, argv); #endif - /* Initialize OS */ - sysinit(); + /* Initialize OS */ + sysinit(); - /* Initialize the NimBLE host configuration. */ - ble_hs_cfg.reset_cb = on_reset; - ble_hs_cfg.sync_cb = on_sync; - ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb, - ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = on_reset; + ble_hs_cfg.sync_cb = on_sync; + ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb, + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; - rc = gatt_svr_init(); - assert(rc == 0); + rc = gatt_svr_init(); + assert(rc == 0); - while (1) { - os_eventq_run(os_eventq_dflt_get()); - } - return 0; + while (1) { + os_eventq_run(os_eventq_dflt_get()); + } + return 0; } diff --git a/lib/bt/host/nimble/nimble/apps/bttester/src/uart_pipe.c b/lib/bt/host/nimble/nimble/apps/bttester/src/uart_pipe.c index 1118d9af..223a7897 100644 --- a/lib/bt/host/nimble/nimble/apps/bttester/src/uart_pipe.c +++ b/lib/bt/host/nimble/nimble/apps/bttester/src/uart_pipe.c @@ -41,7 +41,7 @@ struct uart_pipe_ring { static struct uart_dev *uart_dev; static struct uart_pipe_ring cr_tx; static uint8_t cr_tx_buf[MYNEWT_VAL(BTTESTER_BTP_DATA_SIZE_MAX)]; -typedef void (*console_write_char)(struct uart_dev*, uint8_t); +typedef void (*console_write_char)(struct uart_dev *, uint8_t); static console_write_char write_char_cb; static struct uart_pipe_ring cr_rx; @@ -217,39 +217,39 @@ bttester_pipe_send(const uint8_t *data, int len) int bttester_pipe_send_buf(struct os_mbuf *buf) { - int i, len; - struct os_mbuf *om; - - /* Assure that there is a write cb installed; this enables to debug - * code that is faulting before the console was initialized. - */ - if (!write_char_cb) { - return -1; - } - - for (om = buf; om; om = SLIST_NEXT(om, om_next)) { - len = om->om_len; - for (i = 0; i < len; ++i) { - write_char_cb(uart_dev, om->om_data[i]); - } - } - - uart_start_tx(uart_dev); - - return 0; + int i, len; + struct os_mbuf *om; + + /* Assure that there is a write cb installed; this enables to debug + * code that is faulting before the console was initialized. + */ + if (!write_char_cb) { + return -1; + } + + for (om = buf; om; om = SLIST_NEXT(om, om_next)) { + len = om->om_len; + for (i = 0; i < len; ++i) { + write_char_cb(uart_dev, om->om_data[i]); + } + } + + uart_start_tx(uart_dev); + + return 0; } int bttester_pipe_init(void) { struct uart_conf uc = { - .uc_speed = MYNEWT_VAL(CONSOLE_UART_BAUD), - .uc_databits = 8, - .uc_stopbits = 1, - .uc_parity = UART_PARITY_NONE, - .uc_flow_ctl = MYNEWT_VAL(CONSOLE_UART_FLOW_CONTROL), - .uc_tx_char = uart_console_tx_char, - .uc_rx_char = uart_console_rx_char, + .uc_speed = MYNEWT_VAL(CONSOLE_UART_BAUD), + .uc_databits = 8, + .uc_stopbits = 1, + .uc_parity = UART_PARITY_NONE, + .uc_flow_ctl = MYNEWT_VAL(CONSOLE_UART_FLOW_CONTROL), + .uc_tx_char = uart_console_tx_char, + .uc_rx_char = uart_console_rx_char, }; cr_tx.size = sizeof(cr_tx_buf); @@ -262,8 +262,9 @@ bttester_pipe_init(void) rx_ev.ev_cb = uart_console_rx_char_event; if (!uart_dev) { - uart_dev = (struct uart_dev *)os_dev_open(MYNEWT_VAL(CONSOLE_UART_DEV), - OS_TIMEOUT_NEVER, &uc); + uart_dev = + (struct uart_dev *) os_dev_open(MYNEWT_VAL(CONSOLE_UART_DEV), + OS_TIMEOUT_NEVER, &uc); if (!uart_dev) { return -1; } @@ -274,8 +275,9 @@ bttester_pipe_init(void) void bttester_pipe_register(uint8_t *buf, size_t len, bttester_pipe_recv_cb cb) { - recv_buf = buf; - recv_buf_len = len; - app_cb = cb; + recv_buf = buf; + recv_buf_len = len; + app_cb = cb; } + #endif /* MYNEWT_VAL(BTTESTER_PIPE_UART) */ diff --git a/lib/bt/host/nimble/nimble/apps/bttester/syscfg.yml b/lib/bt/host/nimble/nimble/apps/bttester/syscfg.yml index 330e38d0..5db9af2e 100644 --- a/lib/bt/host/nimble/nimble/apps/bttester/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/bttester/syscfg.yml @@ -80,6 +80,10 @@ syscfg.defs: value: 5 syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + OS_MAIN_STACK_SIZE: 512 SHELL_TASK: 0 SHELL_NEWTMGR: 0 @@ -96,15 +100,15 @@ syscfg.vals: BLE_L2CAP_COC_MAX_NUM: 2 BLE_L2CAP_SIG_MAX_PROCS: 2 BLE_L2CAP_ENHANCED_COC: 1 - BLE_VERSION: 52 + BLE_VERSION: 53 # Some testcases require MPS < MTU BLE_L2CAP_COC_MPS: 100 BLE_RPA_TIMEOUT: 30 BLE_SM_BONDING: 1 BLE_SM_MITM: 0 BLE_SM_SC: 1 - BLE_SM_OUR_KEY_DIST: 7 - BLE_SM_THEIR_KEY_DIST: 7 + BLE_SM_OUR_KEY_DIST: 3 + BLE_SM_THEIR_KEY_DIST: 3 BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION: 1 BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL: 9 BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL: 30 diff --git a/lib/bt/host/nimble/nimble/apps/central/pkg.yml b/lib/bt/host/nimble/nimble/apps/central/pkg.yml index 5f5b27a9..90913711 100644 --- a/lib/bt/host/nimble/nimble/apps/central/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/central/pkg.yml @@ -24,9 +24,9 @@ pkg.author: "Krzysztof Kopyściński " pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util/" diff --git a/lib/bt/host/nimble/nimble/apps/central/syscfg.yml b/lib/bt/host/nimble/nimble/apps/central/syscfg.yml index c23ba042..3761c496 100644 --- a/lib/bt/host/nimble/nimble/apps/central/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/central/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + BLE_ROLE_BROADCASTER: 0 BLE_ROLE_CENTRAL: 1 BLE_ROLE_OBSERVER: 1 diff --git a/lib/bt/host/nimble/nimble/apps/dtm/pkg.yml b/lib/bt/host/nimble/nimble/apps/dtm/pkg.yml new file mode 100644 index 00000000..2204befc --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/dtm/pkg.yml @@ -0,0 +1,33 @@ +# 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. + +pkg.name: apps/dtm +pkg.type: app +pkg.description: "Bluetooth DTM shell application" +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" + - "@apache-mynewt-core/sys/shell" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-nimble/nimble/host" + - "@apache-mynewt-mcumgr/cmd/img_mgmt" + - "@mcuboot/boot/bootutil" diff --git a/lib/bt/host/nimble/nimble/apps/dtm/src/main.c b/lib/bt/host/nimble/nimble/apps/dtm/src/main.c new file mode 100644 index 00000000..e5e0689c --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/dtm/src/main.c @@ -0,0 +1,425 @@ +/* + * 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 "os/mynewt.h" +#include +#include +#include +#include "nimble/ble.h" +#include "nimble/nimble_opt.h" +#include "host/ble_hs.h" +#include "host/ble_dtm.h" +#include +#include + +static const struct kv_pair phy_opts[] = { + { "1M", 0x01 }, + { "2M", 0x02 }, + { "coded", 0x03 }, + { NULL } +}; + +static const struct kv_pair modulation_index_opts[] = { + { "standard", 0x00 }, + { "stable", 0x01 }, + { NULL } +}; + +static int +cmd_rx_test(int argc, char **argv) +{ + struct ble_dtm_rx_params params; + int rc; + + rc = parse_arg_all(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.channel = parse_arg_uint8("channel", &rc); + if ((rc != 0) || (params.channel > 39)) { + console_printf("invalid channel\n"); + return rc; + } + + params.phy = parse_arg_kv_dflt("phy", phy_opts, 0x01, &rc); + if (rc != 0) { + console_printf("invalid 'phy' parameter\n"); + return rc; + } + + params.modulation_index = parse_arg_kv_dflt("modulation_index", + modulation_index_opts, 0x00, &rc); + if (rc != 0) { + console_printf("invalid 'modulation_index' parameter\n"); + return rc; + } + + rc = ble_dtm_rx_start(¶ms); + if (rc) { + console_printf("failed to start RX test\n"); + return rc; + } + + console_printf("RX test started\n"); + return 0; +} + +static int +cmd_tx_test(int argc, char **argv) +{ + struct ble_dtm_tx_params params; + int rc; + + rc = parse_arg_all(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.channel = parse_arg_uint8("channel", &rc); + if ((rc != 0) || (params.channel > 39)) { + console_printf("invalid channel\n"); + return rc; + } + + params.phy = parse_arg_kv_dflt("phy", phy_opts, 0x01, &rc); + if (rc != 0) { + console_printf("invalid 'phy' parameter\n"); + return rc; + } + + params.payload = parse_arg_uint8("payload", &rc); + if ((rc != 0) || ((params.payload > 7))) { + console_printf("invalid 'payload' parameter\n"); + return rc; + } + + params.test_data_len = parse_arg_uint8_dflt("data_length", 0, &rc); + if (rc != 0) { + console_printf("invalid 'data_length' parameter\n"); + return rc; + } + + rc = ble_dtm_tx_start(¶ms); + if (rc) { + console_printf("failed to start TX test\n"); + return rc; + } + + console_printf("TX test started\n"); + return 0; +} + +static int +cmd_stop_test(int argc, char **argv) +{ + uint16_t num_packets; + int rc; + + rc = parse_arg_all(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + rc = ble_dtm_stop(&num_packets); + if (rc) { + console_printf("failed to stop test\n"); + return rc; + } + + console_printf("Test stopped (%u packets)\n", num_packets); + return 0; +} + +static int +cmd_tx_power(int argc, char **argv) +{ + struct ble_hci_vs_set_tx_pwr_cp cmd; + struct ble_hci_vs_set_tx_pwr_rp rsp; + int rc; + + rc = parse_arg_all(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + cmd.tx_power = parse_arg_long_bounds_dflt("power", + -127, 127, 127, &rc); + if (rc != 0) { + console_printf("invalid 'power' parameter\n"); + return rc; + } + + rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_SET_TX_PWR, &cmd, sizeof(cmd), + &rsp, sizeof(rsp)); + if (rc) { + console_printf("failed to set TX power\n"); + return rc; + } + + console_printf("TX power set to %d dBm\n", rsp.tx_power); + return 0; +} + +static int +cmd_set_antenna(int argc, char **argv) +{ + struct ble_hci_vs_set_antenna_cp cmd; + int rc; + + rc = parse_arg_all(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + cmd.antenna = parse_arg_uint8_dflt("antenna", 0, &rc); + if (rc != 0 || ((cmd.antenna > 2))) { + console_printf("invalid 'antenna' parameter\n"); + return rc; + } + + rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_SET_ANTENNA, &cmd, sizeof(cmd), + NULL, 0); + if (rc) { + console_printf("failed to set antenna\n"); + return rc; + } + + console_printf("Antenna set to %u\n", cmd.antenna); + return 0; +} + +#define BLE_HCI_OCF_VS_TEST_CARRIER (0x0020) + +static bool tx_carrier_running = false; + +static int +cmd_tx_carrier(int argc, char **argv) +{ + uint8_t cmd[2]; + int rc; + + rc = parse_arg_all(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + if (tx_carrier_running) { + console_printf("TX carrier already started\n"); + return 0; + } + + cmd[0] = 1; + cmd[1] = parse_arg_uint8("channel", &rc); + if ((rc != 0) || (cmd[1] > 39)) { + console_printf("invalid channel\n"); + return rc; + } + + rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_TEST_CARRIER, &cmd, sizeof(cmd), + NULL, 0); + if (rc) { + console_printf("failed to start TX carrier\n"); + return rc; + } + + console_printf("TX carrier started\n"); + tx_carrier_running = true; + return 0; +} + +static int +cmd_stop_carrier(int argc, char **argv) +{ + uint8_t cmd[2]; + int rc; + + rc = parse_arg_all(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + if (!tx_carrier_running) { + console_printf("TX carrier not started\n"); + return 0; + } + cmd[0] = 0; + cmd[1] = 0; + + rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_TEST_CARRIER, &cmd, sizeof(cmd), + NULL, 0); + if (rc) { + console_printf("failed to stop TX carrier\n"); + return rc; + } + + console_printf("TX carrier stopped\n"); + tx_carrier_running = false; + return 0; +} + +static const struct shell_param cmd_rx_test_params[] = { + {"channel", "RX channel, usage: =[0-39]"}, + {"phy", "usage: =[1M|2M], default: 1M"}, + {"modulation_index", "usage: =[standard|stable], default=standard"}, + {NULL} +}; + +static const struct shell_cmd_help cmd_rx_test_help = { + .summary = "start DTM RX test", + .usage = NULL, + .params = cmd_rx_test_params, +}; + +static const struct shell_param cmd_tx_test_params[] = { + {"channel", "RX channel, usage: =[0-39]"}, + {"phy", "usage: =[1M|2M], default: 1M"}, + {"data_length", "usage: =[0-255], default: 0"}, + {"payload", "usage: =[0-7]"}, + {NULL} +}; + +static const struct shell_cmd_help cmd_tx_test_help = { + .summary = "start DTM TX test", + .usage = NULL, + .params = cmd_tx_test_params, +}; + +static const struct shell_cmd_help cmd_stop_test_help = { + .summary = "stop DTM test", + .usage = NULL, + .params = NULL, +}; + +static const struct shell_param cmd_tx_power_params[] = { + {"power", "usage: =[-127-127], default: 127"}, + {NULL} +}; + +static const struct shell_cmd_help cmd_tx_power_help = { + .summary = "set TX power", + .usage = NULL, + .params = cmd_tx_power_params, +}; + +static const struct shell_param cmd_set_antenna_params[] = { + {"antenna", "usage: =[0,1,2], default: 0"}, + {NULL} +}; + +static const struct shell_cmd_help cmd_set_antenna_help = { + .summary = "set active antenna ", + .usage = NULL, + .params = cmd_set_antenna_params, +}; + +static const struct shell_param cmd_tx_carrier_params[] = { + {"channel", "TX channel, usage: =[0-39]"}, + {NULL} +}; + +static const struct shell_cmd_help cmd_tx_carrier_help = { + .summary = "TX unmodulated carrier", + .usage = NULL, + .params = cmd_tx_carrier_params, +}; + +static const struct shell_cmd_help cmd_stop_carrier_help = { + .summary = "stop TX unmodulated carrier", + .usage = NULL, + .params = NULL, +}; + +static const struct shell_cmd dtm_commands[] = { + { + .sc_cmd = "rx-test", + .sc_cmd_func = cmd_rx_test, + .help = &cmd_rx_test_help, + }, + { + .sc_cmd = "tx-test", + .sc_cmd_func = cmd_tx_test, + .help = &cmd_tx_test_help, + }, + { + .sc_cmd = "stop-test", + .sc_cmd_func = cmd_stop_test, + .help = &cmd_stop_test_help, + }, + { + .sc_cmd = "tx-power", + .sc_cmd_func = cmd_tx_power, + .help = &cmd_tx_power_help, + }, + { + .sc_cmd = "set-antenna", + .sc_cmd_func = cmd_set_antenna, + .help = &cmd_set_antenna_help, + }, + { + .sc_cmd = "tx-carrier", + .sc_cmd_func = cmd_tx_carrier, + .help = &cmd_tx_carrier_help, + }, + { + .sc_cmd = "stop-carrier", + .sc_cmd_func = cmd_stop_carrier, + .help = &cmd_stop_carrier_help, + }, + { } +}; + +static void +on_sync(void) +{ + console_printf("Host and controller synced\n"); +} + +static void +on_reset(int reason) +{ + console_printf("Error: Resetting state; reason=%d\n", reason); +} + +int +main(void) +{ + struct image_version the_version; + char prompt[50]; + + sysinit(); + + img_mgmt_read_info(0, &the_version, NULL, NULL); + + snprintf(prompt, sizeof(prompt), "dtm_%u.%u.%u", + the_version.iv_major, the_version.iv_minor, the_version.iv_revision); + + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = on_reset; + ble_hs_cfg.sync_cb = on_sync; + + shell_register(prompt, dtm_commands); + shell_register_default_module(prompt); + + while (1) { + os_eventq_run(os_eventq_dflt_get()); + } + + return 0; +} diff --git a/lib/bt/host/nimble/nimble/apps/dtm/src/parse.c b/lib/bt/host/nimble/nimble/apps/dtm/src/parse.c new file mode 100644 index 00000000..ed79d740 --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/dtm/src/parse.c @@ -0,0 +1,529 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "console/console.h" + +#define CMD_MAX_ARGS 16 + +static char *cmd_args[CMD_MAX_ARGS][2]; +static int cmd_num_args; + +int +parse_arg_find_idx(const char *key) +{ + int i; + + for (i = 0; i < cmd_num_args; i++) { + if (strcmp(cmd_args[i][0], key) == 0) { + return i; + } + } + + return -1; +} + +char * +parse_arg_peek(const char *key) +{ + int i; + + for (i = 0; i < cmd_num_args; i++) { + if (strcmp(cmd_args[i][0], key) == 0) { + return cmd_args[i][1]; + } + } + + return NULL; +} + +char * +parse_arg_extract(const char *key) +{ + int i; + + for (i = 0; i < cmd_num_args; i++) { + if (strcmp(cmd_args[i][0], key) == 0) { + /* Erase parameter. */ + cmd_args[i][0][0] = '\0'; + + return cmd_args[i][1]; + } + } + + return NULL; +} + +/** + * Determines which number base to use when parsing the specified numeric + * string. This just avoids base '0' so that numbers don't get interpreted as + * octal. + */ +static int +parse_arg_long_base(char *sval) +{ + if (sval[0] == '0' && sval[1] == 'x') { + return 0; + } else { + return 10; + } +} + +long +parse_long_bounds(char *sval, long min, long max, int *out_status) +{ + char *endptr; + long lval; + + lval = strtol(sval, &endptr, parse_arg_long_base(sval)); + if (sval[0] != '\0' && *endptr == '\0' && + lval >= min && lval <= max) { + + *out_status = 0; + return lval; + } + + *out_status = EINVAL; + return 0; +} + +long +parse_arg_long_bounds_peek(char *name, long min, long max, int *out_status) +{ + char *sval; + + sval = parse_arg_peek(name); + if (sval == NULL) { + *out_status = ENOENT; + return 0; + } + return parse_long_bounds(sval, min, max, out_status); +} + +long +parse_arg_long_bounds(char *name, long min, long max, int *out_status) +{ + char *sval; + + sval = parse_arg_extract(name); + if (sval == NULL) { + *out_status = ENOENT; + return 0; + } + return parse_long_bounds(sval, min, max, out_status); +} + +long +parse_arg_long_bounds_dflt(char *name, long min, long max, + long dflt, int *out_status) +{ + long val; + int rc; + + val = parse_arg_long_bounds(name, min, max, &rc); + if (rc == ENOENT) { + rc = 0; + val = dflt; + } + + *out_status = rc; + + return val; +} + +uint64_t +parse_arg_uint64_bounds(char *name, uint64_t min, uint64_t max, int *out_status) +{ + char *endptr; + char *sval; + uint64_t lval; + + sval = parse_arg_extract(name); + if (sval == NULL) { + *out_status = ENOENT; + return 0; + } + + lval = strtoull(sval, &endptr, parse_arg_long_base(sval)); + if (sval[0] != '\0' && *endptr == '\0' && + lval >= min && lval <= max) { + + *out_status = 0; + return lval; + } + + *out_status = EINVAL; + return 0; +} + +long +parse_arg_long(char *name, int *out_status) +{ + return parse_arg_long_bounds(name, LONG_MIN, LONG_MAX, out_status); +} + +uint8_t +parse_arg_bool(char *name, int *out_status) +{ + return parse_arg_long_bounds(name, 0, 1, out_status); +} + +uint8_t +parse_arg_bool_dflt(char *name, uint8_t dflt, int *out_status) +{ + return parse_arg_long_bounds_dflt(name, 0, 1, dflt, out_status); +} + +uint8_t +parse_arg_uint8(char *name, int *out_status) +{ + return parse_arg_long_bounds(name, 0, UINT8_MAX, out_status); +} + +uint16_t +parse_arg_uint16(char *name, int *out_status) +{ + return parse_arg_long_bounds(name, 0, UINT16_MAX, out_status); +} + +uint16_t +parse_arg_uint16_peek(char *name, int *out_status) +{ + return parse_arg_long_bounds_peek(name, 0, UINT16_MAX, out_status); +} + +uint32_t +parse_arg_uint32(char *name, int *out_status) +{ + return parse_arg_uint64_bounds(name, 0, UINT32_MAX, out_status); +} + +uint64_t +parse_arg_uint64(char *name, int *out_status) +{ + return parse_arg_uint64_bounds(name, 0, UINT64_MAX, out_status); +} + +uint8_t +parse_arg_uint8_dflt(char *name, uint8_t dflt, int *out_status) +{ + uint8_t val; + int rc; + + val = parse_arg_uint8(name, &rc); + if (rc == ENOENT) { + val = dflt; + rc = 0; + } + + *out_status = rc; + return val; +} + +uint16_t +parse_arg_uint16_dflt(char *name, uint16_t dflt, int *out_status) +{ + uint16_t val; + int rc; + + val = parse_arg_uint16(name, &rc); + if (rc == ENOENT) { + val = dflt; + rc = 0; + } + + *out_status = rc; + return val; +} + +uint32_t +parse_arg_uint32_dflt(char *name, uint32_t dflt, int *out_status) +{ + uint32_t val; + int rc; + + val = parse_arg_uint32(name, &rc); + if (rc == ENOENT) { + val = dflt; + rc = 0; + } + + *out_status = rc; + return val; +} + +static uint32_t +parse_time_unit_mult(const char *str) +{ + if (!strcasecmp(str, "us")) { + return 1; + } else if (!strcasecmp(str, "ms")) { + return 1000; + } else if (!strcasecmp(str, "s")) { + return 1000000; + } + + return 0; +} + +static uint32_t +parse_time_us(const char *str, int *out_status) +{ + uint32_t val = 0; + uint32_t val_div = 1; + uint32_t val_mult = 1; + uint32_t val_us; + + while (isdigit((unsigned char)*str)) { + val *= 10; + val += *str - '0'; + str++; + } + + if (*str == '.') { + str++; + while (isdigit((unsigned char)*str)) { + val *= 10; + val += *str - '0'; + val_div *= 10; + str++; + } + } + + val_mult = parse_time_unit_mult(str); + if (val_mult == 0) { + *out_status = EINVAL; + return 0; + } + + if (val_mult > val_div) { + val_us = val * (val_mult / val_div); + } else { + val_us = val * (val_div / val_mult); + } + + *out_status = 0; + + return val_us; +} + +uint32_t +parse_arg_time_dflt(char *name, int step_us, uint32_t dflt, int *out_status) +{ + const char *arg; + uint32_t val; + int rc; + + arg = parse_arg_peek(name); + if (!arg) { + *out_status = 0; + return dflt; + } + + val = parse_time_us(arg, &rc); + if (rc) { + val = parse_arg_uint32(name, &rc); + if (rc == ENOENT) { + *out_status = 0; + return dflt; + } + } else { + val /= step_us; + parse_arg_extract(name); + } + + *out_status = rc; + return val; +} + +const struct kv_pair * +parse_kv_find(const struct kv_pair *kvs, char *name) +{ + const struct kv_pair *kv; + int i; + + for (i = 0; kvs[i].key != NULL; i++) { + kv = kvs + i; + if (strcmp(name, kv->key) == 0) { + return kv; + } + } + + return NULL; +} + +int +parse_arg_kv(char *name, const struct kv_pair *kvs, int *out_status) +{ + const struct kv_pair *kv; + char *sval; + + sval = parse_arg_extract(name); + if (sval == NULL) { + *out_status = ENOENT; + return -1; + } + + kv = parse_kv_find(kvs, sval); + if (kv == NULL) { + *out_status = EINVAL; + return -1; + } + + *out_status = 0; + return kv->val; +} + +int +parse_arg_kv_dflt(char *name, const struct kv_pair *kvs, int def_val, + int *out_status) +{ + int val; + int rc; + + val = parse_arg_kv(name, kvs, &rc); + if (rc == ENOENT) { + rc = 0; + val = def_val; + } + + *out_status = rc; + + return val; +} + + +static int +parse_arg_byte_stream_delim(char *sval, char *delims, int max_len, + uint8_t *dst, int *out_len) +{ + unsigned long ul; + char *endptr; + char *token; + int i; + char *tok_ptr; + + i = 0; + for (token = strtok_r(sval, delims, &tok_ptr); + token != NULL; + token = strtok_r(NULL, delims, &tok_ptr)) { + + if (i >= max_len) { + return EINVAL; + } + + ul = strtoul(token, &endptr, 16); + if (sval[0] == '\0' || *endptr != '\0' || ul > UINT8_MAX) { + return -1; + } + + dst[i] = ul; + i++; + } + + *out_len = i; + + return 0; +} + +int +parse_arg_byte_stream(char *name, int max_len, uint8_t *dst, int *out_len) +{ + char *sval; + + sval = parse_arg_extract(name); + if (sval == NULL) { + return ENOENT; + } + + return parse_arg_byte_stream_delim(sval, ":-", max_len, dst, out_len); +} + +int +parse_arg_uint8_list_with_separator(char *name, char *separator, int max_len, + uint8_t *dst, int *out_len) +{ + char *sval; + + sval = parse_arg_extract(name); + if (sval == NULL) { + return ENOENT; + } + + return parse_arg_byte_stream_delim(sval, separator, max_len, dst, out_len); +} + +int +parse_arg_byte_stream_exact_length(char *name, uint8_t *dst, int len) +{ + int actual_len; + int rc; + + rc = parse_arg_byte_stream(name, len, dst, &actual_len); + if (rc != 0) { + return rc; + } + + if (actual_len != len) { + return EINVAL; + } + + return 0; +} + +int +parse_arg_all(int argc, char **argv) +{ + char *key; + char *val; + int i; + char *tok_ptr; + + cmd_num_args = 0; + + for (i = 0; i < argc; i++) { + key = strtok_r(argv[i], "=", &tok_ptr); + val = strtok_r(NULL, "=", &tok_ptr); + + if (key != NULL && val != NULL) { + if (strlen(key) == 0) { + console_printf("Error: invalid argument: %s\n", argv[i]); + return -1; + } + + if (cmd_num_args >= CMD_MAX_ARGS) { + console_printf("Error: too many arguments"); + return -1; + } + + cmd_args[cmd_num_args][0] = key; + cmd_args[cmd_num_args][1] = val; + cmd_num_args++; + } + } + + return 0; +} diff --git a/lib/bt/host/nimble/nimble/apps/dtm/src/parse.h b/lib/bt/host/nimble/nimble/apps/dtm/src/parse.h new file mode 100644 index 00000000..a0255d36 --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/dtm/src/parse.h @@ -0,0 +1,58 @@ +/* + * 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 PARSE_H +#define PARSE_H + +#include + +struct kv_pair { + char *key; + int val; +}; + +uint32_t parse_arg_time_dflt(char *name, int step, uint32_t dflt, int *out_status); +const struct kv_pair *parse_kv_find(const struct kv_pair *kvs, char *name); +int parse_arg_find_idx(const char *key); +char *parse_arg_extract(const char *key); +long parse_arg_long_bounds(char *name, long min, long max, int *out_status); +long parse_arg_long_bounds_dflt(char *name, long min, long max, + long dflt, int *out_status); +uint64_t parse_arg_uint64_bounds(char *name, uint64_t min, + uint64_t max, int *out_status); +long parse_arg_long(char *name, int *staus); +uint8_t parse_arg_bool(char *name, int *status); +uint8_t parse_arg_bool_dflt(char *name, uint8_t dflt, int *out_status); +uint8_t parse_arg_uint8(char *name, int *status); +uint8_t parse_arg_uint8_dflt(char *name, uint8_t dflt, int *out_status); +uint16_t parse_arg_uint16(char *name, int *status); +uint16_t parse_arg_uint16_dflt(char *name, uint16_t dflt, int *out_status); +uint32_t parse_arg_uint32(char *name, int *out_status); +uint32_t parse_arg_uint32_dflt(char *name, uint32_t dflt, int *out_status); +uint64_t parse_arg_uint64(char *name, int *out_status); +int parse_arg_kv(char *name, const struct kv_pair *kvs, int *out_status); +int parse_arg_kv_dflt(char *name, const struct kv_pair *kvs, int def_val, + int *out_status); +int parse_arg_byte_stream(char *name, int max_len, uint8_t *dst, int *out_len); +int parse_arg_uint8_list_with_separator(char *name, char *separator, int max_len, + uint8_t *dst, int *out_len); +int parse_arg_byte_stream_exact_length(char *name, uint8_t *dst, int len); +int parse_arg_all(int argc, char **argv); + +#endif diff --git a/lib/bt/host/nimble/nimble/apps/dtm/syscfg.yml b/lib/bt/host/nimble/nimble/apps/dtm/syscfg.yml new file mode 100644 index 00000000..b88c387a --- /dev/null +++ b/lib/bt/host/nimble/nimble/apps/dtm/syscfg.yml @@ -0,0 +1,28 @@ +# 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. + +syscfg.vals: + # Enable the shell task. + SHELL_TASK: 1 + SHELL_CMD_HELP: 1 + CONSOLE_HISTORY: ram + CONSOLE_HISTORY_RAM_HISTORY_SIZE: 50 + + BLE_LL_DTM: 1 + BLE_LL_DTM_EXTENSIONS: 1 + BLE_LL_CFG_FEAT_LE_2M_PHY: 1 + BLE_LL_CFG_FEAT_LE_CODED_PHY: 1 diff --git a/lib/bt/host/nimble/nimble/apps/ext_advertiser/pkg.yml b/lib/bt/host/nimble/nimble/apps/ext_advertiser/pkg.yml index 32df4efc..baf1ea0b 100644 --- a/lib/bt/host/nimble/nimble/apps/ext_advertiser/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/ext_advertiser/pkg.yml @@ -31,8 +31,8 @@ pkg.deps: - nimble/host/services/gatt - nimble/host/store/config - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/sysinit" - "@apache-mynewt-core/sys/id" diff --git a/lib/bt/host/nimble/nimble/apps/ext_advertiser/src/main.c b/lib/bt/host/nimble/nimble/apps/ext_advertiser/src/main.c index 9cb6c6fe..ec7649ef 100644 --- a/lib/bt/host/nimble/nimble/apps/ext_advertiser/src/main.c +++ b/lib/bt/host/nimble/nimble/apps/ext_advertiser/src/main.c @@ -421,7 +421,7 @@ static void start_periodic(void) ble_addr_t addr; int rc; - /* For periodic we use nstance with non-connectable advertising */ + /* For periodic we use instance with non-connectable advertising */ memset (¶ms, 0, sizeof(params)); /* advertise using random addr */ diff --git a/lib/bt/host/nimble/nimble/apps/ext_advertiser/syscfg.yml b/lib/bt/host/nimble/nimble/apps/ext_advertiser/syscfg.yml index f157ab82..410433fd 100644 --- a/lib/bt/host/nimble/nimble/apps/ext_advertiser/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/ext_advertiser/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Disable not used GAP roles (we only do non-connectable # advertising here) BLE_ROLE_BROADCASTER: 1 diff --git a/lib/bt/host/nimble/nimble/apps/mesh_badge/pkg.yml b/lib/bt/host/nimble/nimble/apps/mesh_badge/pkg.yml index d1276a51..238104d7 100644 --- a/lib/bt/host/nimble/nimble/apps/mesh_badge/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/mesh_badge/pkg.yml @@ -26,10 +26,10 @@ pkg.deps: - "@apache-mynewt-core/hw/drivers/display/cfb" - "@apache-mynewt-core/hw/drivers/display/ssd1673" - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/shell" - nimble/host - nimble/host/services/gap diff --git a/lib/bt/host/nimble/nimble/apps/mesh_badge/syscfg.yml b/lib/bt/host/nimble/nimble/apps/mesh_badge/syscfg.yml index 2b8f457d..81f1d75f 100644 --- a/lib/bt/host/nimble/nimble/apps/mesh_badge/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/mesh_badge/syscfg.yml @@ -19,6 +19,10 @@ # Package: apps/mesh_badge syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Enable the shell task. SHELL_TASK: 1 diff --git a/lib/bt/host/nimble/nimble/apps/peripheral/pkg.yml b/lib/bt/host/nimble/nimble/apps/peripheral/pkg.yml index d5c862c8..82ff496a 100644 --- a/lib/bt/host/nimble/nimble/apps/peripheral/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/peripheral/pkg.yml @@ -25,9 +25,9 @@ pkg.author: "Krzysztof Kopyściński krzysztof.kopyscinski@codecoup.pl" pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util/" diff --git a/lib/bt/host/nimble/nimble/apps/peripheral/src/main.c b/lib/bt/host/nimble/nimble/apps/peripheral/src/main.c index f22579a7..28e8afb1 100755 --- a/lib/bt/host/nimble/nimble/apps/peripheral/src/main.c +++ b/lib/bt/host/nimble/nimble/apps/peripheral/src/main.c @@ -50,6 +50,7 @@ adv_event(struct ble_gap_event *event, void *arg) MODLOG_DFLT(INFO, "connection %s; status=%d\n", event->connect.status == 0 ? "established" : "failed", event->connect.status); + conn_handle = event->connect.conn_handle; break; case BLE_GAP_EVENT_CONN_UPDATE_REQ: /* connected device requests update of connection parameters, diff --git a/lib/bt/host/nimble/nimble/apps/peripheral/syscfg.yml b/lib/bt/host/nimble/nimble/apps/peripheral/syscfg.yml index 0b954231..891ce0f5 100644 --- a/lib/bt/host/nimble/nimble/apps/peripheral/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/peripheral/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + BLE_ROLE_BROADCASTER: 1 BLE_ROLE_CENTRAL: 0 BLE_ROLE_OBSERVER: 0 diff --git a/lib/bt/host/nimble/nimble/apps/scanner/pkg.yml b/lib/bt/host/nimble/nimble/apps/scanner/pkg.yml index 442ab9db..5e17add1 100644 --- a/lib/bt/host/nimble/nimble/apps/scanner/pkg.yml +++ b/lib/bt/host/nimble/nimble/apps/scanner/pkg.yml @@ -25,9 +25,9 @@ pkg.author: "Krzysztof Kopyściński " pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util/" diff --git a/lib/bt/host/nimble/nimble/apps/scanner/syscfg.yml b/lib/bt/host/nimble/nimble/apps/scanner/syscfg.yml index 568a2c6b..75d9dff2 100644 --- a/lib/bt/host/nimble/nimble/apps/scanner/syscfg.yml +++ b/lib/bt/host/nimble/nimble/apps/scanner/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + BLE_ROLE_BROADCASTER: 0 BLE_ROLE_CENTRAL: 0 BLE_ROLE_OBSERVER: 1 diff --git a/lib/bt/host/nimble/nimble/babblesim/core/src/cmsis.c b/lib/bt/host/nimble/nimble/babblesim/core/src/cmsis.c index 9beb3290..1ac6b241 100644 --- a/lib/bt/host/nimble/nimble/babblesim/core/src/cmsis.c +++ b/lib/bt/host/nimble/nimble/babblesim/core/src/cmsis.c @@ -9,7 +9,6 @@ #include #include "irq_ctrl.h" -#include "irq_sources.h" #include #include "cmsis.h" #include "os/sim.h" diff --git a/lib/bt/host/nimble/nimble/babblesim/core/src/irq_handler.c b/lib/bt/host/nimble/nimble/babblesim/core/src/irq_handler.c index f72aaf24..05eb881a 100644 --- a/lib/bt/host/nimble/nimble/babblesim/core/src/irq_handler.c +++ b/lib/bt/host/nimble/nimble/babblesim/core/src/irq_handler.c @@ -8,7 +8,6 @@ #include #include "irq_ctrl.h" -#include "irq_sources.h" #include "os/sim.h" static int currently_running_irq = -1; @@ -23,6 +22,12 @@ extern void (* const systemVectors[256])(void); * handler and therefore its priority handling */ +int +os_arch_in_isr(void) +{ + return currently_running_irq >= 0; +} + void posix_interrupt_raised(void) { uint64_t irq_lock; diff --git a/lib/bt/host/nimble/nimble/babblesim/edtt/hci_transport/src/ble_hci_edtt.c b/lib/bt/host/nimble/nimble/babblesim/edtt/hci_transport/src/ble_hci_edtt.c index aa70f056..5f84fa7b 100644 --- a/lib/bt/host/nimble/nimble/babblesim/edtt/hci_transport/src/ble_hci_edtt.c +++ b/lib/bt/host/nimble/nimble/babblesim/edtt/hci_transport/src/ble_hci_edtt.c @@ -142,7 +142,7 @@ ble_hci_edtt_cmdevt_tx(uint8_t *hci_ev, uint8_t edtt_type) * A BLE_ERR_[...] error code on failure. */ int -ble_transport_to_hs_evt(void *buf) +ble_transport_to_hs_evt_impl(void *buf) { return ble_hci_edtt_cmdevt_tx(buf, BLE_HCI_EDTT_EVT); } @@ -156,11 +156,17 @@ ble_transport_to_hs_evt(void *buf) * A BLE_ERR_[...] error code on failure. */ int -ble_transport_to_hs_acl(struct os_mbuf *om) +ble_transport_to_hs_acl_impl(struct os_mbuf *om) { return ble_hci_edtt_acl_tx(om); } +void +ble_transport_hs_init(void) +{ + +} + /** * @brief Clean out excess bytes from the input buffer */ diff --git a/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/include/os/os_arch.h b/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/include/os/os_arch.h index 32bc97bc..574f1e81 100644 --- a/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/include/os/os_arch.h +++ b/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/include/os/os_arch.h @@ -48,11 +48,8 @@ void os_arch_frame_init(struct stack_frame *sf); #define OS_IDLE_STACK_SIZE (4000) #endif -static inline int -os_arch_in_isr(void) -{ - return hw_irq_ctrl_get_irq_status(); -} +/* Implemented in irq_handler */ +int os_arch_in_isr(void); /* Include common arch definitions and APIs */ #include "os/arch/common.h" diff --git a/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c b/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c index 8277ae7c..b545688c 100644 --- a/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c +++ b/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c @@ -148,7 +148,7 @@ os_arch_restore_sr(os_sr_t osr) { hw_irq_ctrl_change_lock(osr); - if (!osr && bsim_pend_sv) { + if (!osr && bsim_pend_sv && !os_arch_in_isr()) { do_ctx_sw(); } } diff --git a/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/syscfg.yml b/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/syscfg.yml index 5a45e9d0..e5733dd5 100644 --- a/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/syscfg.yml +++ b/lib/bt/host/nimble/nimble/babblesim/hw/bsp/nrf52_bsim/syscfg.yml @@ -17,6 +17,7 @@ # syscfg.defs: + BABBLESIM: 1 BSP_NRF52: description: 'Set to indicate that BSP has NRF52' value: 1 @@ -72,3 +73,4 @@ syscfg.vals.BLE_CONTROLLER: OS_CPUTIME_FREQ: 32768 OS_CPUTIME_TIMER_NUM: 5 BLE_LL_RFMGMT_ENABLE_TIME: 1500 + BLE_LL_STACK_SIZE: 4000 diff --git a/lib/bt/host/nimble/nimble/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml b/lib/bt/host/nimble/nimble/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml index 99e59a26..5e4279b3 100644 --- a/lib/bt/host/nimble/nimble/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml +++ b/lib/bt/host/nimble/nimble/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml @@ -29,4 +29,4 @@ pkg.deps: - "babblesim/core" pkg.deps.BLE_CONTROLLER: - - "@apache-mynewt-nimble/nimble/drivers/nrf52" + - "@apache-mynewt-nimble/nimble/drivers/nrf5x" diff --git a/lib/bt/host/nimble/nimble/babblesim/sdk/scripts/link_babblesim.sh b/lib/bt/host/nimble/nimble/babblesim/sdk/scripts/link_babblesim.sh index 9254a18a..1c069eb3 100755 --- a/lib/bt/host/nimble/nimble/babblesim/sdk/scripts/link_babblesim.sh +++ b/lib/bt/host/nimble/nimble/babblesim/sdk/scripts/link_babblesim.sh @@ -22,7 +22,7 @@ if [ -z ${BSIM_COMPONENTS_PATH+x} ]; then echo "This board requires the BabbleSim simulator. Please set" \ "the environment variable BSIM_COMPONENTS_PATH to point to its components" \ "folder. More information can be found in" \ - "https://babblesim.github.io/folder_structure_and_env.html" + "https://babblesim.github.io/folder_structure_and_env.html" 1>&2 exit 1 fi @@ -30,7 +30,7 @@ if [ -z ${BSIM_OUT_PATH+x} ]; then echo "This board requires the BabbleSim simulator. Please set" \ "the environment variable BSIM_OUT_PATH to point to the folder where the" \ "simulator is compiled to. More information can be found in" \ - "https://babblesim.github.io/folder_structure_and_env.html" + "https://babblesim.github.io/folder_structure_and_env.html" 1>&2 exit 1 fi diff --git a/lib/bt/host/nimble/nimble/babblesim/targets/blehci/syscfg.yml b/lib/bt/host/nimble/nimble/babblesim/targets/blehci/syscfg.yml index aec4c4a4..14a909e9 100644 --- a/lib/bt/host/nimble/nimble/babblesim/targets/blehci/syscfg.yml +++ b/lib/bt/host/nimble/nimble/babblesim/targets/blehci/syscfg.yml @@ -18,4 +18,4 @@ syscfg.vals: BLE_LL_PUBLIC_DEV_ADDR: 0xbabb1e000001 - BLE_HCI_TRANSPORT: uart + BLE_HCI_TRANSPORT_HS: uart diff --git a/lib/bt/host/nimble/nimble/babblesim/targets/edtthci/syscfg.yml b/lib/bt/host/nimble/nimble/babblesim/targets/edtthci/syscfg.yml index 972659e3..0476ccf3 100644 --- a/lib/bt/host/nimble/nimble/babblesim/targets/edtthci/syscfg.yml +++ b/lib/bt/host/nimble/nimble/babblesim/targets/edtthci/syscfg.yml @@ -26,6 +26,7 @@ syscfg.vals: EDTT_HCI_LOG_FILE: ("hci_logs") EDTT_HCI_LOGS: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 0 BLE_LL_CFG_FEAT_LE_ENCRYPTION: 1 BLE_LL_CFG_FEAT_CONN_PARAM_REQ: 1 BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG: 1 @@ -47,7 +48,6 @@ syscfg.vals: BLE_ROLE_OBSERVER: 1 BLE_VERSION: 52 - BLE_CONTROLLER: 1 BLE_LL_ROLE_CENTRAL: 1 BLE_LL_ROLE_PERIPHERAL: 1 BLE_LL_ROLE_BROADCASTER: 1 diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_fem.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_fem.h new file mode 100644 index 00000000..bd0b93e1 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_fem.h @@ -0,0 +1,63 @@ +/* + * 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 H_BLE_FEM_ +#define H_BLE_FEM_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_FEM_PA) +void ble_fem_pa_init(void); +void ble_fem_pa_enable(void); +void ble_fem_pa_disable(void); +#if MYNEWT_VAL(BLE_FEM_PA_GAIN_TUNABLE) +/* Configures FEM to selected TX power and returns expected PHY TX power */ +int ble_fem_pa_tx_power_set(int tx_power); + +/* returns rounded FEM TX power */ +int ble_fem_pa_tx_power_round(int tx_power); +#endif +#endif + +#if MYNEWT_VAL(BLE_FEM_LNA) +void ble_fem_lna_init(void); +void ble_fem_lna_enable(void); +void ble_fem_lna_disable(void); + +#if MYNEWT_VAL(BLE_FEM_LNA_GAIN_TUNABLE) +/* Return current value of FEM LNA RX gain (in dBm) */ +int ble_fem_lna_rx_gain(void); +#endif + +#endif + +#if MYNEWT_VAL(BLE_FEM_ANTENNA) +/* 0 sets default antenna, any other value is FEM specific */ +int ble_fem_antenna(uint8_t antenna); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_FEM_ */ diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll.h index 7136852d..408f03b6 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll.h @@ -107,8 +107,8 @@ struct ble_ll_obj uint8_t ll_state; /* Global channel map */ - uint8_t chan_map_num_used; uint8_t chan_map[BLE_LL_CHAN_MAP_LEN]; + uint8_t chan_map_used; #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* Number of ACL data packets supported */ @@ -118,6 +118,11 @@ struct ble_ll_obj uint16_t ll_acl_pkt_size; #endif +#if MYNEWT_VAL(BLE_LL_ISO) + uint8_t ll_num_iso_pkts; + uint16_t ll_iso_pkt_size; +#endif + /* Preferred PHY's */ uint8_t ll_pref_tx_phys; uint8_t ll_pref_rx_phys; @@ -237,6 +242,12 @@ extern STATS_SECT_DECL(ble_ll_stats) ble_ll_stats; #if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) #define BLE_LL_STATE_SCAN_AUX (7) #endif +#if MYNEWT_VAL(BLE_LL_EXT) +#define BLE_LL_STATE_EXTERNAL (8) +#endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +#define BLE_LL_STATE_BIG (9) +#endif /* LL Features */ #define BLE_LL_FEAT_LE_ENCRYPTION (0x0000000001) @@ -289,11 +300,16 @@ extern STATS_SECT_DECL(ble_ll_stats) ble_ll_stats; #define BLE_LL_CONN_CLEAR_FEATURE(connsm, feature) (connsm->conn_features &= ~(feature)) /* All the features which can be controlled by the Host */ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) #define BLE_LL_HOST_CONTROLLED_FEATURES (BLE_LL_FEAT_CONN_SUBRATING_HOST) +#else +#define BLE_LL_HOST_CONTROLLED_FEATURES (0) +#endif /* LL timing */ #define BLE_LL_IFS (150) /* usecs */ #define BLE_LL_MAFS (300) /* usecs */ +#define BLE_LL_MSS (150) /* usecs */ /* * BLE LL device address. Note that element 0 of the array is the LSB and @@ -328,6 +344,27 @@ struct ble_dev_addr #define BLE_LL_MAX_PDU_LEN ((BLE_LL_PDU_HDR_LEN) + (BLE_LL_MAX_PAYLOAD_LEN)) #define BLE_LL_CRCINIT_ADV (0x555555) +#define BLE_LL_CONN_HANDLE(t, h) ((((t) << 8) & BLE_LL_CONN_HANDLE_TYPE_MASK) | \ + ((h) & BLE_LL_CONN_HANDLE_IDX_MASK)) +#define BLE_LL_CONN_HANDLE_TYPE_MASK (0x0700) +#define BLE_LL_CONN_HANDLE_IDX_MASK (0x00ff) +#define BLE_LL_CONN_HANDLE_TYPE(conn_h) (((conn_h) & BLE_LL_CONN_HANDLE_TYPE_MASK) >> 8) +#define BLE_LL_CONN_HANDLE_IDX(conn_h) ((conn_h) & BLE_LL_CONN_HANDLE_IDX_MASK) + +#define BLE_LL_CONN_HANDLE_TYPE_ACL (0x00) +#define BLE_LL_CONN_HANDLE_TYPE_CIS (0x01) +#define BLE_LL_CONN_HANDLE_TYPE_BIS (0x02) +#define BLE_LL_CONN_HANDLE_TYPE_BIS_SYNC (0x03) + +#define BLE_LL_CONN_HANDLE_IS_ACL(ch) \ + (BLE_LL_CONN_HANDLE_TYPE(ch) == BLE_LL_CONN_HANDLE_TYPE_ACL) +#define BLE_LL_CONN_HANDLE_IS_CIS(ch) \ + (BLE_LL_CONN_HANDLE_TYPE(ch) == BLE_LL_CONN_HANDLE_TYPE_CIS) +#define BLE_LL_CONN_HANDLE_IS_BIS(ch) \ + (BLE_LL_CONN_HANDLE_TYPE(ch) == BLE_LL_CONN_HANDLE_TYPE_BIS) +#define BLE_LL_CONN_HANDLE_IS_BIS_SYNC(ch) \ + (BLE_LL_CONN_HANDLE_TYPE(ch) == BLE_LL_CONN_HANDLE_TYPE_BIS_SYNC) + /* Access address for advertising channels */ #define BLE_ACCESS_ADDR_ADV (0x8E89BED6) @@ -468,6 +505,7 @@ struct ble_dev_addr /* ACAD data types */ #define BLE_LL_ACAD_CHANNEL_MAP_UPDATE_IND 0x28 +#define BLE_LL_ACAD_BIGINFO 0x2C struct ble_ll_acad_channel_map_update_ind { uint8_t map[5]; @@ -488,10 +526,6 @@ int ble_ll_is_valid_random_addr(const uint8_t *addr); int ble_ll_is_valid_own_addr_type(uint8_t own_addr_type, const uint8_t *random_addr); -/* Calculate the amount of time in microseconds a PDU with payload length of - * 'payload_len' will take to transmit on a PHY 'phy_mode'. */ -uint32_t ble_ll_pdu_tx_time_get(uint16_t payload_len, int phy_mode); - /* Calculate maximum octets of PDU payload which can be transmitted during * 'usecs' on a PHY 'phy_mode'. */ uint16_t ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode); @@ -559,8 +593,11 @@ void ble_ll_state_set(uint8_t ll_state); /* Get the link layer state */ uint8_t ble_ll_state_get(void); -/* Send an event to LL task */ -void ble_ll_event_send(struct ble_npl_event *ev); +/* Add an event to LL task */ +void ble_ll_event_add(struct ble_npl_event *ev); + +/* Remove an event from LL task */ +void ble_ll_event_remove(struct ble_npl_event *ev); /* Hand received pdu's to LL task */ void ble_ll_rx_pdu_in(struct os_mbuf *rxpdu); @@ -589,10 +626,6 @@ int ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len); /* Read set of states supported by the Link Layer */ uint64_t ble_ll_read_supp_states(void); -/* Check if octets and time are valid. Returns 0 if not valid */ -int ble_ll_chk_txrx_octets(uint16_t octets); -int ble_ll_chk_txrx_time(uint16_t time); - /* Random numbers */ int ble_ll_rand_init(void); void ble_ll_rand_sample(uint8_t rnum); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_adv.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_adv.h index 4afaadd0..ba17ed5e 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_adv.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_adv.h @@ -199,6 +199,20 @@ int ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len); int ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); +/* Get advertising instance with periodic advertising configured */ +struct ble_ll_adv_sm *ble_ll_adv_sync_get(uint8_t handle); + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +struct ble_ll_iso_big; + +/* Add BIG to periodic advertising instance */ +int ble_ll_adv_sync_big_add(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big); +/* Remove BIG from periodic advertising instance */ +int ble_ll_adv_sync_big_remove(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big); +#endif /* BLE_LL_ISO_BROADCASTER */ + /* Called to notify adv code about RPA rotation */ void ble_ll_adv_rpa_timeout(void); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_conn.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_conn.h index 437d7c25..cb7ad60a 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_conn.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_conn.h @@ -98,44 +98,44 @@ struct ble_ll_conn_enc_data #endif /* Connection state machine flags. */ -union ble_ll_conn_sm_flags { - struct { - uint32_t pkt_rxd:1; - uint32_t terminate_ind_txd:1; - uint32_t terminate_ind_rxd:1; - uint32_t terminate_ind_rxd_acked:1; - uint32_t allow_periph_latency:1; - uint32_t periph_set_last_anchor:1; - uint32_t awaiting_host_reply:1; - uint32_t terminate_started:1; - uint32_t conn_update_sched:1; - uint32_t host_expects_upd_event:1; - uint32_t version_ind_sent:1; - uint32_t rxd_version_ind:1; - uint32_t chanmap_update_scheduled:1; - uint32_t conn_empty_pdu_txd:1; - uint32_t last_txd_md:1; - uint32_t conn_req_txd:1; - uint32_t send_ltk_req:1; - uint32_t encrypted:1; - uint32_t encrypt_chg_sent:1; - uint32_t le_ping_supp:1; - uint32_t csa2_supp:1; - uint32_t host_phy_update: 1; - uint32_t phy_update_sched: 1; - uint32_t ctrlr_phy_update: 1; - uint32_t phy_update_event: 1; - uint32_t peer_phy_update: 1; /* XXX:combine with ctrlr udpate bit? */ - uint32_t aux_conn_req: 1; - uint32_t rxd_features:1; - uint32_t pending_hci_rd_features:1; - uint32_t pending_initiate_dle:1; - uint32_t subrate_trans:1; - uint32_t subrate_ind_txd:1; - uint32_t subrate_host_req:1; - } cfbit; - uint32_t conn_flags; -} __attribute__((packed)); +struct ble_ll_conn_sm_flags { + uint32_t pkt_rxd : 1; + uint32_t last_txd_md : 1; + uint32_t empty_pdu_txd : 1; + uint32_t periph_use_latency : 1; + uint32_t periph_set_last_anchor : 1; + uint32_t csa2 : 1; + uint32_t encrypted : 1; + uint32_t encrypt_ltk_req : 1; + uint32_t encrypt_event_sent : 1; + uint32_t version_ind_txd : 1; + uint32_t version_ind_rxd : 1; + uint32_t features_rxd : 1; + uint32_t features_host_req : 1; + uint32_t terminate_started : 1; + uint32_t terminate_ind_txd : 1; + uint32_t terminate_ind_rxd : 1; + uint32_t terminate_ind_rxd_acked : 1; + uint32_t conn_update_sched : 1; + uint32_t conn_update_use_cp : 1; + uint32_t conn_update_host_w4reply : 1; + uint32_t conn_update_host_w4event : 1; + uint32_t chanmap_update_sched : 1; + uint32_t phy_update_sched : 1; + uint32_t phy_update_self_initiated : 1; + uint32_t phy_update_peer_initiated : 1; + uint32_t phy_update_host_initiated : 1; + uint32_t phy_update_host_w4event : 1; + uint32_t le_ping_supp : 1; +#if MYNEWT_VAL(BLE_LL_CONN_INIT_AUTO_DLE) + uint32_t pending_initiate_dle : 1; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + uint8_t subrate_trans : 1; + uint8_t subrate_ind_txd : 1; + uint8_t subrate_host_req : 1; +#endif +}; /** * Structure used for PHY data inside a connection. @@ -204,7 +204,7 @@ struct ble_ll_conn_subrate_req_params { struct ble_ll_conn_sm { /* Connection state machine flags */ - union ble_ll_conn_sm_flags csmflags; + struct ble_ll_conn_sm_flags flags; /* Current connection handle, state and role */ uint16_t conn_handle; @@ -227,8 +227,10 @@ struct ble_ll_conn_sm uint16_t rem_max_rx_time; uint16_t eff_max_tx_time; uint16_t eff_max_rx_time; + uint16_t ota_max_rx_time; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) uint16_t host_req_max_tx_time; + uint16_t host_req_max_rx_time; #endif #if (BLE_LL_BT5_PHY_SUPPORTED == 1) @@ -238,14 +240,14 @@ struct ble_ll_conn_sm #endif /* Used to calculate data channel index for connection */ - uint8_t chanmap[BLE_LL_CHAN_MAP_LEN]; + uint8_t chan_map[BLE_LL_CHAN_MAP_LEN]; uint8_t req_chanmap[BLE_LL_CHAN_MAP_LEN]; uint16_t chanmap_instant; uint16_t channel_id; /* TODO could be union with hop and last chan used */ uint8_t hop_inc; uint8_t data_chan_index; uint8_t last_unmapped_chan; - uint8_t num_used_chans; + uint8_t chan_map_used; /* Ack/Flow Control */ uint8_t tx_seqnum; /* note: can be 1 bit */ @@ -287,8 +289,7 @@ struct ble_ll_conn_sm /* Connection timing */ uint16_t conn_itvl; uint16_t supervision_tmo; - uint16_t min_ce_len; - uint16_t max_ce_len; + uint32_t max_ce_len_ticks; uint16_t tx_win_off; uint32_t anchor_point; uint8_t anchor_point_usecs; /* XXX: can this be uint8_t ?*/ @@ -310,7 +311,8 @@ struct ble_ll_conn_sm uint16_t subrate_base_event; uint16_t subrate_factor; uint16_t cont_num; - uint16_t last_pdu_event; + uint16_t cont_num_left; + uint8_t has_nonempty_pdu; union { struct ble_ll_conn_subrate_params subrate_trans; @@ -377,6 +379,7 @@ struct ble_ll_conn_sm /* For connection update procedure */ struct ble_ll_conn_upd_req conn_update_req; + uint16_t conn_update_anchor_offset_req; /* XXX: for now, just store them all */ struct ble_ll_conn_params conn_cp; @@ -388,29 +391,13 @@ struct ble_ll_conn_sm #endif #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + SLIST_ENTRY(ble_ll_conn_sm) css_sle; uint16_t css_slot_idx; uint16_t css_slot_idx_pending; uint8_t css_period_idx; #endif }; -/* Flags */ -#define CONN_F_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.conn_update_sched) -#define CONN_F_EMPTY_PDU_TXD(csm) ((csm)->csmflags.cfbit.conn_empty_pdu_txd) -#define CONN_F_LAST_TXD_MD(csm) ((csm)->csmflags.cfbit.last_txd_md) -#define CONN_F_CONN_REQ_TXD(csm) ((csm)->csmflags.cfbit.conn_req_txd) -#define CONN_F_ENCRYPTED(csm) ((csm)->csmflags.cfbit.encrypted) -#define CONN_F_ENC_CHANGE_SENT(csm) ((csm)->csmflags.cfbit.encrypt_chg_sent) -#define CONN_F_LE_PING_SUPP(csm) ((csm)->csmflags.cfbit.le_ping_supp) -#define CONN_F_TERMINATE_STARTED(csm) ((csm)->csmflags.cfbit.terminate_started) -#define CONN_F_CSA2_SUPP(csm) ((csm)->csmflags.cfbit.csa2_supp) -#define CONN_F_HOST_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.host_phy_update) -#define CONN_F_PHY_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.phy_update_sched) -#define CONN_F_CTRLR_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.ctrlr_phy_update) -#define CONN_F_PHY_UPDATE_EVENT(csm) ((csm)->csmflags.cfbit.phy_update_event) -#define CONN_F_PEER_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.peer_phy_update) -#define CONN_F_AUX_CONN_REQ(csm) ((csm)->csmflags.cfbit.aux_conn_req) - /* Role */ #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define CONN_IS_CENTRAL(csm) (csm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) @@ -454,6 +441,9 @@ struct ble_ll_conn_sm *ble_ll_conn_find_by_handle(uint16_t handle); struct ble_ll_conn_sm *ble_ll_conn_find_by_peer_addr(const uint8_t* addr, uint8_t addr_type); +/* Perform channel map update on all connections (applies to central role) */ +void ble_ll_conn_chan_map_update(void); + /* required for unit testing */ uint8_t ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_crypto.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_crypto.h new file mode 100644 index 00000000..4514b0b1 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_crypto.h @@ -0,0 +1,50 @@ +/* + * 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 H_BLE_LL_CRYPTO_ +#define H_BLE_LL_CRYPTO_ + +#ifdef __cplusplus +extern "C" { +#endif + +int +ble_ll_crypto_cmac(const uint8_t *key, const uint8_t *in, int len, + uint8_t *out); + +static inline int +ble_ll_crypto_h6(const uint8_t *w, const uint8_t *key_id, uint8_t *out) +{ + return ble_ll_crypto_cmac(w, key_id, 4, out); +} + +static inline int +ble_ll_crypto_h7(const uint8_t *salt, const uint8_t *w, uint8_t *out) +{ + return ble_ll_crypto_cmac(salt, w, 16, out); +} + +int ble_ll_crypto_h8(const uint8_t *k, const uint8_t *s, const uint8_t *key_id, + uint8_t *out); + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_CRYPTO_ */ diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_ctrl.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_ctrl.h index 379960ec..89502a45 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_ctrl.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_ctrl.h @@ -333,8 +333,9 @@ void ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle, int ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status); void ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm); void ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm); -void ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm); +void ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm, bool initial); void ble_ll_hci_ev_send_vs_assert(const char *file, uint32_t line); +void ble_ll_hci_ev_send_vs_printf(uint8_t id, const char *fmt, ...); void ble_ll_hci_ev_send_vs_llcp_trace(uint8_t type, uint16_t handle, uint16_t count, void *pdu, size_t length); @@ -350,6 +351,11 @@ void ble_ll_hci_ev_sca_update(struct ble_ll_conn_sm *connsm, void ble_ll_hci_ev_subrate_change(struct ble_ll_conn_sm *connsm, uint8_t status); #endif +#if MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) +void ble_ll_hci_ev_send_vs_css_slot_changed(uint16_t conn_handle, + uint16_t slot_idx); +#endif + #ifdef __cplusplus } #endif diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_ext.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_ext.h new file mode 100644 index 00000000..5b3bb376 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_ext.h @@ -0,0 +1,62 @@ +/* + * 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 H_BLE_LL_EXT_ +#define H_BLE_LL_EXT_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if MYNEWT_VAL(BLE_LL_EXT) + +/* Quickstart guide: + * - create scheduling item with sched_type set to BLE_LL_SCHED_EXTERNAL + * - use sched_ext_type to differentiate between different types of custom items + * - insert into scheduler using ble_ll_sched_insert() + * - set LL state to BLE_LL_STATE_EXTERNAL when item is being executed + * - set LL state back to BLE_LL_STATE_IDLE when item is done + */ + +struct ble_ll_sched_item; + +/* Called when LL package is initialized (before ll_task is started) */ +void ble_ll_ext_init(void); +/* Called when LL is reset (i.e. HCI_Reset) */ +void ble_ll_ext_reset(void); +/* Called when LL is in "external" state and PHY starts to receive a PDU */ +int ble_ll_ext_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr); +/* Called when LL is in "external" state and PHY finished to receive a PDU */ +int ble_ll_ext_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); +/* Called when PDU received in "external" state reaches LL */ +void ble_ll_ext_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *rxhdr); +/* Called when LL is in "external" state and was preempted */ +void ble_ll_ext_halt(void); +/* Called when LL is in "external" state and PHY failed to receive a PDU */ +void ble_ll_ext_wfr_timer_exp(void); +/* Called when an "external" scheduling item was removed from scheduler queue */ +void ble_ll_ext_sched_removed(struct ble_ll_sched_item *sch); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_EXT_ */ diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_hci.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_hci.h index 37d6d205..6fef1f7b 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_hci.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_hci.h @@ -27,10 +27,6 @@ extern "C" { #include "nimble/hci_common.h" #include "nimble/transport.h" -/* For supported commands */ -#define BLE_LL_SUPP_CMD_LEN (47) -extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN]; - /* The largest event the controller will send. */ #define BLE_LL_MAX_EVT_LEN MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE) @@ -42,7 +38,7 @@ extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN]; */ #define BLE_LL_CFG_NUM_HCI_CMD_PKTS (1) -typedef void (*ble_ll_hci_post_cmd_complete_cb)(void); +typedef void (*ble_ll_hci_post_cmd_complete_cb)(void *user_data); #if MYNEWT_VAL(BLE_LL_HCI_VS) typedef int (* ble_ll_hci_vs_cb_t)(uint16_t ocf, @@ -61,6 +57,10 @@ struct ble_ll_hci_vs_cmd { /* Initialize LL HCI */ void ble_ll_hci_init(void); +int ble_ll_hci_cmd_rx(uint8_t *cmdbuf); +int ble_ll_hci_acl_rx(struct os_mbuf *om); +int ble_ll_hci_iso_rx(struct os_mbuf *om); + /* Used to determine if the LE event is enabled/disabled */ bool ble_ll_hci_is_le_event_enabled(unsigned int subev); @@ -80,8 +80,13 @@ int ble_ll_hci_chk_phy_masks(uint8_t all_phys, uint8_t tx_phys, uint8_t rx_phys, /* Returns true if Extended Advertising HCI commands are in use */ bool ble_ll_hci_adv_mode_ext(void); -/* Get TX power compensation rounded to integer dB */ -int8_t ble_ll_get_tx_pwr_compensation(void); +/* Check if max octets/time are within allowed range */ +int ble_ll_hci_check_dle(uint16_t max_octets, uint16_t max_time); + +void ble_ll_hci_supp_cmd_get(uint8_t *buf); + +/* Used to set post HCI command hook */ +void ble_ll_hci_post_cmd_cb_set(ble_ll_hci_post_cmd_complete_cb cb, void *user_data); #if MYNEWT_VAL(BLE_LL_HCI_VS) void ble_ll_hci_vs_register(struct ble_ll_hci_vs_cmd *cmds, uint32_t num_cmds); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_iso_big.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_iso_big.h new file mode 100644 index 00000000..30cf1b46 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_iso_big.h @@ -0,0 +1,60 @@ +/* + * 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 H_BLE_LL_ISO_BIG_ +#define H_BLE_LL_ISO_BIG_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + +struct ble_ll_iso_big; +struct ble_ll_iso_bis; + +int ble_ll_iso_big_biginfo_copy(struct ble_ll_iso_big *big, uint8_t *dptr, + uint32_t base_ticks, uint8_t base_rem_us); +int ble_ll_iso_big_biginfo_len(struct ble_ll_iso_big *big); + +struct ble_ll_iso_bis *ble_ll_iso_big_find_bis_by_handle(uint16_t conn_handle); +struct ble_ll_isoal_mux *ble_ll_iso_big_find_mux_by_handle(uint16_t conn_handle); +int ble_ll_iso_big_last_tx_timestamp_get(struct ble_ll_iso_bis *bis, + uint16_t *packet_seq_num, + uint32_t *timestamp); + +void ble_ll_iso_big_chan_map_update(void); + +void ble_ll_iso_big_halt(void); + +int ble_ll_iso_big_hci_create(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_iso_big_hci_create_test(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_iso_big_hci_terminate(const uint8_t *cmdbuf, uint8_t len); +void ble_ll_iso_big_hci_evt_complete(void); + +void ble_ll_iso_big_init(void); +void ble_ll_iso_big_reset(void); + +#endif /* BLE_LL_ISO_BROADCASTER */ + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_ISO_BIG_ */ diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_isoal.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_isoal.h new file mode 100644 index 00000000..5104ea97 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_isoal.h @@ -0,0 +1,84 @@ +/* + * 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 H_BLE_LL_ISOAL_ +#define H_BLE_LL_ISOAL_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if MYNEWT_VAL(BLE_LL_ISO) + +struct ble_ll_isoal_mux { + /* Max PDU length */ + uint8_t max_pdu; + /* Number of expected SDUs per ISO interval */ + uint8_t sdu_per_interval; + /* Number of expected PDUs per SDU */ + uint8_t pdu_per_sdu; + /* Number of SDUs required to fill complete BIG/CIG event (i.e. with pt) */ + uint8_t sdu_per_event; + /* Number of SDUs available for current event */ + uint8_t sdu_in_event; + + STAILQ_HEAD(, os_mbuf_pkthdr) sdu_q; + + struct os_mbuf *frag; + + uint32_t sdu_counter; + + uint32_t event_tx_timestamp; + uint32_t last_tx_timestamp; + uint16_t last_tx_packet_seq_num; +}; + +void +ble_ll_isoal_mux_init(struct ble_ll_isoal_mux *mux, uint8_t max_pdu, + uint32_t iso_interval_us, uint32_t sdu_interval_us, + uint8_t bn, uint8_t pte); +void ble_ll_isoal_mux_free(struct ble_ll_isoal_mux *mux); + +int ble_ll_isoal_mux_event_start(struct ble_ll_isoal_mux *mux, + uint32_t timestamp); +int ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux); + +int +ble_ll_isoal_mux_unframed_get(struct ble_ll_isoal_mux *mux, uint8_t idx, + uint8_t *llid, void *dptr); + +/* HCI command handlers */ +int ble_ll_isoal_hci_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_isoal_hci_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_isoal_hci_read_tx_sync(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen); + +void ble_ll_isoal_init(void); +void ble_ll_isoal_reset(void); +int ble_ll_isoal_data_in(struct os_mbuf *om); + +#endif /* BLE_LL_ISO */ + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_ISOAL_ */ diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_pdu.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_pdu.h new file mode 100644 index 00000000..b18db944 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_pdu.h @@ -0,0 +1,47 @@ +/* + * 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 H_BLE_LL_PDU_ +#define H_BLE_LL_PDU_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Header mask for keystream generation */ +#define BLE_LL_PDU_HEADERMASK_DATA (0xe3) +#define BLE_LL_PDU_HEADERMASK_BIS (0xc3) +#define BLE_LL_PDU_HEADERMASK_CIS (0xa3) + +#define BLE_LL_PDU_PREAMBLE_1M_LEN (1) +#define BLE_LL_PDU_PREAMBLE_2M_LEN (2) +#define BLE_LL_PDU_AA_LEN (4) +#define BLE_LL_PDU_HEADER_LEN (2) +#define BLE_LL_PDU_CRC_LEN (3) + +uint32_t ble_ll_pdu_syncword_us(uint8_t phy_mode); +uint32_t ble_ll_pdu_us(uint8_t payload_len, uint8_t phy_mode); + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_PDU_ */ diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_scan.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_scan.h index 34bcd60b..07e4c920 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_scan.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_scan.h @@ -235,11 +235,6 @@ void ble_ll_scan_wfr_timer_exp(void); /* Called when scan could be interrupted */ void ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -/* Called to parse extended advertising*/ -void ble_ll_scan_end_adv_evt(struct ble_ll_aux_data *aux_data); -#endif - /* Called to halt currently running scan */ void ble_ll_scan_halt(void); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_scan_aux.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_scan_aux.h index c7d63b84..b1d6c9ca 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_scan_aux.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_scan_aux.h @@ -29,8 +29,8 @@ extern "C" { struct ble_ll_scan_aux_data; void ble_ll_scan_aux_init(void); -int ble_ll_scan_aux_sched(struct ble_ll_scan_aux_data *aux, uint32_t pdu_time, - uint8_t pdu_time_rem, uint32_t aux_ptr); +int ble_ll_scan_aux_sched(struct ble_ll_scan_aux_data *aux, uint32_t pdu_ticks, + uint8_t pdu_rem_us, uint32_t aux_ptr); int ble_ll_scan_aux_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr); int ble_ll_scan_aux_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok); void ble_ll_scan_aux_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *rxhdr); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_sched.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_sched.h index a65b5d43..cceb96ce 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_sched.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_sched.h @@ -70,6 +70,10 @@ extern uint8_t g_ble_ll_sched_offset_ticks; #define BLE_LL_SCHED_TYPE_PERIODIC (6) #define BLE_LL_SCHED_TYPE_SYNC (7) #define BLE_LL_SCHED_TYPE_SCAN_AUX (8) +#define BLE_LL_SCHED_TYPE_BIG (9) +#if MYNEWT_VAL(BLE_LL_EXT) +#define BLE_LL_SCHED_TYPE_EXTERNAL (255) +#endif /* Return values for schedule callback. */ #define BLE_LL_SCHED_STATE_RUNNING (0) @@ -80,6 +84,10 @@ struct ble_ll_sched_item; typedef int (*sched_cb_func)(struct ble_ll_sched_item *sch); typedef void (*sched_remove_cb_func)(struct ble_ll_sched_item *sch); +typedef int (* ble_ll_sched_preempt_cb_t)(struct ble_ll_sched_item *sch, + struct ble_ll_sched_item *item); + + /* * Schedule item * sched_type: This is the type of the schedule item. @@ -91,6 +99,9 @@ typedef void (*sched_remove_cb_func)(struct ble_ll_sched_item *sch); struct ble_ll_sched_item { uint8_t sched_type; +#if MYNEWT_VAL(BLE_LL_EXT) + uint8_t sched_ext_type; +#endif uint8_t enqueued; uint8_t remainder; uint32_t start_time; @@ -103,6 +114,10 @@ struct ble_ll_sched_item /* Initialize the scheduler */ int ble_ll_sched_init(void); +int ble_ll_sched_insert(struct ble_ll_sched_item *sch, uint32_t max_delay, + ble_ll_sched_preempt_cb_t preempt_cb); +void ble_ll_sched_restart(void); + /* Remove item(s) from schedule */ int ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch); @@ -127,13 +142,8 @@ int ble_ll_sched_adv_new(struct ble_ll_sched_item *sch, /* Schedule periodic advertising event */ int ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, bool first_event); -int ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, - uint32_t anchor_point, - uint8_t anchor_point_usecs, - uint32_t window_widening, int8_t phy_mode); -int ble_ll_sched_sync(struct ble_ll_sched_item *sch, - uint32_t beg_cputime, uint32_t rem_usecs, uint32_t offset, - int8_t phy_mode); +int ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, uint32_t ww_us); +int ble_ll_sched_sync(struct ble_ll_sched_item *sch); /* Reschedule an advertising event */ int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, @@ -158,14 +168,7 @@ int ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm * connsm); int ble_ll_sched_next_time(uint32_t *next_event_time); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -struct ble_ll_scan_sm; -struct ble_ll_aux_data; -int ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr, - struct ble_ll_scan_sm *scansm, - struct ble_ll_aux_data *aux_scan); - -int ble_ll_sched_scan_aux(struct ble_ll_sched_item *sch, uint32_t pdu_time, - uint8_t pdu_time_rem, uint32_t offset_us); +int ble_ll_sched_scan_aux(struct ble_ll_sched_item *sch); #endif /* Stop the scheduler */ @@ -179,8 +182,16 @@ int ble_ll_sched_dtm(struct ble_ll_sched_item *sch); #if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) void ble_ll_sched_css_set_params(uint32_t slot_us, uint32_t period_slots); #endif +void ble_ll_sched_css_set_enabled(uint8_t enabled); +void ble_ll_sched_css_update_anchor(struct ble_ll_conn_sm *connsm); void ble_ll_sched_css_set_conn_anchor(struct ble_ll_conn_sm *connsm); #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) +static inline bool +ble_ll_sched_css_is_enabled(void) +{ + return true; +} + static inline uint32_t ble_ll_sched_css_get_slot_us(void) { @@ -200,12 +211,17 @@ ble_ll_sched_css_get_conn_interval_us(void) ble_ll_sched_css_get_slot_us() / 1250; } #else +bool ble_ll_sched_css_is_enabled(void); uint32_t ble_ll_sched_css_get_slot_us(void); uint32_t ble_ll_sched_css_get_period_slots(void); uint32_t ble_ll_sched_css_get_conn_interval_us(void); #endif #endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +int ble_ll_sched_iso_big(struct ble_ll_sched_item *sch, int first); +#endif /* BLE_LL_ISO_BROADCASTER */ + #ifdef __cplusplus } #endif diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_sync.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_sync.h index 8002d2a3..b4f9e944 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_sync.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_sync.h @@ -34,7 +34,7 @@ struct ble_ll_scan_addr_data; struct ble_ll_sync_sm; int ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb); +int ble_ll_sync_cancel(void); int ble_ll_sync_terminate(const uint8_t *cmdbuf, uint8_t len); int ble_ll_sync_list_add(const uint8_t *cmdbuf, uint8_t len); int ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_utils.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_utils.h index 16b91a0c..291872bf 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_utils.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_ll_utils.h @@ -23,17 +23,28 @@ #define INT16_LT(_a, _b) ((int16_t)((_a) - (_b)) < 0) #define INT16_LTE(_a, _b) ((int16_t)((_a) - (_b)) <= 0) -uint32_t ble_ll_utils_calc_access_addr(void); -uint8_t ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap); +#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b)) +#define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b)) +#define CLAMP(_n, _min, _max) (MAX(_min, MIN(_n, _max))) +#define IN_RANGE(_n, _min, _max) (((_n) >= (_min)) && ((_n) <= (_max))) + +int ble_ll_utils_verify_aa(uint32_t aa); +uint32_t ble_ll_utils_calc_aa(void); +uint32_t ble_ll_utils_calc_seed_aa(void); +uint32_t ble_ll_utils_calc_big_aa(uint32_t seed_aa, uint32_t n); + +uint8_t ble_ll_utils_chan_map_remap(const uint8_t *chan_map, uint8_t remap_index); +uint8_t ble_ll_utils_chan_map_used_get(const uint8_t *chan_map); + uint8_t ble_ll_utils_dci_csa2(uint16_t counter, uint16_t chan_id, uint8_t num_used_chans, const uint8_t *chan_map); uint16_t ble_ll_utils_dci_iso_event(uint16_t counter, uint16_t chan_id, - uint16_t *prn_sub_lu, uint8_t num_used_chans, + uint16_t *prn_sub_lu, uint8_t chan_map_used, const uint8_t *chan_map, uint16_t *remap_idx); uint16_t ble_ll_utils_dci_iso_subevent(uint16_t chan_id, uint16_t *prn_sub_lu, - uint8_t num_used_chans, const uint8_t *chan_map, + uint8_t chan_map_used, const uint8_t *chan_map, uint16_t *remap_idx); -uint8_t ble_ll_utils_calc_num_used_chans(const uint8_t *chan_map); + uint32_t ble_ll_utils_calc_window_widening(uint32_t anchor_point, uint32_t last_anchor_point, uint8_t central_sca); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_phy.h b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_phy.h index 44e8809b..ab96cb9c 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_phy.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/include/controller/ble_phy.h @@ -65,6 +65,7 @@ struct os_mbuf; #define BLE_PHY_TRANSITION_NONE (0) #define BLE_PHY_TRANSITION_RX_TX (1) #define BLE_PHY_TRANSITION_TX_RX (2) +#define BLE_PHY_TRANSITION_TX_TX (3) /* PHY error codes */ #define BLE_PHY_ERR_RADIO_STATE (1) @@ -85,6 +86,16 @@ int ble_phy_init(void); /* Set the PHY channel */ int ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit); +uint8_t ble_phy_chan_get(void); + +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) +/* Set T_ifs time for next transition */ +void ble_phy_tifs_set(uint16_t tifs); +#endif + +/* Set T_ifs for tx-tx transitions. Anchor is 0 for start of previous PDU, + * non-zero for end of PDU */ +void ble_phy_tifs_txtx_set(uint16_t usecs, uint8_t anchor); /* Set transmit start time */ int ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs); @@ -101,23 +112,17 @@ typedef uint8_t (*ble_phy_tx_pducb_t)(uint8_t *dptr, void *pducb_arg, /* Place the PHY into transmit mode */ int ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans); -/* Place the PHY into receive mode */ -int ble_phy_rx(void); - /* Copies the received PHY buffer into the allocated pdu */ void ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu); /* Set the transmit power */ -int ble_phy_txpwr_set(int dbm); +int ble_phy_tx_power_set(int dbm); /* Get highest allowed power from range */ -int ble_phy_txpower_round(int dbm); +int ble_phy_tx_power_round(int dbm); /* Get the transmit power */ -int ble_phy_txpwr_get(void); - -/* Set RX path power compensation value rounded to integer dB */ -void ble_phy_set_rx_pwr_compensation(int8_t compensation); +int ble_phy_tx_power_get(void); /* Disable the PHY */ void ble_phy_disable(void); @@ -160,15 +165,16 @@ uint8_t ble_phy_max_data_pdu_pyld(void); uint32_t ble_phy_access_addr_get(void); /* Enable encryption */ -void ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_central); - +void ble_phy_encrypt_enable(const uint8_t *key); +/* Set mask for PDU header (see Core 5.3, Vol 6, Part E, 2.2) */ +void ble_phy_encrypt_header_mask_set(uint8_t mask); +/* Set encryption IV */ +void ble_phy_encrypt_iv_set(const uint8_t *iv); +/* Set encryption packet counter and direction bit */ +void ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit); /* Disable encryption */ void ble_phy_encrypt_disable(void); -/* Set the packet counters and dir used by LE encyption */ -void ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir); - /* Enable phy resolving list */ void ble_phy_resolv_list_enable(void); @@ -205,14 +211,9 @@ void ble_phy_resolv_list_disable(void); #define BLE_PHY_IDX_CODED (2) #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)) -uint32_t ble_phy_mode_pdu_start_off(int phy); void ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode); -#else -#define ble_phy_mode_pdu_start_off(phy) (40) - #endif -int ble_phy_get_cur_phy(void); static inline int ble_ll_phy_to_phy_mode(int phy, int phy_options) { int phy_mode; diff --git a/lib/bt/host/nimble/nimble/nimble/controller/pkg.yml b/lib/bt/host/nimble/nimble/nimble/controller/pkg.yml index 702f3d89..5e43ba39 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/pkg.yml +++ b/lib/bt/host/nimble/nimble/nimble/controller/pkg.yml @@ -29,12 +29,15 @@ pkg.req_apis: - ble_driver - ble_transport - stats -pkg.req_apis.BLE_LL_PA: - - ble_ll_pa -pkg.req_apis.BLE_LL_LNA: - - ble_ll_lna +pkg.req_apis.BLE_FEM_PA: + - ble_fem_pa +pkg.req_apis.BLE_FEM_LNA: + - ble_fem_lna +pkg.req_apis.BLE_FEM_ANTENNA: + - ble_fem_antenna pkg.deps: - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-core/crypto/tinycrypt" - nimble - nimble/transport diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll.c index b6681abf..84475c32 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll.c @@ -29,10 +29,12 @@ #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" #include "nimble/transport.h" +#include "controller/ble_ll_utils.h" #include "controller/ble_hw.h" #include "controller/ble_phy.h" #include "controller/ble_phy_trace.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_scan.h" @@ -43,7 +45,12 @@ #include "controller/ble_ll_rfmgmt.h" #include "controller/ble_ll_trace.h" #include "controller/ble_ll_sync.h" -#include "controller/ble_ll_plna.h" +#include "controller/ble_fem.h" +#include "controller/ble_ll_isoal.h" +#include "controller/ble_ll_iso_big.h" +#if MYNEWT_VAL(BLE_LL_EXT) +#include "controller/ble_ll_ext.h" +#endif #include "ble_ll_conn_priv.h" #include "ble_ll_hci_priv.h" #include "ble_ll_priv.h" @@ -53,6 +60,10 @@ #include "ble_ll_dtm_priv.h" #endif +#if MYNEWT_VAL(BLE_LL_EXT) +#include +#endif + /* XXX: * * 1) use the sanity task! @@ -65,7 +76,11 @@ * right thing to do. */ -int8_t g_ble_ll_tx_power = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); +/* This is TX power on PHY (or FEM PA if enabled) */ +int8_t g_ble_ll_tx_power; +static int8_t g_ble_ll_tx_power_phy_current; +int8_t g_ble_ll_tx_power_compensation; +int8_t g_ble_ll_rx_power_compensation; /* Supported states */ #if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) @@ -202,17 +217,13 @@ int8_t g_ble_ll_tx_power = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); #define BLE_LL_S_CA_INIT ((uint64_t)1 << 32) #define BLE_LL_S_HDCA_INIT ((uint64_t)1 << 33) #define BLE_LL_S_LDCA_INIT ((uint64_t)1 << 34) -#else -#define BLE_LL_S_CA_INIT ((uint64_t)0 << 32) -#define BLE_LL_S_HDCA_INIT ((uint64_t)0 << 33) -#define BLE_LL_S_LDCA_INIT ((uint64_t)0 << 34) -#endif - -#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_LL_S_CA_CENTRAL ((uint64_t)1 << 35) #define BLE_LL_S_HDCA_CENTRAL ((uint64_t)1 << 36) #define BLE_LL_S_LDCA_CENTRAL ((uint64_t)1 << 37) #else +#define BLE_LL_S_CA_INIT ((uint64_t)0 << 32) +#define BLE_LL_S_HDCA_INIT ((uint64_t)0 << 33) +#define BLE_LL_S_LDCA_INIT ((uint64_t)0 << 34) #define BLE_LL_S_CA_CENTRAL ((uint64_t)0 << 35) #define BLE_LL_S_HDCA_CENTRAL ((uint64_t)0 << 36) #define BLE_LL_S_LDCA_CENTRAL ((uint64_t)0 << 37) @@ -357,22 +368,11 @@ static void ble_ll_event_tx_pkt(struct ble_npl_event *ev); static void ble_ll_event_dbuf_overflow(struct ble_npl_event *ev); #endif -#if MYNEWT - -#if BABBLESIM -#define BLE_LL_STACK_SIZE (4000) -#else +#ifdef MYNEWT /* The BLE LL task data structure */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_LL_STACK_SIZE (120) -#else -#define BLE_LL_STACK_SIZE (90) -#endif -#endif - struct os_task g_ble_ll_task; -OS_TASK_STACK_DEFINE(g_ble_ll_stack, BLE_LL_STACK_SIZE); +OS_TASK_STACK_DEFINE(g_ble_ll_stack, MYNEWT_VAL(BLE_LL_STACK_SIZE)); #endif /* MYNEWT */ @@ -382,25 +382,6 @@ uint8_t g_dev_addr[BLE_DEV_ADDR_LEN]; /** Our random address */ uint8_t g_random_addr[BLE_DEV_ADDR_LEN]; -static const uint16_t g_ble_ll_pdu_header_tx_time[BLE_PHY_NUM_MODE] = -{ - [BLE_PHY_MODE_1M] = - (BLE_LL_PREAMBLE_LEN + BLE_LL_ACC_ADDR_LEN + BLE_LL_CRC_LEN + - BLE_LL_PDU_HDR_LEN) << 3, - [BLE_PHY_MODE_2M] = - (BLE_LL_PREAMBLE_LEN * 2 + BLE_LL_ACC_ADDR_LEN + BLE_LL_CRC_LEN + - BLE_LL_PDU_HDR_LEN) << 2, - /* For Coded PHY we have exact TX times provided by specification: - * - Preamble, Access Address, CI, TERM1 (always coded as S=8) - * - PDU, CRC, TERM2 (coded as S=2 or S=8) - * (Vol 6, Part B, 2.2). - */ - [BLE_PHY_MODE_CODED_125KBPS] = - (80 + 256 + 16 + 24 + 8 * (BLE_LL_PDU_HDR_LEN * 8 + 24 + 3)), - [BLE_PHY_MODE_CODED_500KBPS] = - (80 + 256 + 16 + 24 + 2 * (BLE_LL_PDU_HDR_LEN * 8 + 24 + 3)), -}; - /** * Counts the number of advertising PDU's received, by type. For advertising * PDU's that contain a destination address, we still count these packets even @@ -518,36 +499,6 @@ rxpdu_alloc_fail: return NULL; } -int -ble_ll_chk_txrx_octets(uint16_t octets) -{ - int rc; - - if ((octets < BLE_LL_CONN_SUPP_BYTES_MIN) || - (octets > BLE_LL_CONN_SUPP_BYTES_MAX)) { - rc = 0; - } else { - rc = 1; - } - - return rc; -} - -int -ble_ll_chk_txrx_time(uint16_t time) -{ - int rc; - - if ((time < BLE_LL_CONN_SUPP_TIME_MIN) || - (time > BLE_LL_CONN_SUPP_TIME_MAX)) { - rc = 0; - } else { - rc = 1; - } - - return rc; -} - /** * Checks to see if the address is a resolvable private address. * @@ -842,6 +793,11 @@ ble_ll_wfr_timer_exp(void *arg) case BLE_LL_STATE_DTM: ble_ll_dtm_wfr_timer_exp(); break; +#endif +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_STATE_EXTERNAL: + ble_ll_ext_wfr_timer_exp(); + break; #endif default: break; @@ -1017,6 +973,11 @@ ble_ll_rx_pkt_in(void) case BLE_LL_STATE_DTM: ble_ll_dtm_rx_pkt_in(m, ble_hdr); break; +#endif +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_STATE_EXTERNAL: + ble_ll_ext_rx_pkt_in(m, ble_hdr); + break; #endif default: /* Any other state should never occur */ @@ -1042,7 +1003,7 @@ ble_ll_rx_pdu_in(struct os_mbuf *rxpdu) pkthdr = OS_MBUF_PKTHDR(rxpdu); STAILQ_INSERT_TAIL(&g_ble_ll_data.ll_rx_pkt_q, pkthdr, omp_next); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_rx_pkt_ev); + ble_ll_event_add(&g_ble_ll_data.ll_rx_pkt_ev); } #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) @@ -1061,7 +1022,7 @@ ble_ll_acl_data_in(struct os_mbuf *txpkt) OS_ENTER_CRITICAL(sr); STAILQ_INSERT_TAIL(&g_ble_ll_data.ll_tx_pkt_q, pkthdr, omp_next); OS_EXIT_CRITICAL(sr); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_tx_pkt_ev); + ble_ll_event_add(&g_ble_ll_data.ll_tx_pkt_ev); } /** @@ -1074,7 +1035,7 @@ ble_ll_acl_data_in(struct os_mbuf *txpkt) void ble_ll_data_buffer_overflow(void) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_dbuf_overflow_ev); + ble_ll_event_add(&g_ble_ll_data.ll_dbuf_overflow_ev); } #endif @@ -1163,6 +1124,11 @@ ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *rxhdr) case BLE_LL_STATE_DTM: rc = ble_ll_dtm_rx_isr_start(rxhdr, ble_phy_access_addr_get()); break; +#endif +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_STATE_EXTERNAL: + rc = ble_ll_ext_rx_isr_start(pdu_type, rxhdr); + break; #endif default: /* Should not be in this state! */ @@ -1207,6 +1173,13 @@ ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) ble_ll_trace_u32x3(BLE_LL_TRACE_ID_RX_END, pdu_type, len, rxhdr->rxinfo.flags); +#if MYNEWT_VAL(BLE_LL_EXT) + if (BLE_MBUF_HDR_RX_STATE(rxhdr) == BLE_LL_STATE_EXTERNAL) { + rc = ble_ll_ext_rx_isr_end(rxbuf, rxhdr); + return rc; + } +#endif + #if MYNEWT_VAL(BLE_LL_DTM) if (BLE_MBUF_HDR_RX_STATE(rxhdr) == BLE_LL_STATE_DTM) { rc = ble_ll_dtm_rx_isr_end(rxbuf, rxhdr); @@ -1392,8 +1365,10 @@ ble_ll_task(void *arg) /* Init ble phy */ ble_phy_init(); - /* Set output power to 1mW (0 dBm) */ - ble_phy_txpwr_set(g_ble_ll_tx_power); + /* Set output power to default */ + g_ble_ll_tx_power = ble_ll_tx_power_round(MIN(MYNEWT_VAL(BLE_LL_TX_PWR_DBM), + MYNEWT_VAL(BLE_LL_TX_PWR_MAX_DBM))); + g_ble_ll_tx_power_phy_current = INT8_MAX; /* Tell the host that we are ready to receive packets */ ble_ll_hci_send_noop(); @@ -1442,16 +1417,29 @@ ble_ll_state_get(void) /** * ble ll event send * - * Send an event to the Link Layer task + * Add an event to the Link Layer task * * @param ev Event to add to the Link Layer event queue. */ void -ble_ll_event_send(struct ble_npl_event *ev) +ble_ll_event_add(struct ble_npl_event *ev) { ble_npl_eventq_put(&g_ble_ll_data.ll_evq, ev); } +/** + * ble ll event remove + * + * Remove an event from the Link Layer task + * + * @param ev Event to remove from the Link Layer event queue. + */ +void +ble_ll_event_remove(struct ble_npl_event *ev) +{ + ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, ev); +} + /** * Returns the features supported by the link layer * @@ -1482,7 +1470,7 @@ ble_ll_read_supp_features(void) int ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len) { - const struct ble_hci_le_set_host_feat_cp *cmd = (const void *) cmdbuf; + const struct ble_hci_le_set_host_feature_cp *cmd = (const void *) cmdbuf; uint64_t mask; if (len != sizeof(*cmd)) { @@ -1495,7 +1483,7 @@ ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len) } #endif - if ((cmd->bit_num > 0x3F) || (cmd->val > 1)) { + if ((cmd->bit_num > 0x3F) || (cmd->bit_val > 1)) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -1504,7 +1492,7 @@ ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_UNSUPPORTED; } - if (cmd->val == 0) { + if (cmd->bit_val == 0) { g_ble_ll_data.ll_supp_features &= ~(mask); } else { g_ble_ll_data.ll_supp_features |= mask; @@ -1607,6 +1595,10 @@ ble_ll_reset(void) ble_ll_rfmgmt_reset(); OS_EXIT_CRITICAL(sr); +#if MYNEWT_VAL(BLE_LL_EXT) + ble_ll_ext_reset(); +#endif + #if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) /* Stop any advertising */ ble_ll_adv_reset(); @@ -1621,6 +1613,15 @@ ble_ll_reset(void) ble_ll_sync_reset(); #endif + /* reset power compensation */ + g_ble_ll_tx_power_compensation = 0; + g_ble_ll_rx_power_compensation = 0; + + /* Set output power to default */ + g_ble_ll_tx_power = ble_ll_tx_power_round(MIN(MYNEWT_VAL(BLE_LL_TX_PWR_DBM), + MYNEWT_VAL(BLE_LL_TX_PWR_MAX_DBM))); + g_ble_ll_tx_power_phy_current = INT8_MAX; + /* FLush all packets from Link layer queues */ ble_ll_flush_pkt_queue(&g_ble_ll_data.ll_tx_pkt_q); ble_ll_flush_pkt_queue(&g_ble_ll_data.ll_rx_pkt_q); @@ -1642,7 +1643,7 @@ ble_ll_reset(void) g_ble_ll_data.ll_pref_rx_phys = phy_mask; /* Enable all channels in channel map */ - g_ble_ll_data.chan_map_num_used = BLE_PHY_NUM_DATA_CHANS; + g_ble_ll_data.chan_map_used = BLE_PHY_NUM_DATA_CHANS; memset(g_ble_ll_data.chan_map, 0xff, BLE_LL_CHAN_MAP_LEN - 1); g_ble_ll_data.chan_map[4] = 0x1f; @@ -1672,11 +1673,18 @@ ble_ll_reset(void) #endif -#if MYNEWT_VAL(BLE_LL_PA) - ble_ll_plna_pa_init(); +#if MYNEWT_VAL(BLE_FEM_PA) + ble_fem_pa_init(); +#endif +#if MYNEWT_VAL(BLE_FEM_LNA) + ble_fem_lna_init(); +#endif + +#if MYNEWT_VAL(BLE_LL_ISO) + ble_ll_isoal_reset(); #endif -#if MYNEWT_VAL(BLE_LL_LNA) - ble_ll_plna_lna_init(); +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + ble_ll_iso_big_reset(); #endif /* Re-initialize the PHY */ @@ -1685,37 +1693,6 @@ ble_ll_reset(void) return rc; } -uint32_t -ble_ll_pdu_tx_time_get(uint16_t payload_len, int phy_mode) -{ - uint32_t usecs; - -#if (BLE_LL_BT5_PHY_SUPPORTED) - if (phy_mode == BLE_PHY_MODE_1M) { - /* 8 usecs per byte */ - usecs = payload_len << 3; - } else if (phy_mode == BLE_PHY_MODE_2M) { - /* 4 usecs per byte */ - usecs = payload_len << 2; - } else if (phy_mode == BLE_PHY_MODE_CODED_125KBPS) { - /* S=8 => 8 * 8 = 64 usecs per byte */ - usecs = payload_len << 6; - } else if (phy_mode == BLE_PHY_MODE_CODED_500KBPS) { - /* S=2 => 2 * 8 = 16 usecs per byte */ - usecs = payload_len << 4; - } else { - BLE_LL_ASSERT(0); - } - - usecs += g_ble_ll_pdu_header_tx_time[phy_mode]; -#else - usecs = (((payload_len) + BLE_LL_PDU_HDR_LEN + BLE_LL_ACC_ADDR_LEN - + BLE_LL_PREAMBLE_LEN + BLE_LL_CRC_LEN) << 3); -#endif - - return usecs; -} - uint16_t ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode) { @@ -1724,14 +1701,14 @@ ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode) BLE_LL_ASSERT(phy_mode < BLE_PHY_NUM_MODE); - header_tx_time = g_ble_ll_pdu_header_tx_time[phy_mode]; + header_tx_time = ble_ll_pdu_us(0, phy_mode); /* * Current conn max tx time can be too short to even send a packet header * and this can happen if we changed connection form uncoded to coded phy. * However, the lower bound for conn max tx time (all of them) depends on * current phy (uncoded/coded) but it always allows to send at least 27 - * bytes of payload thus we alwyas return at least 27 from here. + * bytes of payload thus we always return at least 27 from here. * * Reference: * Core v5.0, Vol 6, Part B, section 4.5.10 @@ -1761,7 +1738,7 @@ ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode) } /* see comment at the beginning */ - return max(27, octets); + return MAX(27, octets); } static inline bool @@ -1774,10 +1751,10 @@ ble_ll_is_addr_empty(const uint8_t *addr) void ble_ll_assert(const char *file, unsigned line) { + ble_ll_hci_ev_send_vs_assert(file, line); + if (hal_debugger_connected()) { __BKPT(0); - } else { - ble_ll_hci_ev_send_vs_assert(file, line); \ } while (1); @@ -1838,6 +1815,11 @@ ble_ll_init(void) lldata->ll_acl_pkt_size = MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE); #endif +#if MYNEWT_VAL(BLE_LL_ISO) + lldata->ll_num_iso_pkts = MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_HS_COUNT); + lldata->ll_iso_pkt_size = MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE); +#endif + /* Initialize eventq */ ble_npl_eventq_init(&lldata->ll_evq); @@ -1945,8 +1927,11 @@ ble_ll_init(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) features |= BLE_LL_FEAT_CIS_CENTRAL; features |= BLE_LL_FEAT_CIS_PERIPH; + features |= BLE_LL_FEAT_CIS_HOST; +#endif + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) features |= BLE_LL_FEAT_ISO_BROADCASTER; - features |= BLE_LL_FEAT_ISO_HOST_SUPPORT; #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) @@ -1974,11 +1959,22 @@ ble_ll_init(void) ble_ll_hci_vs_init(); #endif -#if MYNEWT +#if MYNEWT_VAL(BLE_LL_ISO) + ble_ll_isoal_init(); +#endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + ble_ll_iso_big_init(); +#endif + +#if MYNEWT_VAL(BLE_LL_EXT) + ble_ll_ext_init(); +#endif + +#ifdef MYNEWT /* Initialize the LL task */ os_task_init(&g_ble_ll_task, "ble_ll", ble_ll_task, NULL, MYNEWT_VAL(BLE_LL_PRIO), OS_WAIT_FOREVER, g_ble_ll_stack, - BLE_LL_STACK_SIZE); + MYNEWT_VAL(BLE_LL_STACK_SIZE)); #else /* @@ -1994,13 +1990,19 @@ ble_ll_init(void) int ble_transport_to_ll_cmd_impl(void *buf) { - return ble_ll_hci_cmd_rx(buf, NULL); + return ble_ll_hci_cmd_rx(buf); } int ble_transport_to_ll_acl_impl(struct os_mbuf *om) { - return ble_ll_hci_acl_rx(om, NULL); + return ble_ll_hci_acl_rx(om); +} + +int +ble_transport_to_ll_iso_impl(struct os_mbuf *om) +{ + return ble_ll_hci_iso_rx(om); } void @@ -2008,3 +2010,94 @@ ble_transport_ll_init(void) { ble_ll_init(); } + +int +ble_ll_tx_power_round(int tx_power) +{ +#if MYNEWT_VAL(BLE_FEM_PA) +#if MYNEWT_VAL(BLE_FEM_PA_GAIN_TUNABLE) + tx_power = ble_fem_pa_tx_power_round(tx_power); +#else + tx_power = ble_phy_tx_power_round(tx_power); + tx_power += MYNEWT_VAL(BLE_FEM_PA_GAIN); +#endif +#else + tx_power = ble_phy_tx_power_round(tx_power); +#endif + + return tx_power; +} + +void +ble_ll_tx_power_set(int tx_power) +{ +#if MYNEWT_VAL(BLE_FEM_PA) +#if MYNEWT_VAL(BLE_FEM_PA_GAIN_TUNABLE) + /* TODO should rounding be in assert only? or just skip it and assume + * power is already rounded? + */ + tx_power = ble_fem_pa_tx_power_round(tx_power); + tx_power = ble_fem_pa_tx_power_set(tx_power); +#else + tx_power -= MYNEWT_VAL(BLE_FEM_PA_GAIN); +#endif +#endif + + /* If current TX power configuration matches requested one we don't need + * to update PHY tx power. + */ + if (g_ble_ll_tx_power_phy_current == tx_power) { + return; + } + + g_ble_ll_tx_power_phy_current = tx_power; + ble_phy_tx_power_set(tx_power); +} + +int +ble_ll_is_busy(unsigned int flags) +{ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + struct ble_ll_conn_sm *cur; + int i = 0; +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + if (ble_ll_sync_enabled()) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + if (ble_ll_adv_enabled()) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + if (ble_ll_scan_enabled()) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (g_ble_ll_conn_create_sm.connsm) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (!(flags & BLE_LL_BUSY_EXCLUDE_CONNECTIONS)) { + STAILQ_FOREACH(cur, &g_ble_ll_conn_free_list, free_stqe) { + i++; + } + + /* check if all connection objects are free */ + if (i < MYNEWT_VAL(BLE_MAX_CONNECTIONS)) { + return 1; + } + } +#endif + + return 0; +} diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_adv.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_adv.c index 7c13743b..7056c8de 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_adv.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_adv.c @@ -16,6 +16,8 @@ * specific language governing permissions and limitations * under the License. */ + +#include #include #include #include @@ -29,6 +31,7 @@ #include "controller/ble_phy.h" #include "controller/ble_hw.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_sched.h" @@ -39,6 +42,7 @@ #include "controller/ble_ll_trace.h" #include "controller/ble_ll_utils.h" #include "controller/ble_ll_rfmgmt.h" +#include "controller/ble_ll_iso_big.h" #include "ble_ll_conn_priv.h" #include "ble_ll_priv.h" @@ -58,22 +62,27 @@ struct ble_ll_adv_aux { struct ble_ll_sched_item sch; uint32_t start_time; - uint16_t aux_data_offset; + uint16_t data_offset; uint8_t chan; - uint8_t ext_hdr; - uint8_t aux_data_len; + uint8_t ext_hdr_flags; + uint8_t data_len; uint8_t payload_len; + uint8_t auxptr_zero; }; /* Scheduling data for sync PDUs */ struct ble_ll_adv_sync { struct ble_ll_sched_item sch; uint32_t start_time; - uint16_t sync_data_offset; + uint16_t data_offset; uint8_t chan; - uint8_t ext_hdr; - uint8_t sync_data_len; + uint8_t ext_hdr_flags; + uint8_t data_len; uint8_t payload_len; + uint8_t auxptr_zero; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + struct ble_ll_iso_big *big; +#endif }; /* @@ -103,11 +112,9 @@ struct ble_ll_adv_sm uint8_t adv_chan; uint8_t adv_pdu_len; int8_t adv_rpa_index; - int8_t adv_txpwr; + int8_t tx_power; uint16_t flags; uint16_t props; - uint16_t adv_itvl_min; - uint16_t adv_itvl_max; uint32_t adv_itvl_usecs; uint32_t adv_event_start_time; uint32_t adv_pdu_start_time; @@ -173,6 +180,11 @@ struct ble_ll_adv_sm uint16_t periodic_event_cntr_last_sent; #endif #endif + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + struct ble_ll_iso_big *big; +#endif /* BLE_LL_ISO_BROADCASTER */ + #endif }; @@ -190,21 +202,26 @@ struct ble_ll_adv_sm #define BLE_LL_ADV_SM_FLAG_PERIODIC_DATA_INCOMPLETE 0x1000 #define BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING 0x2000 #define BLE_LL_ADV_SM_FLAG_PERIODIC_NEW_DATA 0x4000 +#define BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD_ERR 0x8000 #define ADV_DATA_LEN(_advsm) \ - ((_advsm->adv_data) ? OS_MBUF_PKTLEN(advsm->adv_data) : 0) + (((_advsm)->adv_data) ? OS_MBUF_PKTLEN((_advsm)->adv_data) : 0) #define SCAN_RSP_DATA_LEN(_advsm) \ - ((_advsm->scan_rsp_data) ? OS_MBUF_PKTLEN(advsm->scan_rsp_data) : 0) -#define AUX_DATA_LEN(_advsm) \ - (*(_advsm->aux_data) ? OS_MBUF_PKTLEN(*advsm->aux_data) : 0) + (((_advsm)->scan_rsp_data) ? OS_MBUF_PKTLEN((_advsm)->scan_rsp_data) : 0) -#define AUX_CURRENT(_advsm) (&(_advsm->aux[_advsm->aux_index])) -#define AUX_NEXT(_advsm) (&(_advsm->aux[_advsm->aux_index ^ 1])) +#define AUX_CURRENT(_advsm) \ + (&((_advsm)->aux[(_advsm)->aux_index])) +#define AUX_NEXT(_advsm) \ + (&((_advsm)->aux[(_advsm)->aux_index ^ 1])) +#define AUX_DATA_LEN(_advsm) \ + (*((_advsm)->aux_data) ? OS_MBUF_PKTLEN(*(_advsm)->aux_data) : 0) -#define SYNC_CURRENT(_advsm) (&(_advsm->periodic_sync[_advsm->periodic_sync_index])) -#define SYNC_NEXT(_advsm) (&(_advsm->periodic_sync[_advsm->periodic_sync_index ^ 1])) +#define SYNC_CURRENT(_advsm) \ + (&((_advsm)->periodic_sync[(_advsm)->periodic_sync_index])) +#define SYNC_NEXT(_advsm) \ + (&((_advsm)->periodic_sync[(_advsm)->periodic_sync_index ^ 1])) #define SYNC_DATA_LEN(_advsm) \ - (_advsm->periodic_adv_data ? OS_MBUF_PKTLEN(advsm->periodic_adv_data) : 0) + ((_advsm)->periodic_adv_data ? OS_MBUF_PKTLEN((_advsm)->periodic_adv_data) : 0) /* The advertising state machine global object */ struct ble_ll_adv_sm g_ble_ll_adv_sm[BLE_ADV_INSTANCES]; @@ -216,7 +233,7 @@ static struct ble_ll_adv_sm * ble_ll_adv_sm_find_configured(uint8_t instance) { struct ble_ll_adv_sm *advsm; - int i; + unsigned int i; /* in legacy mode we only allow instance 0 */ if (!ble_ll_hci_adv_mode_ext()) { @@ -729,17 +746,17 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) adv_mode |= BLE_LL_EXT_ADV_MODE_CONN; } - ext_hdr_len = aux->payload_len - BLE_LL_EXT_ADV_HDR_LEN - aux->aux_data_len; + ext_hdr_len = aux->payload_len - BLE_LL_EXT_ADV_HDR_LEN - aux->data_len; dptr[0] = (adv_mode << 6) | ext_hdr_len; dptr += 1; /* only put flags if needed */ - if (aux->ext_hdr) { - dptr[0] = aux->ext_hdr; + if (aux->ext_hdr_flags) { + dptr[0] = aux->ext_hdr_flags; dptr += 1; } - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { /* Set TxAdd to random if needed. */ if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { @@ -750,7 +767,7 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) dptr += BLE_LL_EXT_ADV_ADVA_SIZE; } - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { memcpy(dptr, advsm->initiator_addr, BLE_LL_EXT_ADV_TARGETA_SIZE); dptr += BLE_LL_EXT_ADV_TARGETA_SIZE; @@ -760,13 +777,13 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) } } - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { dptr[0] = advsm->adi & 0x00ff; dptr[1] = advsm->adi >> 8; dptr += BLE_LL_EXT_ADV_DATA_INFO_SIZE; } - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { if (!AUX_NEXT(advsm)->sch.enqueued) { /* * Trim data here in case we do not have next aux scheduled. This @@ -776,11 +793,13 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) offset = 0; } else if (advsm->rx_ble_hdr) { offset = ble_ll_tmr_t2u(AUX_NEXT(advsm)->start_time - advsm->rx_ble_hdr->beg_cputime); - offset -= (advsm->rx_ble_hdr->rem_usecs + ble_ll_pdu_tx_time_get(12, advsm->sec_phy) + BLE_LL_IFS); + offset -= (advsm->rx_ble_hdr->rem_usecs + ble_ll_pdu_us(12, advsm->sec_phy) + BLE_LL_IFS); } else { offset = ble_ll_tmr_t2u(AUX_NEXT(advsm)->start_time - aux->start_time); } + aux->auxptr_zero = offset == 0; + ble_ll_adv_put_aux_ptr(AUX_NEXT(advsm)->chan, advsm->sec_phy, offset, dptr); @@ -788,20 +807,20 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { ble_ll_adv_put_syncinfo(advsm, NULL, NULL, dptr); dptr += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; } #endif - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { - dptr[0] = advsm->adv_txpwr + ble_ll_get_tx_pwr_compensation(); + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { + dptr[0] = advsm->tx_power + g_ble_ll_tx_power_compensation; dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; } - if (aux->aux_data_len) { - os_mbuf_copydata(*advsm->aux_data, aux->aux_data_offset, - aux->aux_data_len, dptr); + if (aux->data_len) { + os_mbuf_copydata(*advsm->aux_data, aux->data_offset, + aux->data_len, dptr); } *hdr_byte = pdu_type; @@ -872,7 +891,7 @@ ble_ll_adv_aux_scannable_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_b if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) { *ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; *ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); - dptr[0] = advsm->adv_txpwr + ble_ll_get_tx_pwr_compensation(); + dptr[0] = advsm->tx_power + g_ble_ll_tx_power_compensation; dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; } @@ -1022,9 +1041,6 @@ ble_ll_adv_tx_done(void *arg) { struct ble_ll_adv_sm *advsm; - /* reset power to max after advertising */ - ble_phy_txpwr_set(g_ble_ll_tx_power); - advsm = (struct ble_ll_adv_sm *)arg; ble_ll_trace_u32x2(BLE_LL_TRACE_ID_ADV_TXDONE, advsm->adv_instance, @@ -1032,14 +1048,14 @@ ble_ll_adv_tx_done(void *arg) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (ble_ll_adv_active_chanset_is_pri(advsm)) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_add(&advsm->adv_txdone_ev); } else if (ble_ll_adv_active_chanset_is_sec(advsm)) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); + ble_ll_event_add(&advsm->adv_sec_txdone_ev); } else { BLE_LL_ASSERT(0); } #else - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_add(&advsm->adv_txdone_ev); #endif ble_ll_state_set(BLE_LL_STATE_STANDBY); @@ -1068,7 +1084,7 @@ ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm) void ble_ll_adv_periodic_rmvd_from_sched(struct ble_ll_adv_sm *advsm) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_periodic_txdone_ev); + ble_ll_event_add(&advsm->adv_periodic_txdone_ev); } #endif @@ -1103,9 +1119,6 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch) goto adv_tx_done; } - /* Set the power */ - ble_phy_txpwr_set(advsm->adv_txpwr); - /* Set channel */ rc = ble_phy_setchan(advsm->adv_chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); BLE_LL_ASSERT(rc == 0); @@ -1123,6 +1136,9 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch) #endif #endif + /* Set the power */ + ble_ll_tx_power_set(advsm->tx_power); + /* Set transmit start time. */ txstart = sch->start_time + g_ble_ll_sched_offset_ticks; rc = ble_phy_tx_set_start_time(txstart, sch->remainder); @@ -1199,7 +1215,7 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm) /* Set end time to maximum time this schedule item may take */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - max_usecs = ble_ll_pdu_tx_time_get(advsm->adv_pdu_len, BLE_PHY_MODE_1M); + max_usecs = ble_ll_pdu_us(advsm->adv_pdu_len, BLE_PHY_MODE_1M); if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { max_usecs += BLE_LL_SCHED_DIRECT_ADV_MAX_USECS; @@ -1211,10 +1227,10 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm) * In ADV_EXT_IND we always set only ADI and AUX so the payload length * is always 7 bytes. */ - max_usecs = ble_ll_pdu_tx_time_get(7, advsm->pri_phy); + max_usecs = ble_ll_pdu_us(7, advsm->pri_phy); } #else - max_usecs = ble_ll_pdu_tx_time_get(advsm->adv_pdu_len, BLE_PHY_MODE_1M); + max_usecs = ble_ll_pdu_us(advsm->adv_pdu_len, BLE_PHY_MODE_1M); if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { max_usecs += BLE_LL_SCHED_DIRECT_ADV_MAX_USECS; @@ -1247,9 +1263,6 @@ ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch) ble_ll_adv_active_chanset_set_sec(advsm); - /* Set the power */ - ble_phy_txpwr_set(advsm->adv_txpwr); - /* Set channel */ aux = AUX_CURRENT(advsm); rc = ble_phy_setchan(aux->chan, BLE_ACCESS_ADDR_ADV, @@ -1261,6 +1274,9 @@ ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch) ble_phy_mode_set(advsm->sec_phy, advsm->sec_phy); #endif + /* Set the power */ + ble_ll_tx_power_set(advsm->tx_power); + /* Set transmit start time. */ txstart = sch->start_time + g_ble_ll_sched_offset_ticks; rc = ble_phy_tx_set_start_time(txstart, sch->remainder); @@ -1352,117 +1368,173 @@ ble_ll_adv_aux_scannable_pdu_payload_len(struct ble_ll_adv_sm *advsm) return len; } -static void -ble_ll_adv_aux_calculate(struct ble_ll_adv_sm *advsm, - struct ble_ll_adv_aux *aux, uint16_t aux_data_offset) +static uint16_t +ble_ll_adv_aux_calculate_payload(struct ble_ll_adv_sm *advsm, uint16_t props, + struct os_mbuf *data, uint32_t data_offset, + uint8_t *data_len_o, uint8_t *ext_hdr_flags_o) { - uint16_t rem_aux_data_len; - uint8_t hdr_len; + uint16_t rem_data_len; + uint8_t data_len; + uint8_t ext_hdr_flags; + uint8_t ext_hdr_len; bool chainable; + bool first_pdu; - BLE_LL_ASSERT(!aux->sch.enqueued); - BLE_LL_ASSERT((AUX_DATA_LEN(advsm) > aux_data_offset) || - (AUX_DATA_LEN(advsm) == 0 && aux_data_offset == 0)); + /* Note: advsm shall only be used to check if periodic advertising is + * enabled, other parameters in advsm may have different values than + * those we want to check (e.g. when reconfiguring instance). + */ - aux->aux_data_offset = aux_data_offset; - aux->aux_data_len = 0; - aux->payload_len = 0; - aux->ext_hdr = 0; + rem_data_len = (data ? OS_MBUF_PKTLEN(data) : 0) - data_offset; + BLE_LL_ASSERT((int16_t)rem_data_len >= 0); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - aux->chan = ble_ll_utils_dci_csa2(advsm->event_cntr++, - advsm->channel_id, - g_ble_ll_data.chan_map_num_used, - g_ble_ll_data.chan_map); -#else - aux->chan = ble_ll_utils_remapped_channel(ble_ll_rand() % BLE_PHY_NUM_DATA_CHANS, - g_ble_ll_conn_params.central_chan_map); -#endif - - rem_aux_data_len = AUX_DATA_LEN(advsm) - aux_data_offset; - chainable = !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE); + first_pdu = (data_offset == 0); + chainable = !(props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE); - hdr_len = BLE_LL_EXT_ADV_HDR_LEN; + ext_hdr_flags = 0; + ext_hdr_len = BLE_LL_EXT_ADV_HDR_LEN; - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { - /* ADI */ - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT); - hdr_len += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + /* ADI for anything but scannable */ + if (!(props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_DATA_INFO_SIZE; } - /* AdvA for 1st PDU in chain (i.e. AUX_ADV_IND or AUX_SCAN_RSP) */ - if (aux_data_offset == 0 && - !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV)) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_ADVA_BIT); - hdr_len += BLE_LL_EXT_ADV_ADVA_SIZE; + /* AdvA in 1st PDU, except for anonymous */ + if (first_pdu && + !(props & BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV)) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_ADVA_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_ADVA_SIZE; } - /* Note: this function does not calculate AUX_ADV_IND when advertising is - * scannable. Instead it is calculated in ble_ll_adv_aux_schedule_first(). - * - * However this function calculates length of AUX_SCAN_RSP and according - * to BT 5.0 Vol 6 Part B, 2.3.2.3, TargetA shall not be include there. + /* TargetA in 1st PDU, if directed * - * This is why TargetA is added to all directed advertising here unless it - * is scannable one. - * - * Note. TargetA shall not be also in AUX_CHAIN_IND + * Note that for scannable this calculates AUX_SCAN_RSP which shall not + * include TargetA (see: Core 5.3, Vol 6, Part B, 2.3.2.3). For scannable + * TargetA is included in AUX_ADV_IND which is in that case calculated in + * ble_ll_adv_aux_schedule_first(). */ - if (aux_data_offset == 0 && - (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) && - !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT); - hdr_len += BLE_LL_EXT_ADV_TARGETA_SIZE; + if (first_pdu && + (props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) && + !(props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_TARGETA_SIZE; } - /* TxPower if configured. - * Note: TxPower should not be be present in AUX_CHAIN_IND - */ - if (aux_data_offset == 0 && - (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR)) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); - hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; + /* TxPower in 1st PDU, if configured */ + if (first_pdu && + (props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR)) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - /* SyncInfo for 1st PDU in chain (i.e. AUX_ADV_IND only) if periodic - * advertising is enabled - */ - if (aux_data_offset == 0 && advsm->periodic_adv_active) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT); - hdr_len += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; + /* SyncInfo in 1st PDU, if periodic advertising is enabled */ + if (first_pdu && advsm->periodic_adv_active) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; } #endif - /* if we have any fields in ext header we need to add flags, note that Aux - * PTR is handled later and it will account for flags if needed + /* Flags, if any field is present in header + * + * Note that this does not account for AuxPtr which is added later if + * remaining data does not fit in single PDU. */ - if (aux->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; + if (ext_hdr_flags) { + ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; } - /* AdvData always */ - aux->aux_data_len = min(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_aux_data_len); + /* AdvData */ + data_len = MIN(BLE_LL_MAX_PAYLOAD_LEN - ext_hdr_len, rem_data_len); /* AuxPtr if there are more AdvData remaining that we can fit here */ - if (chainable && (rem_aux_data_len > aux->aux_data_len)) { - /* adjust for flags that needs to be added if AuxPtr is only field - * in Extended Header - */ - if (!aux->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; - aux->aux_data_len -= BLE_LL_EXT_ADV_FLAGS_SIZE; - } + if (chainable && (rem_data_len > data_len)) { + /* Add flags if not already added */ + if (!ext_hdr_flags) { + ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; + data_len -= BLE_LL_EXT_ADV_FLAGS_SIZE; + } - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); - hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - aux->aux_data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE; + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - /* PDU payload should be full if chained */ - BLE_LL_ASSERT(hdr_len + aux->aux_data_len == BLE_LL_MAX_PAYLOAD_LEN); + data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE; + + /* PDU payload should be full if adding AuxPtr */ + BLE_LL_ASSERT(ext_hdr_len + data_len == BLE_LL_MAX_PAYLOAD_LEN); } - aux->payload_len = hdr_len + aux->aux_data_len; + *data_len_o = data_len; + *ext_hdr_flags_o = ext_hdr_flags; + + return ext_hdr_len + data_len; +} + +static void +ble_ll_adv_aux_calculate(struct ble_ll_adv_sm *advsm, + struct ble_ll_adv_aux *aux, uint16_t data_offset) +{ + BLE_LL_ASSERT(!aux->sch.enqueued); + BLE_LL_ASSERT((AUX_DATA_LEN(advsm) > data_offset) || + (AUX_DATA_LEN(advsm) == 0 && data_offset == 0)); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) + aux->chan = ble_ll_utils_dci_csa2(advsm->event_cntr++, + advsm->channel_id, + g_ble_ll_data.chan_map_used, + g_ble_ll_data.chan_map); +#else + aux->chan = ble_ll_utils_remapped_channel(ble_ll_rand() % BLE_PHY_NUM_DATA_CHANS, + g_ble_ll_data.chan_map); +#endif + + aux->data_offset = data_offset; + aux->payload_len = ble_ll_adv_aux_calculate_payload(advsm, advsm->props, + *advsm->aux_data, + data_offset, + &aux->data_len, + &aux->ext_hdr_flags); +} + +static bool +ble_ll_adv_aux_check_data_itvl(struct ble_ll_adv_sm *advsm, uint16_t props, + uint8_t pri_phy, uint8_t sec_phy, + struct os_mbuf *data, uint32_t interval_us) +{ + uint32_t max_usecs; + uint16_t data_offset; + uint16_t pdu_len; + uint8_t data_len; + uint8_t ext_hdr_flags; + + /* FIXME: + * We should include PDUs on primary channel when calculating advertising + * event duration, but the actual time varies a bit in our case due to + * scheduling. For now let's assume we always schedule all PDUs 300us apart + * and we use shortest possible payload (ADI+AuxPtr, no AdvA). + * + * Note that calculations below do not take channel map and max skip into + * account, but we do not support max skip anyway for now. + */ + + max_usecs = 3 * (ble_ll_pdu_us(7, pri_phy) + 300) + + BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_MAFS_DELAY); + + data_offset = 0; + + do { + pdu_len = ble_ll_adv_aux_calculate_payload(advsm, props, data, data_offset, + &data_len, &ext_hdr_flags); + + max_usecs += ble_ll_pdu_us(pdu_len, sec_phy); + max_usecs += BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY); + + data_offset += data_len; + + } while (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)); + + return max_usecs < interval_us; } static void @@ -1480,8 +1552,8 @@ ble_ll_adv_aux_schedule_next(struct ble_ll_adv_sm *advsm) struct ble_ll_adv_aux *aux; struct ble_ll_adv_aux *aux_next; struct ble_ll_sched_item *sch; - uint16_t rem_aux_data_len; - uint16_t next_aux_data_offset; + uint16_t rem_data_len; + uint16_t next_data_offset; uint32_t max_usecs; BLE_LL_ASSERT(advsm->aux_active); @@ -1503,19 +1575,19 @@ ble_ll_adv_aux_schedule_next(struct ble_ll_adv_sm *advsm) * Do not schedule next aux if current aux does not have AuxPtr in extended * header as this means we do not need subsequent ADV_CHAIN_IND to be sent. */ - if (!(aux->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) { + if (!(aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) { return; } - next_aux_data_offset = aux->aux_data_offset + aux->aux_data_len; + next_data_offset = aux->data_offset + aux->data_len; - BLE_LL_ASSERT(AUX_DATA_LEN(advsm) >= next_aux_data_offset); + BLE_LL_ASSERT(AUX_DATA_LEN(advsm) >= next_data_offset); - rem_aux_data_len = AUX_DATA_LEN(advsm) - next_aux_data_offset; - BLE_LL_ASSERT(rem_aux_data_len > 0); + rem_data_len = AUX_DATA_LEN(advsm) - next_data_offset; + BLE_LL_ASSERT(rem_data_len > 0); - ble_ll_adv_aux_calculate(advsm, aux_next, next_aux_data_offset); - max_usecs = ble_ll_pdu_tx_time_get(aux_next->payload_len, advsm->sec_phy); + ble_ll_adv_aux_calculate(advsm, aux_next, next_data_offset); + max_usecs = ble_ll_pdu_us(aux_next->payload_len, advsm->sec_phy); aux_next->start_time = aux->sch.end_time + ble_ll_tmr_u2t_up(BLE_LL_MAFS + @@ -1527,13 +1599,12 @@ ble_ll_adv_aux_schedule_next(struct ble_ll_adv_sm *advsm) sch->end_time = aux_next->start_time + ble_ll_tmr_u2t_up(max_usecs); ble_ll_sched_adv_new(&aux_next->sch, ble_ll_adv_aux_scheduled, aux_next); - /* - * In case duration is set for advertising set we need to check if newly - * scheduled aux will fit inside duration. If not, remove it from scheduler - * so advertising will stop after current aux. + /* Remove aux if previous one was already sent with zero offset or new one + * is scheduled past advertising duration (if set). */ - if (advsm->duration && - LL_TMR_GT(aux_next->sch.end_time, advsm->adv_end_time)) { + if (aux->auxptr_zero || + (advsm->duration && LL_TMR_GT(aux_next->sch.end_time, + advsm->adv_end_time))) { ble_ll_sched_rmv_elem(&aux_next->sch); } } @@ -1556,17 +1627,18 @@ ble_ll_adv_aux_schedule_first(struct ble_ll_adv_sm *advsm) advsm->aux_dropped = 0; aux = AUX_CURRENT(advsm); + aux->auxptr_zero = 0; ble_ll_adv_aux_calculate(advsm, aux, 0); /* Set end time to maximum time this schedule item may take */ if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - max_usecs = ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy) + + max_usecs = ble_ll_pdu_us(aux->payload_len, advsm->sec_phy) + BLE_LL_IFS + /* AUX_CONN_REQ */ - ble_ll_pdu_tx_time_get(34 + 14, advsm->sec_phy) + + ble_ll_pdu_us(34 + 14, advsm->sec_phy) + BLE_LL_IFS + /* AUX_CONN_RSP */ - ble_ll_pdu_tx_time_get(14, advsm->sec_phy); + ble_ll_pdu_us(14, advsm->sec_phy); } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { /* For scannable advertising we need to calculate how much time we * need for AUX_ADV_IND along with AUX_SCAN_REQ, AUX_SCAN_RSP and @@ -1578,16 +1650,16 @@ ble_ll_adv_aux_schedule_first(struct ble_ll_adv_sm *advsm) * 2. length of AUX_ADV_IND is calculated by special function: * ble_ll_adv_aux_scannable_pdu_payload_len() */ - max_usecs = ble_ll_pdu_tx_time_get(ble_ll_adv_aux_scannable_pdu_payload_len(advsm), + max_usecs = ble_ll_pdu_us(ble_ll_adv_aux_scannable_pdu_payload_len(advsm), advsm->sec_phy) + BLE_LL_IFS + /* AUX_SCAN_REQ */ - ble_ll_pdu_tx_time_get(12, advsm->sec_phy) + + ble_ll_pdu_us(12, advsm->sec_phy) + BLE_LL_IFS + /* AUX_SCAN_RSP */ - ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy); + ble_ll_pdu_us(aux->payload_len, advsm->sec_phy); } else { - max_usecs = ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy); + max_usecs = ble_ll_pdu_us(aux->payload_len, advsm->sec_phy); } sch = &aux->sch; @@ -1615,28 +1687,18 @@ ble_ll_adv_aux_set_start_time(struct ble_ll_adv_sm *advsm) chans = bits[advsm->adv_chanmask]; - /* - * We want to schedule auxiliary packet as soon as possible after the end - * of advertising event, but no sooner than T_MAFS. The interval between - * advertising packets is 250 usecs (8.19 ticks) on LE Coded and a bit less - * on 1M, but it can vary a bit due to scheduling which we can't really - * control. Since we round ticks up for both interval and T_MAFS, we still - * have some margin here. The worst thing that can happen is that we skip - * last advertising packet which is not a bit problem so leave it as-is, no - * need to make code more complicated. - */ - - /* - * XXX: this could be improved if phy has TX-TX transition with controlled - * or predefined interval, but since it makes advertising code even - * more complicated let's skip it for now... - */ - adv_pdu_dur = (int32_t)(sched->end_time - sched->start_time) - g_ble_ll_sched_offset_ticks; - /* 9 is 8.19 ticks rounded up - see comment above */ - adv_event_dur = (adv_pdu_dur * chans) + (9 * (chans - 1)); + /* The interval between advertising PDUs may vary due to scheduling, but in + * general we reserve 3 ticks for end-to-schedule time and add scheduler + * offset. That should be more that enough to make sure there's at least + * T_mafs delay between last advertising PDU and auxiliary PDU. + * + * TODO we can make this much more efficient with TX-TX transition + */ + adv_event_dur = (adv_pdu_dur * chans) + + ((3 + g_ble_ll_sched_offset_ticks) * (chans - 1)); advsm->aux[0].start_time = advsm->adv_event_start_time + adv_event_dur + ble_ll_tmr_u2t_up(BLE_LL_MAFS + @@ -1687,24 +1749,21 @@ ble_ll_adv_halt(void) ble_ll_trace_u32(BLE_LL_TRACE_ID_ADV_HALT, advsm->adv_instance); - ble_phy_txpwr_set(g_ble_ll_tx_power); - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) if (advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING) { ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); + ble_ll_event_add(&advsm->adv_periodic_txdone_ev); ble_ll_state_set(BLE_LL_STATE_STANDBY); g_ble_ll_cur_adv_sm = NULL; return; } #endif - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_add(&advsm->adv_txdone_ev); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); + ble_ll_event_add(&advsm->adv_sec_txdone_ev); } #endif @@ -1734,6 +1793,7 @@ ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len) uint8_t adv_filter_policy; uint16_t adv_itvl_min; uint16_t adv_itvl_max; + uint32_t adv_itvl_usecs; uint16_t props; if (len != sizeof(*cmd)) { @@ -1805,7 +1865,7 @@ ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } - advsm->adv_txpwr = g_ble_ll_tx_power; + advsm->tx_power = ble_ll_tx_power_round(g_ble_ll_tx_power - g_ble_ll_tx_power_compensation); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) if (cmd->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { @@ -1829,13 +1889,20 @@ ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } + /* Determine the advertising interval we will use */ + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { + /* Set it to max. allowed for high duty cycle advertising */ + adv_itvl_usecs = BLE_LL_ADV_PDU_ITVL_HD_MS_MAX; + } else { + adv_itvl_usecs = adv_itvl_max * BLE_LL_ADV_ITVL; + } + /* Fill out rest of advertising state machine */ advsm->own_addr_type = cmd->own_addr_type; advsm->peer_addr_type = cmd->peer_addr_type; advsm->adv_filter_policy = adv_filter_policy; advsm->adv_chanmask = cmd->chan_map; - advsm->adv_itvl_min = adv_itvl_min; - advsm->adv_itvl_max = adv_itvl_max; + advsm->adv_itvl_usecs = adv_itvl_usecs; advsm->props = props; return 0; @@ -1938,9 +2005,9 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm) #endif OS_EXIT_CRITICAL(sr); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_remove(&advsm->adv_txdone_ev); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); + ble_ll_event_remove(&advsm->adv_sec_txdone_ev); #endif #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) @@ -2051,6 +2118,9 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) uint8_t adv_mode; uint8_t pdu_type; uint8_t ext_hdr_len; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + uint8_t biginfo_len; +#endif uint32_t offset; advsm = pducb_arg; @@ -2065,17 +2135,24 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) /* non-connectable and non-scannable */ adv_mode = 0; - ext_hdr_len = sync->payload_len - BLE_LL_EXT_ADV_HDR_LEN - sync->sync_data_len; + ext_hdr_len = sync->payload_len - BLE_LL_EXT_ADV_HDR_LEN - sync->data_len; dptr[0] = (adv_mode << 6) | ext_hdr_len; dptr += 1; /* only put flags if needed */ - if (sync->ext_hdr) { - dptr[0] = sync->ext_hdr; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + if (sync->ext_hdr_flags || sync->big) { + dptr[0] = sync->ext_hdr_flags; dptr += 1; } +#else + if (sync->ext_hdr_flags) { + dptr[0] = sync->ext_hdr_flags; + dptr += 1; + } +#endif - if (sync->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + if (sync->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { if (!SYNC_NEXT(advsm)->sch.enqueued) { /* * Trim data here in case we do not have next sync scheduled. This @@ -2088,20 +2165,34 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) sync->start_time); } + sync->auxptr_zero = offset == 0; + ble_ll_adv_put_aux_ptr(SYNC_NEXT(advsm)->chan, advsm->sec_phy, offset, dptr); dptr += BLE_LL_EXT_ADV_AUX_PTR_SIZE; } - if (sync->ext_hdr & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { - dptr[0] = advsm->adv_txpwr + ble_ll_get_tx_pwr_compensation(); + if (sync->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { + dptr[0] = advsm->tx_power + g_ble_ll_tx_power_compensation; dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; } - if (sync->sync_data_len) { - os_mbuf_copydata(advsm->periodic_adv_data, sync->sync_data_offset, - sync->sync_data_len, dptr); +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + if (advsm->big) { + biginfo_len = ble_ll_iso_big_biginfo_copy(advsm->big, dptr, + sync->sch.start_time + + g_ble_ll_sched_offset_ticks, + sync->sch.remainder); + BLE_LL_ASSERT(biginfo_len > 0); + + dptr += biginfo_len; + } +#endif + + if (sync->data_len) { + os_mbuf_copydata(advsm->periodic_adv_data, sync->data_offset, + sync->data_len, dptr); } *hdr_byte = pdu_type; @@ -2113,16 +2204,13 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) static void ble_ll_adv_sync_tx_done(struct ble_ll_adv_sm *advsm) { - /* reset power to default after advertising */ - ble_phy_txpwr_set(g_ble_ll_tx_power); - /* for sync we trace a no pri nor sec set */ ble_ll_trace_u32x2(BLE_LL_TRACE_ID_ADV_TXDONE, advsm->adv_instance, 0); BLE_LL_ASSERT(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); BLE_LL_ASSERT(!ble_ll_adv_active_chanset_is_sec(advsm)); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_periodic_txdone_ev); + ble_ll_event_add(&advsm->adv_periodic_txdone_ev); ble_ll_state_set(BLE_LL_STATE_STANDBY); ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); @@ -2169,9 +2257,6 @@ ble_ll_adv_sync_tx_start_cb(struct ble_ll_sched_item *sch) ble_ll_adv_active_chanset_clear(advsm); ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - /* Set the power */ - ble_phy_txpwr_set(advsm->adv_txpwr); - /* Set channel */ sync = SYNC_CURRENT(advsm); rc = ble_phy_setchan(sync->chan, advsm->periodic_access_addr, @@ -2184,6 +2269,9 @@ ble_ll_adv_sync_tx_start_cb(struct ble_ll_sched_item *sch) ble_phy_mode_set(advsm->sec_phy, advsm->sec_phy); #endif + /* Set the power */ + ble_ll_tx_power_set(advsm->tx_power); + /* Set transmit start time. */ txstart = sch->start_time + g_ble_ll_sched_offset_ticks; rc = ble_phy_tx_set_start_time(txstart, sch->remainder); @@ -2225,34 +2313,33 @@ adv_tx_done: static void ble_ll_adv_sync_calculate(struct ble_ll_adv_sm *advsm, - struct ble_ll_adv_sync *sync, - uint16_t sync_data_offset, + struct ble_ll_adv_sync *sync, uint16_t data_offset, uint8_t chan) { - uint16_t rem_sync_data_len; - uint8_t hdr_len; + uint16_t rem_data_len; + uint8_t ext_hdr_len; BLE_LL_ASSERT(!sync->sch.enqueued); - BLE_LL_ASSERT((SYNC_DATA_LEN(advsm) > sync_data_offset) || - (SYNC_DATA_LEN(advsm) == 0 && sync_data_offset == 0)); + BLE_LL_ASSERT((SYNC_DATA_LEN(advsm) > data_offset) || + (SYNC_DATA_LEN(advsm) == 0 && data_offset == 0)); - sync->sync_data_offset = sync_data_offset; - sync->sync_data_len = 0; + sync->data_offset = data_offset; + sync->data_len = 0; sync->payload_len = 0; - sync->ext_hdr = 0; + sync->ext_hdr_flags = 0; sync->chan = chan; - rem_sync_data_len = SYNC_DATA_LEN(advsm) - sync_data_offset; + rem_data_len = SYNC_DATA_LEN(advsm) - data_offset; - hdr_len = BLE_LL_EXT_ADV_HDR_LEN; + ext_hdr_len = BLE_LL_EXT_ADV_HDR_LEN; /* TxPower if configured * Note: TxPower shall not be present in chain PDU for SYNC */ - if (sync_data_offset == 0 && + if (data_offset == 0 && (advsm->periodic_adv_props & BLE_HCI_LE_SET_PERIODIC_ADV_PROP_INC_TX_PWR)) { - sync->ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); - hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; + sync->ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; } /* if we have any fields in ext header we need to add flags, note that Aux @@ -2262,32 +2349,48 @@ ble_ll_adv_sync_calculate(struct ble_ll_adv_sm *advsm, * how Aux calculate works and this also make it easier to add more fields * into flags if needed in future */ - if (sync->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + sync->big = advsm->big; + /* If BIG is present flags will always be also present even if none is set + * to indicate ACAD is present. + */ + if (sync->ext_hdr_flags || sync->big) { + ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; } +#else + if (sync->ext_hdr_flags) { + ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + if (advsm->big) { + ext_hdr_len += ble_ll_iso_big_biginfo_len(advsm->big); + } +#endif /* AdvData always */ - sync->sync_data_len = min(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_sync_data_len); + sync->data_len = MIN(BLE_LL_MAX_PAYLOAD_LEN - ext_hdr_len, rem_data_len); /* AuxPtr if there are more AdvData remaining that we can fit here */ - if ((rem_sync_data_len > sync->sync_data_len)) { - /* adjust for flags that needs to be added if AuxPtr is only field - * in Extended Header - */ - if (!sync->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; - sync->sync_data_len -= BLE_LL_EXT_ADV_FLAGS_SIZE; - } + if ((rem_data_len > sync->data_len)) { + /* adjust for flags that needs to be added if AuxPtr is only field + * in Extended Header + */ + if (!sync->ext_hdr_flags) { + ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; + sync->data_len -= BLE_LL_EXT_ADV_FLAGS_SIZE; + } - sync->ext_hdr |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); - hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - sync->sync_data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE; + sync->ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; + sync->data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE; - /* PDU payload should be full if chained */ - BLE_LL_ASSERT(hdr_len + sync->sync_data_len == BLE_LL_MAX_PAYLOAD_LEN); + /* PDU payload should be full if chained */ + BLE_LL_ASSERT(ext_hdr_len + sync->data_len == BLE_LL_MAX_PAYLOAD_LEN); } - sync->payload_len = hdr_len + sync->sync_data_len; + sync->payload_len = ext_hdr_len + sync->data_len; } static void @@ -2308,6 +2411,7 @@ ble_ll_adv_periodic_schedule_first(struct ble_ll_adv_sm *advsm, advsm->periodic_sync_index = 0; sync = SYNC_CURRENT(advsm); + sync->auxptr_zero = 0; /* For first SYNC packet in chain we use separate CSA#2 state to maintain * freq hopping as advertised in SyncInfo @@ -2323,7 +2427,7 @@ ble_ll_adv_periodic_schedule_first(struct ble_ll_adv_sm *advsm, ble_ll_adv_sync_calculate(advsm, sync, 0, chan); /* sync is always non-connectable and non-scannable*/ - max_usecs = ble_ll_pdu_tx_time_get(sync->payload_len, advsm->sec_phy); + max_usecs = ble_ll_pdu_us(sync->payload_len, advsm->sec_phy); sch = &sync->sch; @@ -2339,8 +2443,7 @@ ble_ll_adv_periodic_schedule_first(struct ble_ll_adv_sm *advsm, rc = ble_ll_sched_periodic_adv(sch, first_pdu); if (rc) { STATS_INC(ble_ll_stats, periodic_adv_drop_event); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); + ble_ll_event_add(&advsm->adv_periodic_txdone_ev); return; } @@ -2368,8 +2471,8 @@ ble_ll_adv_periodic_schedule_next(struct ble_ll_adv_sm *advsm) struct ble_ll_adv_sync *sync; struct ble_ll_adv_sync *sync_next; struct ble_ll_sched_item *sch; - uint16_t rem_sync_data_len; - uint16_t next_sync_data_offset; + uint16_t rem_data_len; + uint16_t next_data_offset; uint32_t max_usecs; uint8_t chan; @@ -2392,16 +2495,16 @@ ble_ll_adv_periodic_schedule_next(struct ble_ll_adv_sm *advsm) * Do not schedule next sync if current sync does not have AuxPtr in extended * header as this means we do not need subsequent ADV_CHAIN_IND to be sent. */ - if (!(sync->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) { + if (!(sync->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) { return; } - next_sync_data_offset = sync->sync_data_offset + sync->sync_data_len; + next_data_offset = sync->data_offset + sync->data_len; - BLE_LL_ASSERT(SYNC_DATA_LEN(advsm) >= next_sync_data_offset); + BLE_LL_ASSERT(SYNC_DATA_LEN(advsm) >= next_data_offset); - rem_sync_data_len = SYNC_DATA_LEN(advsm) - next_sync_data_offset; - BLE_LL_ASSERT(rem_sync_data_len > 0); + rem_data_len = SYNC_DATA_LEN(advsm) - next_data_offset; + BLE_LL_ASSERT(rem_data_len > 0); /* we use separate counter for chaining */ chan = ble_ll_utils_dci_csa2(advsm->periodic_chain_event_cntr++, @@ -2409,8 +2512,8 @@ ble_ll_adv_periodic_schedule_next(struct ble_ll_adv_sm *advsm) advsm->periodic_num_used_chans, advsm->periodic_chanmap); - ble_ll_adv_sync_calculate(advsm, sync_next, next_sync_data_offset, chan); - max_usecs = ble_ll_pdu_tx_time_get(sync_next->payload_len, advsm->sec_phy); + ble_ll_adv_sync_calculate(advsm, sync_next, next_data_offset, chan); + max_usecs = ble_ll_pdu_us(sync_next->payload_len, advsm->sec_phy); sync_next->start_time = sync->sch.end_time + ble_ll_tmr_u2t_up(BLE_LL_MAFS + @@ -2427,13 +2530,14 @@ ble_ll_adv_periodic_schedule_next(struct ble_ll_adv_sm *advsm) ble_ll_sched_adv_new(&sync_next->sch, ble_ll_adv_sync_next_scheduled, sync_next); - /* if we are pass advertising interval, drop chain */ - if (LL_TMR_GT(sch->end_time, advsm->periodic_adv_event_start_time + - advsm->periodic_adv_itvl_ticks)) { + /* Remove aux if previous one was already sent with zero offset or new one + * is scheduled past advertising interval. + */ + if (sync->auxptr_zero || + (LL_TMR_GT(sch->end_time, advsm->periodic_adv_event_start_time + + advsm->periodic_adv_itvl_ticks))) { STATS_INC(ble_ll_stats, periodic_chain_drop_event); ble_ll_sched_rmv_elem(&sync->sch); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); } } @@ -2503,7 +2607,7 @@ ble_ll_adv_periodic_done(struct ble_ll_adv_sm *advsm) /* Remove anything else scheduled for periodic */ ble_ll_sched_rmv_elem(&sync->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_periodic_txdone_ev); + ble_ll_event_remove(&advsm->adv_periodic_txdone_ev); /* If we have next SYNC scheduled, try to schedule another one */ if (sync_next->sch.enqueued) { @@ -2546,11 +2650,11 @@ ble_ll_adv_sm_start_periodic(struct ble_ll_adv_sm *advsm) /* keep channel map since we cannot change it later on */ memcpy(advsm->periodic_chanmap, g_ble_ll_data.chan_map, BLE_LL_CHAN_MAP_LEN); - advsm->periodic_num_used_chans = g_ble_ll_data.chan_map_num_used; + advsm->periodic_num_used_chans = g_ble_ll_data.chan_map_used; advsm->periodic_event_cntr = 0; /* for chaining we start with random counter as we share access addr */ advsm->periodic_chain_event_cntr = ble_ll_rand(); - advsm->periodic_access_addr = ble_ll_utils_calc_access_addr(); + advsm->periodic_access_addr = ble_ll_utils_calc_aa(); advsm->periodic_channel_id = ((advsm->periodic_access_addr & 0xffff0000) >> 16) ^ (advsm->periodic_access_addr & 0x0000ffff); advsm->periodic_crcinit = ble_ll_rand() & 0xffffff; @@ -2612,8 +2716,7 @@ ble_ll_adv_sm_stop_periodic(struct ble_ll_adv_sm *advsm) ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); + ble_ll_event_remove(&advsm->adv_periodic_txdone_ev); ble_ll_adv_update_periodic_data(advsm); } @@ -2706,20 +2809,11 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) advsm->event_cntr = 0; - access_addr = ble_ll_utils_calc_access_addr(); + access_addr = ble_ll_utils_calc_aa(); advsm->channel_id = ((access_addr & 0xffff0000) >> 16) ^ (access_addr & 0x0000ffff); #endif - /* Determine the advertising interval we will use */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { - /* Set it to max. allowed for high duty cycle advertising */ - advsm->adv_itvl_usecs = BLE_LL_ADV_PDU_ITVL_HD_MS_MAX; - } else { - advsm->adv_itvl_usecs = (uint32_t)advsm->adv_itvl_max; - advsm->adv_itvl_usecs *= BLE_LL_ADV_ITVL; - } - /* Set first advertising channel */ adv_chan = ble_ll_adv_first_chan(advsm); advsm->adv_chan = adv_chan; @@ -2990,6 +3084,19 @@ ble_ll_adv_set_scan_rsp_data(const uint8_t *data, uint8_t datalen, if (!advsm->new_scan_rsp_data) { return BLE_ERR_MEM_CAPACITY; } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && + !ble_ll_adv_aux_check_data_itvl(advsm, advsm->props, advsm->pri_phy, + advsm->sec_phy, + advsm->new_scan_rsp_data, + advsm->adv_itvl_usecs)) { + os_mbuf_free_chain(advsm->new_scan_rsp_data); + advsm->new_scan_rsp_data = NULL; + return BLE_ERR_PACKET_TOO_LONG; + } +#endif + ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_NEW_SCAN_RSP_DATA); } else { ble_ll_adv_update_data_mbuf(&advsm->scan_rsp_data, new_data, @@ -2999,6 +3106,16 @@ ble_ll_adv_set_scan_rsp_data(const uint8_t *data, uint8_t datalen, } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && + !ble_ll_adv_aux_check_data_itvl(advsm, advsm->props, advsm->pri_phy, + advsm->sec_phy, + advsm->scan_rsp_data, + advsm->adv_itvl_usecs)) { + os_mbuf_free_chain(advsm->scan_rsp_data); + advsm->scan_rsp_data = NULL; + return BLE_ERR_PACKET_TOO_LONG; + } + /* DID shall be updated when host provides new scan response data */ ble_ll_adv_update_did(advsm); #endif @@ -3132,6 +3249,18 @@ ble_ll_adv_set_adv_data(const uint8_t *data, uint8_t datalen, uint8_t instance, if (!advsm->new_adv_data) { return BLE_ERR_MEM_CAPACITY; } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && + !ble_ll_adv_aux_check_data_itvl(advsm, advsm->props, advsm->pri_phy, + advsm->sec_phy, advsm->new_adv_data, + advsm->adv_itvl_usecs)) { + os_mbuf_free_chain(advsm->new_adv_data); + advsm->new_adv_data = NULL; + return BLE_ERR_PACKET_TOO_LONG; + } +#endif + ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_NEW_ADV_DATA); } else { ble_ll_adv_update_data_mbuf(&advsm->adv_data, new_data, @@ -3141,6 +3270,15 @@ ble_ll_adv_set_adv_data(const uint8_t *data, uint8_t datalen, uint8_t instance, } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && + !ble_ll_adv_aux_check_data_itvl(advsm, advsm->props, advsm->pri_phy, + advsm->sec_phy, advsm->adv_data, + advsm->adv_itvl_usecs)) { + os_mbuf_free_chain(advsm->adv_data); + advsm->adv_data = NULL; + return BLE_ERR_PACKET_TOO_LONG; + } + /* DID shall be updated when host provides new advertising data */ ble_ll_adv_update_did(advsm); #endif @@ -3198,7 +3336,7 @@ static struct ble_ll_adv_sm * ble_ll_adv_sm_get(uint8_t instance) { struct ble_ll_adv_sm *advsm; - int i; + unsigned int i; advsm = ble_ll_adv_sm_find_configured(instance); if (advsm) { @@ -3229,6 +3367,7 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, struct ble_ll_adv_sm *advsm; uint32_t adv_itvl_min; uint32_t adv_itvl_max; + uint32_t adv_itvl_usecs; uint16_t props; int rc; @@ -3410,13 +3549,29 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, goto done; } + /* Determine the advertising interval we will use */ + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { + /* Set it to max. allowed for high duty cycle advertising */ + adv_itvl_usecs = BLE_LL_ADV_PDU_ITVL_HD_MS_MAX; + } else { + adv_itvl_usecs = adv_itvl_max * BLE_LL_ADV_ITVL; + } + + if (!ble_ll_adv_aux_check_data_itvl(advsm, props, cmd->pri_phy, cmd->sec_phy, + advsm->adv_data, adv_itvl_usecs) || + !ble_ll_adv_aux_check_data_itvl(advsm, props, cmd->pri_phy, cmd->sec_phy, + advsm->scan_rsp_data, adv_itvl_usecs)) { + return BLE_ERR_PACKET_TOO_LONG; + } + rc = BLE_ERR_SUCCESS; if (cmd->tx_power == 127) { /* no preference */ - advsm->adv_txpwr = g_ble_ll_tx_power; + advsm->tx_power = ble_ll_tx_power_round(g_ble_ll_tx_power - g_ble_ll_tx_power_compensation); } else { - advsm->adv_txpwr = ble_phy_txpower_round(cmd->tx_power); + advsm->tx_power = ble_ll_tx_power_round(MIN(cmd->tx_power, MYNEWT_VAL(BLE_LL_TX_PWR_MAX_DBM)) - + g_ble_ll_tx_power_compensation); } /* we can always store as those are validated and used only when needed */ @@ -3425,8 +3580,7 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, advsm->own_addr_type = cmd->own_addr_type; advsm->adv_filter_policy = cmd->filter_policy; advsm->adv_chanmask = cmd->pri_chan_map; - advsm->adv_itvl_min = adv_itvl_min; - advsm->adv_itvl_max = adv_itvl_max; + advsm->adv_itvl_usecs = adv_itvl_usecs; advsm->pri_phy = cmd->pri_phy; advsm->sec_phy = cmd->sec_phy; /* Update SID only */ @@ -3453,7 +3607,7 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, done: /* Update TX power */ - rsp->tx_power = rc ? 0 : advsm->adv_txpwr; + rsp->tx_power = rc ? 0 : (advsm->tx_power + g_ble_ll_tx_power_compensation); *rsplen = sizeof(*rsp); return rc; @@ -3714,7 +3868,7 @@ ble_ll_adv_sync_get_pdu_len(uint16_t data_len, uint16_t *data_offset, } /* AdvData always */ - data_len = min(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_data_len); + data_len = MIN(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_data_len); /* AuxPtr if there are more AdvData remaining that we can fit here */ if (rem_data_len > data_len) { @@ -3750,9 +3904,8 @@ ble_ll_adv_periodic_check_data_itvl(uint16_t payload_len, uint16_t props, while (offset < payload_len) { pdu_len = ble_ll_adv_sync_get_pdu_len(payload_len, &offset, props); - max_usecs += ble_ll_pdu_tx_time_get(pdu_len, phy); - max_usecs += ble_ll_tmr_u2t_up(BLE_LL_MAFS + - MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY)); + max_usecs += ble_ll_pdu_us(pdu_len, phy); + max_usecs += BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY); } itvl_usecs = (uint32_t)itvl * BLE_LL_ADV_PERIODIC_ITVL; @@ -4399,6 +4552,11 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr, if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD)) { ble_ll_adv_sm_stop(advsm); } + } else if (advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD_ERR); + valid = 1; +#endif } } @@ -4591,12 +4749,12 @@ ble_ll_adv_drop_event(struct ble_ll_adv_sm *advsm) ble_ll_sched_rmv_elem(&advsm->aux[0].sch); ble_ll_sched_rmv_elem(&advsm->aux[1].sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); + ble_ll_event_remove(&advsm->adv_sec_txdone_ev); advsm->aux_active = 0; #endif advsm->adv_chan = ble_ll_adv_final_chan(advsm); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_add(&advsm->adv_txdone_ev); } static void @@ -4675,7 +4833,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) /* Remove the element from the schedule if it is still there. */ ble_ll_sched_rmv_elem(&advsm->adv_sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_remove(&advsm->adv_txdone_ev); /* * Check if we have ended our advertising event. If our last advertising @@ -4736,12 +4894,12 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) ++advsm->adv_chan; } - /* - * We will transmit right away. Set next pdu start time to now - * plus a xcvr start delay just so we dont count late adv starts + /* We want to send next PDU right away so start time is set to "now" + * plus scheduling offset. Add an extra tick since LL timer may tick + * when we calculate other things in the meantime. */ advsm->adv_pdu_start_time = ble_ll_tmr_get() + - g_ble_ll_sched_offset_ticks; + g_ble_ll_sched_offset_ticks + 1; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) /* If we're past aux (unlikely, but can happen), just drop an event */ @@ -4815,7 +4973,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) rc = ble_ll_sched_adv_resched_pdu(&advsm->adv_sch); if (rc) { STATS_INC(ble_ll_stats, adv_resched_pdu_fail); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_add(&advsm->adv_txdone_ev); } } @@ -4859,12 +5017,17 @@ ble_ll_adv_sec_done(struct ble_ll_adv_sm *advsm) /* Remove anything else scheduled for secondary channel */ ble_ll_sched_rmv_elem(&aux->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); + ble_ll_event_remove(&advsm->adv_sec_txdone_ev); /* Stop advertising due to transmitting connection response */ if (advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD) { - ble_ll_adv_sm_stop(advsm); - return; + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD_ERR)) { + ble_ll_adv_sm_stop(advsm); + return; + } else { + ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD | + BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD_ERR); + } } /* If we have next AUX scheduled, try to schedule another one */ @@ -5089,8 +5252,6 @@ ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm) { memset(advsm, 0, sizeof(struct ble_ll_adv_sm)); - advsm->adv_itvl_min = BLE_HCI_ADV_ITVL_DEF; - advsm->adv_itvl_max = BLE_HCI_ADV_ITVL_DEF; advsm->adv_chanmask = BLE_HCI_ADV_CHANMASK_DEF; /* Initialize advertising tx done event */ @@ -5130,6 +5291,55 @@ ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm) advsm->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY; } +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +struct ble_ll_adv_sm * +ble_ll_adv_sync_get(uint8_t handle) +{ + struct ble_ll_adv_sm *advsm; + + advsm = ble_ll_adv_sm_find_configured(handle); + if (!advsm) { + return NULL; + } + + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED)) { + return NULL; + } + + return advsm; +} + +int +ble_ll_adv_sync_big_add(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big) +{ + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED)) { + return -EINVAL; + } + + if (advsm->big && (advsm->big != big)) { + return -EBUSY; + } + + advsm->big = big; + + return 0; +} + +int +ble_ll_adv_sync_big_remove(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big) +{ + if (advsm->big != big) { + return -EINVAL; + } + + advsm->big = NULL; + + return 0; +} +#endif /* BLE_LL_ISO_BROADCASTER */ + /** * Initialize the advertising functionality of a BLE device. This should * be called once on initialization diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn.c index dc43fecc..3565e104 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn.c @@ -28,6 +28,7 @@ #include "nimble/hci_common.h" #include "nimble/transport.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_ll_conn.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_scan.h" @@ -43,6 +44,10 @@ #include "controller/ble_ll_utils.h" #include "ble_ll_conn_priv.h" #include "ble_ll_ctrl_priv.h" +#include "ble_ll_priv.h" +#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc +#include +#endif #if (BLETEST_THROUGHPUT_TEST == 1) extern void bletest_completed_pkt(uint16_t handle); @@ -167,6 +172,11 @@ struct ble_ll_conn_active_list g_ble_ll_conn_active_list; /* List of free connections */ struct ble_ll_conn_free_list g_ble_ll_conn_free_list; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) +static uint16_t g_ble_ll_conn_css_next_slot = BLE_LL_CONN_CSS_NO_SLOT; +struct ble_ll_conn_css_list g_ble_ll_conn_css_list; +#endif + STATS_SECT_START(ble_ll_conn_stats) STATS_SECT_ENTRY(cant_set_sched) STATS_SECT_ENTRY(conn_ev_late) @@ -374,7 +384,7 @@ ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf) cp = (const void *)cmd->data; if (cmd->length != sizeof(cp->handles) + cp->handles * sizeof(cp->h[0])) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_conn_cth_flow_error_ev); + ble_ll_event_add(&g_ble_ll_conn_cth_flow_error_ev); return; } @@ -394,9 +404,54 @@ ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf) } #endif - #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) -static uint16_t g_ble_ll_conn_css_next_slot = BLE_LL_CONN_CSS_NO_SLOT; +static void +ble_ll_conn_css_update_list(struct ble_ll_conn_sm *connsm) +{ + struct ble_ll_conn_sm *e; + struct ble_ll_conn_sm *e_last; + struct ble_ll_conn_sm *e_insert_after = NULL; + bool found_to_insert = false; + + if (SLIST_FIRST(&g_ble_ll_conn_css_list) == connsm) { + SLIST_REMOVE_HEAD(&g_ble_ll_conn_css_list, css_sle); + } else { + e_last = NULL; + SLIST_FOREACH(e, &g_ble_ll_conn_css_list, css_sle) { + if (e == connsm) { + SLIST_NEXT(e_last, css_sle) = SLIST_NEXT(e, css_sle); + break; + } + e_last = e; + } + } + + if (SLIST_EMPTY(&g_ble_ll_conn_css_list)) { + SLIST_INSERT_HEAD(&g_ble_ll_conn_css_list, connsm, css_sle); + return; + } + + e_last = NULL; + SLIST_FOREACH(e, &g_ble_ll_conn_css_list, css_sle) { + if (e->css_slot_idx > connsm->css_slot_idx) { + found_to_insert = true; + e_insert_after = e_last; + break; + } + + e_last = e; + } + + if (found_to_insert) { + if (e_insert_after) { + SLIST_INSERT_AFTER(e_last, connsm, css_sle); + } else { + SLIST_INSERT_HEAD(&g_ble_ll_conn_css_list, connsm, css_sle); + } + } else { + SLIST_INSERT_AFTER(e_last, connsm, css_sle); + } +} void ble_ll_conn_css_set_next_slot(uint16_t slot_idx) @@ -417,9 +472,8 @@ ble_ll_conn_css_get_next_slot(void) /* CSS connections are sorted in active conn list so just need to find 1st * free value. */ - SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { - if ((connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) && - (connsm->css_slot_idx != slot_idx) && + SLIST_FOREACH(connsm, &g_ble_ll_conn_css_list, css_sle) { + if ((connsm->css_slot_idx != slot_idx) && (connsm->css_slot_idx_pending != slot_idx)) { break; } @@ -438,10 +492,13 @@ ble_ll_conn_css_is_slot_busy(uint16_t slot_idx) { struct ble_ll_conn_sm *connsm; - SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { - if ((connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) && - ((connsm->css_slot_idx == slot_idx) || - (connsm->css_slot_idx_pending == slot_idx))) { + if (g_ble_ll_conn_css_next_slot == slot_idx) { + return 1; + } + + SLIST_FOREACH(connsm, &g_ble_ll_conn_css_list, css_sle) { + if ((connsm->css_slot_idx == slot_idx) || + (connsm->css_slot_idx_pending == slot_idx)) { return 1; } } @@ -463,15 +520,12 @@ ble_ll_conn_css_move(struct ble_ll_conn_sm *connsm, uint16_t slot_idx) (slot_idx != BLE_LL_CONN_CSS_NO_SLOT)); slot_diff = slot_idx - connsm->css_slot_idx; - - if (slot_diff > 0) { - offset = slot_diff * ble_ll_sched_css_get_slot_us() / - BLE_LL_CONN_ITVL_USECS; - } else { - offset = (ble_ll_sched_css_get_period_slots() + slot_diff) * - ble_ll_sched_css_get_slot_us() / BLE_LL_CONN_ITVL_USECS; + if (slot_diff < 0) { + slot_diff += ble_ll_sched_css_get_period_slots(); } + offset = slot_diff * ble_ll_sched_css_get_slot_us() / BLE_LL_CONN_ITVL_USECS; + if (offset >= 0xffff) { return -1; } @@ -660,7 +714,7 @@ ble_ll_conn_current_sm_over(struct ble_ll_conn_sm *connsm) * need to post to the LL the connection event end event */ if (connsm) { - ble_ll_event_send(&connsm->conn_ev_end); + ble_ll_event_add(&connsm->conn_ev_end); } } @@ -722,14 +776,14 @@ ble_ll_conn_calc_dci_csa1(struct ble_ll_conn_sm *conn) /* Is this a valid channel? */ bitpos = 1 << (curchan & 0x07); - if (conn->chanmap[curchan >> 3] & bitpos) { + if (conn->chan_map[curchan >> 3] & bitpos) { return curchan; } /* Calculate remap index */ - remap_index = curchan % conn->num_used_chans; + remap_index = curchan % conn->chan_map_used; - return ble_ll_utils_remapped_channel(remap_index, conn->chanmap); + return ble_ll_utils_chan_map_remap(conn->chan_map, remap_index); } /** @@ -747,9 +801,9 @@ ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency) uint8_t index; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - if (CONN_F_CSA2_SUPP(conn)) { + if (conn->flags.csa2) { return ble_ll_utils_dci_csa2(conn->event_cntr, conn->channel_id, - conn->num_used_chans, conn->chanmap); + conn->chan_map_used, conn->chan_map); } #endif @@ -804,11 +858,11 @@ ble_ll_conn_start_rx_encrypt(void *arg) struct ble_ll_conn_sm *connsm; connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 1; - ble_phy_encrypt_enable(connsm->enc_data.rx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - !CONN_IS_CENTRAL(connsm)); + connsm->flags.encrypted = 1; + ble_phy_encrypt_enable(connsm->enc_data.enc_block.cipher_text); + ble_phy_encrypt_iv_set(connsm->enc_data.iv); + ble_phy_encrypt_counter_set(connsm->enc_data.rx_pkt_cntr, + !CONN_IS_CENTRAL(connsm)); } #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) @@ -818,7 +872,7 @@ ble_ll_conn_start_rx_unencrypt(void *arg) struct ble_ll_conn_sm *connsm; connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 0; + connsm->flags.encrypted = 0; ble_phy_encrypt_disable(); } #endif @@ -829,7 +883,7 @@ ble_ll_conn_txend_encrypt(void *arg) struct ble_ll_conn_sm *connsm; connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 1; + connsm->flags.encrypted = 1; ble_ll_conn_current_sm_over(connsm); } @@ -840,7 +894,7 @@ ble_ll_conn_rxend_unencrypt(void *arg) struct ble_ll_conn_sm *connsm; connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 0; + connsm->flags.encrypted = 0; ble_ll_conn_current_sm_over(connsm); } #endif @@ -851,8 +905,8 @@ ble_ll_conn_continue_rx_encrypt(void *arg) struct ble_ll_conn_sm *connsm; connsm = (struct ble_ll_conn_sm *)arg; - ble_phy_encrypt_set_pkt_cntr(connsm->enc_data.rx_pkt_cntr, - !CONN_IS_CENTRAL(connsm)); + ble_phy_encrypt_counter_set(connsm->enc_data.rx_pkt_cntr, + !CONN_IS_CENTRAL(connsm)); } #endif @@ -886,6 +940,14 @@ ble_ll_conn_get_next_sched_time(struct ble_ll_conn_sm *connsm) rem_us = connsm->anchor_point_usecs; ble_ll_tmr_add_u(&ce_end, &rem_us, connsm->conn_itvl_usecs); + ce_end -= ble_ll_tmr_u2t_up(MYNEWT_VAL(BLE_LL_CONN_EVENT_END_MARGIN)); + + if (connsm->max_ce_len_ticks) { + if (LL_TMR_LT(connsm->anchor_point + connsm->max_ce_len_ticks, ce_end)) { + ce_end = connsm->anchor_point + connsm->max_ce_len_ticks; + } + } + if (ble_ll_sched_next_time(&next_sched_time)) { if (LL_TMR_LT(next_sched_time, ce_end)) { ce_end = next_sched_time; @@ -907,7 +969,7 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm) uint8_t update_status; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (connsm->csmflags.cfbit.send_ltk_req) { + if (connsm->flags.encrypt_ltk_req) { /* * Send Long term key request event to host. If masked, we need to * send a REJECT_IND. @@ -916,7 +978,7 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm) ble_ll_ctrl_reject_ind_send(connsm, BLE_LL_CTRL_ENC_REQ, BLE_ERR_PINKEY_MISSING); } - connsm->csmflags.cfbit.send_ltk_req = 0; + connsm->flags.encrypt_ltk_req = 0; } #endif @@ -926,7 +988,7 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm) * has passed the instant. * 2) We successfully sent the reject reason. */ - if (connsm->csmflags.cfbit.host_expects_upd_event) { + if (connsm->flags.conn_update_host_w4event) { update_status = BLE_ERR_SUCCESS; if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) { ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE); @@ -937,27 +999,27 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm) } } ble_ll_hci_ev_conn_update(connsm, update_status); - connsm->csmflags.cfbit.host_expects_upd_event = 0; + connsm->flags.conn_update_host_w4event = 0; } /* Check if we need to send PHY update complete event */ #if (BLE_LL_BT5_PHY_SUPPORTED == 1) - if (CONN_F_PHY_UPDATE_EVENT(connsm)) { + if (connsm->flags.phy_update_host_w4event) { if (!ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS)) { /* Sent event. Clear flag */ - CONN_F_PHY_UPDATE_EVENT(connsm) = 0; + connsm->flags.phy_update_host_w4event = 0; } } #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) - if (connsm->csmflags.cfbit.subrate_ind_txd) { + if (connsm->flags.subrate_ind_txd) { ble_ll_conn_subrate_set(connsm, &connsm->subrate_trans); connsm->subrate_trans.subrate_factor = 0; ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SUBRATE_UPDATE); - connsm->csmflags.cfbit.subrate_ind_txd = 0; - connsm->csmflags.cfbit.subrate_host_req = 0; + connsm->flags.subrate_ind_txd = 0; + connsm->flags.subrate_host_req = 0; } #endif /* BLE_LL_CTRL_SUBRATE_IND */ #endif /* BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE */ @@ -999,7 +1061,7 @@ ble_ll_conn_adjust_pyld_len(struct ble_ll_conn_sm *connsm, uint16_t pyld_len) ret = pyld_len; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (CONN_F_ENCRYPTED(connsm)) { + if (connsm->flags.encrypted) { max_pyld_len -= BLE_LL_DATA_MIC_LEN; } #endif @@ -1047,11 +1109,11 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) md = 0; hdr_byte = BLE_LL_LLID_DATA_FRAG; - if (connsm->csmflags.cfbit.terminate_ind_rxd) { + if (connsm->flags.terminate_ind_rxd) { /* We just received terminate indication. * Just send empty packet as an ACK */ - CONN_F_EMPTY_PDU_TXD(connsm) = 1; + connsm->flags.empty_pdu_txd = 1; goto conn_tx_pdu; } @@ -1060,8 +1122,8 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) * the transmit queue. */ pkthdr = STAILQ_FIRST(&connsm->conn_txq); - if (!connsm->cur_tx_pdu && !CONN_F_EMPTY_PDU_TXD(connsm) && !pkthdr) { - CONN_F_EMPTY_PDU_TXD(connsm) = 1; + if (!connsm->cur_tx_pdu && !connsm->flags.empty_pdu_txd && !pkthdr) { + connsm->flags.empty_pdu_txd = 1; goto conn_tx_pdu; } @@ -1070,7 +1132,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) * the connection transmit queue */ cur_offset = 0; - if (!connsm->cur_tx_pdu && !CONN_F_EMPTY_PDU_TXD(connsm)) { + if (!connsm->cur_tx_pdu && !connsm->flags.empty_pdu_txd) { /* Convert packet header to mbuf */ m = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); nextpkthdr = STAILQ_NEXT(pkthdr, omp_next); @@ -1088,7 +1150,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) ((connsm->enc_data.enc_state > CONN_ENC_S_ENC_RSP_TO_BE_SENT) && CONN_IS_PERIPHERAL(connsm))) { if (!ble_ll_ctrl_enc_allowed_pdu_tx(pkthdr)) { - CONN_F_EMPTY_PDU_TXD(connsm) = 1; + connsm->flags.empty_pdu_txd = 1; goto conn_tx_pdu; } @@ -1212,13 +1274,13 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) tx_phy_mode = BLE_PHY_MODE_1M; #endif - ticks = (BLE_LL_IFS * 3) + connsm->eff_max_rx_time + - ble_ll_pdu_tx_time_get(next_txlen, tx_phy_mode) + - ble_ll_pdu_tx_time_get(cur_txlen, tx_phy_mode); + ticks = (BLE_LL_IFS * 3) + connsm->ota_max_rx_time + + ble_ll_pdu_us(next_txlen, tx_phy_mode) + + ble_ll_pdu_us(cur_txlen, tx_phy_mode); #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { - ticks += (BLE_LL_IFS + connsm->eff_max_rx_time); + ticks += (BLE_LL_IFS + connsm->ota_max_rx_time); } #endif @@ -1230,7 +1292,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) /* If we send an empty PDU we need to initialize the header */ conn_tx_pdu: - if (CONN_F_EMPTY_PDU_TXD(connsm)) { + if (connsm->flags.empty_pdu_txd) { /* * This looks strange, but we dont use the data pointer in the mbuf * when we have an empty pdu. @@ -1275,7 +1337,7 @@ conn_tx_pdu: * We could do this. Now, we just keep going and hope that we dont * overrun next scheduled item. */ - if ((connsm->csmflags.cfbit.terminate_ind_rxd) || + if ((connsm->flags.terminate_ind_rxd) || (CONN_IS_PERIPHERAL(connsm) && (md == 0) && (connsm->cons_rxd_bad_crc == 0) && ((connsm->last_rxd_hdr_byte & BLE_LL_DATA_HDR_MD_MASK) == 0) && @@ -1304,18 +1366,21 @@ conn_tx_pdu: * Both central and peripheral send the START_ENC_RSP encrypted and receive * encrypted */ - CONN_F_ENCRYPTED(connsm) = 1; + connsm->flags.encrypted = 1; connsm->enc_data.tx_encrypted = 1; - ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - CONN_IS_CENTRAL(connsm)); + ble_phy_encrypt_enable(connsm->enc_data.enc_block.cipher_text); + ble_phy_encrypt_iv_set(connsm->enc_data.iv); + ble_phy_encrypt_counter_set(connsm->enc_data.tx_pkt_cntr, + CONN_IS_CENTRAL(connsm)); + if (txend_func == NULL) { + txend_func = ble_ll_conn_continue_rx_encrypt; + } } else if (is_ctrl && (opcode == BLE_LL_CTRL_START_ENC_REQ)) { /* * Only the peripheral sends this and it gets sent unencrypted but * we receive encrypted */ - CONN_F_ENCRYPTED(connsm) = 0; + connsm->flags.encrypted = 0; connsm->enc_data.enc_state = CONN_ENC_S_START_ENC_RSP_WAIT; connsm->enc_data.tx_encrypted = 0; ble_phy_encrypt_disable(); @@ -1332,7 +1397,7 @@ conn_tx_pdu: switch (connsm->conn_role) { #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_CONN_ROLE_CENTRAL: - CONN_F_ENCRYPTED(connsm) = 0; + connsm->flags.encrypted = 0; connsm->enc_data.enc_state = CONN_ENC_S_PAUSED; connsm->enc_data.tx_encrypted = 0; ble_phy_encrypt_disable(); @@ -1340,12 +1405,12 @@ conn_tx_pdu: #endif #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_LL_CONN_ROLE_PERIPHERAL: - CONN_F_ENCRYPTED(connsm) = 1; + connsm->flags.encrypted = 1; connsm->enc_data.tx_encrypted = 1; - ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - CONN_IS_CENTRAL(connsm)); + ble_phy_encrypt_enable(connsm->enc_data.enc_block.cipher_text); + ble_phy_encrypt_iv_set(connsm->enc_data.iv); + ble_phy_encrypt_counter_set(connsm->enc_data.tx_pkt_cntr, + CONN_IS_CENTRAL(connsm)); if (txend_func == NULL) { txend_func = ble_ll_conn_start_rx_unencrypt; } else { @@ -1359,10 +1424,10 @@ conn_tx_pdu: } } else { /* If encrypted set packet counter */ - if (CONN_F_ENCRYPTED(connsm)) { + if (connsm->flags.encrypted) { connsm->enc_data.tx_encrypted = 1; - ble_phy_encrypt_set_pkt_cntr(connsm->enc_data.tx_pkt_cntr, - CONN_IS_CENTRAL(connsm)); + ble_phy_encrypt_counter_set(connsm->enc_data.tx_pkt_cntr, + CONN_IS_CENTRAL(connsm)); if (txend_func == NULL) { txend_func = ble_ll_conn_continue_rx_encrypt; } @@ -1380,18 +1445,24 @@ conn_tx_pdu: ble_hdr->txinfo.offset); /* Set last transmitted MD bit */ - CONN_F_LAST_TXD_MD(connsm) = md; + connsm->flags.last_txd_md = md; /* Increment packets transmitted */ - if (CONN_F_EMPTY_PDU_TXD(connsm)) { - if (connsm->csmflags.cfbit.terminate_ind_rxd) { - connsm->csmflags.cfbit.terminate_ind_rxd_acked = 1; + if (connsm->flags.empty_pdu_txd) { + if (connsm->flags.terminate_ind_rxd) { + connsm->flags.terminate_ind_rxd_acked = 1; } STATS_INC(ble_ll_conn_stats, tx_empty_pdus); } else if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + connsm->has_nonempty_pdu = 1; +#endif STATS_INC(ble_ll_conn_stats, tx_ctrl_pdus); STATS_INCN(ble_ll_conn_stats, tx_ctrl_bytes, cur_txlen); } else { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + connsm->has_nonempty_pdu = 1; +#endif STATS_INC(ble_ll_conn_stats, tx_l2cap_pdus); STATS_INCN(ble_ll_conn_stats, tx_l2cap_bytes, cur_txlen); } @@ -1411,7 +1482,7 @@ conn_tx_pdu: static int ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) { - int rc; + int rc = 0; #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) uint32_t usecs; #endif @@ -1424,12 +1495,12 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) connsm = (struct ble_ll_conn_sm *)sch->cb_arg; g_ble_ll_conn_cur_sm = connsm; BLE_LL_ASSERT(connsm); + + /* In rare cases 1st connection event is fired before LL finished processing + * new connection. In such case just skip this connection event and LL will + * reschedule to next connection event. + */ if (connsm->conn_state == BLE_LL_CONN_STATE_IDLE) { - /* That should not happen. If it does it means connection - * is already closed - */ - STATS_INC(ble_ll_conn_stats, sched_start_in_idle); - BLE_LL_ASSERT(0); ble_ll_conn_current_sm_over(connsm); return BLE_LL_SCHED_STATE_DONE; } @@ -1455,6 +1526,9 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) ble_phy_mode_set(connsm->phy_data.tx_phy_mode, connsm->phy_data.rx_phy_mode); #endif + /* Set the power */ + ble_ll_tx_power_set(g_ble_ll_tx_power); + switch (connsm->conn_role) { #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_CONN_ROLE_CENTRAL: @@ -1463,11 +1537,10 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) rc = ble_phy_tx_set_start_time(start, sch->remainder); if (!rc) { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (CONN_F_ENCRYPTED(connsm)) { - ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - 1); + if (connsm->flags.encrypted) { + ble_phy_encrypt_enable(connsm->enc_data.enc_block.cipher_text); + ble_phy_encrypt_iv_set(connsm->enc_data.iv); + ble_phy_encrypt_counter_set(connsm->enc_data.tx_pkt_cntr, 1); } else { ble_phy_encrypt_disable(); } @@ -1488,11 +1561,10 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_LL_CONN_ROLE_PERIPHERAL: #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (CONN_F_ENCRYPTED(connsm)) { - ble_phy_encrypt_enable(connsm->enc_data.rx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - 1); + if (connsm->flags.encrypted) { + ble_phy_encrypt_enable(connsm->enc_data.enc_block.cipher_text); + ble_phy_encrypt_iv_set(connsm->enc_data.iv); + ble_phy_encrypt_counter_set(connsm->enc_data.rx_pkt_cntr, 1); } else { ble_phy_encrypt_disable(); } @@ -1510,7 +1582,7 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) * Set flag that tells peripheral to set last anchor point if a packet * has been received. */ - connsm->csmflags.cfbit.periph_set_last_anchor = 1; + connsm->flags.periph_set_last_anchor = 1; /* * Set the wait for response time. The anchor point is when we @@ -1550,10 +1622,7 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) } if (rc == BLE_LL_SCHED_STATE_DONE) { - ble_ll_event_send(&connsm->conn_ev_end); - ble_phy_disable(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - g_ble_ll_conn_cur_sm = NULL; + ble_ll_conn_current_sm_over(connsm); } /* Set time that we last serviced the schedule */ @@ -1619,12 +1688,12 @@ ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime, if (rem_bytes > connsm->eff_max_tx_octets) { rem_bytes = connsm->eff_max_tx_octets; } - usecs = ble_ll_pdu_tx_time_get(rem_bytes, tx_phy_mode); + usecs = ble_ll_pdu_us(rem_bytes, tx_phy_mode); } else { /* We will send empty pdu (just a LL header) */ - usecs = ble_ll_pdu_tx_time_get(0, tx_phy_mode); + usecs = ble_ll_pdu_us(0, tx_phy_mode); } - usecs += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time; + usecs += (BLE_LL_IFS * 2) + connsm->ota_max_rx_time; ticks = (uint32_t)(next_sched_time - begtime); allowed_usecs = ble_ll_tmr_t2u(ticks); @@ -1699,8 +1768,8 @@ ble_ll_conn_central_common_init(struct ble_ll_conn_sm *connsm) connsm->hop_inc = (ble_ll_rand() % 12) + 5; /* Set channel map to map requested by host */ - connsm->num_used_chans = g_ble_ll_data.chan_map_num_used; - memcpy(connsm->chanmap, g_ble_ll_data.chan_map, BLE_LL_CHAN_MAP_LEN); + connsm->chan_map_used = g_ble_ll_data.chan_map_used; + memcpy(connsm->chan_map, g_ble_ll_data.chan_map, BLE_LL_CHAN_MAP_LEN); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) connsm->acc_subrate_min = g_ble_ll_conn_params.acc_subrate_min; @@ -1711,7 +1780,7 @@ ble_ll_conn_central_common_init(struct ble_ll_conn_sm *connsm) #endif /* Calculate random access address and crc initialization value */ - connsm->access_addr = ble_ll_utils_calc_access_addr(); + connsm->access_addr = ble_ll_utils_calc_aa(); connsm->crcinit = ble_ll_rand() & 0xffffff; /* Set initial schedule callback */ @@ -1743,8 +1812,59 @@ ble_ll_conn_central_init(struct ble_ll_conn_sm *connsm, connsm->conn_itvl_usecs = cc_params->conn_itvl_usecs; connsm->periph_latency = cc_params->conn_latency; connsm->supervision_tmo = cc_params->supervision_timeout; - connsm->min_ce_len = cc_params->min_ce_len; - connsm->max_ce_len = cc_params->max_ce_len; + connsm->max_ce_len_ticks = ble_ll_tmr_u2t_up(cc_params->max_ce_len * BLE_LL_CONN_CE_USECS); +} +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) +int +ble_ll_conn_set_data_len(struct ble_ll_conn_sm *connsm, + uint16_t tx_octets, uint16_t tx_time, + uint16_t rx_octets, uint16_t rx_time) +{ + int init_dle = 0; + + /* Note: octets/time shall be checked by caller! */ + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + /* Keep original values requested by host since we may want to recalculate + * after PHY changes between coded and uncoded. + */ + connsm->host_req_max_tx_time = tx_time; + connsm->host_req_max_rx_time = rx_time; + + /* If peer does not support coded, we cannot use value larger than 2120us */ + if (!ble_ll_conn_rem_feature_check(connsm, BLE_LL_FEAT_LE_CODED_PHY)) { + tx_time = MIN(tx_time, BLE_LL_CONN_SUPP_TIME_MAX_UNCODED); + rx_time = MIN(rx_time, BLE_LL_CONN_SUPP_TIME_MAX_UNCODED); + } +#endif + + if (connsm->max_tx_time != tx_time) { + connsm->max_tx_time = tx_time; + init_dle = 1; + } + + if (connsm->max_tx_octets != tx_octets) { + connsm->max_tx_octets = tx_octets; + init_dle = 1; + } + + if (rx_time && (connsm->max_rx_time != rx_time)) { + connsm->max_rx_time = rx_time; + init_dle = 1; + } + + if (rx_octets && (connsm->max_rx_octets != rx_octets)) { + connsm->max_rx_octets = rx_octets; + init_dle = 1; + } + + if (init_dle) { + ble_ll_ctrl_initiate_dle(connsm, false); + } + + return 0; } #endif @@ -1825,7 +1945,7 @@ ble_ll_conn_set_csa(struct ble_ll_conn_sm *connsm, bool chsel) { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) if (chsel) { - CONN_F_CSA2_SUPP(connsm) = 1; + connsm->flags.csa2 = 1; connsm->channel_id = ((connsm->access_addr & 0xffff0000) >> 16) ^ (connsm->access_addr & 0x0000ffff); @@ -1854,13 +1974,9 @@ void ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) { struct ble_ll_conn_global_params *conn_params; -#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - struct ble_ll_conn_sm *connsm_css_prev = NULL; - struct ble_ll_conn_sm *connsm_css; -#endif /* Reset following elements */ - connsm->csmflags.conn_flags = 0; + memset(&connsm->flags, 0, sizeof(connsm->flags)); connsm->event_cntr = 0; connsm->conn_state = BLE_LL_CONN_STATE_IDLE; connsm->disconnect_reason = 0; @@ -1878,7 +1994,8 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) connsm->subrate_base_event = 0; connsm->subrate_factor = 1; connsm->cont_num = 0; - connsm->last_pdu_event = 0; + connsm->cont_num_left = 0; + connsm->has_nonempty_pdu = 0; #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) @@ -1934,12 +2051,14 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) connsm->rem_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN; connsm->eff_max_tx_time = BLE_LL_CONN_SUPP_TIME_MIN; connsm->eff_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN; + connsm->ota_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN; connsm->rem_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; connsm->rem_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; connsm->eff_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) connsm->host_req_max_tx_time = 0; + connsm->host_req_max_rx_time = 0; #endif /* Reset encryption data */ @@ -1950,87 +2069,83 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) connsm->auth_pyld_tmo = BLE_LL_CONN_DEF_AUTH_PYLD_TMO; - CONN_F_LE_PING_SUPP(connsm) = 1; - ble_npl_callout_init(&connsm->auth_pyld_timer, - &g_ble_ll_data.ll_evq, - ble_ll_conn_auth_pyld_timer_cb, - connsm); + connsm->flags.le_ping_supp = 1; #endif /* Add to list of active connections */ -#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { - /* We will insert sorted by css_slot_idx to make finding free slot - * easier. - */ - SLIST_FOREACH(connsm_css, &g_ble_ll_conn_active_list, act_sle) { - if ((connsm_css->conn_role == BLE_LL_CONN_ROLE_CENTRAL) && - (connsm_css->css_slot_idx > connsm->css_slot_idx)) { - if (connsm_css_prev) { - SLIST_INSERT_AFTER(connsm_css_prev, connsm, act_sle); - } - break; - } - connsm_css_prev = connsm_css; - } + SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle); - if (!connsm_css_prev) { - /* List was empty or need to insert before 1st connection */ - SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle); - } else if (!connsm_css) { - /* Insert at the end of list */ - SLIST_INSERT_AFTER(connsm_css_prev, connsm, act_sle); - } - } else { - SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle); +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled() && + (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL)) { + ble_ll_conn_css_update_list(connsm); } -#else - SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle); #endif } void ble_ll_conn_update_eff_data_len(struct ble_ll_conn_sm *connsm) { + int ota_max_rx_time_calc = 0; int send_event; uint16_t eff_time; uint16_t eff_bytes; + uint16_t ota_time; + uint8_t phy_mode; /* Assume no event sent */ send_event = 0; /* See if effective times have changed */ - eff_time = min(connsm->rem_max_tx_time, connsm->max_rx_time); + eff_time = MIN(connsm->rem_max_tx_time, connsm->max_rx_time); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) if (connsm->phy_data.cur_rx_phy == BLE_PHY_CODED) { - eff_time = max(eff_time, BLE_LL_CONN_SUPP_TIME_MIN_CODED); + eff_time = MAX(eff_time, BLE_LL_CONN_SUPP_TIME_MIN_CODED); } #endif if (eff_time != connsm->eff_max_rx_time) { connsm->eff_max_rx_time = eff_time; + ota_max_rx_time_calc = 1; send_event = 1; } - eff_time = min(connsm->rem_max_rx_time, connsm->max_tx_time); + eff_time = MIN(connsm->rem_max_rx_time, connsm->max_tx_time); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) if (connsm->phy_data.cur_tx_phy == BLE_PHY_CODED) { - eff_time = max(eff_time, BLE_LL_CONN_SUPP_TIME_MIN_CODED); + eff_time = MAX(eff_time, BLE_LL_CONN_SUPP_TIME_MIN_CODED); } #endif if (eff_time != connsm->eff_max_tx_time) { connsm->eff_max_tx_time = eff_time; send_event = 1; } - eff_bytes = min(connsm->rem_max_tx_octets, connsm->max_rx_octets); + eff_bytes = MIN(connsm->rem_max_tx_octets, connsm->max_rx_octets); if (eff_bytes != connsm->eff_max_rx_octets) { connsm->eff_max_rx_octets = eff_bytes; + ota_max_rx_time_calc = 1; send_event = 1; } - eff_bytes = min(connsm->rem_max_rx_octets, connsm->max_tx_octets); + eff_bytes = MIN(connsm->rem_max_rx_octets, connsm->max_tx_octets); if (eff_bytes != connsm->eff_max_tx_octets) { connsm->eff_max_tx_octets = eff_bytes; send_event = 1; } + /* If effective rx octets and/or time value changes, we need to calculate + * actual OTA max rx time, i.e. lesser of effective max rx time and rx time + * of PDU containing max rx octets of payload. This is then used to calculate + * connection events timings. + */ + if (ota_max_rx_time_calc) { +#if BLE_LL_BT5_PHY_SUPPORTED + phy_mode = ble_ll_phy_to_phy_mode(connsm->phy_data.cur_rx_phy, + BLE_HCI_LE_PHY_CODED_S8_PREF); +#else + phy_mode = BLE_PHY_MODE_1M; +#endif + ota_time = ble_ll_pdu_us(connsm->eff_max_rx_octets, phy_mode); + connsm->ota_max_rx_time = MIN(ota_time, connsm->eff_max_rx_time); + } + if (send_event) { ble_ll_hci_ev_datalen_chg(connsm); } @@ -2077,16 +2192,17 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle); #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - /* If current connection was reference for CSS, we need to find another - * one. It does not matter which one we'll pick. - */ - if (connsm == g_ble_ll_conn_css_ref) { - SLIST_FOREACH(g_ble_ll_conn_css_ref, &g_ble_ll_conn_active_list, - act_sle) { - if (g_ble_ll_conn_css_ref->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { - break; - } + if (ble_ll_sched_css_is_enabled() && + (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL)) { + /* If current connection was reference for CSS, we need to find another + * one. It does not matter which one we'll pick. + */ + OS_ENTER_CRITICAL(sr); + SLIST_REMOVE(&g_ble_ll_conn_css_list, connsm, ble_ll_conn_sm, css_sle); + if (connsm == g_ble_ll_conn_css_ref) { + g_ble_ll_conn_css_ref = SLIST_FIRST(&g_ble_ll_conn_css_list); } + OS_EXIT_CRITICAL(sr); } #endif @@ -2114,7 +2230,7 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) } /* Make sure events off queue */ - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end); + ble_ll_event_remove(&connsm->conn_ev_end); /* Connection state machine is now idle */ connsm->conn_state = BLE_LL_CONN_STATE_IDLE; @@ -2123,19 +2239,19 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) * If we have features and there's pending HCI command, send an event before * disconnection event so it does make sense to host. */ - if (connsm->csmflags.cfbit.pending_hci_rd_features && - connsm->csmflags.cfbit.rxd_features) { + if (connsm->flags.features_host_req && + connsm->flags.features_rxd) { ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; + connsm->flags.features_host_req = 0; } /* * If there is still pending read features request HCI command, send an * event to complete it. */ - if (connsm->csmflags.cfbit.pending_hci_rd_features) { + if (connsm->flags.features_host_req) { ble_ll_hci_ev_rd_rem_used_feat(connsm, ble_err); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; + connsm->flags.features_host_req = 0; } /* @@ -2147,7 +2263,7 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) * received and we should not send an event. */ if (ble_err && (ble_err != BLE_ERR_UNK_CONN_ID || - connsm->csmflags.cfbit.terminate_ind_rxd)) { + connsm->flags.terminate_ind_rxd)) { ble_ll_disconn_comp_event_send(connsm, ble_err); } @@ -2185,8 +2301,6 @@ ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event, int ble_ll_conn_move_anchor(struct ble_ll_conn_sm *connsm, uint16_t offset) { - struct ble_ll_conn_params cp = { }; - BLE_LL_ASSERT(connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL); if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ) || @@ -2194,14 +2308,8 @@ ble_ll_conn_move_anchor(struct ble_ll_conn_sm *connsm, uint16_t offset) return -1; } - /* Keep parameters, we just want to move anchor */ - cp.interval_max = connsm->conn_itvl; - cp.interval_min = connsm->conn_itvl; - cp.latency = connsm->periph_latency; - cp.timeout = connsm->supervision_tmo; - cp.offset0 = offset; - - ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE, &cp); + connsm->conn_update_anchor_offset_req = offset; + ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE, NULL); return 0; } @@ -2239,17 +2347,19 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) uint16_t trans_next_event_cntr; uint16_t subrate_conn_upd_event_cntr; #endif - +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + uint8_t anchor_calc_for_css = 0; +#endif /* XXX: deal with connection request procedure here as well */ ble_ll_conn_chk_csm_flags(connsm); /* If unable to start terminate procedure, start it now */ - if (connsm->disconnect_reason && !CONN_F_TERMINATE_STARTED(connsm)) { + if (connsm->disconnect_reason && !connsm->flags.terminate_started) { ble_ll_ctrl_terminate_start(connsm); } - if (CONN_F_TERMINATE_STARTED(connsm) && CONN_IS_PERIPHERAL(connsm)) { + if (connsm->flags.terminate_started && CONN_IS_PERIPHERAL(connsm)) { /* Some of the devices waits whole connection interval to ACK our * TERMINATE_IND sent as a Slave. Since we are here it means we are still waiting for ACK. * Make sure we catch it in next connection event. @@ -2262,10 +2372,25 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) base_event_cntr = connsm->subrate_base_event; subrate_factor = connsm->subrate_factor; - if ((connsm->cont_num > 0) && - (connsm->event_cntr + 1 == connsm->subrate_base_event + - connsm->subrate_factor) && - (connsm->event_cntr - connsm->last_pdu_event < connsm->cont_num)) { + /* We need to restore remaining continuation events counter if a non-empty + * PDU was txd/rxd in this connection event. Also we need to set counter to + * 0 in case there was no valid PDU at subrated event, since we should not + * use continuation events in such case (i.e. ignore any valid PDUs prior + * to subrated event). + * + * Note that has_nonempty_pdu flag is also cleared here since LL may move to + * next connection event due to scheduling conflict and there will be no + * start callback for new event. + */ + if (connsm->has_nonempty_pdu) { + connsm->cont_num_left = connsm->cont_num; + connsm->has_nonempty_pdu = 0; + } else if (connsm->event_cntr == connsm->subrate_base_event) { + connsm->cont_num_left = 0; + } + + if (connsm->cont_num_left > 0) { + connsm->cont_num_left--; next_is_subrated = 0; } #else @@ -2288,11 +2413,11 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) /* Set event counter to the next connection event that we will tx/rx in */ use_periph_latency = next_is_subrated && - connsm->csmflags.cfbit.allow_periph_latency && - !connsm->csmflags.cfbit.conn_update_sched && - !connsm->csmflags.cfbit.phy_update_sched && - !connsm->csmflags.cfbit.chanmap_update_scheduled && - connsm->csmflags.cfbit.pkt_rxd; + connsm->flags.periph_use_latency && + !connsm->flags.conn_update_sched && + !connsm->flags.phy_update_sched && + !connsm->flags.chanmap_update_sched && + connsm->flags.pkt_rxd; if (next_is_subrated) { next_event_cntr = base_event_cntr + subrate_factor; @@ -2304,7 +2429,7 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) /* If we are in subrate transition mode, we should also listen on * subrated connection events based on new parameters. */ - if (connsm->csmflags.cfbit.subrate_trans) { + if (connsm->flags.subrate_trans) { BLE_LL_ASSERT(CONN_IS_CENTRAL(connsm)); cstp = &connsm->subrate_trans; @@ -2330,7 +2455,7 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) * and one connection event before instant regardless of subrating. */ if (CONN_IS_PERIPHERAL(connsm) && - connsm->csmflags.cfbit.conn_update_sched && + connsm->flags.conn_update_sched && (connsm->subrate_factor > 1)) { subrate_conn_upd_event_cntr = connsm->conn_update_req.instant - 1; if (connsm->event_cntr == subrate_conn_upd_event_cntr) { @@ -2362,14 +2487,16 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) connsm->event_cntr = next_event_cntr; #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + if (ble_ll_sched_css_is_enabled() && + connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { connsm->css_period_idx += event_cntr_diff; - /* If this is non-reference connection, we set anchor from reference - * instead of calculating manually. + /* If this is non-reference connection, we calculate anchor point from + * reference connection instead of using connection interval. This is + * to make sure connections do not drift over time. */ if (g_ble_ll_conn_css_ref != connsm) { - ble_ll_sched_css_set_conn_anchor(connsm); + anchor_calc_for_css = 1; skip_anchor_calc = 1; } } @@ -2397,7 +2524,7 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) * connection by the the transmit window offset. We also copy in the * update parameters as they now should take effect. */ - if (connsm->csmflags.cfbit.conn_update_sched && + if (connsm->flags.conn_update_sched && (connsm->event_cntr == connsm->conn_update_req.instant)) { /* Set flag so we send connection update event */ @@ -2408,7 +2535,7 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) (connsm->conn_itvl != upd->interval) || (connsm->periph_latency != upd->latency) || (connsm->supervision_tmo != upd->timeout)) { - connsm->csmflags.cfbit.host_expects_upd_event = 1; + connsm->flags.conn_update_host_w4event = 1; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) @@ -2419,6 +2546,36 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) } #endif +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled() && + connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + BLE_LL_ASSERT(connsm->css_slot_idx_pending != + BLE_LL_CONN_CSS_NO_SLOT); + + /* If we are moving to an earlier slot, we are effectively skipping + * one period. + */ + if (connsm->css_slot_idx_pending < connsm->css_slot_idx) { + connsm->css_period_idx++; + } + + connsm->css_slot_idx = connsm->css_slot_idx_pending; + connsm->css_slot_idx_pending = BLE_LL_CONN_CSS_NO_SLOT; + + ble_ll_conn_css_update_list(connsm); + + if (anchor_calc_for_css) { + ble_ll_sched_css_set_conn_anchor(connsm); + anchor_calc_for_css = 0; + } + +#if MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) + ble_ll_hci_ev_send_vs_css_slot_changed(connsm->conn_handle, + connsm->css_slot_idx); +#endif + } +#endif + connsm->supervision_tmo = upd->timeout; connsm->periph_latency = upd->latency; connsm->tx_win_size = upd->winsize; @@ -2430,6 +2587,11 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) ble_ll_conn_itvl_to_ticks(connsm->conn_itvl, &connsm->conn_itvl_ticks, &connsm->conn_itvl_usecs); + if (connsm->conn_param_req.handle != 0) { + connsm->max_ce_len_ticks = ble_ll_tmr_u2t_up(connsm->conn_param_req.max_ce_len * BLE_LL_CONN_CE_USECS); + connsm->conn_param_req.handle = 0; + } + if (upd->winoffset != 0) { usecs = upd->winoffset * BLE_LL_CONN_ITVL_USECS; ble_ll_tmr_add(&connsm->anchor_point, &connsm->anchor_point_usecs, @@ -2439,17 +2601,8 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) /* Reset the starting point of the connection supervision timeout */ connsm->last_rxd_pdu_cputime = connsm->anchor_point; -#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { - BLE_LL_ASSERT(connsm->css_slot_idx_pending != - BLE_LL_CONN_CSS_NO_SLOT); - connsm->css_slot_idx = connsm->css_slot_idx_pending; - connsm->css_slot_idx_pending = BLE_LL_CONN_CSS_NO_SLOT; - } -#endif - /* Reset update scheduled flag */ - connsm->csmflags.cfbit.conn_update_sched = 0; + connsm->flags.conn_update_sched = 0; } /* @@ -2461,18 +2614,18 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) * new channel map once the event counter equals or has passed channel * map update instant. */ - if (connsm->csmflags.cfbit.chanmap_update_scheduled && + if (connsm->flags.chanmap_update_sched && ((int16_t)(connsm->chanmap_instant - connsm->event_cntr) <= 0)) { /* XXX: there is a chance that the control packet is still on * the queue of the central. This means that we never successfully * transmitted update request. Would end up killing connection on peripheral side. Could ignore it or see if still enqueued. */ - connsm->num_used_chans = - ble_ll_utils_calc_num_used_chans(connsm->req_chanmap); - memcpy(connsm->chanmap, connsm->req_chanmap, BLE_LL_CHAN_MAP_LEN); + connsm->chan_map_used = + ble_ll_utils_chan_map_used_get(connsm->req_chanmap); + memcpy(connsm->chan_map, connsm->req_chanmap, BLE_LL_CHAN_MAP_LEN); - connsm->csmflags.cfbit.chanmap_update_scheduled = 0; + connsm->flags.chanmap_update_sched = 0; ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CHAN_MAP_UPD); @@ -2480,8 +2633,14 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) check to make sure we dont have to restart! */ } +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (anchor_calc_for_css) { + ble_ll_sched_css_set_conn_anchor(connsm); + } +#endif + #if (BLE_LL_BT5_PHY_SUPPORTED == 1) - if (CONN_F_PHY_UPDATE_SCHED(connsm) && + if (connsm->flags.phy_update_sched && (connsm->event_cntr == connsm->phy_instant)) { /* Set cur phy to new phy */ @@ -2500,8 +2659,8 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) } /* Clear flags and set flag to send event at next instant */ - CONN_F_PHY_UPDATE_SCHED(connsm) = 0; - CONN_F_PHY_UPDATE_EVENT(connsm) = 1; + connsm->flags.phy_update_sched = 0; + connsm->flags.phy_update_host_w4event = 1; ble_ll_ctrl_phy_update_proc_complete(connsm); @@ -2520,7 +2679,7 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) !ble_ll_conn_rem_feature_check(connsm, BLE_LL_FEAT_LE_CODED_PHY)) { ble_ll_conn_rem_feature_add(connsm, BLE_LL_FEAT_LE_CODED_PHY); connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_CODED; - ble_ll_ctrl_initiate_dle(connsm); + ble_ll_ctrl_initiate_dle(connsm, false); } #endif } @@ -2534,18 +2693,31 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) * passed the termination timeout. If so, no need to continue with * connection as we will time out anyway. */ - if (CONN_F_TERMINATE_STARTED(connsm)) { + if (connsm->flags.terminate_started) { if ((int32_t)(connsm->terminate_timeout - connsm->anchor_point) <= 0) { return -1; } } /* - * Calculate ce end time. For a peripgheral, we need to add window widening + * Calculate ce end time. For a peripheral, we need to add window widening * and the transmit window if we still have one. */ +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + /* If css is enabled, use slot duration instead of conn_init_slots for + * reservation. + */ + if (ble_ll_sched_css_is_enabled() && + connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + ce_duration = ble_ll_tmr_u2t(ble_ll_sched_css_get_slot_us()); + } else { + ce_duration = ble_ll_tmr_u2t(MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * + BLE_LL_SCHED_USECS_PER_SLOT); + } +#else ce_duration = ble_ll_tmr_u2t(MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * - BLE_LL_SCHED_USECS_PER_SLOT); + BLE_LL_SCHED_USECS_PER_SLOT); +#endif #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { @@ -2601,7 +2773,7 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) connsm->conn_state = BLE_LL_CONN_STATE_CREATED; /* Clear packet received flag */ - connsm->csmflags.cfbit.pkt_rxd = 0; + connsm->flags.pkt_rxd = 0; /* Consider time created the last scheduled time */ connsm->last_scheduled = ble_ll_tmr_get(); @@ -2630,7 +2802,7 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) usecs = rxhdr->rem_usecs + 1250 + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS) + - ble_ll_pdu_tx_time_get(BLE_CONNECT_REQ_LEN, + ble_ll_pdu_us(BLE_CONNECT_REQ_LEN, rxhdr->rxinfo.phy_mode); if (rxhdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { @@ -2684,12 +2856,19 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) * the other side can support it? */ if (!ble_ll_conn_phy_update_if_needed(connsm)) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 1; + connsm->flags.phy_update_self_initiated = 1; } #endif switch (connsm->conn_role) { #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_CONN_ROLE_CENTRAL: +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + ble_ll_sched_css_update_anchor(connsm); + ble_ll_conn_css_set_next_slot(BLE_LL_CONN_CSS_NO_SLOT); + } +#endif + evbuf = ble_ll_init_get_conn_comp_ev(); ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, NULL); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) @@ -2742,20 +2921,6 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) /* Better be a connection state machine! */ connsm = (struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev); BLE_LL_ASSERT(connsm); - if (connsm->conn_state == BLE_LL_CONN_STATE_IDLE) { - /* That should not happen. If it does it means connection - * is already closed. - * Make sure LL state machine is in idle - */ - STATS_INC(ble_ll_conn_stats, sched_end_in_idle); - BLE_LL_ASSERT(0); - - /* Just in case */ - ble_ll_state_set(BLE_LL_STATE_STANDBY); - - ble_ll_scan_chk_resume(); - return; - } /* Log event end */ ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CONN_EV_END, connsm->conn_handle, @@ -2764,10 +2929,10 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) ble_ll_scan_chk_resume(); /* If we have transmitted the terminate IND successfully, we are done */ - if ((connsm->csmflags.cfbit.terminate_ind_txd) || - (connsm->csmflags.cfbit.terminate_ind_rxd && - connsm->csmflags.cfbit.terminate_ind_rxd_acked)) { - if (connsm->csmflags.cfbit.terminate_ind_txd) { + if ((connsm->flags.terminate_ind_txd) || + (connsm->flags.terminate_ind_rxd && + connsm->flags.terminate_ind_rxd_acked)) { + if (connsm->flags.terminate_ind_txd) { ble_err = BLE_ERR_CONN_TERM_LOCAL; } else { /* Make sure the disconnect reason is valid! */ @@ -2781,13 +2946,13 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) } /* Remove any connection end events that might be enqueued */ - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end); + ble_ll_event_remove(&connsm->conn_ev_end); /* * If we have received a packet, we can set the current transmit window * usecs to 0 since we dont need to listen in the transmit window. */ - if (connsm->csmflags.cfbit.pkt_rxd) { + if (connsm->flags.pkt_rxd) { connsm->periph_cur_tx_win_usecs = 0; } @@ -2814,7 +2979,7 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) /* Reset "per connection event" variables */ connsm->cons_rxd_bad_crc = 0; - connsm->csmflags.cfbit.pkt_rxd = 0; + connsm->flags.pkt_rxd = 0; /* See if we need to start any control procedures */ ble_ll_ctrl_chk_proc_start(connsm); @@ -2865,10 +3030,10 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) ble_ll_conn_num_comp_pkts_event_send(connsm); /* If we have features and there's pending HCI command, send an event */ - if (connsm->csmflags.cfbit.pending_hci_rd_features && - connsm->csmflags.cfbit.rxd_features) { + if (connsm->flags.features_host_req && + connsm->flags.features_rxd) { ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; + connsm->flags.features_host_req = 0; } } @@ -3006,7 +3171,7 @@ ble_ll_conn_tx_connect_ind_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_by put_le16(dptr + 10, connsm->conn_itvl); put_le16(dptr + 12, connsm->periph_latency); put_le16(dptr + 14, connsm->supervision_tmo); - memcpy(dptr + 16, &connsm->chanmap, BLE_LL_CHAN_MAP_LEN); + memcpy(dptr + 16, &connsm->chan_map, BLE_LL_CHAN_MAP_LEN); dptr[21] = connsm->hop_inc | (connsm->central_sca << 5); *hdr_byte = pdu_data->hdr_byte; @@ -3027,8 +3192,8 @@ ble_ll_conn_event_halt(void) { ble_ll_state_set(BLE_LL_STATE_STANDBY); if (g_ble_ll_conn_cur_sm) { - g_ble_ll_conn_cur_sm->csmflags.cfbit.pkt_rxd = 0; - ble_ll_event_send(&g_ble_ll_conn_cur_sm->conn_ev_end); + g_ble_ll_conn_cur_sm->flags.pkt_rxd = 0; + ble_ll_event_add(&g_ble_ll_conn_cur_sm->conn_ev_end); g_ble_ll_conn_cur_sm = NULL; } } @@ -3226,7 +3391,7 @@ ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa) if (aa != connsm->access_addr) { STATS_INC(ble_ll_conn_stats, rx_data_pdu_bad_aa); ble_ll_state_set(BLE_LL_STATE_STANDBY); - ble_ll_event_send(&connsm->conn_ev_end); + ble_ll_event_add(&connsm->conn_ev_end); g_ble_ll_conn_cur_sm = NULL; return -1; } @@ -3235,14 +3400,14 @@ ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa) rxhdr->rxinfo.handle = connsm->conn_handle; /* Set flag denoting we have received a packet in connection event */ - connsm->csmflags.cfbit.pkt_rxd = 1; + connsm->flags.pkt_rxd = 1; /* Connection is established */ connsm->conn_state = BLE_LL_CONN_STATE_ESTABLISHED; /* Set anchor point (and last) if 1st rxd frame in connection event */ - if (connsm->csmflags.cfbit.periph_set_last_anchor) { - connsm->csmflags.cfbit.periph_set_last_anchor = 0; + if (connsm->flags.periph_set_last_anchor) { + connsm->flags.periph_set_last_anchor = 0; connsm->last_anchor_point = rxhdr->beg_cputime; connsm->anchor_point = connsm->last_anchor_point; connsm->anchor_point_usecs = rxhdr->rem_usecs; @@ -3290,16 +3455,18 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) hdr_byte = rxbuf[0]; acl_len = rxbuf[1]; llid = hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) - connsm->last_pdu_event = connsm->event_cntr; -#endif - + rxd_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) if (BLE_MBUF_HDR_MIC_FAILURE(hdr)) { - STATS_INC(ble_ll_conn_stats, mic_failures); - ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC); + /* MIC failure is expected on retransmissions since packet counter does + * not match, so we simply ignore retransmitted PDU with MIC failure as + * they do not have proper decrypted contents. + */ + if (rxd_sn != connsm->last_rxd_sn) { + STATS_INC(ble_ll_conn_stats, mic_failures); + ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC); + } goto conn_rx_data_pdu_end; } #endif @@ -3337,13 +3504,13 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) * connection */ if ((connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED) && - CONN_F_LE_PING_SUPP(connsm) && (acl_len != 0)) { + connsm->flags.le_ping_supp && (acl_len != 0)) { ble_ll_conn_auth_pyld_timer_start(connsm); } #endif /* Update RSSI */ - connsm->conn_rssi = hdr->rxinfo.rssi; + connsm->conn_rssi = hdr->rxinfo.rssi - ble_ll_rx_gain(); /* * If we are a peripheral, we can only start to use peripheral latency @@ -3352,7 +3519,7 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { if (hdr_byte & BLE_LL_DATA_HDR_NESN_MASK) { - connsm->csmflags.cfbit.allow_periph_latency = 1; + connsm->flags.periph_use_latency = 1; } } #endif @@ -3361,7 +3528,6 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) * Discard the received PDU if the sequence number is the same * as the last received sequence number */ - rxd_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK; if (rxd_sn == connsm->last_rxd_sn) { STATS_INC(ble_ll_conn_stats, data_pdu_rx_dup); goto conn_rx_data_pdu_end; @@ -3375,6 +3541,10 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) goto conn_rx_data_pdu_end; } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + connsm->has_nonempty_pdu = 1; +#endif + if (llid == BLE_LL_LLID_CTRL) { /* Process control frame */ STATS_INC(ble_ll_conn_stats, rx_ctrl_pdus); @@ -3402,9 +3572,9 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) /* Free buffer */ conn_rx_data_pdu_end: -#if MYNEWT_VAL(BLE_TRANSPORT_INT_FLOW_CTL) +#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_CONN_CREDIT_INT) { - ble_transport_int_flow_ctl_put(); + hci_ipc_put(HCI_IPC_TYPE_ACL); } #endif @@ -3440,7 +3610,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) uint8_t hdr_nesn; uint8_t conn_sn; uint8_t conn_nesn; - uint8_t reply; + uint8_t reply = 0; uint16_t rem_bytes; uint8_t opcode = 0; uint8_t rx_pyld_len; @@ -3468,12 +3638,12 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) alloc_rxpdu = false; } -#if MYNEWT_VAL(BLE_TRANSPORT_INT_FLOW_CTL) - /* Do not alloc PDU if there are no free buffers in transport. We'll nak - * this PDU in LL. +#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc + /* If IPC transport is used, make sure there is buffer available on app side + * for this PDU. We'll just nak in LL if there are no free buffers. */ if (alloc_rxpdu && BLE_LL_LLID_IS_DATA(hdr_byte) && (rx_pyld_len > 0)) { - if (ble_transport_int_flow_ctl_get()) { + if (hci_ipc_get(HCI_IPC_TYPE_ACL)) { rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_CREDIT_INT; } else { alloc_rxpdu = false; @@ -3493,8 +3663,9 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) if (ble_ll_conn_cth_flow_alloc_credit(connsm)) { rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_CREDIT; } else { -#if MYNEWT_VAL(BLE_TRANSPORT_INT_FLOW_CTL) - ble_transport_int_flow_ctl_put(); +#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc + /* Need to return app buffer to pool since we won't use it */ + hci_ipc_put(HCI_IPC_TYPE_ACL); #endif alloc_rxpdu = false; } @@ -3533,7 +3704,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) rx_phy_mode = BLE_PHY_MODE_1M; #endif add_usecs = rxhdr->rem_usecs + - ble_ll_pdu_tx_time_get(rx_pyld_len, rx_phy_mode); + ble_ll_pdu_us(rx_pyld_len, rx_phy_mode); /* * Check the packet CRC. A connection event can continue even if the @@ -3552,7 +3723,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) switch (connsm->conn_role) { #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_CONN_ROLE_CENTRAL: - reply = CONN_F_LAST_TXD_MD(connsm); + reply = connsm->flags.last_txd_md; break; #endif #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) @@ -3589,7 +3760,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) if (rxpdu && ((hdr_sn && conn_nesn) || (!hdr_sn && !conn_nesn))) { connsm->next_exp_seqnum ^= 1; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (CONN_F_ENCRYPTED(connsm) && !ble_ll_conn_is_empty_pdu(rxbuf)) { + if (connsm->flags.encrypted && !ble_ll_conn_is_empty_pdu(rxbuf)) { ++connsm->enc_data.rx_pkt_cntr; } #endif @@ -3602,7 +3773,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) * Check NESN bit from header. If same as tx seq num, the transmission * is acknowledged. Otherwise we need to resend this PDU. */ - if (CONN_F_EMPTY_PDU_TXD(connsm) || connsm->cur_tx_pdu) { + if (connsm->flags.empty_pdu_txd || connsm->cur_tx_pdu) { hdr_nesn = hdr_byte & BLE_LL_DATA_HDR_NESN_MASK; conn_sn = connsm->tx_seqnum; if ((hdr_nesn && conn_sn) || (!hdr_nesn && !conn_sn)) { @@ -3614,8 +3785,8 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) STATS_INC(ble_ll_conn_stats, data_pdu_txg); /* If we transmitted the empty pdu, clear flag */ - if (CONN_F_EMPTY_PDU_TXD(connsm)) { - CONN_F_EMPTY_PDU_TXD(connsm) = 0; + if (connsm->flags.empty_pdu_txd) { + connsm->flags.empty_pdu_txd = 0; goto chk_rx_terminate_ind; } @@ -3654,8 +3825,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) #endif ++connsm->completed_pkts; if (connsm->completed_pkts > 2) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &g_ble_ll_data.ll_comp_pkt_ev); + ble_ll_event_add(&g_ble_ll_data.ll_comp_pkt_ev); } } os_mbuf_free_chain(txpdu); @@ -3687,14 +3857,14 @@ chk_rx_terminate_ind: if (BLE_LL_LLID_IS_CTRL(hdr_byte) && (opcode == BLE_LL_CTRL_TERMINATE_IND) && (rx_pyld_len == (1 + BLE_LL_CTRL_TERMINATE_IND_LEN))) { - connsm->csmflags.cfbit.terminate_ind_rxd = 1; + connsm->flags.terminate_ind_rxd = 1; connsm->rxd_disconnect_reason = rxbuf[3]; } switch (connsm->conn_role) { #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_CONN_ROLE_CENTRAL: - reply = CONN_F_LAST_TXD_MD(connsm) || (hdr_byte & BLE_LL_DATA_HDR_MD_MASK); + reply = connsm->flags.last_txd_md || (hdr_byte & BLE_LL_DATA_HDR_MD_MASK); break; #endif #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) @@ -3711,7 +3881,7 @@ chk_rx_terminate_ind: /* If reply flag set, send data pdu and continue connection event */ rc = -1; - if (rx_pyld_len && CONN_F_ENCRYPTED(connsm)) { + if (rx_pyld_len && connsm->flags.encrypted) { rx_pyld_len += BLE_LL_DATA_MIC_LEN; } if (reply && ble_ll_conn_can_send_next_pdu(connsm, begtime, add_usecs)) { @@ -3869,29 +4039,13 @@ ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length) } } #endif -/** - * Called to set the global channel mask that we use for all connections. - * - * @param num_used_chans - * @param chanmap - */ + void -ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap) +ble_ll_conn_chan_map_update(void) { #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) struct ble_ll_conn_sm *connsm; -#endif - - /* Do nothing if same channel map */ - if (!memcmp(g_ble_ll_data.chan_map, chanmap, BLE_LL_CHAN_MAP_LEN)) { - return; - } - - /* Change channel map and cause channel map update procedure to start */ - g_ble_ll_data.chan_map_num_used = num_used_chans; - memcpy(g_ble_ll_data.chan_map, chanmap, BLE_LL_CHAN_MAP_LEN); -#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /* Perform channel map update */ SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { @@ -3963,7 +4117,7 @@ ble_ll_conn_periph_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr connsm->conn_itvl = get_le16(dptr + 10); connsm->periph_latency = get_le16(dptr + 12); connsm->supervision_tmo = get_le16(dptr + 14); - memcpy(&connsm->chanmap, dptr + 16, BLE_LL_CHAN_MAP_LEN); + memcpy(&connsm->chan_map, dptr + 16, BLE_LL_CHAN_MAP_LEN); connsm->hop_inc = dptr[21] & 0x1F; connsm->central_sca = dptr[21] >> 5; @@ -4001,8 +4155,8 @@ ble_ll_conn_periph_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr connsm->peer_addr_type = pat; /* Calculate number of used channels; make sure it meets min requirement */ - connsm->num_used_chans = ble_ll_utils_calc_num_used_chans(connsm->chanmap); - if (connsm->num_used_chans < 2) { + connsm->chan_map_used = ble_ll_utils_chan_map_used_get(connsm->chan_map); + if (connsm->chan_map_used < 2) { goto err_periph_start; } @@ -4090,14 +4244,14 @@ ble_ll_conn_subrate_req_hci(struct ble_ll_conn_sm *connsm, connsm->subrate_trans.periph_latency = srp->max_latency; connsm->subrate_trans.cont_num = srp->cont_num; connsm->subrate_trans.supervision_tmo = srp->supervision_tmo; - connsm->csmflags.cfbit.subrate_host_req = 1; + connsm->flags.subrate_host_req = 1; ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_SUBRATE_UPDATE, NULL); break; #endif #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_LL_CONN_ROLE_PERIPHERAL: connsm->subrate_req = *srp; - connsm->csmflags.cfbit.subrate_host_req = 1; + connsm->flags.subrate_host_req = 1; ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_SUBRATE_REQ, NULL); break; #endif @@ -4136,15 +4290,15 @@ ble_ll_conn_subrate_req_llcp(struct ble_ll_conn_sm *connsm, return -EINVAL; } - connsm->subrate_trans.subrate_factor = min(connsm->acc_subrate_max, + connsm->subrate_trans.subrate_factor = MIN(connsm->acc_subrate_max, srp->subrate_max); connsm->subrate_trans.subrate_base_event = connsm->event_cntr; - connsm->subrate_trans.periph_latency = min(connsm->acc_max_latency, + connsm->subrate_trans.periph_latency = MIN(connsm->acc_max_latency, srp->max_latency); - connsm->subrate_trans.cont_num = min(max(connsm->acc_cont_num, + connsm->subrate_trans.cont_num = MIN(MAX(connsm->acc_cont_num, srp->cont_num), connsm->subrate_trans.subrate_factor - 1); - connsm->subrate_trans.supervision_tmo = min(connsm->supervision_tmo, + connsm->subrate_trans.supervision_tmo = MIN(connsm->supervision_tmo, srp->supervision_tmo); ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_SUBRATE_UPDATE, NULL); @@ -4162,7 +4316,7 @@ ble_ll_conn_subrate_set(struct ble_ll_conn_sm *connsm, /* Assume parameters were checked by caller */ - send_ev = connsm->csmflags.cfbit.subrate_host_req || + send_ev = connsm->flags.subrate_host_req || (connsm->subrate_factor != sp->subrate_factor) || (connsm->periph_latency != sp->periph_latency) || (connsm->cont_num != sp->cont_num) || @@ -4186,11 +4340,9 @@ ble_ll_conn_subrate_set(struct ble_ll_conn_sm *connsm, #endif #define MAX_TIME_UNCODED(_maxbytes) \ - ble_ll_pdu_tx_time_get(_maxbytes + BLE_LL_DATA_MIC_LEN, \ - BLE_PHY_MODE_1M); + ble_ll_pdu_us(_maxbytes + BLE_LL_DATA_MIC_LEN, BLE_PHY_MODE_1M); #define MAX_TIME_CODED(_maxbytes) \ - ble_ll_pdu_tx_time_get(_maxbytes + BLE_LL_DATA_MIC_LEN, \ - BLE_PHY_MODE_CODED_125KBPS); + ble_ll_pdu_us(_maxbytes + BLE_LL_DATA_MIC_LEN, BLE_PHY_MODE_CODED_125KBPS); /** * Called to reset the connection module. When this function is called the @@ -4240,7 +4392,7 @@ ble_ll_conn_module_reset(void) /* Configure the global LL parameters */ conn_params = &g_ble_ll_conn_params; - maxbytes = min(MYNEWT_VAL(BLE_LL_SUPP_MAX_RX_BYTES), max_phy_pyld); + maxbytes = MIN(MYNEWT_VAL(BLE_LL_SUPP_MAX_RX_BYTES), max_phy_pyld); conn_params->supp_max_rx_octets = maxbytes; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) conn_params->supp_max_rx_time = MAX_TIME_CODED(maxbytes); @@ -4248,7 +4400,7 @@ ble_ll_conn_module_reset(void) conn_params->supp_max_rx_time = MAX_TIME_UNCODED(maxbytes); #endif - maxbytes = min(MYNEWT_VAL(BLE_LL_SUPP_MAX_TX_BYTES), max_phy_pyld); + maxbytes = MIN(MYNEWT_VAL(BLE_LL_SUPP_MAX_TX_BYTES), max_phy_pyld); conn_params->supp_max_tx_octets = maxbytes; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) conn_params->supp_max_tx_time = MAX_TIME_CODED(maxbytes); @@ -4256,7 +4408,7 @@ ble_ll_conn_module_reset(void) conn_params->supp_max_tx_time = MAX_TIME_UNCODED(maxbytes); #endif - maxbytes = min(MYNEWT_VAL(BLE_LL_CONN_INIT_MAX_TX_BYTES), max_phy_pyld); + maxbytes = MIN(MYNEWT_VAL(BLE_LL_CONN_INIT_MAX_TX_BYTES), max_phy_pyld); conn_params->conn_init_max_tx_octets = maxbytes; conn_params->conn_init_max_tx_time = MAX_TIME_UNCODED(maxbytes); conn_params->conn_init_max_tx_time_uncoded = MAX_TIME_UNCODED(maxbytes); @@ -4288,6 +4440,10 @@ ble_ll_conn_module_reset(void) g_ble_ll_conn_cth_flow.max_buffers = 1; g_ble_ll_conn_cth_flow.num_buffers = 1; #endif + +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + g_ble_ll_conn_css_next_slot = BLE_LL_CONN_CSS_NO_SLOT; +#endif } /* Initialize the connection module */ @@ -4302,6 +4458,10 @@ ble_ll_conn_module_init(void) SLIST_INIT(&g_ble_ll_conn_active_list); STAILQ_INIT(&g_ble_ll_conn_free_list); +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + SLIST_INIT(&g_ble_ll_conn_css_list); +#endif + /* * Take all the connections off the free memory pool and add them to * the free connection list, assigning handles in linear order. Note: diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn_hci.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn_hci.c index 2ffda58a..7f5ab699 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn_hci.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn_hci.c @@ -140,7 +140,7 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, struct ble_hci_ev_le_subev_enh_conn_complete *enh_ev; struct ble_hci_ev_le_subev_conn_complete *ev; struct ble_hci_ev *hci_ev = (void *) evbuf; - uint8_t *rpa; + uint8_t *rpa = NULL; BLE_LL_ASSERT(evbuf); @@ -480,12 +480,14 @@ ble_ll_conn_hci_create_check_params(struct ble_ll_conn_create_params *cc_params) return BLE_ERR_INV_HCI_CMD_PARMS; } - /* Adjust min/max ce length to be less than interval */ - if (cc_params->min_ce_len > cc_params->conn_itvl) { - cc_params->min_ce_len = cc_params->conn_itvl; + /* Adjust min/max ce length to be less than interval + * Note that interval is in 1.25ms and CE is in 625us + */ + if (cc_params->min_ce_len > cc_params->conn_itvl * 2) { + cc_params->min_ce_len = cc_params->conn_itvl * 2; } - if (cc_params->max_ce_len > cc_params->conn_itvl) { - cc_params->max_ce_len = cc_params->conn_itvl; + if (cc_params->max_ce_len > cc_params->conn_itvl * 2) { + cc_params->max_ce_len = cc_params->conn_itvl * 2; } /* Precalculate conn interval */ @@ -514,7 +516,7 @@ ble_ll_conn_hci_create(const uint8_t *cmdbuf, uint8_t len) uint16_t conn_itvl_min; uint16_t conn_itvl_max; #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - uint16_t css_slot_idx; + uint16_t css_slot_idx = 0; #endif int rc; @@ -537,9 +539,11 @@ ble_ll_conn_hci_create(const uint8_t *cmdbuf, uint8_t len) } #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - css_slot_idx = ble_ll_conn_css_get_next_slot(); - if (css_slot_idx == BLE_LL_CONN_CSS_NO_SLOT) { - return BLE_ERR_MEM_CAPACITY; + if (ble_ll_sched_css_is_enabled()) { + css_slot_idx = ble_ll_conn_css_get_next_slot(); + if (css_slot_idx == BLE_LL_CONN_CSS_NO_SLOT) { + return BLE_ERR_MEM_CAPACITY; + } } #endif @@ -575,10 +579,14 @@ ble_ll_conn_hci_create(const uint8_t *cmdbuf, uint8_t len) } #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - cc_params.conn_itvl = ble_ll_sched_css_get_conn_interval_us(); - if ((cc_params.conn_itvl < conn_itvl_min) || - (cc_params.conn_itvl > conn_itvl_max)) { - return BLE_ERR_INV_HCI_CMD_PARMS; + if (ble_ll_sched_css_is_enabled()) { + cc_params.conn_itvl = ble_ll_sched_css_get_conn_interval_us(); + if ((cc_params.conn_itvl < conn_itvl_min) || + (cc_params.conn_itvl > conn_itvl_max)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } else { + cc_params.conn_itvl = conn_itvl_max; } #else cc_params.conn_itvl = conn_itvl_max; @@ -618,6 +626,11 @@ ble_ll_conn_hci_create(const uint8_t *cmdbuf, uint8_t len) if (rc) { SLIST_REMOVE(&g_ble_ll_conn_active_list,connsm,ble_ll_conn_sm,act_sle); STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + SLIST_REMOVE(&g_ble_ll_conn_css_list, connsm, ble_ll_conn_sm, css_sle); + } +#endif } return rc; @@ -668,10 +681,14 @@ ble_ll_conn_hci_ext_create_parse_params(const struct conn_params *params, } #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - cc_params->conn_itvl = ble_ll_sched_css_get_conn_interval_us(); - if ((cc_params->conn_itvl < conn_itvl_min) || - (cc_params->conn_itvl > conn_itvl_max)) { - return BLE_ERR_INV_HCI_CMD_PARMS; + if (ble_ll_sched_css_is_enabled()) { + cc_params->conn_itvl = ble_ll_sched_css_get_conn_interval_us(); + if ((cc_params->conn_itvl < conn_itvl_min) || + (cc_params->conn_itvl > conn_itvl_max)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } else { + cc_params->conn_itvl = conn_itvl_max; } #else cc_params->conn_itvl = conn_itvl_max; @@ -735,7 +752,7 @@ ble_ll_conn_hci_ext_create(const uint8_t *cmdbuf, uint8_t len) struct ble_ll_conn_sm *connsm; const struct init_phy *init_phy; #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - uint16_t css_slot_idx; + uint16_t css_slot_idx = 0; #endif int rc; @@ -760,9 +777,11 @@ ble_ll_conn_hci_ext_create(const uint8_t *cmdbuf, uint8_t len) } #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - css_slot_idx = ble_ll_conn_css_get_next_slot(); - if (css_slot_idx == BLE_LL_CONN_CSS_NO_SLOT) { - return BLE_ERR_MEM_CAPACITY; + if (ble_ll_sched_css_is_enabled()) { + css_slot_idx = ble_ll_conn_css_get_next_slot(); + if (css_slot_idx == BLE_LL_CONN_CSS_NO_SLOT) { + return BLE_ERR_MEM_CAPACITY; + } } #endif @@ -784,7 +803,7 @@ ble_ll_conn_hci_ext_create(const uint8_t *cmdbuf, uint8_t len) cc_params_fb = NULL; - for (int i = 0; i < ARRAY_SIZE(init_phys); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(init_phys); i++) { init_phy = &init_phys[i]; if ((cc_scan.init_phy_mask & init_phy->mask) == 0) { @@ -834,6 +853,11 @@ ble_ll_conn_hci_ext_create(const uint8_t *cmdbuf, uint8_t len) if (rc) { SLIST_REMOVE(&g_ble_ll_conn_active_list,connsm,ble_ll_conn_sm,act_sle); STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + SLIST_REMOVE(&g_ble_ll_conn_css_list, connsm, ble_ll_conn_sm, css_sle); + } +#endif } return rc; @@ -897,7 +921,7 @@ ble_ll_conn_hci_read_rem_features(const uint8_t *cmdbuf, uint8_t len) } /* If already pending exit with error */ - if (connsm->csmflags.cfbit.pending_hci_rd_features) { + if (connsm->flags.features_host_req) { return BLE_ERR_CMD_DISALLOWED; } @@ -905,8 +929,8 @@ ble_ll_conn_hci_read_rem_features(const uint8_t *cmdbuf, uint8_t len) * Start control procedure if we did not receive peer's features and did not * start procedure already. */ - if (!connsm->csmflags.cfbit.rxd_features && - !IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) { + if (!connsm->flags.features_rxd && + !IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) { #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if ((connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) && !(ble_ll_read_supp_features() & BLE_LL_FEAT_PERIPH_INIT)) { @@ -917,11 +941,39 @@ ble_ll_conn_hci_read_rem_features(const uint8_t *cmdbuf, uint8_t len) ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG, NULL); } - connsm->csmflags.cfbit.pending_hci_rd_features = 1; + connsm->flags.features_host_req = 1; return BLE_ERR_SUCCESS; } +static bool +ble_ll_conn_params_in_range(struct ble_ll_conn_sm *connsm, + const struct ble_hci_le_conn_update_cp *cmd) +{ + if (!IN_RANGE(connsm->conn_itvl, le16toh(cmd->conn_itvl_min), + le16toh(cmd->conn_itvl_max))) { + return false; + } + + if (connsm->periph_latency != le16toh(cmd->conn_latency)) { + return false; + } + + if (connsm->supervision_tmo != le16toh(cmd->supervision_timeout)) { + return false; + } + + return true; +} + +static void +ble_ll_conn_hci_update_complete_event(void *user_data) +{ + struct ble_ll_conn_sm *connsm = user_data; + + ble_ll_hci_ev_conn_update(connsm, BLE_ERR_SUCCESS); +} + /** * Called to process a connection update command. * @@ -938,6 +990,7 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) uint16_t handle; struct ble_ll_conn_sm *connsm; struct hci_conn_update *hcu; + uint16_t max_ce_len; /* * XXX: must deal with peripheral not supporting this feature and using @@ -955,6 +1008,36 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_UNK_CONN_ID; } + /* if current connection parameters fit updated values we don't have to + * trigger LL procedure and just update local values (Min/Max CE Length) + * + * Note that this is also allowed for CSS as nothing changes WRT connections + * scheduling. + */ + if (ble_ll_conn_params_in_range(connsm, cmd)) { + max_ce_len = le16toh(cmd->max_ce_len); + + if (le16toh(cmd->min_ce_len) > max_ce_len) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + connsm->max_ce_len_ticks = ble_ll_tmr_u2t_up(max_ce_len * BLE_LL_CONN_CE_USECS); + + ble_ll_hci_post_cmd_cb_set(ble_ll_conn_hci_update_complete_event, connsm); + + return BLE_ERR_SUCCESS; + } + +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + /* Do not allow connection update if css in enabled, we only allow to move + * anchor point (i.e. change slot) via dedicated HCI command. + */ + if (ble_ll_sched_css_is_enabled() && + connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + return BLE_ERR_CMD_DISALLOWED; + } +#endif + /* Better not have this procedure ongoing! */ if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ) || IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) { @@ -979,11 +1062,11 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) * peripheral has initiated the procedure, we need to send a reject to the * peripheral. */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { + if (connsm->flags.conn_update_host_w4reply) { switch (connsm->conn_role) { #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_CONN_ROLE_CENTRAL: - connsm->csmflags.cfbit.awaiting_host_reply = 0; + connsm->flags.conn_update_host_w4reply = 0; /* XXX: If this fails no reject ind will be sent! */ ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode, @@ -1006,7 +1089,7 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) * update procedure we should deny the peripheral request for now. */ #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) - if (connsm->csmflags.cfbit.chanmap_update_scheduled) { + if (connsm->flags.chanmap_update_sched) { if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { return BLE_ERR_DIFF_TRANS_COLL; } @@ -1076,7 +1159,7 @@ ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len, rc = ble_ll_conn_process_conn_params(cmd, connsm); /* The connection should be awaiting a reply. If not, just discard */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { + if (connsm->flags.conn_update_host_w4reply) { /* Get a control packet buffer */ if (rc == BLE_ERR_SUCCESS) { om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN, @@ -1094,7 +1177,7 @@ ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len, ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode, BLE_ERR_CONN_PARMS); } - connsm->csmflags.cfbit.awaiting_host_reply = 0; + connsm->flags.conn_update_host_w4reply = 0; /* XXX: if we cant get a buffer, what do we do? We need to remember * reason if it was a negative reply. We also would need to have @@ -1141,11 +1224,11 @@ ble_ll_conn_hci_param_nrr(const uint8_t *cmdbuf, uint8_t len, rc = BLE_ERR_SUCCESS; /* The connection should be awaiting a reply. If not, just discard */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { + if (connsm->flags.conn_update_host_w4reply) { /* XXX: check return code and deal */ ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode, cmd->reason); - connsm->csmflags.cfbit.awaiting_host_reply = 0; + connsm->flags.conn_update_host_w4reply = 0; /* XXX: if we cant get a buffer, what do we do? We need to remember * reason if it was a negative reply. We also would need to have @@ -1164,7 +1247,7 @@ done: * safe to use g_ble_ll_conn_comp_ev */ static void -ble_ll_conn_hci_cancel_conn_complete_event(void) +ble_ll_conn_hci_cancel_conn_complete_event(void *user_data) { BLE_LL_ASSERT(g_ble_ll_conn_comp_ev); @@ -1182,7 +1265,7 @@ ble_ll_conn_hci_cancel_conn_complete_event(void) * @return int */ int -ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) +ble_ll_conn_create_cancel(void) { int rc; struct ble_ll_conn_sm *connsm; @@ -1202,7 +1285,7 @@ ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) ble_ll_scan_sm_stop(1); ble_ll_conn_end(connsm, BLE_ERR_UNK_CONN_ID); - *post_cmd_cb = ble_ll_conn_hci_cancel_conn_complete_event; + ble_ll_hci_post_cmd_cb_set(ble_ll_conn_hci_cancel_conn_complete_event, NULL); rc = BLE_ERR_SUCCESS; } else { @@ -1251,7 +1334,7 @@ ble_ll_conn_hci_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd) rc = BLE_ERR_CMD_DISALLOWED; } else { /* This control procedure better not be pending! */ - BLE_LL_ASSERT(CONN_F_TERMINATE_STARTED(connsm) == 0); + BLE_LL_ASSERT(connsm->flags.terminate_started == 0); /* Record the disconnect reason */ connsm->disconnect_reason = cmd->reason; @@ -1310,7 +1393,7 @@ ble_ll_conn_hci_rd_rem_ver_cmd(const uint8_t *cmdbuf, uint8_t len) * NOTE: we cant just send the event here. That would cause the event to * be queued before the command status. */ - if (!connsm->csmflags.cfbit.version_ind_sent) { + if (!connsm->flags.version_ind_txd) { ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG, NULL); } else { connsm->pending_ctrl_procs |= (1 << BLE_LL_CTRL_PROC_VERSION_XCHG); @@ -1385,10 +1468,10 @@ ble_ll_conn_hci_rd_chan_map(const uint8_t *cmdbuf, uint8_t len, rc = BLE_ERR_UNK_CONN_ID; memset(rsp->chan_map, 0, sizeof(rsp->chan_map)); } else { - if (connsm->csmflags.cfbit.chanmap_update_scheduled) { + if (connsm->flags.chanmap_update_sched) { memcpy(rsp->chan_map, connsm->req_chanmap, BLE_LL_CHAN_MAP_LEN); } else { - memcpy(rsp->chan_map, connsm->chanmap, BLE_LL_CHAN_MAP_LEN); + memcpy(rsp->chan_map, connsm->chan_map, BLE_LL_CHAN_MAP_LEN); } rc = BLE_ERR_SUCCESS; } @@ -1400,38 +1483,6 @@ ble_ll_conn_hci_rd_chan_map(const uint8_t *cmdbuf, uint8_t len, } #endif -/** - * Called when the host issues the LE command "set host channel classification" - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_conn_hci_set_chan_class(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_host_chan_class_cp *cmd = (const void *) cmdbuf; - uint8_t num_used_chans; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* - * The HCI command states that the host is allowed to mask in just one - * channel but the Link Layer needs minimum two channels to operate. So - * I will not allow this command if there are less than 2 channels masked. - */ - num_used_chans = ble_ll_utils_calc_num_used_chans(cmd->chan_map); - if ((num_used_chans < 2) || ((cmd->chan_map[4] & 0xe0) != 0)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Set the host channel mask */ - ble_ll_conn_set_global_chanmap(num_used_chans, cmd->chan_map); - return BLE_ERR_SUCCESS; -} - #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) @@ -1443,8 +1494,8 @@ ble_ll_conn_hci_set_data_len(const uint8_t *cmdbuf, uint8_t len, struct ble_hci_le_set_data_len_rp *rsp = (void *) rspbuf; int rc; uint16_t handle; - uint16_t txoctets; - uint16_t txtime; + uint16_t tx_octets; + uint16_t tx_time; struct ble_ll_conn_sm *connsm; if (len != sizeof(*cmd)) { @@ -1459,42 +1510,19 @@ ble_ll_conn_hci_set_data_len(const uint8_t *cmdbuf, uint8_t len, goto done; } - txoctets = le16toh(cmd->tx_octets); - txtime = le16toh(cmd->tx_time); + tx_octets = le16toh(cmd->tx_octets); + tx_time = le16toh(cmd->tx_time); - /* Make sure it is valid */ - if (!ble_ll_chk_txrx_octets(txoctets) || - !ble_ll_chk_txrx_time(txtime)) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - goto done; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - /* - * Keep original value requested by host since we may want to recalculate - * MaxTxTime after PHY changes between coded and uncoded. - */ - connsm->host_req_max_tx_time = txtime; - - /* If peer does not support coded, we cannot use value larger than 2120us */ - if (!ble_ll_conn_rem_feature_check(connsm, BLE_LL_FEAT_LE_CODED_PHY)) { - txtime = min(txtime, BLE_LL_CONN_SUPP_TIME_MAX_UNCODED); + if (!ble_ll_hci_check_dle(tx_octets, tx_time)) { + return BLE_ERR_INV_HCI_CMD_PARMS; } -#endif - rc = BLE_ERR_SUCCESS; - if (connsm->max_tx_time != txtime || - connsm->max_tx_octets != txoctets) { - - connsm->max_tx_time = txtime; - connsm->max_tx_octets = txoctets; - - ble_ll_ctrl_initiate_dle(connsm); - } + rc = ble_ll_conn_set_data_len(connsm, tx_octets, tx_time, 0, 0); done: rsp->conn_handle = htole16(handle); *rsplen = sizeof(*rsp); + return rc; } #endif @@ -1962,7 +1990,7 @@ ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len) * If host has requested a PHY update and we are not finished do * not allow another one */ - if (CONN_F_HOST_PHY_UPDATE(connsm)) { + if (connsm->flags.phy_update_host_initiated) { return BLE_ERR_CMD_DISALLOWED; } @@ -1991,9 +2019,9 @@ ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len) */ if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE)) { if (connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_PHY_UPDATE) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; + connsm->flags.phy_update_self_initiated = 0; } - CONN_F_HOST_PHY_UPDATE(connsm) = 1; + connsm->flags.phy_update_host_initiated = 1; } else { /* * We could be doing a peer-initiated PHY update procedure. If this @@ -2001,20 +2029,20 @@ ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len) * we are not done with a peer-initiated procedure we just set the * pending bit but do not start the control procedure. */ - if (CONN_F_PEER_PHY_UPDATE(connsm)) { + if (connsm->flags.phy_update_peer_initiated) { connsm->pending_ctrl_procs |= (1 << BLE_LL_CTRL_PROC_PHY_UPDATE); - CONN_F_HOST_PHY_UPDATE(connsm) = 1; + connsm->flags.phy_update_host_initiated = 1; } else { /* Check if we should start phy update procedure */ if (!ble_ll_conn_phy_update_if_needed(connsm)) { - CONN_F_HOST_PHY_UPDATE(connsm) = 1; + connsm->flags.phy_update_host_initiated = 1; } else { /* * Set flag to send a PHY update complete event. We set flag * even if we do not do an update procedure since we have to * inform the host even if we decide not to change anything. */ - CONN_F_PHY_UPDATE_EVENT(connsm) = 1; + connsm->flags.phy_update_host_w4event = 1; } } } diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn_priv.h b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn_priv.h index 90c32c0c..954a2766 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_conn_priv.h @@ -104,6 +104,11 @@ STAILQ_HEAD(ble_ll_conn_free_list, ble_ll_conn_sm); extern struct ble_ll_conn_active_list g_ble_ll_conn_active_list; extern struct ble_ll_conn_free_list g_ble_ll_conn_free_list; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) +SLIST_HEAD(ble_ll_conn_css_list, ble_ll_conn_sm); +extern struct ble_ll_conn_css_list g_ble_ll_conn_css_list; +#endif + struct ble_ll_conn_create_scan { uint8_t filter_policy; uint8_t own_addr_type; @@ -177,7 +182,6 @@ int ble_ll_conn_periph_start(uint8_t *rxbuf, uint8_t pat, /* Link Layer interface */ void ble_ll_conn_module_init(void); -void ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap); void ble_ll_conn_module_reset(void); void ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t len); int ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa); @@ -200,7 +204,7 @@ int ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_conn_hci_param_nrr(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb); +int ble_ll_conn_create_cancel(void); void ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm); void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, uint8_t *evbuf, struct ble_ll_adv_sm *advsm); @@ -236,6 +240,7 @@ int ble_ll_conn_hci_subrate_req(const uint8_t *cmdbuf, uint8_t len, #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) void ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm); +void ble_ll_conn_auth_pyld_timer_cb(struct ble_npl_event *ev); #else #define ble_ll_conn_auth_pyld_timer_start(x) #endif @@ -246,12 +251,15 @@ bool ble_ll_conn_cth_flow_enable(bool enabled); void ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf); #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) +int ble_ll_conn_set_data_len(struct ble_ll_conn_sm *connsm, + uint16_t tx_octets, uint16_t tx_time, + uint16_t rx_octets, uint16_t rx_time); +#endif + void ble_ll_conn_itvl_to_ticks(uint32_t itvl, uint32_t *itvl_ticks, uint8_t *itvl_usecs); -int ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg); -int ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg); - int ble_ll_conn_hci_le_rd_phy(const uint8_t *cmdbuf, uint8_t len, uint8_t *rsp, uint8_t *rsplen); int ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_crypto.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_crypto.c new file mode 100644 index 00000000..be3e1be3 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_crypto.c @@ -0,0 +1,62 @@ +/* + * 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 +#include +#include +#include +#include +#include + +int +ble_ll_crypto_cmac(const uint8_t *key, const uint8_t *in, int len, + uint8_t *out) +{ + struct tc_aes_key_sched_struct sched; + struct tc_cmac_struct state; + + if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { + return -1; + } + + if (tc_cmac_update(&state, in, len) == TC_CRYPTO_FAIL) { + return -1; + } + + if (tc_cmac_final(out, &state) == TC_CRYPTO_FAIL) { + return -1; + } + + return 0; +} + +int +ble_ll_crypto_h8(const uint8_t *k, const uint8_t *s, const uint8_t *key_id, + uint8_t *out) +{ + uint8_t ik[16]; + int rc; + + rc = ble_ll_crypto_cmac(s, k, 16, ik); + if (rc) { + return rc; + } + + return ble_ll_crypto_cmac(ik, key_id, 4, out); +} diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_ctrl.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_ctrl.c index 7ece7b1c..ed03fd10 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_ctrl.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_ctrl.c @@ -24,6 +24,7 @@ #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" +#include "controller/ble_ll_utils.h" #include "controller/ble_ll.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_ctrl.h" @@ -197,13 +198,13 @@ ble_ll_ctrl_phy_update_cancel(struct ble_ll_conn_sm *connsm, uint8_t ble_err) CLR_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); /* Check if the host wants an event */ - if (CONN_F_HOST_PHY_UPDATE(connsm)) { + if (connsm->flags.phy_update_host_initiated) { ble_ll_hci_ev_phy_update(connsm, ble_err); - CONN_F_HOST_PHY_UPDATE(connsm) = 0; + connsm->flags.phy_update_host_initiated = 0; } /* Clear any bits for phy updates that might be in progress */ - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; + connsm->flags.phy_update_self_initiated = 0; } #endif @@ -366,7 +367,7 @@ conn_parm_req_do_indicate: */ ble_ll_hci_ev_rem_conn_parm_req(connsm, req); connsm->host_reply_opcode = opcode; - connsm->csmflags.cfbit.awaiting_host_reply = 1; + connsm->flags.conn_update_host_w4reply = 1; rsp_opcode = 255; } else { /* Create reply to connection request */ @@ -382,18 +383,29 @@ conn_param_pdu_exit: return rsp_opcode; } -/** - * Called to make a connection update request LL control PDU - * - * Context: Link Layer - * - * @param connsm - * @param rsp - */ static void -ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld, - struct ble_ll_conn_params *cp) +ble_ll_ctrl_conn_update_init_proc(struct ble_ll_conn_sm *connsm, + struct ble_ll_conn_params *cp) { + /* This only stores conn params, if any. The caller will enqueue LL Control + * PDU and we will calculate its contents when dequeued so we know that + * instant is in the future. + */ + + connsm->flags.conn_update_sched = 0; + connsm->flags.conn_update_use_cp = (cp != NULL); + + if (cp) { + connsm->conn_cp = *cp; + } +} + +static void +ble_ll_ctrl_conn_update_make_ind_pdu(struct ble_ll_conn_sm *connsm, + uint8_t *ctrdata) +{ + struct ble_ll_conn_params *cp = NULL; + struct ble_ll_conn_params offset_cp = { }; uint16_t instant; uint32_t dt; uint32_t num_old_ce; @@ -402,6 +414,10 @@ ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld, struct hci_conn_update *hcu; struct ble_ll_conn_upd_req *req; + if (connsm->flags.conn_update_use_cp) { + cp = &connsm->conn_cp; + } + /* * Set instant. We set the instant to the current event counter plus * the amount of peripheral latency as the peripheral may not be listening @@ -416,6 +432,18 @@ ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld, instant = connsm->event_cntr + connsm->periph_latency + 6 + 1; #endif + /* Check if this is a move anchor request and configure proper connection + * parameters */ + if (connsm->conn_update_anchor_offset_req) { + offset_cp.interval_min = connsm->conn_itvl; + offset_cp.interval_max = connsm->conn_itvl; + offset_cp.latency = connsm->periph_latency; + offset_cp.timeout = connsm->supervision_tmo; + offset_cp.offset0 = connsm->conn_update_anchor_offset_req; + connsm->conn_update_anchor_offset_req = 0; + cp = &offset_cp; + } + /* * XXX: This should change in the future, but for now we will just * start the new instant at the same anchor using win offset 0. @@ -461,15 +489,12 @@ ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld, req->instant = instant; /* XXX: make sure this works for the connection parameter request proc. */ - pyld[0] = req->winsize; - put_le16(pyld + 1, req->winoffset); - put_le16(pyld + 3, req->interval); - put_le16(pyld + 5, req->latency); - put_le16(pyld + 7, req->timeout); - put_le16(pyld + 9, instant); - - /* Set flag in state machine to denote we have scheduled an update */ - connsm->csmflags.cfbit.conn_update_sched = 1; + ctrdata[0] = req->winsize; + put_le16(ctrdata + 1, req->winoffset); + put_le16(ctrdata + 3, req->interval); + put_le16(ctrdata + 5, req->latency); + put_le16(ctrdata + 7, req->timeout); + put_le16(ctrdata + 9, instant); } /** @@ -505,7 +530,7 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t * BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_CONN_PARM_REQ); #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { - ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL); + ble_ll_ctrl_conn_update_init_proc(connsm, NULL); connsm->reject_reason = BLE_ERR_SUCCESS; return BLE_LL_CTRL_CONN_UPDATE_IND; } @@ -545,11 +570,11 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t * if (ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) { ble_ll_hci_ev_conn_update(connsm, BLE_ERR_UNSUPP_REM_FEATURE); } else if (ctrl_proc == BLE_LL_CTRL_PROC_FEATURE_XCHG) { - if (connsm->csmflags.cfbit.pending_hci_rd_features) { + if (connsm->flags.features_host_req) { ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_UNSUPP_REM_FEATURE); } - connsm->csmflags.cfbit.pending_hci_rd_features = 0; + connsm->flags.features_host_req = 0; } } @@ -662,24 +687,24 @@ ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm) connsm->phy_tx_transition = 0; - if (CONN_F_PEER_PHY_UPDATE(connsm)) { - CONN_F_PEER_PHY_UPDATE(connsm) = 0; - } else if (CONN_F_CTRLR_PHY_UPDATE(connsm)) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; + if (connsm->flags.phy_update_peer_initiated) { + connsm->flags.phy_update_peer_initiated = 0; + } else if (connsm->flags.phy_update_self_initiated) { + connsm->flags.phy_update_self_initiated = 0; } else { /* Must be a host-initiated update */ - CONN_F_HOST_PHY_UPDATE(connsm) = 0; + connsm->flags.phy_update_host_initiated = 0; chk_host_phy = 0; - if (CONN_F_PHY_UPDATE_EVENT(connsm) == 0) { + if (connsm->flags.phy_update_host_w4event == 0) { ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS); } } /* Must check if we need to start host procedure */ if (chk_host_phy) { - if (CONN_F_HOST_PHY_UPDATE(connsm)) { + if (connsm->flags.phy_update_host_initiated) { if (ble_ll_conn_phy_update_if_needed(connsm)) { - CONN_F_HOST_PHY_UPDATE(connsm) = 0; + connsm->flags.phy_update_host_initiated = 0; } else { chk_proc_stop = 0; } @@ -804,14 +829,14 @@ ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * one running. */ if ((m_to_s == 0) && (s_to_m == 0)) { - if (CONN_F_PEER_PHY_UPDATE(connsm)) { - CONN_F_PEER_PHY_UPDATE(connsm) = 0; - } else if (CONN_F_CTRLR_PHY_UPDATE(connsm)) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; + if (connsm->flags.phy_update_peer_initiated) { + connsm->flags.phy_update_peer_initiated = 0; + } else if (connsm->flags.phy_update_self_initiated) { + connsm->flags.phy_update_self_initiated = 0; ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); } else { ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS); - CONN_F_HOST_PHY_UPDATE(connsm) = 0; + connsm->flags.phy_update_host_initiated = 0; ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); } instant = 0; @@ -819,7 +844,7 @@ ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr, /* Determine instant we will use. 6 more is minimum */ instant = connsm->event_cntr + connsm->periph_latency + 6 + 1; connsm->phy_instant = instant; - CONN_F_PHY_UPDATE_SCHED(connsm) = 1; + connsm->flags.phy_update_sched = 1; /* Set new phys to use when instant occurs */ connsm->phy_data.new_tx_phy = m_to_s; @@ -896,7 +921,7 @@ ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req, * NOTE: do not change order of these two lines as the call to * make the LL_PHY_UPDATE_IND pdu might clear the flag. */ - CONN_F_PEER_PHY_UPDATE(connsm) = 1; + connsm->flags.phy_update_peer_initiated = 1; ble_ll_ctrl_phy_update_ind_make(connsm, req, rsp, 1); rsp_opcode = BLE_LL_CTRL_PHY_UPDATE_IND; } @@ -915,14 +940,14 @@ ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req, ble_ll_ctrl_phy_update_cancel(connsm, err); /* XXX: ? Should not be any phy update events */ - CONN_F_PHY_UPDATE_EVENT(connsm) = 0; + connsm->flags.phy_update_host_w4event = 0; } /* XXX: TODO: if we started another procedure with an instant * why are we doing this? Need to look into this.*/ /* Respond to central's phy update procedure */ - CONN_F_PEER_PHY_UPDATE(connsm) = 1; + connsm->flags.phy_update_peer_initiated = 1; ble_ll_ctrl_phy_req_rsp_make(connsm, rsp); rsp_opcode = BLE_LL_CTRL_PHY_RSP; @@ -1068,7 +1093,7 @@ ble_ll_ctrl_rx_phy_update_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) connsm->phy_data.new_tx_phy = new_tx_phy; connsm->phy_data.new_rx_phy = new_rx_phy; connsm->phy_instant = instant; - CONN_F_PHY_UPDATE_SCHED(connsm) = 1; + connsm->flags.phy_update_sched = 1; } return BLE_ERR_MAX; } @@ -1265,7 +1290,7 @@ ble_ll_ctrl_rx_subrate_ind(struct ble_ll_conn_sm *connsm, uint8_t *req, ble_ll_conn_subrate_set(connsm, sp); ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SUBRATE_REQ); - connsm->csmflags.cfbit.subrate_host_req = 0; + connsm->flags.subrate_host_req = 0; return BLE_ERR_MAX; } @@ -1706,7 +1731,7 @@ ble_ll_ctrl_rx_pause_enc_req(struct ble_ll_conn_sm *connsm) static uint8_t ble_ll_ctrl_rx_pause_enc_rsp(struct ble_ll_conn_sm *connsm) { - int rc; + int rc = 0; switch (connsm->conn_role) { #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) @@ -1747,7 +1772,7 @@ ble_ll_ctrl_rx_pause_enc_rsp(struct ble_ll_conn_sm *connsm) static uint8_t ble_ll_ctrl_rx_start_enc_rsp(struct ble_ll_conn_sm *connsm) { - int rc; + int rc = 0; /* Not in proper state. Discard */ if (connsm->enc_data.enc_state != CONN_ENC_S_START_ENC_RSP_WAIT) { @@ -1850,11 +1875,11 @@ static void ble_ll_ctrl_version_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld) { /* Set flag to denote we have sent/received this */ - connsm->csmflags.cfbit.version_ind_sent = 1; + connsm->flags.version_ind_txd = 1; /* Fill out response */ pyld[0] = BLE_HCI_VER_BCS; - put_le16(pyld + 1, MYNEWT_VAL(BLE_LL_MFRG_ID)); + put_le16(pyld + 1, MYNEWT_VAL(BLE_LL_MANUFACTURER_ID)); put_le16(pyld + 3, BLE_LL_SUB_VERS_NR); } @@ -1876,7 +1901,7 @@ ble_ll_ctrl_chanmap_req_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld) put_le16(pyld + BLE_LL_CHAN_MAP_LEN, connsm->chanmap_instant); /* Set scheduled flag */ - connsm->csmflags.cfbit.chanmap_update_scheduled = 1; + connsm->flags.chanmap_update_sched = 1; } /** @@ -1893,13 +1918,12 @@ uint8_t ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, uint8_t *rsp, struct ble_ll_conn_params *req) { - uint8_t rsp_opcode; + uint8_t rsp_opcode = 0; switch (connsm->conn_role) { #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_CONN_ROLE_CENTRAL: - /* Create a connection update pdu */ - ble_ll_ctrl_conn_upd_make(connsm, rsp + 1, req); + ble_ll_ctrl_conn_update_init_proc(connsm, req); rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND; break; #endif @@ -1940,6 +1964,9 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, ble_error = dptr[1]; } + /* Suppress unused-but-set if not used by following code (due to syscfg) */ + (void)ble_error; + /* XXX: should I check to make sure the rejected opcode is sane if we receive ind ext? */ switch (connsm->cur_ctrl_proc) { @@ -1950,7 +1977,7 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, case BLE_LL_CONN_ROLE_CENTRAL: /* As a central we should send connection update indication in this point */ rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND; - ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL); + ble_ll_ctrl_conn_update_init_proc(connsm, NULL); connsm->reject_reason = BLE_ERR_SUCCESS; break; #endif @@ -2046,7 +2073,7 @@ ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr) if (conn_events >= 32767) { ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED); } else { - connsm->csmflags.cfbit.conn_update_sched = 1; + connsm->flags.conn_update_sched = 1; /* * Errata says that receiving a connection update when the event @@ -2068,7 +2095,7 @@ ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr) } void -ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm) +ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm, bool initial) { if (!(connsm->conn_features & BLE_LL_FEAT_DATA_LEN_EXT)) { return; @@ -2077,12 +2104,15 @@ ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm) /* * Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets * exceeds the minimum, data length procedure needs to occur + * "at the earliest practical opportunity". */ - if ((connsm->max_tx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) && - (connsm->max_rx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) && - (connsm->max_tx_time <= BLE_LL_CONN_SUPP_TIME_MIN) && - (connsm->max_rx_time <= BLE_LL_CONN_SUPP_TIME_MIN)) { - return; + if (initial) { + if ((connsm->max_tx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) && + (connsm->max_rx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) && + (connsm->max_tx_time <= BLE_LL_CONN_SUPP_TIME_MIN) && + (connsm->max_rx_time <= BLE_LL_CONN_SUPP_TIME_MIN)) { + return; + } } ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD, NULL); @@ -2095,7 +2125,7 @@ ble_ll_ctrl_update_features(struct ble_ll_conn_sm *connsm, uint8_t *feat) memcpy(connsm->remote_features, feat + 1, 7); /* If we received peer's features for the 1st time, we should try DLE */ - if (!connsm->csmflags.cfbit.rxd_features) { + if (!connsm->flags.features_rxd) { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) /* * If connection was established on uncoded PHY, by default we use @@ -2106,17 +2136,25 @@ ble_ll_ctrl_update_features(struct ble_ll_conn_sm *connsm, uint8_t *feat) */ if (ble_ll_conn_rem_feature_check(connsm, BLE_LL_FEAT_LE_CODED_PHY)) { if (connsm->host_req_max_tx_time) { - connsm->max_tx_time = max(connsm->max_tx_time, + connsm->max_tx_time = MAX(connsm->max_tx_time, connsm->host_req_max_tx_time); } else { connsm->max_tx_time = g_ble_ll_conn_params.conn_init_max_tx_time_coded; } - connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_CODED; + if (connsm->host_req_max_rx_time) { + connsm->max_rx_time = MAX(connsm->max_rx_time, + connsm->host_req_max_rx_time); + } else { + connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_CODED; + } } #endif - connsm->csmflags.cfbit.pending_initiate_dle = 1; - connsm->csmflags.cfbit.rxd_features = 1; +#if MYNEWT_VAL(BLE_LL_CONN_INIT_AUTO_DLE) + connsm->flags.pending_initiate_dle = 1; +#endif + + connsm->flags.features_rxd = 1; } } @@ -2196,9 +2234,9 @@ ble_ll_ctrl_rx_feature_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr) } /* Send event to host if pending features read */ - if (connsm->csmflags.cfbit.pending_hci_rd_features) { + if (connsm->flags.features_host_req) { ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; + connsm->flags.features_host_req = 0; } } @@ -2227,13 +2265,14 @@ ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * well. This is not expected to happen anyway. A return of BLE_ERR_MAX * means that we will simply discard the connection parameter request */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { + if (connsm->flags.conn_update_host_w4reply) { return BLE_ERR_MAX; } #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) /* Reject any attempts to change connection parameters by peripheral */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + if (ble_ll_sched_css_is_enabled() && + connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; rspbuf[1] = BLE_LL_CTRL_CONN_PARM_REQ; rspbuf[2] = BLE_ERR_UNSUPPORTED; @@ -2287,7 +2326,7 @@ ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, */ #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if ((connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) && - (connsm->csmflags.cfbit.chanmap_update_scheduled)) { + (connsm->flags.chanmap_update_sched)) { rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; rspbuf[1] = BLE_LL_CTRL_CONN_PARM_REQ; rspbuf[2] = BLE_ERR_DIFF_TRANS_COLL; @@ -2320,8 +2359,8 @@ ble_ll_ctrl_rx_conn_param_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * state just clear the awaiting reply. The peripheral will hopefully stop its * procedure when we reply. */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { - connsm->csmflags.cfbit.awaiting_host_reply = 0; + if (connsm->flags.conn_update_host_w4reply) { + connsm->flags.conn_update_host_w4reply = 0; } /* If we receive a response and no procedure is pending, just leave */ @@ -2356,10 +2395,10 @@ ble_ll_ctrl_rx_version_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, connsm->vers_nr = dptr[0]; connsm->comp_id = get_le16(dptr + 1); connsm->sub_vers_nr = get_le16(dptr + 3); - connsm->csmflags.cfbit.rxd_version_ind = 1; + connsm->flags.version_ind_rxd = 1; rsp_opcode = BLE_ERR_MAX; - if (!connsm->csmflags.cfbit.version_ind_sent) { + if (!connsm->flags.version_ind_txd) { rsp_opcode = BLE_LL_CTRL_VERSION_IND; ble_ll_ctrl_version_ind_make(connsm, rspbuf); } @@ -2400,7 +2439,7 @@ ble_ll_ctrl_rx_chanmap_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr) } else { connsm->chanmap_instant = instant; memcpy(connsm->req_chanmap, dptr, BLE_LL_CHAN_MAP_LEN); - connsm->csmflags.cfbit.chanmap_update_scheduled = 1; + connsm->flags.chanmap_update_sched = 1; } return BLE_ERR_MAX; @@ -2422,7 +2461,7 @@ static struct os_mbuf * ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc, void *data) { uint8_t len; - uint8_t opcode; + uint8_t opcode = 0; uint8_t *dptr; uint8_t *ctrdata; struct os_mbuf *om; @@ -2438,7 +2477,7 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc, void *data) switch (ctrl_proc) { case BLE_LL_CTRL_PROC_CONN_UPDATE: opcode = BLE_LL_CTRL_CONN_UPDATE_IND; - ble_ll_ctrl_conn_upd_make(connsm, ctrdata, data); + ble_ll_ctrl_conn_update_init_proc(connsm, data); break; case BLE_LL_CTRL_PROC_CHAN_MAP_UPD: opcode = BLE_LL_CTRL_CHANNEL_MAP_REQ; @@ -2604,7 +2643,7 @@ ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm) ctrl_proc = BLE_LL_CTRL_PROC_TERMINATE; om = ble_ll_ctrl_proc_init(connsm, ctrl_proc, NULL); if (om) { - CONN_F_TERMINATE_STARTED(connsm) = 1; + connsm->flags.terminate_started = 1; /* Set terminate "timeout" */ usecs = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000; @@ -2670,7 +2709,7 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm) * terminate if needed */ if (connsm->disconnect_reason) { - if (!CONN_F_TERMINATE_STARTED(connsm)) { + if (!connsm->flags.terminate_started) { /* * If the terminate procedure has not started it means we were not * able to start it right away (no control pdu was available). @@ -2695,7 +2734,7 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm) * received the information dont start it. */ if ((i == BLE_LL_CTRL_PROC_VERSION_XCHG) && - (connsm->csmflags.cfbit.rxd_version_ind)) { + (connsm->flags.version_ind_rxd)) { ble_ll_hci_ev_rd_rem_ver(connsm, BLE_ERR_SUCCESS); CLR_PENDING_CTRL_PROC(connsm, i); } else { @@ -2727,7 +2766,6 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) uint64_t feature; uint8_t len; uint8_t opcode; - uint8_t rsp_opcode; uint8_t *dptr; uint8_t *rspbuf; uint8_t *rspdata; @@ -2735,6 +2773,7 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) int restart_encryption; #endif int rc = 0; + uint8_t rsp_opcode = 0; /* XXX: where do we validate length received and packet header length? * do this in LL task when received. Someplace!!! What I mean @@ -3027,10 +3066,12 @@ ll_ctrl_send_rsp: #endif } - if (connsm->csmflags.cfbit.pending_initiate_dle) { - connsm->csmflags.cfbit.pending_initiate_dle = 0; - ble_ll_ctrl_initiate_dle(connsm); +#if MYNEWT_VAL(BLE_LL_CONN_INIT_AUTO_DLE) + if (connsm->flags.pending_initiate_dle) { + connsm->flags.pending_initiate_dle = 0; + ble_ll_ctrl_initiate_dle(connsm, true); } +#endif return rc; } @@ -3085,12 +3126,21 @@ int ble_ll_ctrl_tx_start(struct ble_ll_conn_sm *connsm, struct os_mbuf *txpdu) { uint8_t opcode; + uint8_t *ctrdata; opcode = txpdu->om_data[0]; + ctrdata = &txpdu->om_data[1]; + switch (opcode) { + case BLE_LL_CTRL_CONN_UPDATE_IND: + ble_ll_ctrl_conn_update_make_ind_pdu(connsm, ctrdata); + connsm->flags.conn_update_sched = 1; + break; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) case BLE_LL_CTRL_SUBRATE_IND: - connsm->csmflags.cfbit.subrate_trans = 1; + connsm->flags.subrate_trans = 1; break; +#endif } return 0; @@ -3122,7 +3172,7 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) opcode = txpdu->om_data[0]; switch (opcode) { case BLE_LL_CTRL_TERMINATE_IND: - connsm->csmflags.cfbit.terminate_ind_txd = 1; + connsm->flags.terminate_ind_txd = 1; rc = -1; break; case BLE_LL_CTRL_REJECT_IND_EXT: @@ -3134,7 +3184,7 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) if (txpdu->om_data[1] == BLE_LL_CTRL_CONN_PARM_REQ && txpdu->om_data[2] != BLE_ERR_LMP_COLLISION) { connsm->reject_reason = txpdu->om_data[2]; - connsm->csmflags.cfbit.host_expects_upd_event = 1; + connsm->flags.conn_update_host_w4event = 1; } } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) @@ -3156,13 +3206,13 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) break; case BLE_LL_CTRL_ENC_RSP: connsm->enc_data.enc_state = CONN_ENC_S_LTK_REQ_WAIT; - connsm->csmflags.cfbit.send_ltk_req = 1; + connsm->flags.encrypt_ltk_req = 1; break; #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_LL_CTRL_START_ENC_RSP: if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { connsm->enc_data.enc_state = CONN_ENC_S_ENCRYPTED; - if (CONN_F_LE_PING_SUPP(connsm)) { + if (connsm->flags.le_ping_supp) { ble_ll_conn_auth_pyld_timer_start(connsm); } } @@ -3192,8 +3242,8 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_CTRL_SUBRATE_IND: - connsm->csmflags.cfbit.subrate_trans = 0; - connsm->csmflags.cfbit.subrate_ind_txd = 1; + connsm->flags.subrate_trans = 0; + connsm->flags.subrate_ind_txd = 1; break; #endif /* BLE_LL_CTRL_SUBRATE_IND */ #endif /* BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE */ @@ -3210,5 +3260,10 @@ ble_ll_ctrl_init_conn_sm(struct ble_ll_conn_sm *connsm) { ble_npl_callout_init(&connsm->ctrl_proc_rsp_timer, &g_ble_ll_data.ll_evq, ble_ll_ctrl_proc_rsp_timer_cb, connsm); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) + ble_npl_callout_init(&connsm->auth_pyld_timer, &g_ble_ll_data.ll_evq, + ble_ll_conn_auth_pyld_timer_cb, connsm); +#endif } #endif diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_dtm.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_dtm.c index 2c787da8..07e25fe2 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_dtm.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_dtm.c @@ -26,11 +26,13 @@ #include "os/os.h" #include "stats/stats.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_phy.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_rfmgmt.h" #include "controller/ble_ll_tmr.h" #include "ble_ll_dtm_priv.h" +#include "ble_ll_priv.h" STATS_SECT_START(ble_ll_dtm_stats) STATS_SECT_ENTRY(rx_count) @@ -194,16 +196,6 @@ ble_ll_dtm_ev_tx_resched_cb(struct ble_npl_event *evt) { BLE_LL_ASSERT(rc == 0); } -static int ble_ll_dtm_rx_start(void); - -static void -ble_ll_dtm_ev_rx_restart_cb(struct ble_npl_event *evt) { - if (ble_ll_dtm_rx_start() != 0) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); - STATS_INC(ble_ll_dtm_stats, rx_failed); - } -} - static void ble_ll_dtm_tx_done(void *arg) { @@ -217,7 +209,7 @@ ble_ll_dtm_tx_done(void *arg) g_ble_ll_dtm_ctx.num_of_packets++; /* Reschedule event in LL context */ - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt); + ble_ll_event_add(&ctx->evt); ble_ll_state_set(BLE_LL_STATE_STANDBY); } @@ -243,7 +235,7 @@ ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item *sch) ble_phy_mode_set(ctx->phy_mode, ctx->phy_mode); #endif ble_phy_set_txend_cb(ble_ll_dtm_tx_done, ctx); - ble_phy_txpwr_set(0); + ble_ll_tx_power_set(g_ble_ll_tx_power); sch->start_time += g_ble_ll_sched_offset_ticks; @@ -263,7 +255,7 @@ ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item *sch) resched: /* Reschedule from LL task if late for this PDU */ - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt); + ble_ll_event_add(&ctx->evt); STATS_INC(ble_ll_dtm_stats, tx_failed); @@ -278,7 +270,7 @@ ble_ll_dtm_calculate_itvl(struct dtm_ctx *ctx, uint8_t len, uint32_t itvl_usec; /* Calculate interval as per spec Bluetooth 5.0 Vol 6. Part F, 4.1.6 */ - l = ble_ll_pdu_tx_time_get(len + BLE_LL_PDU_HDR_LEN, phy_mode); + l = ble_ll_pdu_us(len, phy_mode); itvl_usec = ((l + 249 + 624) / 625) * 625; #if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) @@ -401,7 +393,7 @@ ble_ll_dtm_rx_start(void) #endif OS_ENTER_CRITICAL(sr); - rc = ble_phy_rx_set_start_time(ble_ll_tmr_get(), 0); + rc = ble_phy_rx_set_start_time(ble_ll_rfmgmt_enable_now(), 0); OS_EXIT_CRITICAL(sr); if (rc && rc != BLE_PHY_ERR_RX_LATE) { return rc; @@ -412,22 +404,9 @@ ble_ll_dtm_rx_start(void) return 0; } -static int -ble_ll_dtm_rx_sched_cb(struct ble_ll_sched_item *sch) -{ - if (ble_ll_dtm_rx_start() != 0) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); - STATS_INC(ble_ll_dtm_stats, rx_failed); - return BLE_LL_SCHED_STATE_DONE; - } - - return BLE_LL_SCHED_STATE_RUNNING; -} - static int ble_ll_dtm_rx_create_ctx(uint8_t rf_channel, uint8_t phy_mode) { - struct ble_ll_sched_item *sch = &g_ble_ll_dtm_ctx.sch; int rc; g_ble_ll_dtm_ctx.phy_mode = phy_mode; @@ -435,16 +414,8 @@ ble_ll_dtm_rx_create_ctx(uint8_t rf_channel, uint8_t phy_mode) STATS_CLEAR(ble_ll_dtm_stats, rx_count); - ble_npl_event_init(&g_ble_ll_dtm_ctx.evt, ble_ll_dtm_ev_rx_restart_cb, - NULL); - - sch->sched_cb = ble_ll_dtm_rx_sched_cb; - sch->cb_arg = &g_ble_ll_dtm_ctx; - sch->sched_type = BLE_LL_SCHED_TYPE_DTM; - sch->start_time = ble_ll_rfmgmt_enable_now(); - - rc = ble_ll_sched_dtm(sch); - BLE_LL_ASSERT(rc == 0); + rc = ble_ll_dtm_rx_start(); + assert(rc == 0); ble_phy_enable_dtm(); @@ -464,7 +435,7 @@ ble_ll_dtm_ctx_free(struct dtm_ctx * ctx) } ble_ll_sched_rmv_elem(&ctx->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); + ble_ll_event_remove(&g_ble_ll_dtm_ctx.evt); ble_phy_disable(); ble_phy_disable_dtm(); @@ -482,7 +453,7 @@ ble_ll_dtm_tx_test(uint8_t tx_chan, uint8_t len, uint8_t packet_payload, { uint8_t phy_mode; - if (g_ble_ll_dtm_ctx.active) { + if (g_ble_ll_dtm_ctx.active || ble_ll_is_busy(0)) { return BLE_ERR_CTLR_BUSY; } @@ -584,7 +555,7 @@ ble_ll_dtm_rx_test(uint8_t rx_chan, uint8_t hci_phy) { uint8_t phy_mode; - if (g_ble_ll_dtm_ctx.active) { + if (g_ble_ll_dtm_ctx.active || ble_ll_is_busy(0)) { return BLE_ERR_CTLR_BUSY; } @@ -664,10 +635,7 @@ ble_ll_dtm_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) STATS_INC(ble_ll_dtm_stats, rx_count); } - if (ble_ll_dtm_rx_start() != 0) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); - STATS_INC(ble_ll_dtm_stats, rx_failed); - } + ble_phy_restart_rx(); } int @@ -704,6 +672,12 @@ ble_ll_dtm_reset(void) ble_ll_dtm_ctx_free(&g_ble_ll_dtm_ctx); } +int +ble_ll_dtm_enabled(void) +{ + return g_ble_ll_dtm_ctx.active; +} + void ble_ll_dtm_init(void) { diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_dtm_priv.h b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_dtm_priv.h index e04af07b..1e0e2c6f 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_dtm_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_dtm_priv.h @@ -37,4 +37,5 @@ int ble_ll_dtm_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); void ble_ll_dtm_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr); void ble_ll_dtm_wfr_timer_exp(void); void ble_ll_dtm_reset(void); +int ble_ll_dtm_enabled(void); #endif diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci.c index 9666b023..c2b3af71 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci.c @@ -24,6 +24,7 @@ #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" +#include "controller/ble_ll_utils.h" #include "controller/ble_hw.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_scan.h" @@ -32,7 +33,10 @@ #include "controller/ble_ll_whitelist.h" #include "controller/ble_ll_resolv.h" #include "controller/ble_ll_sync.h" +#include +#include "controller/ble_ll_isoal.h" #include "controller/ble_ll_iso.h" +#include "controller/ble_ll_iso_big.h" #include "ble_ll_priv.h" #include "ble_ll_conn_priv.h" #include "ble_ll_hci_priv.h" @@ -54,6 +58,9 @@ static uint64_t g_ble_ll_hci_event_mask2; static int16_t rx_path_pwr_compensation; static int16_t tx_path_pwr_compensation; +static ble_ll_hci_post_cmd_complete_cb hci_cmd_post_cb = NULL; +static void *hci_cmd_post_cb_user_data = NULL; + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) static enum { ADV_MODE_ANY, @@ -211,7 +218,7 @@ ble_ll_hci_rd_local_version(uint8_t *rspbuf, uint8_t *rsplen) rsp->hci_ver = BLE_HCI_VER_BCS; rsp->hci_rev = 0; rsp->lmp_ver = BLE_LMP_VER_BCS; - rsp->manufacturer = htole16(MYNEWT_VAL(BLE_LL_MFRG_ID)); + rsp->manufacturer = htole16(MYNEWT_VAL(BLE_LL_MANUFACTURER_ID)); rsp->lmp_subver = 0; *rsplen = sizeof(*rsp); @@ -255,8 +262,7 @@ ble_ll_hci_rd_local_supp_cmd(uint8_t *rspbuf, uint8_t *rsplen) { struct ble_hci_ip_rd_loc_supp_cmd_rp *rsp = (void *) rspbuf; - memset(rsp->commands, 0, sizeof(rsp->commands)); - memcpy(rsp->commands, g_ble_ll_supp_cmds, sizeof(g_ble_ll_supp_cmds)); + ble_ll_hci_supp_cmd_get(rsp->commands); *rsplen = sizeof(*rsp); return BLE_ERR_SUCCESS; @@ -334,7 +340,7 @@ ble_ll_hci_le_read_bufsize(uint8_t *rspbuf, uint8_t *rsplen) return BLE_ERR_SUCCESS; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) +#if MYNEWT_VAL(BLE_LL_ISO) /** * HCI read buffer size v2 command. Returns the ACL and ISO data packet length and * num data packets. @@ -351,8 +357,8 @@ ble_ll_hci_le_read_bufsize_v2(uint8_t *rspbuf, uint8_t *rsplen) rp->data_len = htole16(g_ble_ll_data.ll_acl_pkt_size); rp->data_packets = g_ble_ll_data.ll_num_acl_pkts; - rp->iso_data_len = 0; - rp->iso_data_packets = 0; + rp->iso_data_len = htole16(g_ble_ll_data.ll_iso_pkt_size); + rp->iso_data_packets = g_ble_ll_data.ll_num_iso_pkts; *rsplen = sizeof(*rp); return BLE_ERR_SUCCESS; @@ -435,6 +441,15 @@ ble_ll_hci_le_set_def_phy(const uint8_t *cmdbuf, uint8_t len) #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) +int +ble_ll_hci_check_dle(uint16_t max_octets, uint16_t max_time) +{ + return (max_octets >= BLE_LL_CONN_SUPP_BYTES_MIN) && + (max_octets <= BLE_LL_CONN_SUPP_BYTES_MAX) && + (max_time >= BLE_LL_CONN_SUPP_TIME_MIN) && + (max_time <= BLE_LL_CONN_SUPP_TIME_MAX); +} + /** * HCI write suggested default data length command. * @@ -453,51 +468,47 @@ ble_ll_hci_le_set_def_phy(const uint8_t *cmdbuf, uint8_t len) static int ble_ll_hci_le_wr_sugg_data_len(const uint8_t *cmdbuf, uint8_t len) { - const struct ble_hci_le_wr_sugg_def_data_len_cp *cmd = (const void*) cmdbuf; - uint16_t tx_oct; + const struct ble_hci_le_wr_sugg_def_data_len_cp *cmd = (const void *)cmdbuf; + uint16_t tx_octets; uint16_t tx_time; - int rc; if (len != sizeof(*cmd)) { return BLE_ERR_INV_HCI_CMD_PARMS; } /* Get suggested octets and time */ - tx_oct = le16toh(cmd->max_tx_octets); + tx_octets = le16toh(cmd->max_tx_octets); tx_time = le16toh(cmd->max_tx_time); - /* If valid, write into suggested and change connection initial times */ - if (ble_ll_chk_txrx_octets(tx_oct) && ble_ll_chk_txrx_time(tx_time)) { - g_ble_ll_conn_params.sugg_tx_octets = (uint8_t)tx_oct; - g_ble_ll_conn_params.sugg_tx_time = tx_time; + if (!ble_ll_hci_check_dle(tx_octets, tx_time)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } - /* - * We can disregard host suggestion, but we are a nice controller so - * let's use host suggestion, unless they exceed max supported values - * in which case we just use our max. - */ - g_ble_ll_conn_params.conn_init_max_tx_octets = - min(tx_oct, g_ble_ll_conn_params.supp_max_tx_octets); - g_ble_ll_conn_params.conn_init_max_tx_time = - min(tx_time, g_ble_ll_conn_params.supp_max_tx_time); + g_ble_ll_conn_params.sugg_tx_octets = tx_octets; + g_ble_ll_conn_params.sugg_tx_time = tx_time; - /* - * Use the same for coded and uncoded defaults. These are used when PHY - * parameters are initialized and we want to use values overridden by - * host. Make sure we do not exceed max supported time on uncoded. - */ - g_ble_ll_conn_params.conn_init_max_tx_time_uncoded = - min(BLE_LL_CONN_SUPP_TIME_MAX_UNCODED, - g_ble_ll_conn_params.conn_init_max_tx_time); - g_ble_ll_conn_params.conn_init_max_tx_time_coded = - g_ble_ll_conn_params.conn_init_max_tx_time; + /* + * We can disregard host suggestion, but we are a nice controller so + * let's use host suggestion, unless they exceed max supported values + * in which case we just use our max. + */ + g_ble_ll_conn_params.conn_init_max_tx_octets = + MIN(tx_octets, g_ble_ll_conn_params.supp_max_tx_octets); + g_ble_ll_conn_params.conn_init_max_tx_time = + MIN(tx_time, g_ble_ll_conn_params.supp_max_tx_time); - rc = BLE_ERR_SUCCESS; - } else { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - } + /* + * Use the same for coded and uncoded defaults. These are used when PHY + * parameters are initialized and we want to use values overridden by + * host. Make sure we do not exceed max supported time on uncoded. + */ + g_ble_ll_conn_params.conn_init_max_tx_time_uncoded = + MIN(BLE_LL_CONN_SUPP_TIME_MAX_UNCODED, + g_ble_ll_conn_params.conn_init_max_tx_time); + g_ble_ll_conn_params.conn_init_max_tx_time_coded = + g_ble_ll_conn_params.conn_init_max_tx_time; - return rc; + return 0; } /** @@ -652,6 +663,11 @@ ble_ll_hci_le_cmd_send_cmd_status(uint16_t ocf) case BLE_HCI_OCF_LE_GEN_DHKEY: case BLE_HCI_OCF_LE_SET_PHY: case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC: +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + case BLE_HCI_OCF_LE_CREATE_BIG: + case BLE_HCI_OCF_LE_CREATE_BIG_TEST: + case BLE_HCI_OCF_LE_TERMINATE_BIG: +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) case BLE_HCI_OCF_LE_REQ_PEER_SCA: #endif @@ -781,8 +797,8 @@ ble_ll_read_tx_power(uint8_t *rspbuf, uint8_t *rsplen) { struct ble_hci_le_rd_transmit_power_rp *rsp = (void *) rspbuf; - rsp->min_tx_power = ble_phy_txpower_round(-127); - rsp->max_tx_power = ble_phy_txpower_round(126); + rsp->min_tx_power = ble_ll_tx_power_round(-127); + rsp->max_tx_power = ble_ll_tx_power_round(126); *rsplen = sizeof(*rsp); return BLE_ERR_SUCCESS; @@ -821,15 +837,43 @@ ble_ll_write_rf_path_compensation(const uint8_t *cmdbuf, uint8_t len) tx_path_pwr_compensation = tx; rx_path_pwr_compensation = rx; - ble_phy_set_rx_pwr_compensation(rx_path_pwr_compensation / 10); + g_ble_ll_tx_power_compensation = tx / 10; + g_ble_ll_rx_power_compensation = rx / 10; return BLE_ERR_SUCCESS; } -int8_t -ble_ll_get_tx_pwr_compensation(void) +static int +ble_ll_hci_le_set_host_chan_class(const uint8_t *cmdbuf, uint8_t len) { - return tx_path_pwr_compensation / 10; + const struct ble_hci_le_set_host_chan_class_cp *cmd = (const void *)cmdbuf; + uint8_t chan_map_used; + + if (len != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* HCI command allows only single channel to be enabled, but LL needs at + * least 2 channels to work so let's reject in such case. + */ + chan_map_used = ble_ll_utils_chan_map_used_get(cmd->chan_map); + if ((chan_map_used < 2) || (cmd->chan_map[4] & 0xe0)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!memcmp(g_ble_ll_data.chan_map, cmd->chan_map, BLE_LL_CHAN_MAP_LEN)) { + return BLE_ERR_SUCCESS; + } + + memcpy(g_ble_ll_data.chan_map, cmd->chan_map, BLE_LL_CHAN_MAP_LEN); + g_ble_ll_data.chan_map_used = chan_map_used; + + ble_ll_conn_chan_map_update(); +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + ble_ll_iso_big_chan_map_update(); +#endif + + return BLE_ERR_SUCCESS; } /** @@ -848,8 +892,7 @@ ble_ll_get_tx_pwr_compensation(void) */ static int ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, - uint8_t *rspbuf, uint8_t *rsplen, - ble_ll_hci_post_cmd_complete_cb *cb) + uint8_t *rspbuf, uint8_t *rsplen) { int rc; @@ -929,7 +972,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, break; case BLE_HCI_OCF_LE_CREATE_CONN_CANCEL: if (len == 0) { - rc = ble_ll_conn_create_cancel(cb); + rc = ble_ll_conn_create_cancel(); } break; #endif @@ -956,7 +999,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, break; #endif case BLE_HCI_OCF_LE_SET_HOST_CHAN_CLASS: - rc = ble_ll_conn_hci_set_chan_class(cmdbuf, len); + rc = ble_ll_hci_le_set_host_chan_class(cmdbuf, len); break; #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_RD_CHAN_MAP: @@ -1156,7 +1199,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, break; case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC_CANCEL: if (len == 0) { - rc = ble_ll_sync_cancel(cb); + rc = ble_ll_sync_cancel(); } break; case BLE_HCI_OCF_LE_PERIODIC_ADV_TERM_SYNC: @@ -1221,6 +1264,17 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_set_default_sync_transfer_params(cmdbuf, len); break; #endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + case BLE_HCI_OCF_LE_CREATE_BIG: + rc = ble_ll_iso_big_hci_create(cmdbuf, len); + break; + case BLE_HCI_OCF_LE_CREATE_BIG_TEST: + rc = ble_ll_iso_big_hci_create_test(cmdbuf, len); + break; + case BLE_HCI_OCF_LE_TERMINATE_BIG: + rc = ble_ll_iso_big_hci_terminate(cmdbuf, len); + break; +#endif /* BLE_LL_ISO_BROADCASTER */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) case BLE_HCI_OCF_LE_READ_ISO_TX_SYNC: rc = ble_ll_iso_read_tx_sync(cmdbuf, len); @@ -1240,30 +1294,29 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, case BLE_HCI_OCF_LE_REJECT_CIS_REQ: rc = ble_ll_iso_reject_cis_req(cmdbuf, len); break; - case BLE_HCI_OCF_LE_CREATE_BIG: - rc = ble_ll_iso_create_big(cmdbuf, len); - break; - case BLE_HCI_OCF_LE_TERMINATE_BIG: - rc = ble_ll_iso_terminate_big(cmdbuf, len); - break; case BLE_HCI_OCF_LE_BIG_CREATE_SYNC: rc = ble_ll_iso_big_create_sync(cmdbuf, len); break; case BLE_HCI_OCF_LE_BIG_TERMINATE_SYNC: rc = ble_ll_iso_big_terminate_sync(cmdbuf,len); break; +#endif +#if MYNEWT_VAL(BLE_LL_ISO) case BLE_HCI_OCF_LE_SETUP_ISO_DATA_PATH: - rc = ble_ll_iso_setup_iso_data_path(cmdbuf, len); + rc = ble_ll_isoal_hci_setup_iso_data_path(cmdbuf, len, rspbuf, rsplen); break; case BLE_HCI_OCF_LE_REMOVE_ISO_DATA_PATH: - rc = ble_ll_iso_remove_iso_data_path(cmdbuf, len); + rc = ble_ll_isoal_hci_remove_iso_data_path(cmdbuf, len, rspbuf, rsplen); + break; + case BLE_HCI_OCF_LE_READ_ISO_TX_SYNC: + rc = ble_ll_isoal_hci_read_tx_sync(cmdbuf, len, rspbuf, rsplen); break; case BLE_HCI_OCF_LE_RD_BUF_SIZE_V2: if (len == 0) { rc = ble_ll_hci_le_read_bufsize_v2(rspbuf, rsplen); } break; -#endif +#endif /* BLE_LL_ISO */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO_TEST) case BLE_HCI_OCF_LE_SET_CIG_PARAM_TEST: rc = ble_ll_iso_set_cig_param_test(cmdbuf, len, rspbuf, rsplen); @@ -1285,7 +1338,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, break; #endif #if MYNEWT_VAL(BLE_VERSION) >= 52 - case BLE_HCI_OCF_LE_SET_HOST_FEAT: + case BLE_HCI_OCF_LE_SET_HOST_FEATURE: rc = ble_ll_set_host_feat(cmdbuf, len); break; #endif @@ -1433,17 +1486,9 @@ ble_ll_hci_cb_host_buf_size(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } - /* - * Core 5.2 Vol 4 Part E section 7.3.39 states that "Both the Host and the - * Controller shall support command and event packets, where the data portion - * (excluding header) contained in the packets is 255 octets in size.". - * This means we can basically accept any allowed value since LL does not - * reassemble incoming data thus will not send more than 255 octets in single - * data packet. - */ acl_num = le16toh(cmd->acl_num); acl_data_len = le16toh(cmd->acl_data_len); - if (acl_data_len < 255) { + if ((acl_num < 1) || (acl_data_len < 1)) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -1580,6 +1625,43 @@ ble_ll_hci_status_params_cmd_proc(const uint8_t *cmdbuf, uint8_t len, } #if MYNEWT_VAL(BLE_LL_HBD_FAKE_DUAL_MODE) +static void +ble_ll_hci_cmd_fake_dual_mode_inquiry_complete(struct ble_npl_event *ev) +{ + struct ble_hci_ev *hci_ev; + + hci_ev = ble_transport_alloc_evt(1); + if (!hci_ev) { + return; + } + + hci_ev->opcode = BLE_HCI_EVCODE_INQUIRY_CMP; + hci_ev->length = 1; + hci_ev->data[0] = 0; + + ble_ll_hci_event_send(hci_ev); +} + +static void +ble_ll_hci_cmd_fake_dual_mode_inquiry(uint32_t length) +{ + static struct ble_npl_callout inquiry_timer; + static bool init; + + if (!init) { + ble_npl_callout_init(&inquiry_timer, &g_ble_ll_data.ll_evq, + ble_ll_hci_cmd_fake_dual_mode_inquiry_complete, + NULL); + } + + if (length) { + ble_npl_callout_reset(&inquiry_timer, + ble_npl_time_ms_to_ticks32(length * 1280)); + } else { + ble_npl_callout_stop(&inquiry_timer); + } +} + static int ble_ll_hci_cmd_fake_dual_mode(uint16_t opcode, uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen) @@ -1588,10 +1670,16 @@ ble_ll_hci_cmd_fake_dual_mode(uint16_t opcode, uint8_t *cmdbuf, uint8_t len, switch (opcode) { case BLE_HCI_OP(BLE_HCI_OGF_LINK_CTRL, 0x01): /* Inquiry */ + ble_ll_hci_cmd_fake_dual_mode_inquiry(cmdbuf[3]); rc = BLE_ERR_MAX + 1; break; case BLE_HCI_OP(BLE_HCI_OGF_LINK_CTRL, 0x02): /* Inquiry Cancel */ + ble_ll_hci_cmd_fake_dual_mode_inquiry(0); + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x05): /* Set Event Filter */ case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x13): /* Write Local Name */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x16): /* Write Connection Accept Timeout */ case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x18): /* Write Page Timeout */ case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x1a): /* Write Scan Enable */ case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x1c): /* Write Page Scan Activity */ @@ -1601,9 +1689,37 @@ ble_ll_hci_cmd_fake_dual_mode(uint16_t opcode, uint8_t *cmdbuf, uint8_t len, case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x33): /* Host Buffer Size */ case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x45): /* Write Inquiry Mode */ case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x52): /* Write Extended Inquiry Response */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x56): /* Write Simple Pairing Mode */ case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x6d): /* Write LE Host Support */ rc = 0; break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x14): /* Read Local Name */ + memset(rspbuf, 0, 248); + strcpy((char *)rspbuf, "NimBLE"); + *rsplen = 248; + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x23): /* Read Class Of Device */ + put_le24(rspbuf, 0); + *rsplen = 3; + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x25): /* Read Voice Settings */ + put_le16(rspbuf, 0); + *rsplen = 2; + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x38): /* Read Number Of Supported IAC */ + rspbuf[0] = 1; + *rsplen = 1; + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x39): /* Read Current IAC LAP */ + rspbuf[0] = 1; + put_le24(&rspbuf[1], 0x9e8b33); + *rsplen = 4; + rc = 0; + break; case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x58): /* Read Inquiry Response Transmit Power Level */ rspbuf[0] = 0x04; *rsplen = 1; @@ -1614,6 +1730,13 @@ ble_ll_hci_cmd_fake_dual_mode(uint16_t opcode, uint8_t *cmdbuf, uint8_t len, *rsplen = 8; rc = 0; break; + case BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS, 0x04): /* Read Local Extended Features */ + rspbuf[0] = 0; + rspbuf[1] = 0; + put_le64(&rspbuf[2], 0x877bffdbfe0ffebf); + *rsplen = 10; + rc = 0; + break; case BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS, BLE_HCI_OCF_IP_RD_BUF_SIZE): put_le16(rspbuf, 255); rspbuf[2] = 0; @@ -1635,6 +1758,15 @@ ble_ll_hci_cmd_fake_dual_mode(uint16_t opcode, uint8_t *cmdbuf, uint8_t len, } #endif + +void +ble_ll_hci_post_cmd_cb_set(ble_ll_hci_post_cmd_complete_cb cb, void *user_data) +{ + BLE_LL_ASSERT(hci_cmd_post_cb == NULL); + hci_cmd_post_cb = cb; + hci_cmd_post_cb_user_data = user_data; +} + /** * Called to process an HCI command from the host. * @@ -1649,7 +1781,6 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) struct ble_hci_cmd *cmd; uint16_t opcode; uint16_t ocf; - ble_ll_hci_post_cmd_complete_cb post_cb = NULL; struct ble_hci_ev *hci_ev; struct ble_hci_ev_command_status *cmd_status; struct ble_hci_ev_command_complete *cmd_complete; @@ -1678,6 +1809,22 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) /* Assume response length is zero */ rsplen = 0; +#if MYNEWT_VAL(BLE_LL_DTM) + /* if DTM test is enabled disallow any command other than LE Test End or + * HCI Reset + */ + if (ble_ll_dtm_enabled()) { + switch (opcode) { + case BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_TEST_END): + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_RESET): + break; + default: + rc = BLE_ERR_CMD_DISALLOWED; + goto send_cc_cs; + } + } +#endif + #if MYNEWT_VAL(BLE_LL_HBD_FAKE_DUAL_MODE) rc = ble_ll_hci_cmd_fake_dual_mode(opcode, cmd->data, cmd->length, rspbuf, &rsplen); @@ -1700,7 +1847,7 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) rc = ble_ll_hci_status_params_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); break; case BLE_HCI_OGF_LE: - rc = ble_ll_hci_le_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen, &post_cb); + rc = ble_ll_hci_le_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); break; #if MYNEWT_VAL(BLE_LL_HCI_VS) case BLE_HCI_OGF_VENDOR: @@ -1720,7 +1867,7 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) rc += (BLE_ERR_MAX + 1); } -#if MYNEWT_VAL(BLE_LL_HBD_FAKE_DUAL_MODE) +#if MYNEWT_VAL(BLE_LL_HBD_FAKE_DUAL_MODE) || MYNEWT_VAL(BLE_LL_DTM) send_cc_cs: #endif /* If no response is generated, we free the buffers */ @@ -1758,26 +1905,18 @@ send_cc_cs: ble_ll_hci_event_send(hci_ev); /* Call post callback if set by command handler */ - if (post_cb) { - post_cb(); + if (hci_cmd_post_cb) { + hci_cmd_post_cb(hci_cmd_post_cb_user_data); + + hci_cmd_post_cb = NULL; + hci_cmd_post_cb_user_data = NULL; } BLE_LL_DEBUG_GPIO(HCI_CMD, 0); } -/** - * Sends an HCI command to the controller. On success, the supplied buffer is - * relinquished to the controller task. On failure, the caller must free the - * buffer. - * - * @param cmd A flat buffer containing the HCI command to - * send. - * - * @return 0 on success; - * BLE_ERR_MEM_CAPACITY on HCI buffer exhaustion. - */ int -ble_ll_hci_cmd_rx(uint8_t *cmdbuf, void *arg) +ble_ll_hci_cmd_rx(uint8_t *cmdbuf) { struct ble_npl_event *ev; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) @@ -1813,14 +1952,13 @@ ble_ll_hci_cmd_rx(uint8_t *cmdbuf, void *arg) /* Fill out the event and post to Link Layer */ ble_npl_event_set_arg(ev, cmdbuf); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, ev); + ble_ll_event_add(ev); return 0; } -/* Send ACL data from host to contoller */ int -ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg) +ble_ll_hci_acl_rx(struct os_mbuf *om) { #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) ble_ll_acl_data_in(om); @@ -1831,6 +1969,17 @@ ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg) return 0; } +int +ble_ll_hci_iso_rx(struct os_mbuf *om) +{ +#if MYNEWT_VAL(BLE_LL_ISO) + ble_ll_isoal_data_in(om); +#else + os_mbuf_free_chain(om); +#endif + return 0; +} + /** * Initalize the LL HCI. * diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci_ev.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci_ev.c index 6da2545c..dc748062 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci_ev.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci_ev.c @@ -16,8 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -#include + #include +#include +#include +#include #include #include "syscfg/syscfg.h" #include "nimble/ble.h" @@ -132,7 +135,7 @@ ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status) struct ble_hci_ev_enrypt_chg *ev_enc_chf; struct ble_hci_ev *hci_ev; - if (CONN_F_ENC_CHANGE_SENT(connsm) == 0) { + if (connsm->flags.encrypt_event_sent == 0) { if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_ENCRYPT_CHG)) { hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { @@ -148,7 +151,7 @@ ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status) } } - CONN_F_ENC_CHANGE_SENT(connsm) = 1; + connsm->flags.encrypt_event_sent = 1; return; } @@ -328,7 +331,7 @@ ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm) ev->subev_code = BLE_HCI_LE_SUBEV_CHAN_SEL_ALG; ev->conn_handle = htole16(connsm->conn_handle); - ev->csa = connsm->csmflags.cfbit.csa2_supp ? 0x01 : 0x00; + ev->csa = connsm->flags.csa2 ? 0x01 : 0x00; ble_ll_hci_event_send(hci_ev); } @@ -523,10 +526,36 @@ ble_ll_hci_ev_subrate_change(struct ble_ll_conn_sm *connsm, uint8_t status) } #endif +#if MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) +void +ble_ll_hci_ev_send_vs_css_slot_changed(uint16_t conn_handle, uint16_t slot_idx) +{ + struct ble_hci_ev_vs_css_slot_changed *ev; + struct ble_hci_ev_vs *ev_vs; + struct ble_hci_ev *hci_ev; + + hci_ev = ble_transport_alloc_evt(0); + if (!hci_ev) { + return; + + } + + hci_ev->opcode = BLE_HCI_EVCODE_VS; + hci_ev->length = sizeof(*ev_vs) + sizeof(*ev); + ev_vs = (void *)hci_ev->data; + ev_vs->id = BLE_HCI_VS_SUBEV_ID_CSS_SLOT_CHANGED; + ev = (void *)ev_vs->data; + ev->conn_handle = htole16(conn_handle); + ev->slot_idx = htole16(slot_idx); + + ble_ll_hci_event_send(hci_ev); +} +#endif + void ble_ll_hci_ev_send_vs_assert(const char *file, uint32_t line) { - struct ble_hci_ev_vs_debug *ev; + struct ble_hci_ev_vs *ev; struct ble_hci_ev *hci_ev; unsigned int str_len; bool skip = true; @@ -541,12 +570,12 @@ ble_ll_hci_ev_send_vs_assert(const char *file, uint32_t line) hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_VS_DEBUG; + hci_ev->opcode = BLE_HCI_EVCODE_VS; hci_ev->length = sizeof(*ev); ev = (void *) hci_ev->data; /* Debug id for future use */ - ev->id = 0x00; + ev->id = BLE_HCI_VS_SUBEV_ID_ASSERT; /* snprintf would be nicer but this is heavy on flash * len = snprintf((char *) ev->data, max_len, "%s:%u", file, line); @@ -559,7 +588,7 @@ ble_ll_hci_ev_send_vs_assert(const char *file, uint32_t line) * hci_ev->length += len; */ str_len = strlen(file); - if (str_len > max_len) { + if (str_len > (unsigned int)max_len) { str_len = max_len; } @@ -583,21 +612,47 @@ ble_ll_hci_ev_send_vs_assert(const char *file, uint32_t line) } } +void +ble_ll_hci_ev_send_vs_printf(uint8_t id, const char *fmt, ...) +{ + struct ble_hci_ev_vs *ev; + struct ble_hci_ev *hci_ev; + va_list ap; + + hci_ev = ble_transport_alloc_evt(1); + if (!hci_ev) { + return; + } + + hci_ev->opcode = BLE_HCI_EVCODE_VS; + hci_ev->length = sizeof(*ev); + + ev = (void *) hci_ev->data; + ev->id = id; + + va_start(ap, fmt); + hci_ev->length += vsnprintf((void *)ev->data, + BLE_HCI_MAX_DATA_LEN - sizeof(*ev), fmt, ap); + va_end(ap); + + ble_ll_hci_event_send(hci_ev); +} + #if MYNEWT_VAL(BLE_LL_HCI_LLCP_TRACE) void ble_ll_hci_ev_send_vs_llcp_trace(uint8_t type, uint16_t handle, uint16_t count, void *pdu, size_t length) { - struct ble_hci_ev_vs_debug *ev; + struct ble_hci_ev_vs *ev; struct ble_hci_ev *hci_ev; hci_ev = ble_transport_alloc_evt(1); if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_VS_DEBUG; + hci_ev->opcode = BLE_HCI_EVCODE_VS; hci_ev->length = sizeof(*ev) + 8 + length; ev = (void *) hci_ev->data; - ev->id = 0x17; + ev->id = BLE_HCI_VS_SUBEV_ID_LLCP_TRACE; ev->data[0] = type; put_le16(&ev->data[1], handle); put_le16(&ev->data[3], count); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci_supp_cmd.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci_supp_cmd.c new file mode 100644 index 00000000..f10c8989 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci_supp_cmd.c @@ -0,0 +1,341 @@ +/* + * 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 +#include +#include +#include +#include + +/* Magic macros */ +#define BIT(n) (1 << (n)) | +#define OCTET(x) (0 | x 0) + +static const uint8_t octet_0 = OCTET( +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(5) /* HCI Disconnect */ +#endif +); + +static const uint8_t octet_2 = OCTET( +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(7) /* HCI Read Remote Version Information */ +#endif +); + +static const uint8_t octet_5 = OCTET( + BIT(6) /* HCI Set Event Mask */ + BIT(7) /* HCI Reset */ +); + +static const uint8_t octet_10 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) + BIT(5) /* HCI Set Controller To Host Flow Control */ + BIT(6) /* HCI Host Buffer Size */ + BIT(7) /* HCI Host Number Of Completed Packets */ +#endif +); + +static const uint8_t octet_14 = OCTET( + BIT(3) /* HCI Read Local Version Information */ + BIT(5) /* HCI Read Local Supported Features */ +); + +static const uint8_t octet_15 = OCTET( + BIT(1) /* HCI Read BD ADDR */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(5) /* HCI Read RSSI */ +#endif +); + +static const uint8_t octet_25 = OCTET( + BIT(0) /* HCI LE Set Event Mask */ + BIT(1) /* HCI LE Read Buffer Size [v1] */ + BIT(2) /* HCI LE Read Local Supported Features */ + BIT(4) /* HCI LE Set Random Address */ +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(5) /* HCI LE Set Advertising Parameters */ + BIT(6) /* HCI LE Read Advertising Physical Channel Tx Power */ + BIT(7) /* HCI LE Set Advertising Data */ +#endif +); + +static const uint8_t octet_26 = OCTET( +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(0) /* HCI LE Set Scan Response Data */ + BIT(1) /* HCI LE Set Advertising Enable */ +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + BIT(2) /* HCI LE Set Scan Parameters */ + BIT(3) /* HCI LE Set Scan Enable */ +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(4) /* HCI LE Create Connection */ + BIT(5) /* HCI LE Create Connection Cancel */ +#endif + BIT(6) /* HCI LE Read Filter Accept List Size */ + BIT(7) /* HCI LE Clear Filter Accept List */ +); + +static const uint8_t octet_27 = OCTET( + BIT(0) /* HCI LE Add Device To Filter Accept List */ + BIT(1) /* HCI LE Remove Device From Filter Accept List */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(2) /* HCI LE Connection Update */ +#endif + BIT(3) /* HCI LE Set Host Channel Classification */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(4) /* HCI LE Read Channel Map */ + BIT(5) /* HCI LE Read Remote Features */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + BIT(6) /* HCI LE Encrypt */ +#endif + BIT(7) /* HCI LE Rand */ +); + +static const uint8_t octet_28 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(0) /* HCI LE Enable Encryption */ +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + BIT(1) /* HCI LE Long Term Key Request Reply */ + BIT(2) /* HCI LE Long Term Key Request Negative Reply */ +#endif +#endif + BIT(3) /* HCI LE Read Supported States */ +#if MYNEWT_VAL(BLE_LL_DTM) + BIT(4) /* HCI LE Receiver Test [v1] */ + BIT(5) /* HCI LE Transmitter Test [v1] */ + BIT(6) /* HCI LE Test End */ +#endif +); + +static const uint8_t octet_33 = OCTET( +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(4) /* HCI LE Remote Connection Parameter Request Reply */ + BIT(5) /* HCI LE Remote Connection Parameter Request Negative Reply */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) + BIT(6) /* HCI LE Set Data Length */ + BIT(7) /* HCI LE Read Suggested Default Data Length */ +#endif +); + +static const uint8_t octet_34 = OCTET( +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) + BIT(0) /* HCI LE Write Suggested Data Length */ +#endif +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + BIT(3) /* HCI LE Add Device To Resolving List */ + BIT(4) /* HCI LE Remove Device From Resolving List */ + BIT(5) /* HCI LE Clear Resolving List */ + BIT(6) /* HCI LE Read Resolving List Size */ + BIT(7) /* HCI LE Read Peer Resolvable Address */ +#endif +); + +static const uint8_t octet_35 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + BIT(0) /* HCI LE Read Local Resolvable Address */ + BIT(1) /* HCI LE Set Address Resolution Enable */ + BIT(2) /* HCI LE Set Resolvable Private Address Timeout */ +#endif + BIT(3) /* HCI LE Read Maximum Data Length */ +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(4) /* HCI LE Read PHY */ + BIT(5) /* HCI LE Set Default PHY */ + BIT(6) /* HCI LE Set PHY */ +#endif +#endif +#if MYNEWT_VAL(BLE_LL_DTM) + BIT(7) /* HCI LE Receiver Test [v2] */ +#endif +); + +static const uint8_t octet_36 = OCTET( +#if MYNEWT_VAL(BLE_LL_DTM) + BIT(0) /* HCI LE Transmitter Test [v2] */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(1) /* HCI LE Set Advertising Set Random Address */ + BIT(2) /* HCI LE Set Extended Advertising Parameters */ + BIT(3) /* HCI LE Set Extended Advertising Data */ + BIT(4) /* HCI LE Set Extended Scan Response Data */ + BIT(5) /* HCI LE Set Extended Advertising Enable */ + BIT(6) /* HCI LE Read Maximum Advertising Data Length */ + BIT(7) /* HCI LE Read Number of Supported Advertising Sets */ +#endif +); + +static const uint8_t octet_37 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(0) /* HCI LE Remove Advertising Set */ + BIT(1) /* HCI LE Clear Advertising Sets */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(2) /* HCI LE Set Periodic Advertising Parameters */ + BIT(3) /* HCI LE Set Periodic Advertising Data */ + BIT(4) /* HCI LE Set Periodic Advertising Enable */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + BIT(5) /* HCI LE Set Extended Scan Parameters */ + BIT(6) /* HCI LE Set Extended Scan Enable */ +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(7) /* HCI LE Extended Create Connection */ +#endif +#endif +); + +static const uint8_t octet_38 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + BIT(0) /* HCI LE Periodic Advertising Create Sync */ + BIT(1) /* HCI LE Periodic Advertising Create Sync Cancel */ + BIT(2) /* HCI LE Periodic Advertising Terminate Sync */ + BIT(3) /* HCI LE Add Device To Periodic Advertiser List */ + BIT(4) /* HCI LE Remove Device From Periodic Advertiser List */ + BIT(5) /* HCI LE Clear Periodic Advertiser List */ + BIT(6) /* HCI LE Read Periodic Advertiser List Size */ +#endif + BIT(7) /* HCI LE Read Transmit Power */ +); + +static const uint8_t octet_39 = OCTET( + BIT(0) /* HCI LE Read RF Path Compensation */ + BIT(1) /* HCI LE Write RF Path Compensation */ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + BIT(2) /* HCI LE Set Privacy Mode */ +#endif +); + +static const uint8_t octet_40 = OCTET( +#if MYNEWT_VAL(BLE_VERSION) >= 51 && MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + BIT(5) /* HCI LE Set Periodic Advertising Receive Enable */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + BIT(6) /* HCI LE Periodic Advertising Sync Transfer */ +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(7) /* HCI LE Periodic Advertising Set Info Transfer */ +#endif +#endif +#endif +); + +static const uint8_t octet_41 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) + BIT(0) /* HCI LE Set Periodic Advertising Sync Transfer Parameters */ + BIT(1) /* HCI LE Set Default Periodic Advertising Sync Transfer Parameters */ +#endif +#if MYNEWT_VAL(BLE_LL_ISO) + BIT(5) /* HCI LE Read Buffer Size [v2] */ + BIT(6) /* HCI LE Read ISO TX Sync */ +#endif +); + +static const uint8_t octet_42 = OCTET( +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + BIT(5) /* HCI LE Create BIG */ + BIT(6) /* HCI LE Create BIG Test */ + BIT(7) /* HCI LE Terminate BIG */ +#endif +); + +static const uint8_t octet_43 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) + BIT(2) /* HCI LE Request Peer SCA */ +#endif +); + +static const uint8_t octet_44 = OCTET( +#if MYNEWT_VAL(BLE_VERSION) >= 52 + BIT(1) /* HCI LE Set Host Feature */ +#endif +); + +static const uint8_t octet_46 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + BIT(0) /* HCI LE Set Default Subrate */ + BIT(1) /* HCI LE Subrate Request */ +#endif +); + +static const uint8_t g_ble_ll_hci_supp_cmds[64] = { + octet_0, + 0, + octet_2, + 0, + 0, + octet_5, + 0, + 0, + 0, + 0, + octet_10, + 0, + 0, + 0, + octet_14, + octet_15, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + octet_25, + octet_26, + octet_27, + octet_28, + 0, + 0, + 0, + 0, + octet_33, + octet_34, + octet_35, + octet_36, + octet_37, + octet_38, + octet_39, + octet_40, + octet_41, + octet_42, + octet_43, + octet_44, + 0, + octet_46, +}; + +void +ble_ll_hci_supp_cmd_get(uint8_t *buf) +{ + memcpy(buf, g_ble_ll_hci_supp_cmds, sizeof(g_ble_ll_hci_supp_cmds)); +} diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci_vs.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci_vs.c index 2b390920..7fd9a6ea 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci_vs.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_hci_vs.c @@ -19,12 +19,14 @@ #include #include "syscfg/syscfg.h" +#include "controller/ble_ll_utils.h" #include "controller/ble_ll.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_sync.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_scan.h" #include "controller/ble_hw.h" +#include "controller/ble_fem.h" #include "ble_ll_conn_priv.h" #include "ble_ll_priv.h" @@ -56,56 +58,6 @@ ble_ll_hci_vs_rd_static_addr(uint16_t ocf, return BLE_ERR_SUCCESS; } -/* disallow changing TX power if there is any radio activity - * note: we could allow to change it if there is no TX activity (eg only - * passive scan or sync) but lets just keep this simple for now - */ -static int -ble_ll_hci_vs_is_controller_busy(void) -{ -#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) - struct ble_ll_conn_sm *cur; - int i = 0; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) - if (ble_ll_sync_enabled()) { - return 1; - } -#endif - -#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) - if (ble_ll_adv_enabled()) { - return 1; - } -#endif - -#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) - if (ble_ll_scan_enabled()) { - return 1; - } -#endif - -#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) - if (g_ble_ll_conn_create_sm.connsm) { - return 1; - } -#endif - -#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) - STAILQ_FOREACH(cur, &g_ble_ll_conn_free_list, free_stqe) { - i++; - } - - /* check if all connection objects are free */ - if (i < MYNEWT_VAL(BLE_MAX_CONNECTIONS)) { - return 1; - } -#endif - - return 0; -} - static int ble_ll_hci_vs_set_tx_power(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, uint8_t *rspbuf, uint8_t *rsplen) @@ -117,18 +69,22 @@ ble_ll_hci_vs_set_tx_power(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, return BLE_ERR_INV_HCI_CMD_PARMS; } - if (ble_ll_hci_vs_is_controller_busy()) { + if (ble_ll_is_busy(0)) { return BLE_ERR_CMD_DISALLOWED; } if (cmd->tx_power == 127) { /* restore reset default */ - g_ble_ll_tx_power = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); + g_ble_ll_tx_power = ble_ll_tx_power_round(MIN(MYNEWT_VAL(BLE_LL_TX_PWR_DBM), + MYNEWT_VAL(BLE_LL_TX_PWR_MAX_DBM)) - + g_ble_ll_tx_power_compensation); } else { - g_ble_ll_tx_power = ble_phy_txpower_round(cmd->tx_power); + g_ble_ll_tx_power = ble_ll_tx_power_round(MIN(cmd->tx_power, + MYNEWT_VAL(BLE_LL_TX_PWR_MAX_DBM)) - + g_ble_ll_tx_power_compensation); } - rsp->tx_power = g_ble_ll_tx_power; + rsp->tx_power = g_ble_ll_tx_power + g_ble_ll_tx_power_compensation; *rsplen = sizeof(*rsp); return BLE_ERR_SUCCESS; @@ -138,7 +94,7 @@ ble_ll_hci_vs_set_tx_power(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, #if MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) #if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) static int -ble_ll_hci_vs_css_configure(const uint8_t *cmdbuf, uint8_t cmdlen, +ble_ll_hci_vs_css_configure(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, uint8_t *rspbuf, uint8_t *rsplen) { const struct ble_hci_vs_css_configure_cp *cmd = (const void *)cmdbuf; @@ -149,8 +105,8 @@ ble_ll_hci_vs_css_configure(const uint8_t *cmdbuf, uint8_t cmdlen, return BLE_ERR_INV_HCI_CMD_PARMS; } - if (!SLIST_EMPTY(&g_ble_ll_conn_active_list)) { - return BLE_ERR_CTLR_BUSY; + if (ble_ll_sched_css_is_enabled()) { + return BLE_ERR_CMD_DISALLOWED; } slot_us = le32toh(cmd->slot_us); @@ -171,8 +127,32 @@ ble_ll_hci_vs_css_configure(const uint8_t *cmdbuf, uint8_t cmdlen, #endif static int -ble_ll_hci_vs_css_set_next_slot(const uint8_t *cmdbuf, uint8_t cmdlen, - uint8_t *rspbuf, uint8_t *rsplen) +ble_ll_hci_vs_css_enable(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_vs_css_enable_cp *cmd = (const void *)cmdbuf; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!SLIST_EMPTY(&g_ble_ll_conn_active_list)) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (cmd->enable & 0xfe) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + ble_ll_sched_css_set_enabled(cmd->enable); + + return BLE_ERR_SUCCESS; +} + +static int +ble_ll_hci_vs_css_set_next_slot(uint16_t ocf, const uint8_t *cmdbuf, + uint8_t cmdlen, uint8_t *rspbuf, + uint8_t *rsplen) { const struct ble_hci_vs_css_set_next_slot_cp *cmd = (const void *)cmdbuf; uint16_t slot_idx; @@ -197,8 +177,9 @@ ble_ll_hci_vs_css_set_next_slot(const uint8_t *cmdbuf, uint8_t cmdlen, } static int -ble_ll_hci_vs_css_set_conn_slot(const uint8_t *cmdbuf, uint8_t cmdlen, - uint8_t *rspbuf, uint8_t *rsplen) +ble_ll_hci_vs_css_set_conn_slot(uint16_t ocf, const uint8_t *cmdbuf, + uint8_t cmdlen, uint8_t *rspbuf, + uint8_t *rsplen) { const struct ble_hci_vs_css_set_conn_slot_cp *cmd = (const void *)cmdbuf; struct ble_ll_conn_sm *connsm; @@ -209,6 +190,10 @@ ble_ll_hci_vs_css_set_conn_slot(const uint8_t *cmdbuf, uint8_t cmdlen, return BLE_ERR_INV_HCI_CMD_PARMS; } + if (!ble_ll_sched_css_is_enabled()) { + return BLE_ERR_CMD_DISALLOWED; + } + slot_idx = le16toh(cmd->slot_idx); if ((slot_idx >= ble_ll_sched_css_get_period_slots()) && (slot_idx != BLE_LL_CONN_CSS_NO_SLOT)) { @@ -220,7 +205,7 @@ ble_ll_hci_vs_css_set_conn_slot(const uint8_t *cmdbuf, uint8_t cmdlen, } conn_handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(conn_handle); + connsm = ble_ll_conn_find_by_handle(conn_handle); if (!connsm) { return BLE_ERR_UNK_CONN_ID; } @@ -241,29 +226,105 @@ ble_ll_hci_vs_css_set_conn_slot(const uint8_t *cmdbuf, uint8_t cmdlen, } static int -ble_ll_hci_vs_css(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, - uint8_t *rspbuf, uint8_t *rsplen) +ble_ll_hci_vs_css_read_conn_slot(uint16_t ocf, const uint8_t *cmdbuf, + uint8_t cmdlen, uint8_t *rspbuf, + uint8_t *rsplen) { - const struct ble_hci_vs_css_cp *cmd = (const void *)cmdbuf; + const struct ble_hci_vs_css_read_conn_slot_cp *cmd = (const void *)cmdbuf; + struct ble_hci_vs_css_read_conn_slot_rp *rsp = (void *)rspbuf; + struct ble_ll_conn_sm *connsm; + uint16_t conn_handle; - if (cmdlen < sizeof(*cmd)) { + if (cmdlen != sizeof(*cmd)) { return BLE_ERR_INV_HCI_CMD_PARMS; } - *rsplen = 0; + if (!ble_ll_sched_css_is_enabled()) { + return BLE_ERR_CMD_DISALLOWED; + } - switch (cmd->opcode) { -#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) - case BLE_HCI_VS_CSS_OP_CONFIGURE: - return ble_ll_hci_vs_css_configure(cmdbuf, cmdlen, rspbuf, rsplen); + conn_handle = le16toh(cmd->conn_handle); + connsm = ble_ll_conn_find_by_handle(conn_handle); + if (!connsm) { + return BLE_ERR_UNK_CONN_ID; + } + + *rsplen = sizeof(*rsp); + rsp->conn_handle = cmd->conn_handle; + rsp->slot_idx = htole16(connsm->css_slot_idx); + + return BLE_ERR_SUCCESS; +} +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) +static int +ble_ll_hci_vs_set_data_len(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_vs_set_data_len_cp *cmd = (const void *) cmdbuf; + struct ble_hci_vs_set_data_len_rp *rsp = (void *) rspbuf; + struct ble_ll_conn_sm *connsm; + uint16_t conn_handle; + uint16_t tx_octets; + uint16_t tx_time; + uint16_t rx_octets; + uint16_t rx_time; + int rc; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + conn_handle = le16toh(cmd->conn_handle); + connsm = ble_ll_conn_find_by_handle(conn_handle); + if (!connsm) { + return BLE_ERR_UNK_CONN_ID; + } + + tx_octets = le16toh(cmd->tx_octets); + tx_time = le16toh(cmd->tx_time); + rx_octets = le16toh(cmd->rx_octets); + rx_time = le16toh(cmd->rx_time); + + if (!ble_ll_hci_check_dle(tx_octets, tx_time) || + !ble_ll_hci_check_dle(rx_octets, rx_time)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + rc = ble_ll_conn_set_data_len(connsm, tx_octets, tx_time, rx_octets, + rx_time); + if (rc) { + return rc; + } + + rsp->conn_handle = htole16(conn_handle); + *rsplen = sizeof(*rsp); + + return 0; +} #endif - case BLE_HCI_VS_CSS_OP_SET_NEXT_SLOT: - return ble_ll_hci_vs_css_set_next_slot(cmdbuf, cmdlen, rspbuf, rsplen); - case BLE_HCI_VS_CSS_OP_SET_CONN_SLOT: - return ble_ll_hci_vs_css_set_conn_slot(cmdbuf, cmdlen, rspbuf, rsplen); + +#if MYNEWT_VAL(BLE_FEM_ANTENNA) +static int +ble_ll_hci_vs_set_antenna(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_vs_set_antenna_cp *cmd = (const void *) cmdbuf; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; } - return BLE_ERR_INV_HCI_CMD_PARMS; + if (ble_ll_is_busy(0)) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (ble_fem_antenna(cmd->antenna)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + return BLE_ERR_SUCCESS; } #endif @@ -273,8 +334,25 @@ static struct ble_ll_hci_vs_cmd g_ble_ll_hci_vs_cmds[] = { BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_SET_TX_PWR, ble_ll_hci_vs_set_tx_power), #if MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) - BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_CSS, - ble_ll_hci_vs_css), +#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_CSS_CONFIGURE, + ble_ll_hci_vs_css_configure), +#endif + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_CSS_ENABLE, + ble_ll_hci_vs_css_enable), + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_CSS_SET_NEXT_SLOT, + ble_ll_hci_vs_css_set_next_slot), + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_CSS_SET_CONN_SLOT, + ble_ll_hci_vs_css_set_conn_slot), + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_CSS_READ_CONN_SLOT, + ble_ll_hci_vs_css_read_conn_slot), +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_SET_DATA_LEN, + ble_ll_hci_vs_set_data_len), +#endif +#if MYNEWT_VAL(BLE_FEM_ANTENNA) + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_SET_ANTENNA, ble_ll_hci_vs_set_antenna), #endif }; diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_iso_big.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_iso_big.c new file mode 100644 index 00000000..31bcd21f --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_iso_big.c @@ -0,0 +1,1376 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ble_ll_priv.h" + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + +/* XXX make those configurable */ +#define BIG_POOL_SIZE (10) +#define BIS_POOL_SIZE (10) + +#define BIG_HANDLE_INVALID (0xff) + +#define BIG_CONTROL_ACTIVE_CHAN_MAP 1 +#define BIG_CONTROL_ACTIVE_TERM 2 + +struct ble_ll_iso_big; + +struct ble_ll_iso_bis { + struct ble_ll_iso_big *big; + uint8_t num; + uint16_t conn_handle; + + uint32_t aa; + uint32_t crc_init; + uint16_t chan_id; + uint8_t iv[8]; + + struct { + uint16_t prn_sub_lu; + uint16_t remap_idx; + + uint8_t subevent_num; + uint8_t n; + uint8_t g; + } tx; + + struct ble_ll_isoal_mux mux; + uint16_t num_completed_pkt; + + STAILQ_ENTRY(ble_ll_iso_bis) bis_q_next; +}; + +STAILQ_HEAD(ble_ll_iso_bis_q, ble_ll_iso_bis); + +struct big_params { + uint8_t nse; /* 1-31 */ + uint8_t bn; /* 1-7, mandatory 1 */ + uint8_t irc; /* 1-15 */ + uint8_t pto; /* 0-15, mandatory 0 */ + uint32_t sdu_interval; + uint16_t iso_interval; + uint16_t max_transport_latency; + uint16_t max_sdu; + uint8_t max_pdu; + uint8_t phy; + uint8_t interleaved : 1; + uint8_t framed : 1; + uint8_t encrypted : 1; + uint8_t broadcast_code[16]; +}; + +struct ble_ll_iso_big { + struct ble_ll_adv_sm *advsm; + + uint8_t handle; + uint8_t num_bis; + uint16_t iso_interval; + uint16_t bis_spacing; + uint16_t sub_interval; + uint8_t phy; + uint8_t max_pdu; + uint16_t max_sdu; + uint16_t mpt; + uint8_t bn; /* 1-7, mandatory 1 */ + uint8_t pto; /* 0-15, mandatory 0 */ + uint8_t irc; /* 1-15 */ + uint8_t nse; /* 1-31 */ + uint8_t interleaved : 1; + uint8_t framed : 1; + uint8_t encrypted : 1; + uint8_t giv[8]; + uint8_t gskd[16]; + uint8_t gsk[16]; + uint8_t iv[8]; + uint8_t gc; + + uint32_t sdu_interval; + + uint32_t ctrl_aa; + uint16_t crc_init; + uint8_t chan_map[BLE_LL_CHAN_MAP_LEN]; + uint8_t chan_map_used; + + uint8_t biginfo[33]; + + uint64_t big_counter; + uint64_t bis_counter; + + uint32_t sync_delay; + uint32_t event_start; + uint8_t event_start_us; + struct ble_ll_sched_item sch; + struct ble_npl_event event_done; + + struct { + uint16_t subevents_rem; + struct ble_ll_iso_bis *bis; + } tx; + + struct ble_ll_iso_bis_q bis_q; + + uint8_t cstf : 1; + uint8_t cssn : 4; + uint8_t control_active : 3; + uint16_t control_instant; + + uint8_t chan_map_new_pending : 1; + uint8_t chan_map_new[BLE_LL_CHAN_MAP_LEN]; + + uint8_t term_pending : 1; + uint8_t term_reason : 7; +}; + +static struct ble_ll_iso_big big_pool[BIG_POOL_SIZE]; +static struct ble_ll_iso_bis bis_pool[BIS_POOL_SIZE]; +static uint8_t big_pool_free = BIG_POOL_SIZE; +static uint8_t bis_pool_free = BIS_POOL_SIZE; + +static struct ble_ll_iso_big *big_pending; +static struct ble_ll_iso_big *big_active; + +struct ble_ll_iso_bis * +ble_ll_iso_big_find_bis_by_handle(uint16_t conn_handle) +{ + struct ble_ll_iso_bis *bis; + uint8_t bis_idx; + + if (!BLE_LL_CONN_HANDLE_IS_BIS(conn_handle)) { + return NULL; + } + + bis_idx = BLE_LL_CONN_HANDLE_IDX(conn_handle); + + if (bis_idx >= BIS_POOL_SIZE) { + return NULL; + } + + bis = &bis_pool[bis_idx]; + if (!bis->big) { + return NULL; + } + + return bis; +} + +struct ble_ll_isoal_mux * +ble_ll_iso_big_find_mux_by_handle(uint16_t conn_handle) +{ + struct ble_ll_iso_bis *bis; + + bis = ble_ll_iso_big_find_bis_by_handle(conn_handle); + if (bis) { + return &bis->mux; + } + + return NULL; +} + +int +ble_ll_iso_big_last_tx_timestamp_get(struct ble_ll_iso_bis *bis, + uint16_t *packet_seq_num, uint32_t *timestamp) +{ + struct ble_ll_iso_big *big; + + big = bis->big; + + *packet_seq_num = big->bis_counter; + *timestamp = (uint64_t)big->event_start * 1000000 / 32768 + + big->event_start_us; + + return 0; +} + +static void +ble_ll_iso_big_biginfo_calc(struct ble_ll_iso_big *big, uint32_t seed_aa) +{ + uint8_t *buf; + + buf = big->biginfo; + + /* big_offset, big_offset_units, iso_interval, num_bis */ + put_le32(buf, (big->num_bis << 27) | (big->iso_interval << 15)); + buf += 4; + + /* nse, bn */ + *(uint8_t *)buf = (big->bn << 5) | (big->nse); + buf += 1; + + /* sub_interval, pto */ + put_le24(buf,(big->pto << 20) | (big->sub_interval)); + buf += 3; + + /* bis_spacing, irc */ + put_le24(buf, (big->irc << 20) | (big->bis_spacing)); + buf += 3; + + /* max_pdu, rfu */ + put_le16(buf, big->max_pdu); + buf += 2; + + /* seed_access_address */ + put_le32(buf, seed_aa); + buf += 4; + + /* sdu_interval, max_sdu */ + put_le32(buf, (big->max_sdu << 20) | (big->sdu_interval)); + buf += 4; + + /* base_crc_init */ + put_le16(buf, big->crc_init); + buf += 2; + + /* chm, phy */ + memcpy(buf, big->chan_map, 5); + buf[4] |= (big->phy - 1) << 5; + buf += 5; + + /* bis_payload_cnt, framing */ + memset(buf, 0x00, 5); +} + +int +ble_ll_iso_big_biginfo_copy(struct ble_ll_iso_big *big, uint8_t *dptr, + uint32_t base_ticks, uint8_t base_rem_us) +{ + uint8_t *dptr_start; + uint64_t counter; + uint32_t offset_us; + uint32_t offset; + uint32_t d_ticks; + uint8_t d_rem_us; + + dptr_start = dptr; + counter = big->bis_counter; + + d_ticks = big->event_start - base_ticks; + d_rem_us = big->event_start_us; + ble_ll_tmr_sub(&d_ticks, &d_rem_us, base_rem_us); + + offset_us = ble_ll_tmr_t2u(d_ticks) + d_rem_us; + if (offset_us <= 600) { + counter += big->bn; + offset_us += big->iso_interval * 1250; + } + if (offset_us >= 491460) { + offset = 0x4000 | (offset_us / 300); + } else { + offset = offset_us / 30; + } + + *dptr++ = ble_ll_iso_big_biginfo_len(big) - 1; + *dptr++ = 0x2c; + + memcpy(dptr, big->biginfo, 33); + put_le32(dptr, get_le32(dptr) | (offset & 0x7fff)); + dptr += 28; + + *dptr++ = counter & 0xff; + *dptr++ = (counter >> 8) & 0xff; + *dptr++ = (counter >> 16) & 0xff; + *dptr++ = (counter >> 24) & 0xff; + *dptr++ = (counter >> 32) & 0xff; + + if (big->encrypted) { + memcpy(dptr, big->giv, 8); + dptr += 8; + memcpy(dptr, big->gskd, 16); + dptr += 16; + } + + return dptr - dptr_start; +} + +int +ble_ll_iso_big_biginfo_len(struct ble_ll_iso_big *big) +{ + return 2 + sizeof(big->biginfo) + + (big->encrypted ? sizeof(big->giv) + sizeof(big->gskd) : 0); +} + +static void +ble_ll_iso_big_free(struct ble_ll_iso_big *big) +{ + struct ble_ll_iso_bis *bis; + + if (big->handle == BIG_HANDLE_INVALID) { + return; + } + + big->handle = BIG_HANDLE_INVALID; + ble_ll_sched_rmv_elem(&big->sch); + ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &big->event_done); + + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + ble_ll_isoal_mux_free(&bis->mux); + bis->big = NULL; + bis_pool_free++; + } + + big_pool_free++; +} + +static void +ble_ll_iso_big_terminate_complete(struct ble_ll_iso_big *big) +{ + struct ble_hci_ev *hci_ev; + struct ble_hci_ev_le_subev_terminate_big_complete *evt; + uint8_t big_handle; + uint8_t reason; + + big_handle = big->handle; + reason = big->term_reason; + + ble_ll_iso_big_free(big); + + hci_ev = ble_transport_alloc_evt(0); + if (!hci_ev) { + BLE_LL_ASSERT(0); + return; + } + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*evt); + + evt = (void *)hci_ev->data; + memset(evt, 0, hci_ev->length); + evt->subev_code = BLE_HCI_LE_SUBEV_TERMINATE_BIG_COMPLETE; + evt->big_handle = big_handle; + evt->reason = reason; + + ble_transport_to_hs_evt(hci_ev); +} + +static void +ble_ll_iso_big_chan_map_update_complete(struct ble_ll_iso_big *big) +{ + memcpy(big->chan_map, big->chan_map_new, BLE_LL_CHAN_MAP_LEN); + big->chan_map_used = ble_ll_utils_chan_map_used_get(big->chan_map); +} + +static void +ble_ll_iso_big_update_event_start(struct ble_ll_iso_big *big) +{ + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + big->event_start = big->sch.start_time + g_ble_ll_sched_offset_ticks; + big->event_start_us = big->sch.remainder; + OS_EXIT_CRITICAL(sr); +} + +static void +ble_ll_iso_big_event_done(struct ble_ll_iso_big *big) +{ + struct ble_ll_iso_bis *bis; + struct ble_hci_ev *hci_ev; + struct ble_hci_ev_num_comp_pkts *hci_ev_ncp; + int num_completed_pkt; + int rc; + + ble_ll_rfmgmt_release(); + + if (big->big_counter == 0) { + BLE_LL_ASSERT(big == big_pending); + ble_ll_iso_big_hci_evt_complete(); + } + + hci_ev = ble_transport_alloc_evt(1); + if (hci_ev) { + hci_ev->opcode = BLE_HCI_EVCODE_NUM_COMP_PKTS; + hci_ev->length = sizeof(*hci_ev_ncp); + hci_ev_ncp = (void *)hci_ev->data; + hci_ev_ncp->count = 0; + } + + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + num_completed_pkt = ble_ll_isoal_mux_event_done(&bis->mux); + if (hci_ev && num_completed_pkt) { + hci_ev_ncp->completed[hci_ev_ncp->count].handle = + htole16(bis->conn_handle); + hci_ev_ncp->completed[hci_ev_ncp->count].packets = + htole16(num_completed_pkt + bis->num_completed_pkt); + bis->num_completed_pkt = 0; + hci_ev_ncp->count++; + } else { + bis->num_completed_pkt += num_completed_pkt; + } + } + + if (hci_ev) { + if (hci_ev_ncp->count) { + hci_ev->length = sizeof(*hci_ev_ncp) + + hci_ev_ncp->count * sizeof(hci_ev_ncp->completed[0]); + ble_transport_to_hs_evt(hci_ev); + } else { + ble_transport_free(hci_ev); + } + } + + big->sch.start_time = big->event_start; + big->sch.remainder = big->event_start_us; + + do { + big->big_counter++; + big->bis_counter += big->bn; + + if (big->control_active && + (big->control_instant == (uint16_t)big->big_counter)) { + switch (big->control_active) { + case BIG_CONTROL_ACTIVE_TERM: + ble_ll_iso_big_terminate_complete(big); + return; + case BIG_CONTROL_ACTIVE_CHAN_MAP: + ble_ll_iso_big_chan_map_update_complete(big); + break; + default: + BLE_LL_ASSERT(0); + break; + } + + big->control_active = 0; + big->cstf = 0; + } + + if (!big->control_active) { + if (big->term_pending) { + big->term_pending = 0; + big->control_active = BIG_CONTROL_ACTIVE_TERM; + } else if (big->chan_map_new_pending) { + memcpy(big->chan_map_new, g_ble_ll_data.chan_map, + BLE_LL_CHAN_MAP_LEN); + big->chan_map_new_pending = 0; + big->control_active = BIG_CONTROL_ACTIVE_CHAN_MAP; + } + + if (big->control_active) { + big->control_instant = big->big_counter + 6; + big->cstf = 1; + big->cssn += 1; + } + } + + /* XXX precalculate some data here? */ + + ble_ll_tmr_add(&big->sch.start_time, &big->sch.remainder, + big->iso_interval * 1250); + big->sch.end_time = big->sch.start_time + + ble_ll_tmr_u2t_up(big->sync_delay) + 1; + big->sch.start_time -= g_ble_ll_sched_offset_ticks; + + if (big->control_active) { + /* XXX fixme */ + big->sch.end_time += 10; + } + + /* XXX this should always succeed since we preempt anything for now */ + rc = ble_ll_sched_iso_big(&big->sch, 0); + assert(rc == 0); + } while (rc < 0); + + ble_ll_iso_big_update_event_start(big); +} + +static void +ble_ll_iso_big_event_done_ev(struct ble_npl_event *ev) +{ + struct ble_ll_iso_big *big; + + big = ble_npl_event_get_arg(ev); + + ble_ll_iso_big_event_done(big); +} + +static void +ble_ll_iso_big_event_done_to_ll(struct ble_ll_iso_big *big) +{ + big_active = NULL; + ble_ll_state_set(BLE_LL_STATE_STANDBY); + ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &big->event_done); +} + +static uint8_t +ble_ll_iso_big_control_pdu_cb(uint8_t *dptr, void *arg, uint8_t *hdr_byte) +{ + struct ble_ll_iso_big *big; + uint8_t len; + + big = arg; + + /* CSTF shall be set to 0 in Control PDU */ + *hdr_byte = 3 | (big->cssn << 2); + + BLE_LL_ASSERT(big->cstf); + BLE_LL_ASSERT(big->control_active); + + if (big->encrypted) { + ble_phy_encrypt_header_mask_set(BLE_LL_PDU_HEADERMASK_BIS); + ble_phy_encrypt_iv_set(big->iv); + ble_phy_encrypt_counter_set(big->bis_counter, 1); + } + + switch (big->control_active) { + case BIG_CONTROL_ACTIVE_CHAN_MAP: + dptr[0] = 0x00; /* BIG_CHANNEL_MAP_IND */ + memcpy(&dptr[1], big->chan_map_new, BLE_LL_CHAN_MAP_LEN); + put_le16(&dptr[6], big->control_instant); + len = 8; + break; + case BIG_CONTROL_ACTIVE_TERM: + dptr[0] = 0x01; /* BIG_TERMINATE_IND */ + dptr[1] = big->term_reason; + put_le16(&dptr[2], big->control_instant); + len = 4; + break; + default: + BLE_LL_ASSERT(0); + len = 0; + break; + } + + return len; +} + +static void +ble_ll_iso_big_control_txend_cb(void *arg) +{ + struct ble_ll_iso_big *big; + + big = arg; + + ble_ll_iso_big_event_done_to_ll(big); +} + +static int +ble_ll_iso_big_control_tx(struct ble_ll_iso_big *big) +{ + uint16_t chan_idx; + uint16_t chan_id; + uint16_t foo, bar; + int rc; + + chan_id = big->ctrl_aa ^ (big->ctrl_aa >> 16); + + chan_idx = ble_ll_utils_dci_iso_event(big->big_counter, chan_id, + &foo, + big->chan_map_used, + big->chan_map, + &bar); + + ble_phy_set_txend_cb(ble_ll_iso_big_control_txend_cb, big); + ble_phy_setchan(chan_idx, big->ctrl_aa, big->crc_init << 8); + + rc = ble_phy_tx(ble_ll_iso_big_control_pdu_cb, big, BLE_PHY_TRANSITION_NONE); + + return rc; +} + +static uint8_t +ble_ll_iso_big_subevent_pdu_cb(uint8_t *dptr, void *arg, uint8_t *hdr_byte) +{ + struct ble_ll_iso_big *big; + struct ble_ll_iso_bis *bis; + int idx; + uint8_t llid; + uint8_t pdu_len; + + big = arg; + bis = big->tx.bis; + + /* Core 5.3, Vol 6, Part B, 4.4.6.6 */ + if (bis->tx.g < big->irc) { + idx = bis->tx.n; + } else { + idx = big->bn * big->pto * (bis->tx.g - big->irc + 1) + bis->tx.n; + } + + if (big->encrypted) { + ble_phy_encrypt_header_mask_set(BLE_LL_PDU_HEADERMASK_BIS); + ble_phy_encrypt_iv_set(bis->iv); + ble_phy_encrypt_counter_set(big->bis_counter + idx, 1); + } + +#if 1 + pdu_len = ble_ll_isoal_mux_unframed_get(&bis->mux, idx, &llid, dptr); +#else + llid = 0; + pdu_len = big->max_pdu; + /* XXX dummy data for testing */ + memset(dptr, bis->num | (bis->num << 4), pdu_len); + put_be32(dptr, big->big_counter); + put_be32(&dptr[4], big->bis_counter + idx); + dptr[8] = bis->tx.subevent_num; + dptr[9] = bis->tx.g; + dptr[10] = bis->tx.n; + if (bis->tx.g == 0) { + dptr[11] = 'B'; + } else if (bis->tx.g < big->irc) { + dptr[11] = 'R'; + } else { + dptr[11] = 'P'; + } + dptr[12] = 0xff; +#endif + + *hdr_byte = llid | (big->cssn << 2) | (big->cstf << 5); + + return pdu_len; +} + +static int +ble_ll_iso_big_subevent_tx(struct ble_ll_iso_big *big) +{ + struct ble_ll_iso_bis *bis; + uint16_t chan_idx; + int to_tx; + int rc; + + bis = big->tx.bis; + + if (bis->tx.subevent_num == 1) { + chan_idx = ble_ll_utils_dci_iso_event(big->big_counter, bis->chan_id, + &bis->tx.prn_sub_lu, + big->chan_map_used, + big->chan_map, + &bis->tx.remap_idx); + } else { + chan_idx = ble_ll_utils_dci_iso_subevent(bis->chan_id, + &bis->tx.prn_sub_lu, + big->chan_map_used, + big->chan_map, + &bis->tx.remap_idx); + } + + ble_phy_setchan(chan_idx, bis->aa, bis->crc_init); + + to_tx = (big->tx.subevents_rem > 1) || big->cstf; + + rc = ble_phy_tx(ble_ll_iso_big_subevent_pdu_cb, big, + to_tx ? BLE_PHY_TRANSITION_TX_TX + : BLE_PHY_TRANSITION_NONE); + return rc; +} + +static void +ble_ll_iso_big_subevent_txend_cb(void *arg) +{ + struct ble_ll_iso_big *big; + struct ble_ll_iso_bis *bis; + int rc; + + big = arg; + bis = big->tx.bis; + + bis->tx.n++; + if (bis->tx.n == big->bn) { + bis->tx.n = 0; + bis->tx.g++; + } + + /* Switch to next BIS if interleaved or all subevents for current BIS were + * transmitted. + */ + if (big->interleaved || (bis->tx.subevent_num == big->nse)) { + bis = STAILQ_NEXT(bis, bis_q_next); + if (!bis) { + bis = STAILQ_FIRST(&big->bis_q); + } + big->tx.bis = bis; + } + + bis->tx.subevent_num++; + big->tx.subevents_rem--; + + if (big->tx.subevents_rem > 0) { + rc = ble_ll_iso_big_subevent_tx(big); + if (rc) { + ble_phy_disable(); + ble_ll_iso_big_event_done_to_ll(big); + } + return; + } + + if (big->cstf) { + rc = ble_ll_iso_big_control_tx(big); + if (rc) { + ble_phy_disable(); + ble_ll_iso_big_event_done_to_ll(big); + } + return; + } + + ble_ll_iso_big_event_done_to_ll(big); +} + +static int +ble_ll_iso_big_event_sched_cb(struct ble_ll_sched_item *sch) +{ + struct ble_ll_iso_big *big; + struct ble_ll_iso_bis *bis; +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) + uint8_t phy_mode; +#endif + int rc; + + big = sch->cb_arg; + + ble_ll_state_set(BLE_LL_STATE_BIG); + big_active = big; + + ble_ll_whitelist_disable(); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + ble_phy_resolv_list_disable(); +#endif +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) + phy_mode = ble_ll_phy_to_phy_mode(big->phy, 0); + ble_phy_mode_set(phy_mode, phy_mode); +#endif + + BLE_LL_ASSERT(!big->framed); + + /* XXX calculate this in advance at the end of previous event? */ + big->tx.subevents_rem = big->num_bis * big->nse; + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + ble_ll_isoal_mux_event_start(&bis->mux, (uint64_t)big->event_start * + 1000000 / 32768 + + big->event_start_us); + + bis->tx.subevent_num = 0; + bis->tx.n = 0; + bis->tx.g = 0; + } + + /* Select 1st BIS for transmission */ + big->tx.bis = STAILQ_FIRST(&big->bis_q); + big->tx.bis->tx.subevent_num = 1; + + if (big->interleaved) { + ble_phy_tifs_txtx_set(big->bis_spacing, 0); + } else { + ble_phy_tifs_txtx_set(big->sub_interval, 0); + } + + rc = ble_phy_tx_set_start_time(sch->start_time + g_ble_ll_sched_offset_ticks, + sch->remainder); + if (rc) { + ble_phy_disable(); + ble_ll_iso_big_event_done_to_ll(big); + return BLE_LL_SCHED_STATE_DONE; + } + + ble_phy_set_txend_cb(ble_ll_iso_big_subevent_txend_cb, big); + + if (big->encrypted) { + ble_phy_encrypt_enable(big->gsk); + } else { + ble_phy_encrypt_disable(); + } + + rc = ble_ll_iso_big_subevent_tx(big); + if (rc) { + ble_phy_disable(); + ble_ll_iso_big_event_done_to_ll(big); + return BLE_LL_SCHED_STATE_DONE; + } + + return BLE_LL_SCHED_STATE_RUNNING; +} + +static void +ble_ll_iso_big_calculate_gsk(struct ble_ll_iso_big *big, + const uint8_t *broadcast_code) +{ + static const uint8_t big1[16] = {0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x42, 0x49, 0x47, 0x31}; + static const uint8_t big2[4] = {0x42, 0x49, 0x47, 0x32}; + static const uint8_t big3[4] = {0x42, 0x49, 0x47, 0x33}; + uint8_t code[16]; + uint8_t igltk[16]; + uint8_t gltk[16]; + + /* broadcast code is lsb-first in hci, we need msb-first */ + swap_buf(code, broadcast_code, 16); + + ble_ll_rand_data_get(big->gskd, sizeof(big->gskd)); + + ble_ll_crypto_h7(big1, code, igltk); + ble_ll_crypto_h6(igltk, big2, gltk); + ble_ll_crypto_h8(gltk, big->gskd, big3, big->gsk); + + /* need gskd for biginfo, i.e. lsb-first */ + swap_in_place(big->gskd, 16); +} + +static void +ble_ll_iso_big_calculate_iv(struct ble_ll_iso_big *big) +{ + struct ble_ll_iso_bis *bis; + uint8_t *aa; + + ble_ll_rand_data_get(big->giv, sizeof(big->giv)); + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + memcpy(&bis->iv[4], &big->giv[4], 4); + aa = (uint8_t *)&bis->aa; + bis->iv[0] = big->giv[0] ^ aa[0]; + bis->iv[1] = big->giv[1] ^ aa[1]; + bis->iv[2] = big->giv[2] ^ aa[2]; + bis->iv[3] = big->giv[3] ^ aa[3]; + } + + memcpy(&big->iv[4], &big->giv[4], 4); + aa = (uint8_t *)&big->ctrl_aa; + big->iv[0] = big->giv[0] ^ aa[0]; + big->iv[1] = big->giv[1] ^ aa[1]; + big->iv[2] = big->giv[2] ^ aa[2]; + big->iv[3] = big->giv[3] ^ aa[3]; +} + +static int +ble_ll_iso_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, + struct big_params *bp) +{ + struct ble_ll_iso_big *big = NULL; + struct ble_ll_iso_bis *bis; + struct ble_ll_adv_sm *advsm; + uint32_t seed_aa; + uint8_t pte; + uint8_t gc; + uint8_t idx; + int rc; + + if ((big_pool_free == 0) || (bis_pool_free < num_bis)) { + return -ENOMEM; + } + + /* Find free BIG */ + for (idx = 0; idx < BIG_POOL_SIZE; idx++) { + if (!big && big_pool[idx].handle == BIG_HANDLE_INVALID) { + big = &big_pool[idx]; + } + if (big_pool[idx].handle == big_handle) { + return -EALREADY; + } + } + + BLE_LL_ASSERT(big); + + advsm = ble_ll_adv_sync_get(adv_handle); + if (!advsm) { + return -ENOENT; + } + + if (ble_ll_adv_sync_big_add(advsm, big) < 0) { + return -ENOENT; + } + + big->advsm = advsm; + big->handle = big_handle; + + big->crc_init = ble_ll_rand(); + memcpy(big->chan_map, g_ble_ll_data.chan_map, BLE_LL_CHAN_MAP_LEN); + big->chan_map_used = g_ble_ll_data.chan_map_used; + + big->big_counter = 0; + big->bis_counter = 0; + + big->cstf = 0; + big->cssn = 0; + big->control_active = 0; + big->control_instant = 0; + big->chan_map_new_pending = 0; + big->term_pending = 0; + big->term_reason = 0; + + /* Calculate number of additional events for pre-transmissions */ + /* Core 5.3, Vol 6, Part B, 4.4.6.6 */ + gc = bp->nse / bp->bn; + if (bp->irc == gc) { + pte = 0; + } else { + pte = bp->pto * (gc - bp->irc); + } + + /* Allocate BISes */ + STAILQ_INIT(&big->bis_q); + big->num_bis = 0; + for (idx = 0; (big->num_bis < num_bis) && (idx < BIS_POOL_SIZE); idx++) { + bis = &bis_pool[idx]; + if (bis->big) { + continue; + } + + big->num_bis++; + STAILQ_INSERT_TAIL(&big->bis_q, bis, bis_q_next); + + bis->big = big; + bis->num = big->num_bis; + bis->crc_init = (big->crc_init << 8) | (big->num_bis); + + BLE_LL_ASSERT(!big->framed); + + ble_ll_isoal_mux_init(&bis->mux, bp->max_pdu, bp->iso_interval * 1250, + bp->sdu_interval, bp->bn, pte); + } + + big_pool_free--; + bis_pool_free -= num_bis; + + /* Calculate AA for each BIS and BIG Control. We have to repeat this process + * until all AAs are valid. + */ + do { + rc = 0; + + seed_aa = ble_ll_utils_calc_seed_aa(); + big->ctrl_aa = ble_ll_utils_calc_big_aa(seed_aa, 0); + + if (!ble_ll_utils_verify_aa(big->ctrl_aa)) { + continue; + } + + rc = 1; + + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + bis->aa = ble_ll_utils_calc_big_aa(seed_aa, bis->num); + if (!ble_ll_utils_verify_aa(bis->aa)) { + rc = 0; + break; + } + bis->chan_id = bis->aa ^ (bis->aa >> 16); + } + } while (rc == 0); + + big->bn = bp->bn; + big->pto = bp->pto; + big->irc = bp->irc; + big->nse = bp->nse; + big->interleaved = bp->interleaved; + big->framed = bp->framed; + big->encrypted = bp->encrypted; + big->sdu_interval = bp->sdu_interval; + big->iso_interval = bp->iso_interval; + big->phy = bp->phy; + big->max_pdu = bp->max_pdu; + big->max_sdu = bp->max_sdu; + /* Core 5.3, Vol 6, Part B, 4.4.6.3 */ + big->mpt = ble_ll_pdu_us(big->max_pdu + (big->encrypted ? 4 : 0), + ble_ll_phy_to_phy_mode(big->phy, + BLE_HCI_LE_PHY_CODED_S8_PREF)); + + /* Core 5.3, Vol 6, Part B, 4.4.6.4 */ + if (big->interleaved) { + big->bis_spacing = big->mpt + BLE_LL_MSS; + big->sub_interval = big->num_bis * big->bis_spacing; + } else { + big->sub_interval = big->mpt + BLE_LL_MSS; + big->bis_spacing = big->nse * big->sub_interval; + } + /* Core 5.3, Vol 6, Part B, 4.4.6.5 */ + big->sync_delay = (big->num_bis - 1) * big->bis_spacing + + (big->nse - 1) * big->sub_interval + big->mpt; + + /* Reset PTO if pre-transmissions won't be used */ + big->gc = gc; + if (big->irc == gc) { + big->pto = 0; + } + + if (big->encrypted) { + ble_ll_iso_big_calculate_gsk(big, bp->broadcast_code); + ble_ll_iso_big_calculate_iv(big); + } + + ble_ll_iso_big_biginfo_calc(big, seed_aa); + + /* For now we will schedule complete event as single item. This allows for + * shortest possible subevent space (150us) but can create sequence of long + * events that will block scheduler from other activities. To mitigate this + * we use preempt_none strategy so scheudling is opportunistic and depending + * on other activities this may create gaps in stream. + * Eventually we should allow for some more robust scheduling, e.g. per-BIS + * for sequential arrangement or per-subevent for interleaved, or event + * per-BIS-subevent but this requires larger subevent space since 150us is + * not enough for some phys to run scheduler item. + */ + + /* Schedule 1st event a bit in future */ + /* FIXME schedule 6ms in the future to avoid conflict with periodic + * advertising when both are started at the same time; we should + * select this value in some smart way later... + */ + big->sch.start_time = ble_ll_tmr_get() + ble_ll_tmr_u2t(6000); + big->sch.remainder = 0; + big->sch.end_time = big->sch.start_time + + ble_ll_tmr_u2t_up(big->sync_delay) + 1; + big->sch.start_time -= g_ble_ll_sched_offset_ticks; + + rc = ble_ll_sched_iso_big(&big->sch, 1); + if (rc < 0) { + ble_ll_iso_big_free(big); + return -EFAULT; + } + + ble_ll_iso_big_update_event_start(big); + + big_pending = big; + + return 0; +} + +static int +ble_ll_iso_big_terminate(uint8_t big_handle, uint8_t reason) +{ + struct ble_ll_iso_big *big = NULL; + unsigned idx; + + for (idx = 0; idx < BIG_POOL_SIZE; idx++) { + if (big_pool[idx].handle == big_handle) { + big = &big_pool[idx]; + break; + } + } + + if (!big) { + return -ENOENT; + } + + /* Not sure if this is correct, but let's remove BIGInfo now since there's + * no point for peer to syncing to a BIG that will be disconnected soon. + */ + ble_ll_adv_sync_big_remove(big->advsm, big); + + big->term_reason = reason; + big->term_pending = 1; + + return 0; +} + +void +ble_ll_iso_big_chan_map_update(void) +{ + struct ble_ll_iso_big *big; + int idx; + + for (idx = 0; idx < BIG_POOL_SIZE; idx++) { + big = &big_pool[idx]; + + if (big->handle == BIG_HANDLE_INVALID) { + continue; + } + + big->chan_map_new_pending = 1; + } +} + +void +ble_ll_iso_big_halt(void) +{ + if (big_active) { + ble_ll_iso_big_event_done_to_ll(big_active); + } +} + +void +ble_ll_iso_big_hci_evt_complete(void) +{ + struct ble_ll_iso_big *big; + struct ble_ll_iso_bis *bis; + struct ble_hci_ev_le_subev_create_big_complete *evt; + struct ble_hci_ev *hci_ev; + uint8_t idx; + + big = big_pending; + big_pending = NULL; + + if (!big) { + return; + } + + hci_ev = ble_transport_alloc_evt(0); + if (!hci_ev) { + BLE_LL_ASSERT(0); + /* XXX should we retry later? */ + return; + } + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*evt) + big->num_bis * sizeof(evt->conn_handle[0]); + + evt = (void *)hci_ev->data; + memset(evt, 0, hci_ev->length); + evt->subev_code = BLE_HCI_LE_SUBEV_CREATE_BIG_COMPLETE; + evt->status = 0x00; + + evt->big_handle = big->handle; + put_le24(evt->big_sync_delay, big->sync_delay); + /* Core 5.3, Vol 6, Part G, 3.2.2 */ + put_le24(evt->transport_latency_big, + big->sync_delay + + (big->pto * (big->nse / big->bn - big->irc) + 1) * big->iso_interval * 1250 - + big->sdu_interval); + evt->phy = big->phy; + evt->nse = big->nse; + evt->bn = big->bn; + evt->pto = big->pto; + evt->irc = big->irc; + evt->max_pdu = htole16(big->max_pdu); + evt->iso_interval = htole16(big->iso_interval); + evt->num_bis = big->num_bis; + + idx = 0; + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + evt->conn_handle[idx] = htole16(bis->conn_handle); + idx++; + } + + ble_ll_hci_event_send(hci_ev); +} + +int +ble_ll_iso_big_hci_create(const uint8_t *cmdbuf, uint8_t len) +{ + const struct ble_hci_le_create_big_cp *cmd = (void *)cmdbuf; + struct big_params bp; + int rc; + + if (len != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!IN_RANGE(cmd->big_handle, 0x00, 0xef) || + !IN_RANGE(cmd->adv_handle, 0x00, 0xef) || + !IN_RANGE(cmd->num_bis, 0x01, 0x1f) || + !IN_RANGE(get_le24(cmd->sdu_interval), 0x0000ff, 0x0fffff) || + !IN_RANGE(le16toh(cmd->max_sdu), 0x0001, 0x0fff) || + !IN_RANGE(le16toh(cmd->max_transport_latency), 0x0005, 0x0fa0) || + !IN_RANGE(cmd->rtn, 0x00, 0x1e) || + (cmd->packing > 1) || (cmd->framing > 1) || (cmd->encryption) > 1) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + bp.sdu_interval = get_le24(cmd->sdu_interval); + bp.max_transport_latency = le16toh(cmd->max_transport_latency); + bp.max_sdu = le16toh(cmd->max_sdu); + if (cmd->phy & BLE_HCI_LE_PHY_2M_PREF_MASK) { + bp.phy = BLE_PHY_2M; + } else if (cmd->phy & BLE_HCI_LE_PHY_1M_PREF_MASK) { + bp.phy = BLE_PHY_1M; + } else { + bp.phy = BLE_PHY_CODED; + } + bp.interleaved = cmd->packing; + bp.framed = cmd->framing; + bp.encrypted = cmd->encryption; + memcpy(bp.broadcast_code, cmd->broadcast_code, 16); + + bp.nse = 1; + bp.bn = 1; + bp.irc = 1; + bp.pto = 0; + bp.iso_interval = bp.sdu_interval / 1250; + bp.max_pdu = bp.max_sdu; + + rc = ble_ll_iso_big_create(cmd->big_handle, cmd->adv_handle, cmd->num_bis, + &bp); + switch (rc) { + case 0: + break; + case -EINVAL: + return BLE_ERR_INV_HCI_CMD_PARMS; + case -ENOMEM: + return BLE_ERR_CONN_REJ_RESOURCES; + case -ENOENT: + return BLE_ERR_UNK_ADV_INDENT; + default: + return BLE_ERR_UNSPECIFIED; + } + + return 0; +} + +int +ble_ll_iso_big_hci_create_test(const uint8_t *cmdbuf, uint8_t len) +{ + const struct ble_hci_le_create_big_test_cp *cmd = (void *)cmdbuf; + struct big_params bp; + uint32_t iso_interval_us; + int rc; + + if (len != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!IN_RANGE(cmd->big_handle, 0x00, 0xef) || + !IN_RANGE(cmd->adv_handle, 0x00, 0xef) || + !IN_RANGE(cmd->num_bis, 0x01, 0x1f) || + !IN_RANGE(get_le24(cmd->sdu_interval), 0x0000ff, 0x0fffff) || + !IN_RANGE(le16toh(cmd->iso_interval), 0x0004, 0x0c80) || + !IN_RANGE(cmd->nse, 0x01, 0x1f) || + !IN_RANGE(le16toh(cmd->max_sdu), 0x0001, 0x0fff) || + !IN_RANGE(le16toh(cmd->max_pdu), 0x0001, 0x00fb) || + /* phy */ + (cmd->packing > 1) || (cmd->framing > 1) || + !IN_RANGE(cmd->bn, 0x01, 0x07) || + !IN_RANGE(cmd->irc, 0x01, 0x0f) || + !IN_RANGE(cmd->pto, 0x00, 0x0f) || + (cmd->encryption) > 1) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + bp.nse = cmd->nse; + bp.bn = cmd->bn; + bp.irc = cmd->irc; + bp.pto = cmd->pto; + bp.sdu_interval = get_le24(cmd->sdu_interval); + bp.iso_interval = le16toh(cmd->iso_interval); + bp.max_sdu = le16toh(cmd->max_sdu); + bp.max_pdu = le16toh(cmd->max_pdu); + /* TODO verify phy */ + if (cmd->phy & BLE_HCI_LE_PHY_2M_PREF_MASK) { + bp.phy = BLE_PHY_2M; + } else if (cmd->phy & BLE_HCI_LE_PHY_1M_PREF_MASK) { + bp.phy = BLE_PHY_1M; + } else { + bp.phy = BLE_PHY_CODED; + } + bp.interleaved = cmd->packing; + bp.framed = cmd->framing; + bp.encrypted = cmd->encryption; + memcpy(bp.broadcast_code, cmd->broadcast_code, 16); + + if (bp.nse % bp.bn) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + iso_interval_us = bp.iso_interval * 1250; + + if (!bp.framed) { + /* sdu_interval shall be an integer multiple of iso_interval */ + if (iso_interval_us % bp.sdu_interval) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* bn shall be an integer multiple of (iso_interval / sdu_interval) */ + if (bp.bn % (iso_interval_us / bp.sdu_interval)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } + + rc = ble_ll_iso_big_create(cmd->big_handle, cmd->adv_handle, cmd->num_bis, + &bp); + switch (rc) { + case 0: + break; + case -EINVAL: + return BLE_ERR_INV_HCI_CMD_PARMS; + case -ENOMEM: + return BLE_ERR_CONN_REJ_RESOURCES; + case -ENOENT: + return BLE_ERR_UNK_ADV_INDENT; + default: + return BLE_ERR_UNSPECIFIED; + } + + return 0; +} + +int +ble_ll_iso_big_hci_terminate(const uint8_t *cmdbuf, uint8_t len) +{ + const struct ble_hci_le_terminate_big_cp *cmd = (void *)cmdbuf; + int err; + + err = ble_ll_iso_big_terminate(cmd->big_handle, cmd->reason); + switch (err) { + case 0: + break; + case -ENOENT: + return BLE_ERR_UNK_ADV_INDENT; + default: + return BLE_ERR_UNSPECIFIED; + } + + return 0; +} + +void +ble_ll_iso_big_init(void) +{ + struct ble_ll_iso_big *big; + struct ble_ll_iso_bis *bis; + uint8_t idx; + + memset(big_pool, 0, sizeof(big_pool)); + memset(bis_pool, 0, sizeof(bis_pool)); + + for (idx = 0; idx < BIG_POOL_SIZE; idx++) { + big = &big_pool[idx]; + + big->handle = BIG_HANDLE_INVALID; + + big->sch.sched_type = BLE_LL_SCHED_TYPE_BIG; + big->sch.sched_cb = ble_ll_iso_big_event_sched_cb; + big->sch.cb_arg = big; + + ble_npl_event_init(&big->event_done, ble_ll_iso_big_event_done_ev, big); + } + + for (idx = 0; idx < BIS_POOL_SIZE; idx++) { + bis = &bis_pool[idx]; + bis->conn_handle = BLE_LL_CONN_HANDLE(BLE_LL_CONN_HANDLE_TYPE_BIS, idx); + } + + big_pool_free = ARRAY_SIZE(big_pool); + bis_pool_free = ARRAY_SIZE(bis_pool); +} + +void +ble_ll_iso_big_reset(void) +{ + struct ble_ll_iso_big *big; + int idx; + + for (idx = 0; idx < BIG_POOL_SIZE; idx++) { + big = &big_pool[idx]; + ble_ll_iso_big_free(big); + } + + ble_ll_iso_big_init(); +} + +#endif /* BLE_LL_ISO_BROADCASTER */ diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_isoal.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_isoal.c new file mode 100644 index 00000000..b0288443 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_isoal.c @@ -0,0 +1,403 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#if MYNEWT_VAL(BLE_LL_ISO) + +STAILQ_HEAD(ble_ll_iso_tx_q, os_mbuf_pkthdr); + +static struct ble_npl_event ll_isoal_tx_pkt_in; +static struct ble_ll_iso_tx_q ll_isoal_tx_q; + +void +ble_ll_isoal_mux_init(struct ble_ll_isoal_mux *mux, uint8_t max_pdu, + uint32_t iso_interval_us, uint32_t sdu_interval_us, + uint8_t bn, uint8_t pte) +{ + memset(mux, 0, sizeof(*mux)); + + mux->max_pdu = max_pdu; + /* Core 5.3, Vol 6, Part G, 2.1 */ + mux->sdu_per_interval = iso_interval_us / sdu_interval_us; + mux->pdu_per_sdu = bn / mux->sdu_per_interval; + + mux->sdu_per_event = (1 + pte) * mux->sdu_per_interval; + + STAILQ_INIT(&mux->sdu_q); +} + +void +ble_ll_isoal_mux_free(struct ble_ll_isoal_mux *mux) +{ + struct os_mbuf_pkthdr *pkthdr; + struct os_mbuf *om; + struct os_mbuf *om_next; + + pkthdr = STAILQ_FIRST(&mux->sdu_q); + while (pkthdr) { + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + + while (om) { + om_next = SLIST_NEXT(om, om_next); + os_mbuf_free(om); + om = om_next; + } + + STAILQ_REMOVE_HEAD(&mux->sdu_q, omp_next); + pkthdr = STAILQ_FIRST(&mux->sdu_q); + } + + STAILQ_INIT(&mux->sdu_q); +} + +static void +ble_ll_isoal_mux_tx_pkt_in(struct ble_ll_isoal_mux *mux, struct os_mbuf *om, + uint8_t pb, uint32_t timestamp) +{ + struct os_mbuf_pkthdr *pkthdr; + struct ble_mbuf_hdr *blehdr; + os_sr_t sr; + + BLE_LL_ASSERT(mux); + + switch (pb) { + case BLE_HCI_ISO_PB_FIRST: + BLE_LL_ASSERT(!mux->frag); + mux->frag = om; + om = NULL; + break; + case BLE_HCI_ISO_PB_CONTINUATION: + BLE_LL_ASSERT(mux->frag); + os_mbuf_concat(mux->frag, om); + om = NULL; + break; + case BLE_HCI_ISO_PB_COMPLETE: + BLE_LL_ASSERT(!mux->frag); + break; + case BLE_HCI_ISO_PB_LAST: + BLE_LL_ASSERT(mux->frag); + os_mbuf_concat(mux->frag, om); + om = mux->frag; + mux->frag = NULL; + break; + default: + BLE_LL_ASSERT(0); + break; + } + + if (!om) { + return; + } + + blehdr = BLE_MBUF_HDR_PTR(om); + blehdr->txiso.packet_seq_num = ++mux->sdu_counter; + + OS_ENTER_CRITICAL(sr); + pkthdr = OS_MBUF_PKTHDR(om); + STAILQ_INSERT_TAIL(&mux->sdu_q, pkthdr, omp_next); + OS_EXIT_CRITICAL(sr); +} + +int +ble_ll_isoal_mux_event_start(struct ble_ll_isoal_mux *mux, uint32_t timestamp) +{ + struct os_mbuf_pkthdr *pkthdr; + uint8_t num_sdu; + + num_sdu = mux->sdu_per_event; + + pkthdr = STAILQ_FIRST(&mux->sdu_q); + while (pkthdr && num_sdu--) { + pkthdr = STAILQ_NEXT(pkthdr, omp_next); + } + + mux->sdu_in_event = mux->sdu_per_event - num_sdu; + mux->event_tx_timestamp = timestamp; + + return mux->sdu_in_event; +} + +int +ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux) +{ + struct os_mbuf_pkthdr *pkthdr; + struct ble_mbuf_hdr *blehdr; + struct os_mbuf *om; + struct os_mbuf *om_next; + uint8_t num_sdu; + int pkt_freed = 0; + + num_sdu = min(mux->sdu_in_event, mux->sdu_per_interval); + + pkthdr = STAILQ_FIRST(&mux->sdu_q); + if (pkthdr) { + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + blehdr = BLE_MBUF_HDR_PTR(om); + mux->last_tx_timestamp = mux->event_tx_timestamp; + mux->last_tx_packet_seq_num = blehdr->txiso.packet_seq_num; + } + + while (pkthdr && num_sdu--) { + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + + while (om) { + om_next = SLIST_NEXT(om, om_next); + os_mbuf_free(om); + pkt_freed++; + om = om_next; + } + + STAILQ_REMOVE_HEAD(&mux->sdu_q, omp_next); + pkthdr = STAILQ_FIRST(&mux->sdu_q); + } + + mux->sdu_in_event = 0; + + return pkt_freed; +} + +int +ble_ll_isoal_mux_unframed_get(struct ble_ll_isoal_mux *mux, uint8_t idx, + uint8_t *llid, void *dptr) +{ + struct os_mbuf_pkthdr *pkthdr; + struct os_mbuf *om; + uint8_t sdu_idx; + uint8_t pdu_idx; + uint16_t sdu_offset; + uint16_t rem_len; + uint8_t pdu_len; + + sdu_idx = idx / mux->pdu_per_sdu; + pdu_idx = idx - sdu_idx * mux->pdu_per_sdu; + + if (sdu_idx >= mux->sdu_in_event) { + *llid = 1; + return 0; + } + + pkthdr = STAILQ_FIRST(&mux->sdu_q); + while (pkthdr && sdu_idx--) { + pkthdr = STAILQ_NEXT(pkthdr, omp_next); + } + + if (!pkthdr) { + *llid = 1; + return 0; + } + + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + sdu_offset = pdu_idx * mux->max_pdu; + rem_len = OS_MBUF_PKTLEN(om) - sdu_offset; + + if ((int32_t)rem_len <= 0) { + *llid = 1; + pdu_len = 0; + } else { + *llid = (pdu_idx < mux->pdu_per_sdu - 1); + pdu_len = min(mux->max_pdu, rem_len); + } + + os_mbuf_copydata(om, sdu_offset, pdu_len, dptr); + + return pdu_len; +} + +static void +ble_ll_isoal_tx_pkt_in(struct ble_npl_event *ev) +{ + struct os_mbuf *om; + struct os_mbuf_pkthdr *pkthdr; + struct ble_hci_iso *hci_iso; + struct ble_hci_iso_data *hci_iso_data; + struct ble_ll_isoal_mux *mux; + uint16_t data_hdr_len; + uint16_t handle; + uint16_t conn_handle; + uint16_t length; + uint16_t pb_flag; + uint16_t ts_flag; + uint32_t timestamp = 0; + os_sr_t sr; + + while (STAILQ_FIRST(&ll_isoal_tx_q)) { + pkthdr = STAILQ_FIRST(&ll_isoal_tx_q); + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&ll_isoal_tx_q, omp_next); + OS_EXIT_CRITICAL(sr); + + hci_iso = (void *)om->om_data; + + handle = le16toh(hci_iso->handle); + conn_handle = BLE_HCI_ISO_CONN_HANDLE(handle); + pb_flag = BLE_HCI_ISO_PB_FLAG(handle); + ts_flag = BLE_HCI_ISO_TS_FLAG(handle); + length = BLE_HCI_ISO_LENGTH(le16toh(hci_iso->length)); + + data_hdr_len = 0; + if ((pb_flag == BLE_HCI_ISO_PB_FIRST) || + (pb_flag == BLE_HCI_ISO_PB_COMPLETE)) { + if (ts_flag) { + timestamp = get_le32(om->om_data + sizeof(*hci_iso)); + data_hdr_len += sizeof(uint32_t); + } + + hci_iso_data = (void *)(om->om_data + sizeof(*hci_iso) + data_hdr_len); + data_hdr_len += sizeof(*hci_iso_data); + } + os_mbuf_adj(om, sizeof(*hci_iso) + data_hdr_len); + + if (OS_MBUF_PKTLEN(om) != length - data_hdr_len) { + os_mbuf_free_chain(om); + continue; + } + + switch (BLE_LL_CONN_HANDLE_TYPE(conn_handle)) { + case BLE_LL_CONN_HANDLE_TYPE_BIS: + mux = ble_ll_iso_big_find_mux_by_handle(conn_handle); + ble_ll_isoal_mux_tx_pkt_in(mux, om, pb_flag, timestamp); + break; + default: + os_mbuf_free_chain(om); + break; + } + } +} + +int +ble_ll_isoal_hci_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_le_setup_iso_data_path_cp *cmd = (const void *)cmdbuf; + struct ble_hci_le_setup_iso_data_path_rp *rsp = (void *)rspbuf; + struct ble_ll_iso_bis *bis; + uint16_t conn_handle; + + conn_handle = le16toh(cmd->conn_handle); + switch (BLE_LL_CONN_HANDLE_TYPE(conn_handle)) { + case BLE_LL_CONN_HANDLE_TYPE_BIS: + bis = ble_ll_iso_big_find_bis_by_handle(conn_handle); + if (bis) { + break; + } + default: + return BLE_ERR_UNK_CONN_ID; + } + + /* Only input for now since we only support BIS */ + if (cmd->data_path_dir) { + return BLE_ERR_CMD_DISALLOWED; + } + + /* We do not (yet) support any vendor-specific data path */ + if (cmd->data_path_id) { + return BLE_ERR_CMD_DISALLOWED; + } + + rsp->conn_handle = cmd->conn_handle; + *rsplen = sizeof(*rsp); + + return 0; +} + +int +ble_ll_isoal_hci_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_le_remove_iso_data_path_cp *cmd = (const void *)cmdbuf; + struct ble_hci_le_remove_iso_data_path_rp *rsp = (void *)rspbuf; + + /* XXX accepts anything for now */ + rsp->conn_handle = cmd->conn_handle; + *rsplen = sizeof(*rsp); + + return 0; +} + +int +ble_ll_isoal_hci_read_tx_sync(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_le_read_iso_tx_sync_cp *cmd = (const void *)cmdbuf; + struct ble_hci_le_read_iso_tx_sync_rp *rsp = (void *)rspbuf; + struct ble_ll_isoal_mux *mux; + uint16_t handle; + + handle = le16toh(cmd->conn_handle); + switch (BLE_LL_CONN_HANDLE_TYPE(handle)) { + case BLE_LL_CONN_HANDLE_TYPE_BIS: + mux = ble_ll_iso_big_find_mux_by_handle(handle); + if (!mux) { + return BLE_ERR_UNK_CONN_ID; + } + break; + default: + return BLE_ERR_UNK_CONN_ID; + } + + rsp->conn_handle = cmd->conn_handle; + rsp->packet_seq_num = htole16(mux->last_tx_packet_seq_num); + rsp->tx_timestamp = htole32(mux->last_tx_timestamp); + put_le24(rsp->time_offset, 0); + + *rsplen = sizeof(*rsp); + + return 0; +} + +void +ble_ll_isoal_init(void) +{ + STAILQ_INIT(&ll_isoal_tx_q); + ble_npl_event_init(&ll_isoal_tx_pkt_in, ble_ll_isoal_tx_pkt_in, NULL); +} + +void +ble_ll_isoal_reset(void) +{ + STAILQ_INIT(&ll_isoal_tx_q); + ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &ll_isoal_tx_pkt_in); +} + +int +ble_ll_isoal_data_in(struct os_mbuf *om) +{ + struct os_mbuf_pkthdr *hdr; + os_sr_t sr; + + hdr = OS_MBUF_PKTHDR(om); + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&ll_isoal_tx_q, hdr, omp_next); + OS_EXIT_CRITICAL(sr); + + ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ll_isoal_tx_pkt_in); + + return 0; +} + +#endif /* BLE_LL_ISO */ diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_pdu.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_pdu.c new file mode 100644 index 00000000..bcbb5ff0 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_pdu.c @@ -0,0 +1,58 @@ +/* + * 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 +#include + +static const uint16_t syncword_len[] = { + [BLE_PHY_MODE_1M] = (BLE_LL_PDU_PREAMBLE_1M_LEN + BLE_LL_PDU_AA_LEN) * 8, + [BLE_PHY_MODE_2M] = (BLE_LL_PDU_PREAMBLE_2M_LEN + BLE_LL_PDU_AA_LEN) * 4, + [BLE_PHY_MODE_CODED_125KBPS] = 80 + 256 + 16 + 24, + [BLE_PHY_MODE_CODED_500KBPS] = 80 + 256 + 16 + 24, +}; + +static const uint16_t payload0_len[] = { + [BLE_PHY_MODE_1M] = (BLE_LL_PDU_PREAMBLE_1M_LEN + BLE_LL_PDU_AA_LEN + + BLE_LL_PDU_HEADER_LEN + BLE_LL_PDU_CRC_LEN) * 8, + [BLE_PHY_MODE_2M] = (BLE_LL_PDU_PREAMBLE_2M_LEN + BLE_LL_PDU_AA_LEN + + BLE_LL_PDU_HEADER_LEN + BLE_LL_PDU_CRC_LEN) * 4, + [BLE_PHY_MODE_CODED_125KBPS] = 80 + 256 + 16 + 24 + + 8 * (BLE_LL_PDU_HEADER_LEN * 8 + 24 + 3), + [BLE_PHY_MODE_CODED_500KBPS] = 80 + 256 + 16 + 24 + + 2 * (BLE_LL_PDU_HEADER_LEN * 8 + 24 + 3), +}; + +static const uint8_t us_per_octet[] = { + [BLE_PHY_MODE_1M] = 8, + [BLE_PHY_MODE_2M] = 4, + [BLE_PHY_MODE_CODED_125KBPS] = 64, + [BLE_PHY_MODE_CODED_500KBPS] = 16, +}; + +uint32_t +ble_ll_pdu_syncword_us(uint8_t phy_mode) +{ + return syncword_len[phy_mode]; +} + +uint32_t +ble_ll_pdu_us(uint8_t payload_len, uint8_t phy_mode) +{ + return payload0_len[phy_mode] + (payload_len * us_per_octet[phy_mode]); +} diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_priv.h b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_priv.h index ca8e0829..f0498fea 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_priv.h @@ -25,6 +25,34 @@ extern "C" { #endif extern int8_t g_ble_ll_tx_power; +extern int8_t g_ble_ll_tx_power_compensation; +extern int8_t g_ble_ll_rx_power_compensation; + +int ble_ll_tx_power_round(int tx_power); +void ble_ll_tx_power_set(int tx_power); + +static inline int +ble_ll_rx_gain(void) +{ + int gain = g_ble_ll_rx_power_compensation; + +#if MYNEWT_VAL(BLE_FEM_LNA) +#if MYNEWT_VAL(BLE_FEM_LNA_GAIN_TUNABLE) + gain += ble_fem_lna_rx_gain(); +#else + gain += MYNEWT_VAL(BLE_FEM_LNA_GAIN); +#endif +#endif + + return gain; +} + +/* if there is any radio related activity enabled + * (scanning, advertising, connection etc) + */ +#define BLE_LL_BUSY_EXCLUDE_CONNECTIONS 0x01 + +int ble_ll_is_busy(unsigned int flags); #ifdef MYNEWT diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_rand.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_rand.c index 06e5d12b..fc7febcf 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_rand.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_rand.c @@ -33,6 +33,10 @@ #include "trng/trng.h" #endif +#ifdef RIOT_VERSION +#include "random.h" +#endif + #if BABBLESIM extern void tm_tick(void); #endif @@ -134,6 +138,7 @@ ble_ll_rand_data_get(uint8_t *buf, uint8_t len) uint32_t ble_ll_rand(void) { +#ifndef RIOT_VERSION static unsigned short xsubi[3]; static bool init = true; @@ -143,6 +148,9 @@ ble_ll_rand(void) } return (uint32_t) jrand48(xsubi); +#else + return random_uint32(); +#endif } /** diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_resolv.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_resolv.c index a972fe3d..8ec9a97d 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_resolv.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_resolv.c @@ -31,6 +31,7 @@ #include "controller/ble_ll_sync.h" #include "controller/ble_hw.h" #include "ble_ll_conn_priv.h" +#include "ble_ll_priv.h" #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) struct ble_ll_resolv_data @@ -47,35 +48,6 @@ struct ble_ll_resolv_data g_ble_ll_resolv_data; __attribute__((aligned(4))) struct ble_ll_resolv_entry g_ble_ll_resolv_list[MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)]; -static int -ble_ll_is_controller_busy(void) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) - if (ble_ll_sync_enabled()) { - return 1; - } -#endif - -#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) - if (ble_ll_adv_enabled()) { - return 1; - } -#endif - -#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) - if (ble_ll_scan_enabled()) { - return 1; - } -#endif - -#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) - if (g_ble_ll_conn_create_sm.connsm) { - return 1; - } -#endif - - return 0; -} /** * Called to determine if a change is allowed to the resolving list at this * time. We are not allowed to modify the resolving list if address translation @@ -90,7 +62,7 @@ ble_ll_resolv_list_chg_allowed(void) int rc; if (g_ble_ll_resolv_data.addr_res_enabled && - ble_ll_is_controller_busy()) { + ble_ll_is_busy(BLE_LL_BUSY_EXCLUDE_CONNECTIONS)) { rc = 0; } else { rc = 1; @@ -456,8 +428,8 @@ ble_ll_resolv_enable_cmd(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } - if (ble_ll_is_controller_busy()) { - return BLE_ERR_CMD_DISALLOWED; + if (ble_ll_is_busy(BLE_LL_BUSY_EXCLUDE_CONNECTIONS)) { + return BLE_ERR_CMD_DISALLOWED; } @@ -561,7 +533,7 @@ ble_ll_resolve_set_priv_mode(const uint8_t *cmdbuf, uint8_t len) const struct ble_hci_le_set_privacy_mode_cp *cmd = (const void *) cmdbuf; struct ble_ll_resolv_entry *rl; - if (ble_ll_is_controller_busy()) { + if (ble_ll_is_busy(BLE_LL_BUSY_EXCLUDE_CONNECTIONS)) { return BLE_ERR_CMD_DISALLOWED; } diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_rfmgmt.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_rfmgmt.c index 1877b619..a9fd64ec 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_rfmgmt.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_rfmgmt.c @@ -236,7 +236,7 @@ ble_ll_rfmgmt_reset(void) rfmgmt->timer_scheduled_at = 0; ble_ll_tmr_stop(&rfmgmt->timer); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev); + ble_ll_event_remove(&rfmgmt->release_ev); ble_ll_rfmgmt_disable(); @@ -290,10 +290,10 @@ ble_ll_rfmgmt_release(void) OS_ENTER_CRITICAL(sr); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev); + ble_ll_event_remove(&rfmgmt->release_ev); if (g_ble_ll_rfmgmt_data.state != RFMGMT_STATE_OFF) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev); + ble_ll_event_add(&rfmgmt->release_ev); } OS_EXIT_CRITICAL(sr); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_scan.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_scan.c index 27c0feaa..d1c3c8ad 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_scan.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_scan.c @@ -41,6 +41,7 @@ #include "controller/ble_ll_trace.h" #include "controller/ble_ll_sync.h" #include "ble_ll_conn_priv.h" +#include "ble_ll_priv.h" #if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) @@ -361,11 +362,6 @@ ble_ll_scan_get_ext_adv_report(struct ext_adv_report *copy_from) return hci_ev; } - -void -ble_ll_scan_end_adv_evt(struct ble_ll_aux_data *aux_data) -{ -} #endif void @@ -441,7 +437,7 @@ ble_ll_scan_add_scan_rsp_adv(uint8_t *addr, uint8_t txadd, /* XXX: for now, if we dont have room, just leave */ num_advs = g_ble_ll_scan_num_rsp_advs; - if (num_advs == MYNEWT_VAL(BLE_LL_NUM_SCAN_RSP_ADVS)) { + if (num_advs >= MYNEWT_VAL(BLE_LL_NUM_SCAN_RSP_ADVS)) { return; } @@ -701,6 +697,14 @@ ble_ll_scan_send_adv_report(uint8_t pdu_type, } if (BLE_MBUF_HDR_TARGETA_RESOLVED(hdr)) { inita_type += 2; + } else { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (scansm->ext_scanning) { + if (ble_ll_is_rpa(inita, inita_type)) { + inita_type = 0xfe; + } + } +#endif } #endif @@ -708,7 +712,7 @@ ble_ll_scan_send_adv_report(uint8_t pdu_type, if (scansm->ext_scanning) { rc = ble_ll_hci_send_legacy_ext_adv_report(evtype, adva, adva_type, - hdr->rxinfo.rssi, + hdr->rxinfo.rssi - ble_ll_rx_gain(), adv_data_len, om, inita, inita_type); goto done; @@ -717,11 +721,12 @@ goto done; if (subev == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT) { rc = ble_ll_hci_send_dir_adv_report(adva, adva_type, inita, inita_type, - hdr->rxinfo.rssi); + hdr->rxinfo.rssi - ble_ll_rx_gain()); goto done; } - rc = ble_ll_hci_send_adv_report(evtype, adva, adva_type, hdr->rxinfo.rssi, + rc = ble_ll_hci_send_adv_report(evtype, adva, adva_type, + hdr->rxinfo.rssi - ble_ll_rx_gain(), adv_data_len, om); done: if (!rc && scansm->scan_filt_dups) { @@ -780,6 +785,13 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm) ble_phy_mode_set(phy_mode, phy_mode); #endif + /* if scan is not passive we need to set tx power as we may end up sending + * package + */ + if (scansm->scanp->scan_type != BLE_SCAN_TYPE_PASSIVE) { + ble_ll_tx_power_set(g_ble_ll_tx_power); + } + rc = ble_phy_rx_set_start_time(ble_ll_tmr_get() + g_ble_ll_sched_offset_ticks, 0); if (!rc || rc == BLE_PHY_ERR_RX_LATE) { @@ -880,10 +892,6 @@ ble_ll_scan_sm_stop(int chk_disable) OS_ENTER_CRITICAL(sr); -#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) - scansm->connsm = NULL; -#endif - /* Disable scanning state machine */ scansm->scan_enabled = 0; scansm->restart_timer_needed = 0; @@ -895,6 +903,10 @@ ble_ll_scan_sm_stop(int chk_disable) } #endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + scansm->connsm = NULL; +#endif + /* Update backoff if we failed to receive scan response */ if (scansm->scan_rsp_pending) { scansm->scan_rsp_pending = 0; @@ -1109,6 +1121,11 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) case BLE_LL_STATE_SCAN_AUX: start_scan = false; break; +#endif +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_STATE_EXTERNAL: + start_scan = false; + break; #endif case BLE_LL_STATE_SCANNING: /* Must disable PHY since we will move to a new channel */ @@ -1117,6 +1134,11 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) ble_ll_state_set(BLE_LL_STATE_STANDBY); } break; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + case BLE_LL_STATE_BIG: + start_scan = false; + break; +#endif case BLE_LL_STATE_STANDBY: break; default: @@ -1267,17 +1289,17 @@ ble_ll_scan_rx_filter(uint8_t own_addr_type, uint8_t scan_filt_policy, switch (ble_ll_addr_subtype(addrd->adva, addrd->adva_type)) { case BLE_LL_ADDR_SUBTYPE_RPA: - if (addrd->rpa_index < 0) { + if (addrd->rpa_index >= 0) { + addrd->adva_resolved = 1; + + /* Use resolved identity address as advertiser address */ + rl = &g_ble_ll_resolv_list[addrd->rpa_index]; + addrd->adv_addr = rl->rl_identity_addr; + addrd->adv_addr_type = rl->rl_addr_type; break; } - addrd->adva_resolved = 1; - - /* Use resolved identity address as advertiser address */ - rl = &g_ble_ll_resolv_list[addrd->rpa_index]; - addrd->adv_addr = rl->rl_identity_addr; - addrd->adv_addr_type = rl->rl_addr_type; - break; + /* fall-through */ case BLE_LL_ADDR_SUBTYPE_IDENTITY: /* If AdvA is an identity address, we need to check if that device was * added to RL in order to use proper privacy mode. @@ -1325,7 +1347,8 @@ ble_ll_scan_rx_filter(uint8_t own_addr_type, uint8_t scan_filt_policy, } /* Ignore if not directed to us */ - if (!ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type)) { + if ((addrd->targeta_type != (own_addr_type & 0x01)) || + !ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type)) { return -1; } break; @@ -1339,7 +1362,8 @@ ble_ll_scan_rx_filter(uint8_t own_addr_type, uint8_t scan_filt_policy, #else /* Ignore if not directed to us */ if (addrd->targeta && - !ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type)) { + ((addrd->targeta_type != (own_addr_type & 0x01)) || + !ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type))) { return -1; } @@ -1525,10 +1549,8 @@ ble_ll_scan_send_scan_req(uint8_t pdu_type, uint8_t *rxbuf, BLE_LL_ASSERT(scansm->scan_rsp_pending == 0); /* We want to send a request. See if backoff allows us */ - if (scansm->backoff_count > 0) { - if (--scansm->backoff_count != 0) { - return false; - } + if (ble_ll_scan_backoff_kick() != 0) { + return false; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) @@ -1674,7 +1696,7 @@ ble_ll_scan_chk_resume(void) OS_ENTER_CRITICAL(sr); if (scansm->restart_timer_needed) { scansm->restart_timer_needed = 0; - ble_ll_event_send(&scansm->scan_sched_ev); + ble_ll_event_add(&scansm->scan_sched_ev); STATS_INC(ble_ll_stats, scan_timer_restarted); OS_EXIT_CRITICAL(sr); return; @@ -1704,13 +1726,13 @@ ble_ll_scan_timer_cb(void *arg) struct ble_ll_scan_sm *scansm; scansm = (struct ble_ll_scan_sm *)arg; - ble_ll_event_send(&scansm->scan_sched_ev); + ble_ll_event_add(&scansm->scan_sched_ev); } void ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm) { - ble_ll_event_send(&scansm->scan_interrupted_ev); + ble_ll_event_add(&scansm->scan_interrupted_ev); } /** @@ -2299,6 +2321,27 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, scansm = &g_ble_ll_scan_sm; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (ext) { + /* + * If Enable is set to 0x01 and the Host has not issued the + * HCI_LE_Set_Extended_Scan_Parameters command, the Controller shall + * either use vendor-specified parameters or return the error code + * Command Disallowed (0x0C) + * + * To keep things simple for devices without public address we + * reject in such case. + */ + for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) { + if (g_ble_ll_scan_params.scan_phys[i].configured) { + break; + } + } + + if (i == BLE_LL_SCAN_PHY_NUMBER) { + return BLE_ERR_CMD_DISALLOWED; + } + } + /* we can do that here since value will never change until reset */ scansm->ext_scanning = ext; diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_scan_aux.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_scan_aux.c index e3b94822..3d5f2775 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_scan_aux.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_scan_aux.c @@ -28,9 +28,11 @@ #include "os/os.h" #include "nimble/ble.h" #include "nimble/hci_common.h" +#include "controller/ble_ll_utils.h" #include "controller/ble_phy.h" #include "controller/ble_hw.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_scan.h" #include "controller/ble_ll_scan_aux.h" @@ -38,6 +40,7 @@ #include "controller/ble_ll_whitelist.h" #include "controller/ble_ll_resolv.h" #include "controller/ble_ll_sync.h" +#include "ble_ll_priv.h" #define BLE_LL_SCAN_AUX_F_AUX_ADV 0x0001 #define BLE_LL_SCAN_AUX_F_AUX_CHAIN 0x0002 @@ -65,7 +68,7 @@ struct ble_ll_scan_aux_data { uint8_t pri_phy; uint8_t sec_phy; uint8_t chan; - uint8_t offset_unit : 1; + uint16_t wfr_us; uint32_t aux_ptr; struct ble_ll_sched_item sch; struct ble_npl_event break_ev; @@ -108,7 +111,6 @@ static int ble_ll_scan_aux_sched_cb(struct ble_ll_sched_item *sch) { struct ble_ll_scan_aux_data *aux = sch->cb_arg; - uint32_t wfr_us; #if BLE_LL_BT5_PHY_SUPPORTED uint8_t phy_mode; #endif @@ -140,6 +142,14 @@ ble_ll_scan_aux_sched_cb(struct ble_ll_sched_item *sch) ble_phy_mode_set(phy_mode, phy_mode); #endif + /* if scan is not passive we need to set tx power as we may end up sending + * package + */ + /* TODO do this only on first AUX? */ + if (aux->scan_type != BLE_SCAN_TYPE_PASSIVE) { + ble_ll_tx_power_set(g_ble_ll_tx_power); + } + rc = ble_phy_rx_set_start_time(sch->start_time + g_ble_ll_sched_offset_ticks, sch->remainder); if (rc != 0 && rc != BLE_PHY_ERR_RX_LATE) { @@ -155,8 +165,7 @@ ble_ll_scan_aux_sched_cb(struct ble_ll_sched_item *sch) ble_ll_whitelist_disable(); } - wfr_us = aux->offset_unit ? 300 : 30; - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_us); + ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, aux->wfr_us); aux_data_current = aux; @@ -198,21 +207,6 @@ ble_ll_scan_aux_free(struct ble_ll_scan_aux_data *aux) os_memblock_put(&aux_data_pool, aux); } -static void -ble_ll_scan_aux_update_scan_backoff(struct ble_ll_scan_aux_data *aux) -{ - if (!(aux->flags & BLE_LL_SCAN_AUX_F_W4_SCAN_RSP) && - !(aux->flags & BLE_LL_SCAN_AUX_F_SCANNED)) { - return; - } - - if ((aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) && - !(aux->hci_state & BLE_LL_SCAN_AUX_H_TRUNCATED)) { - ble_ll_scan_backoff_update(1); - } else { - ble_ll_scan_backoff_update(0); - } -} static inline bool ble_ll_scan_aux_need_truncation(struct ble_ll_scan_aux_data *aux) @@ -270,6 +264,8 @@ ble_ll_hci_ev_alloc_ext_adv_report_for_aux(struct ble_ll_scan_addr_data *addrd, #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) if (addrd->targeta_resolved) { report->dir_addr_type += 2; + } else if (ble_ll_is_rpa(addrd->targeta, addrd->targeta_type)) { + report->dir_addr_type = 0xfe; } #endif } @@ -421,7 +417,7 @@ ble_ll_hci_ev_update_ext_adv_report_from_ext(struct ble_hci_ev *hci_ev, report->pri_phy = rxinfo->phy; report->sec_phy = 0; report->sid = 0xff; - report->rssi = rxhdr->rxinfo.rssi; + report->rssi = rxhdr->rxinfo.rssi - ble_ll_rx_gain(); report->periodic_itvl = 0; report->data_len = 0; @@ -451,7 +447,12 @@ ble_ll_hci_ev_update_ext_adv_report_from_ext(struct ble_hci_ev *hci_ev, report->dir_addr_type = (ble_ll_scan_get_own_addr_type() & 1) + 2; memcpy(report->dir_addr, ble_ll_scan_aux_get_own_addr(), 6); } else { - report->dir_addr_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_MASK); + if (ble_ll_is_rpa(eh_data, pdu_hdr & BLE_ADV_PDU_HDR_RXADD_MASK)) { + report->dir_addr_type = 0xfe; + } else { + report->dir_addr_type = !!(pdu_hdr & + BLE_ADV_PDU_HDR_RXADD_MASK); + } memcpy(report->dir_addr, eh_data, 6); } #else @@ -537,9 +538,9 @@ ble_ll_hci_ev_send_ext_adv_report(struct os_mbuf *rxpdu, hci_subev = (void *)(*hci_ev)->data; report = hci_subev->reports; - report->rssi = rxinfo->rssi; + report->rssi = rxinfo->rssi - ble_ll_rx_gain(); - report->data_len = min(max_data_len, data_len - offset); + report->data_len = MIN(max_data_len, data_len - offset); os_mbuf_copydata(rxpdu, offset, report->data_len, report->data); (*hci_ev)->length += report->data_len; @@ -557,6 +558,8 @@ ble_ll_hci_ev_send_ext_adv_report(struct os_mbuf *rxpdu, } else { report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; } + } else if (rxinfo->flags & BLE_MBUF_HDR_F_AUX_PTR_FAILED) { + report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; } switch (report->evt_type & BLE_HCI_ADV_DATA_STATUS_MASK) { @@ -593,6 +596,7 @@ ble_ll_hci_ev_send_ext_adv_report_for_aux(struct os_mbuf *rxpdu, int rc; if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { + aux->hci_state = BLE_LL_SCAN_AUX_H_DONE; return -1; } @@ -607,6 +611,7 @@ ble_ll_hci_ev_send_ext_adv_report_for_aux(struct os_mbuf *rxpdu, } else { hci_ev = ble_ll_hci_ev_alloc_ext_adv_report_for_aux(addrd, aux); if (!hci_ev) { + aux->hci_state = BLE_LL_SCAN_AUX_H_DONE; return -1; } } @@ -661,7 +666,10 @@ ble_ll_scan_aux_break_ev(struct ble_npl_event *ev) ble_ll_hci_ev_send_ext_adv_truncated_report(aux); } - ble_ll_scan_aux_update_scan_backoff(aux); + /* Update backoff if we were waiting for scan response */ + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_SCAN_RSP) { + ble_ll_scan_backoff_update(0); + } ble_ll_scan_aux_free(aux); ble_ll_scan_chk_resume(); @@ -677,81 +685,91 @@ ble_ll_scan_aux_break(struct ble_ll_scan_aux_data *aux) #endif ble_npl_event_init(&aux->break_ev, ble_ll_scan_aux_break_ev, aux); - ble_ll_event_send(&aux->break_ev); + ble_ll_event_add(&aux->break_ev); } static int -ble_ll_scan_aux_parse_aux_ptr(struct ble_ll_scan_aux_data *aux, - uint32_t aux_ptr, uint32_t *offset_us) +ble_ll_scan_aux_phy_to_phy(uint8_t aux_phy, uint8_t *phy) { - uint8_t offset_unit; - uint32_t offset; - uint8_t chan; - uint8_t phy; - - phy = (aux_ptr >> 21) & 0x07; - switch (phy) { + switch (aux_phy) { case 0: - phy = BLE_PHY_1M; + *phy = BLE_PHY_1M; break; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) case 1: - phy = BLE_PHY_2M; + *phy = BLE_PHY_2M; break; #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) case 2: - phy = BLE_PHY_CODED; + *phy = BLE_PHY_CODED; break; #endif default: return -1; } + return 0; +} + +int +ble_ll_scan_aux_sched(struct ble_ll_scan_aux_data *aux, uint32_t pdu_ticks, + uint8_t pdu_rem_us, uint32_t aux_ptr) +{ + struct ble_ll_sched_item *sch; + uint32_t aux_offset; + uint8_t offset_unit; + uint8_t aux_phy; + uint8_t chan; + uint8_t ca; + uint8_t phy; + uint32_t offset_us; + uint16_t pdu_rx_us; + uint16_t aux_ww_us; + uint16_t aux_tx_win_us; + + /* Parse AuxPtr */ chan = aux_ptr & 0x3f; + ca = aux_ptr & 0x40; + offset_unit = aux_ptr & 0x80; + aux_offset = (aux_ptr >> 8) & 0x1fff; + aux_phy = (aux_ptr >> 21) & 0x07; + if (chan >= BLE_PHY_NUM_DATA_CHANS) { return -1; } - offset = 30 * ((aux_ptr >> 8) & 0x1fff); - if ((aux_ptr >> 7) & 0x01) { - offset *= 10; - offset_unit = 1; - } else { - offset_unit = 0; - } - - if (offset < BLE_LL_MAFS) { + if (ble_ll_scan_aux_phy_to_phy(aux_phy, &phy) < 0) { return -1; } + /* Actual offset */ + offset_us = aux_offset * (offset_unit ? 300 : 30); + /* Time to scan aux PDU */ + pdu_rx_us = ble_ll_pdu_us(MYNEWT_VAL(BLE_LL_SCHED_SCAN_AUX_PDU_LEN), + ble_ll_phy_to_phy_mode(phy, 0)); + /* Transmit window */ + aux_tx_win_us = offset_unit ? 300 : 30; + /* Window widening to include drift due to sleep clock accuracy and jitter */ + aux_ww_us = offset_us * (ca ? 50 : 500) / 1000000 + BLE_LL_JITTER_USECS; + aux->sec_phy = phy; aux->chan = chan; - aux->offset_unit = offset_unit; - - *offset_us = offset; + aux->wfr_us = aux_ww_us + aux_tx_win_us; - return 0; -} + sch = &aux->sch; -int -ble_ll_scan_aux_sched(struct ble_ll_scan_aux_data *aux, uint32_t pdu_time, - uint8_t pdu_time_rem, uint32_t aux_ptr) -{ - uint32_t offset_us; - int rc; + sch->start_time = pdu_ticks; + sch->remainder = pdu_rem_us; + ble_ll_tmr_add(&sch->start_time, &sch->remainder, offset_us - aux_ww_us); - rc = ble_ll_scan_aux_parse_aux_ptr(aux, aux_ptr, &offset_us); - if (rc < 0) { - return -1; - } + sch->end_time = sch->start_time + + ble_ll_tmr_u2t_up(sch->remainder + 2 * aux_ww_us + + aux_tx_win_us + pdu_rx_us); - rc = ble_ll_sched_scan_aux(&aux->sch, pdu_time, pdu_time_rem, offset_us); - if (rc < 0) { - return -1; - } + sch->start_time -= g_ble_ll_sched_offset_ticks; - return 0; + return ble_ll_sched_scan_aux(&aux->sch); } int @@ -1237,7 +1255,10 @@ ble_ll_scan_aux_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) rxinfo = &rxhdr->rxinfo; rxinfo->user_data = aux; - if (!crcok) { + /* It's possible that we received aux while scan was just being disabled in + * LL task. In such case simply ignore aux. + */ + if (!crcok || !ble_ll_scan_enabled()) { rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; goto done; } @@ -1485,6 +1506,7 @@ ble_ll_scan_aux_check_connect_rsp(uint8_t *rxbuf, #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) struct ble_ll_resolv_entry *rl = NULL; #endif + uint8_t match_adva = 1; pdu_hdr = rxbuf[0]; pdu_len = rxbuf[1]; @@ -1517,34 +1539,34 @@ ble_ll_scan_aux_check_connect_rsp(uint8_t *rxbuf, targeta_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_RAND); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* If we have IRK for peer and AdvA is an RPA, we need to check if current - * RPA resolves using that IRK. This is to verify AdvA in case RPS changed - * due to timeout or AdvA in advertising was an identity address but is an - * RPA in AUX_CONNECT_RSP. - * Otherwise, it shall be the same as in AUX_CONNECT_REQ. + /* If AdvA is an RPA and we have peer IRK, we need to check if it resolves + * using that RPA because peer can change RPA between advertising PDU and + * AUX_CONNECT_RSP. In other case, we expect AdvA to be the same as in + * advertising PDU. */ if ((addrd->rpa_index >= 0) && ble_ll_is_rpa(adva, adva_type)) { rl = &g_ble_ll_resolv_list[addrd->rpa_index]; - if (!ble_ll_resolv_rpa(adva, rl->rl_peer_irk)) { - return -1; - } + if (rl->rl_has_peer) { + if (!ble_ll_resolv_rpa(adva, rl->rl_peer_irk)) { + return -1; + } - addrd->adva_resolved = 1; - addrd->adva = adva; - addrd->adva_type = adva_type; - } else if ((adva_type != - !!(pdu_data->hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK)) || - (memcmp(adva, pdu_data->adva, 6) != 0)) { - return -1; - } -#else - if ((adva_type != !!(pdu_data->hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK)) || - (memcmp(adva, pdu_data->adva, 6) != 0)) { - return -1; + addrd->adva_resolved = 1; + addrd->adva = adva; + addrd->adva_type = adva_type; + + match_adva = 0; + } } #endif /* BLE_LL_CFG_FEAT_LL_PRIVACY */ + if (match_adva && + ((adva_type != !!(pdu_data->hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK)) || + (memcmp(adva, pdu_data->adva, 6) != 0))) { + return -1; + } + if ((targeta_type != !!(pdu_data->hdr_byte & BLE_ADV_PDU_HDR_TXADD_MASK)) || (memcmp(targeta, pdu_data->inita, 6) != 0)) { return -1; @@ -1565,6 +1587,9 @@ ble_ll_scan_aux_rx_pkt_in_for_initiator(struct os_mbuf *rxpdu, aux = rxinfo->user_data; if (rxinfo->flags & BLE_MBUF_HDR_F_IGNORED) { + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP) { + ble_ll_conn_send_connect_req_cancel(); + } ble_ll_scan_aux_free(aux); ble_ll_scan_chk_resume(); return; @@ -1637,7 +1662,15 @@ ble_ll_scan_aux_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *rxhdr) aux->hci_state |= BLE_LL_SCAN_AUX_H_DONE; } - ble_ll_scan_aux_update_scan_backoff(aux); + /* Update backoff if we were waiting for scan response */ + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_SCAN_RSP) { + ble_ll_scan_backoff_update(0); + } + } else if (rxinfo->flags & BLE_MBUF_HDR_F_SCAN_RSP_RXD) { + /* We assume scan success when AUX_SCAN_RSP is received, no need to + * wait for complete chain (Core 5.3, Vol 6, Part B, 4.4.3.1). + */ + ble_ll_scan_backoff_update(1); } if (aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) { @@ -1652,6 +1685,7 @@ ble_ll_scan_aux_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *rxhdr) aux->aux_ptr); if (rc < 0) { rxinfo->flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT; + rxinfo->flags |= BLE_MBUF_HDR_F_AUX_PTR_FAILED; } } @@ -1706,15 +1740,16 @@ ble_ll_scan_aux_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *rxhdr) aux->hci_state |= BLE_LL_SCAN_AUX_H_DONE; } - /* - * If we are done processing this chain and aux scan was not scheduled or - * we removed it from scheduler, we can remove aux_data now. Otherwise we - * will remove on next pkt_in. + /* If we are done processing this chain we can remove aux_data now if: + * - we did not send AUX_SCAN_REQ for this PDU + * - there was no aux scan scheduled from this PDU + * - there was aux scan scheduled from this PDU but we removed it + * In other cases, we'll remove aux_data on next pkt_in. */ if ((aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) && + !(rxinfo->flags & BLE_MBUF_HDR_F_SCAN_REQ_TXD) && (!(rxinfo->flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT) || (ble_ll_sched_rmv_elem(&aux->sch) == 0))) { - ble_ll_scan_aux_update_scan_backoff(aux); ble_ll_scan_aux_free(aux); } diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_sched.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_sched.c index 40139a80..8e8cee18 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_sched.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_sched.c @@ -23,6 +23,7 @@ #include "ble/xcvr.h" #include "controller/ble_phy.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_scan.h" @@ -31,6 +32,10 @@ #include "controller/ble_ll_trace.h" #include "controller/ble_ll_tmr.h" #include "controller/ble_ll_sync.h" +#include "controller/ble_ll_iso_big.h" +#if MYNEWT_VAL(BLE_LL_EXT) +#include "controller/ble_ll_ext.h" +#endif #include "ble_ll_priv.h" #include "ble_ll_conn_priv.h" @@ -47,6 +52,7 @@ int32_t g_ble_ll_sched_max_early; #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) struct ble_ll_sched_css { + uint8_t enabled; #if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) uint32_t slot_us; uint32_t period_slots; @@ -65,9 +71,6 @@ static struct ble_ll_sched_css g_ble_ll_sched_css = { }; #endif -typedef int (* ble_ll_sched_preempt_cb_t)(struct ble_ll_sched_item *sch, - struct ble_ll_sched_item *item); - /* XXX: TODO: * 1) Add some accounting to the schedule code to see how late we are * (min/max?) @@ -144,7 +147,7 @@ ble_ll_sched_preempt(struct ble_ll_sched_item *sch, #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_LL_SCHED_TYPE_CONN: connsm = (struct ble_ll_conn_sm *)entry->cb_arg; - ble_ll_event_send(&connsm->conn_ev_end); + ble_ll_event_add(&connsm->conn_ev_end); break; #endif #if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) @@ -168,6 +171,17 @@ ble_ll_sched_preempt(struct ble_ll_sched_item *sch, break; #endif #endif +#endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + case BLE_LL_SCHED_TYPE_BIG: + /* FIXME sometimes it may be useful to preempt... */ + BLE_LL_ASSERT(0); + break; +#endif +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_SCHED_TYPE_EXTERNAL: + ble_ll_ext_sched_removed(entry); + break; #endif default: BLE_LL_ASSERT(0); @@ -190,7 +204,7 @@ ble_ll_sched_q_head_changed(void) ble_ll_tmr_stop(&g_ble_ll_sched_timer); } -static inline void +void ble_ll_sched_restart(void) { struct ble_ll_sched_item *first; @@ -210,7 +224,7 @@ ble_ll_sched_restart(void) } } -static int +int ble_ll_sched_insert(struct ble_ll_sched_item *sch, uint32_t max_delay, ble_ll_sched_preempt_cb_t preempt_cb) { @@ -408,16 +422,15 @@ ble_ll_sched_conn_central_new(struct ble_ll_conn_sm *connsm, { #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) struct ble_ll_sched_css *css = &g_ble_ll_sched_css; - struct ble_ll_conn_sm *connsm_ref; + uint8_t rem_us; #endif struct ble_ll_sched_item *sch; uint32_t orig_start_time; - uint32_t earliest_start; -#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + uint32_t earliest_start = 0; uint32_t min_win_offset; -#endif uint32_t max_delay; uint32_t adv_rxend; + bool calc_sch = true; os_sr_t sr; int rc; @@ -500,61 +513,77 @@ ble_ll_sched_conn_central_new(struct ble_ll_conn_sm *connsm, orig_start_time = earliest_start - g_ble_ll_sched_offset_ticks; #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) - uint8_t rem_us; + if (ble_ll_sched_css_is_enabled()) { + OS_ENTER_CRITICAL(sr); - OS_ENTER_CRITICAL(sr); + if (!g_ble_ll_conn_css_ref) { + css->period_anchor_ticks = earliest_start; + css->period_anchor_rem_us = 0; + css->period_anchor_idx = 0; + css->period_anchor_slot_idx = connsm->css_slot_idx; - connsm_ref = g_ble_ll_conn_css_ref; - if (!connsm_ref) { - g_ble_ll_conn_css_ref = connsm; - - css->period_anchor_slot_idx = connsm->css_slot_idx; - css->period_anchor_idx = 0; - css->period_anchor_ticks = adv_rxend; - css->period_anchor_rem_us = 0; - - connsm->css_period_idx = 1; - } else { - connsm->css_period_idx = css->period_anchor_idx + 1; - } + connsm->css_period_idx = 0; + max_delay = connsm->conn_itvl_ticks; + } else { + /* Reference connection may be already at next period if it has + * slot index lower than our, so we first try schedule one period + * earlier since our slot index in that period may not yet have + * passed. This avoids scheduling 1st connection event too far in + * the future, i.e. more than conn interval. + */ + if (connsm->css_slot_idx > css->period_anchor_slot_idx) { + connsm->css_period_idx = css->period_anchor_idx - 1; + } else { + connsm->css_period_idx = css->period_anchor_idx; + } + max_delay = 0; + } - ble_ll_sched_css_set_conn_anchor(connsm); + /* Calculate anchor point and move to next period if scheduled too + * early. + */ + connsm->css_period_idx--; + do { + connsm->css_period_idx++; + ble_ll_sched_css_set_conn_anchor(connsm); + sch->start_time = + connsm->anchor_point - g_ble_ll_sched_offset_ticks; + } while (LL_TMR_LT(sch->start_time, orig_start_time)); + + sch->end_time = connsm->anchor_point; + sch->remainder = connsm->anchor_point_usecs; - sch->start_time = connsm->anchor_point - g_ble_ll_sched_offset_ticks; - sch->remainder = connsm->anchor_point_usecs; + OS_EXIT_CRITICAL(sr); - OS_EXIT_CRITICAL(sr); + rem_us = sch->remainder; + ble_ll_tmr_add(&sch->end_time, &rem_us, ble_ll_sched_css_get_slot_us()); + if (rem_us == 0) { + sch->end_time--; + } - sch->end_time = sch->start_time; - rem_us = sch->remainder; - ble_ll_tmr_add(&sch->end_time, &rem_us, ble_ll_sched_css_get_period_slots()); - if (rem_us == 0) { - sch->end_time--; + calc_sch = false; } +#endif - max_delay = 0; - -#else - - sch->start_time = earliest_start - g_ble_ll_sched_offset_ticks; - sch->end_time = earliest_start + - ble_ll_tmr_u2t(MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * - BLE_LL_SCHED_USECS_PER_SLOT); - - min_win_offset = ble_ll_tmr_u2t(MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET) * - BLE_LL_SCHED_USECS_PER_SLOT); - sch->start_time += min_win_offset; - sch->end_time += min_win_offset; - sch->remainder = 0; - - max_delay = connsm->conn_itvl_ticks - min_win_offset; + if (calc_sch) { + sch->start_time = earliest_start - g_ble_ll_sched_offset_ticks; + sch->end_time = earliest_start + + ble_ll_tmr_u2t(MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * + BLE_LL_SCHED_USECS_PER_SLOT); + + min_win_offset = ble_ll_tmr_u2t( + MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET) * + BLE_LL_SCHED_USECS_PER_SLOT); + sch->start_time += min_win_offset; + sch->end_time += min_win_offset; + sch->remainder = 0; -#endif + max_delay = connsm->conn_itvl_ticks - min_win_offset; + } OS_ENTER_CRITICAL(sr); rc = ble_ll_sched_insert(sch, max_delay, preempt_none); - if (rc == 0) { connsm->tx_win_off = ble_ll_tmr_t2u(sch->start_time - orig_start_time) / BLE_LL_CONN_TX_OFF_USECS; @@ -562,7 +591,6 @@ ble_ll_sched_conn_central_new(struct ble_ll_conn_sm *connsm, connsm->anchor_point = sch->start_time + g_ble_ll_sched_offset_ticks; connsm->anchor_point_usecs = sch->remainder; connsm->ce_end_time = sch->end_time; - } OS_EXIT_CRITICAL(sr); @@ -643,38 +671,13 @@ ble_ll_sched_sync_overlaps_current(struct ble_ll_sched_item *sch) } int -ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, - uint32_t anchor_point, uint8_t anchor_point_usecs, - uint32_t window_widening, - int8_t phy_mode) +ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, uint32_t ww_us) { - uint8_t start_time_rem_usecs; - uint32_t start_time; - uint32_t end_time; - uint32_t dur; - int rc = 0; os_sr_t sr; + int rc = 0; - start_time = anchor_point; - start_time_rem_usecs = anchor_point_usecs; - - ble_ll_tmr_sub(&start_time, &start_time_rem_usecs, window_widening); - - dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_SYNC_PDU_LEN), - phy_mode); - end_time = start_time + ble_ll_tmr_u2t(dur); - - start_time -= g_ble_ll_sched_offset_ticks; - - /* Set schedule start and end times */ - sch->start_time = start_time; - sch->remainder = start_time_rem_usecs; - sch->end_time = end_time; - - /* Better be past current time or we just leave */ - if (LL_TMR_LEQ(sch->start_time, ble_ll_tmr_get())) { - return -1; - } + /* Adjust start time to include window widening */ + ble_ll_tmr_sub(&sch->start_time, &sch->remainder, ww_us); OS_ENTER_CRITICAL(sr); @@ -693,32 +696,11 @@ ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, } int -ble_ll_sched_sync(struct ble_ll_sched_item *sch, - uint32_t beg_cputime, uint32_t rem_usecs, - uint32_t offset, int8_t phy_mode) +ble_ll_sched_sync(struct ble_ll_sched_item *sch) { - uint8_t start_time_rem_usecs; - uint32_t start_time; - uint32_t end_time; - uint32_t dur; os_sr_t sr; int rc = 0; - start_time = beg_cputime; - start_time_rem_usecs = rem_usecs; - - ble_ll_tmr_add(&start_time, &start_time_rem_usecs, offset); - - dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_SYNC_PDU_LEN), - phy_mode); - end_time = start_time + ble_ll_tmr_u2t(dur); - - start_time -= g_ble_ll_sched_offset_ticks; - - sch->start_time = start_time; - sch->remainder = start_time_rem_usecs; - sch->end_time = end_time; - OS_ENTER_CRITICAL(sr); rc = ble_ll_sched_insert(sch, 0, preempt_none); @@ -727,8 +709,6 @@ ble_ll_sched_sync(struct ble_ll_sched_item *sch, ble_ll_sched_restart(); - STATS_INC(ble_ll_stats, sync_scheduled); - return rc; } #endif @@ -862,6 +842,30 @@ ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch) return rc; } +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +int +ble_ll_sched_iso_big(struct ble_ll_sched_item *sch, int first) +{ + os_sr_t sr; + int rc; + + OS_ENTER_CRITICAL(sr); + + if (first) { + rc = ble_ll_sched_insert(sch, BLE_LL_SCHED_MAX_DELAY_ANY, preempt_none); + } else { + /* XXX provide better strategy for preemption */ + rc = ble_ll_sched_insert(sch, 0, preempt_any); + } + + OS_EXIT_CRITICAL(sr); + + ble_ll_sched_restart(); + + return rc; +} +#endif /* BLE_LL_ISO_BROADCASTER */ + /** * Remove a schedule element * @@ -1001,6 +1005,16 @@ ble_ll_sched_execute_item(struct ble_ll_sched_item *sch) STATS_INC(ble_ll_stats, sched_state_conn_errs); ble_ll_conn_event_halt(); break; +#endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + case BLE_LL_STATE_BIG: + ble_ll_iso_big_halt(); + break; +#endif +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_STATE_EXTERNAL: + ble_ll_ext_halt(); + break; #endif default: BLE_LL_ASSERT(0); @@ -1093,21 +1107,11 @@ ble_ll_sched_next_time(uint32_t *next_event_time) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) int -ble_ll_sched_scan_aux(struct ble_ll_sched_item *sch, uint32_t pdu_time, - uint8_t pdu_time_rem, uint32_t offset_us) +ble_ll_sched_scan_aux(struct ble_ll_sched_item *sch) { - uint32_t offset_ticks; os_sr_t sr; int rc; - offset_us += pdu_time_rem; - offset_ticks = ble_ll_tmr_u2t(offset_us); - - sch->start_time = pdu_time + offset_ticks - g_ble_ll_sched_offset_ticks; - sch->remainder = offset_us - ble_ll_tmr_t2u(offset_ticks); - /* TODO: make some sane slot reservation */ - sch->end_time = sch->start_time + ble_ll_tmr_u2t(5000); - OS_ENTER_CRITICAL(sr); rc = ble_ll_sched_insert(sch, 0, preempt_none); @@ -1182,6 +1186,17 @@ ble_ll_sched_init(void) g_ble_ll_sched_q_head_changed = 0; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + memset(&g_ble_ll_sched_css, 0, sizeof (g_ble_ll_sched_css)); +#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) + g_ble_ll_sched_css.slot_us = MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_SLOT_US); + g_ble_ll_sched_css.period_slots = MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_PERIOD_SLOTS); +#endif +#if !MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) + g_ble_ll_sched_css.enabled = 1; +#endif +#endif + return 0; } @@ -1195,6 +1210,24 @@ ble_ll_sched_css_set_params(uint32_t slot_us, uint32_t period_slots) } #endif +void +ble_ll_sched_css_set_enabled(uint8_t enabled) +{ + g_ble_ll_sched_css.enabled = enabled; +} + +void +ble_ll_sched_css_update_anchor(struct ble_ll_conn_sm *connsm) +{ + struct ble_ll_sched_css *css = &g_ble_ll_sched_css; + + if (!g_ble_ll_conn_css_ref) { + g_ble_ll_conn_css_ref = connsm; + css->period_anchor_ticks = connsm->anchor_point; + css->period_anchor_rem_us = connsm->anchor_point_usecs; + } +} + void ble_ll_sched_css_set_conn_anchor(struct ble_ll_conn_sm *connsm) { @@ -1222,6 +1255,12 @@ ble_ll_sched_css_set_conn_anchor(struct ble_ll_conn_sm *connsm) } #if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) +inline bool +ble_ll_sched_css_is_enabled(void) +{ + return g_ble_ll_sched_css.enabled; +} + inline uint32_t ble_ll_sched_css_get_slot_us(void) { diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_sync.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_sync.c index 65f2fcae..8aef8e2c 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_sync.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_sync.c @@ -25,6 +25,7 @@ #include "syscfg/syscfg.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_sync.h" #include "controller/ble_ll_utils.h" @@ -64,9 +65,11 @@ #define BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP 0x0200 #define BLE_LL_SYNC_SM_FLAG_CHAIN 0x0400 -#define BLE_LL_SYNC_CHMAP_LEN 5 #define BLE_LL_SYNC_ITVL_USECS 1250 +#define BLE_LL_SYNC_BIGINFO_LEN 33 +#define BLE_LL_SYNC_BIGINFO_LEN_ENC 57 + struct ble_ll_sync_sm { uint16_t flags; @@ -75,11 +78,11 @@ struct ble_ll_sync_sm { uint8_t adv_addr_type; uint8_t sca; - uint8_t chanmap[BLE_LL_SYNC_CHMAP_LEN]; - uint8_t num_used_chans; + uint8_t chan_map[BLE_LL_CHAN_MAP_LEN]; + uint8_t chan_map_used; - uint8_t chanmap_new[BLE_LL_SYNC_CHMAP_LEN]; - uint16_t chanmap_new_instant; + uint8_t chan_map_new[BLE_LL_CHAN_MAP_LEN]; + uint16_t chan_map_new_instant; uint8_t chan_index; uint8_t chan_chain; @@ -144,7 +147,7 @@ static int ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch); static int ble_ll_sync_on_list(const uint8_t *addr, uint8_t addr_type, uint8_t sid) { - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { if ((g_ble_ll_sync_adv_list[i].adv_sid == sid) && @@ -160,7 +163,7 @@ ble_ll_sync_on_list(const uint8_t *addr, uint8_t addr_type, uint8_t sid) static int ble_ll_sync_list_get_free(void) { - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { if (g_ble_ll_sync_adv_list[i].adv_sid == 0xff) { @@ -173,7 +176,7 @@ ble_ll_sync_list_get_free(void) static bool ble_ll_sync_list_empty(void) { - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { if (g_ble_ll_sync_adv_list[i].adv_sid != 0xff) { @@ -197,7 +200,7 @@ ble_ll_sync_sm_clear(struct ble_ll_sync_sm *sm) if (sm->flags & (BLE_LL_SYNC_SM_FLAG_ESTABLISHING | BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) { ble_ll_sched_rmv_elem(&sm->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &sm->sync_ev_end); + ble_ll_event_remove(&sm->sync_ev_end); } if (sm->next_report) { @@ -212,8 +215,7 @@ ble_ll_sync_sm_clear(struct ble_ll_sync_sm *sm) } ble_ll_rfmgmt_release(); - - BLE_LL_ASSERT(sm->sync_ev_end.ev.ev_queued == 0); + BLE_LL_ASSERT(ble_npl_event_is_queued(&sm->sync_ev_end) == 0); BLE_LL_ASSERT(sm->sch.enqueued == 0); memset(sm, 0, sizeof(*sm)); @@ -481,7 +483,7 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch) rc = ble_phy_rx_set_start_time(start, sch->remainder); if (rc && rc != BLE_PHY_ERR_RX_LATE) { STATS_INC(ble_ll_stats, sync_event_failed); - ble_ll_event_send(&sm->sync_ev_end); + ble_ll_event_add(&sm->sync_ev_end); ble_ll_sync_current_sm_over(); rc = BLE_LL_SCHED_STATE_DONE; } else { @@ -534,7 +536,7 @@ ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr) /* this also handles chains as those have same PDU type */ if (pdu_type != BLE_ADV_PDU_TYPE_AUX_SYNC_IND) { - ble_ll_event_send(&g_ble_ll_sync_sm_current->sync_ev_end); + ble_ll_event_add(&g_ble_ll_sync_sm_current->sync_ev_end); ble_ll_sync_current_sm_over(); STATS_INC(ble_ll_stats, sched_invalid_pdu); return -1; @@ -663,6 +665,70 @@ ble_ll_sync_send_truncated_per_adv_rpt(struct ble_ll_sync_sm *sm, uint8_t *evbuf ble_ll_hci_event_send(hci_ev); } +#if MYNEWT_VAL(BLE_LL_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) +static void +ble_ll_sync_parse_biginfo_to_ev(struct ble_hci_ev_le_subev_biginfo_adv_report *ev, + const uint8_t *biginfo, uint8_t biginfo_len) +{ + uint32_t fields_buf; + + fields_buf = get_le32(&biginfo[0]); + ev->iso_interval = (fields_buf >> 15) & 0x0FFF; + ev->bis_cnt = (fields_buf >> 27) & 0x1F; + + fields_buf = get_le32(&biginfo[4]); + ev->nse = fields_buf & 0x1F; + ev->bn = (fields_buf >> 5) & 0x07; + ev->pto = (fields_buf >> 28) & 0x0F; + + fields_buf = get_le32(&biginfo[8]); + ev->irc = (fields_buf >> 20) & 0x0F; + ev->max_pdu = (fields_buf >> 24) & 0xFF; + + fields_buf = get_le32(&biginfo[17]); + ev->sdu_interval[0] = fields_buf & 0xFF; + ev->sdu_interval[1] = (fields_buf >> 8) & 0xFF; + ev->sdu_interval[2] = (fields_buf >> 16) & 0x0F; + ev->max_sdu = (fields_buf >> 20) & 0x0FFF; + + ev->phy = (biginfo[27] >> 5) & 0x07; + + ev->framing = (biginfo[32] >> 7) & 0x01; + + if (biginfo_len == BLE_LL_SYNC_BIGINFO_LEN_ENC) { + ev->encryption = 1; + } else { + ev->encryption = 0; + } +} + +static void +ble_ll_sync_send_biginfo_adv_rpt(struct ble_ll_sync_sm *sm, const uint8_t *biginfo, uint8_t biginfo_len) +{ + struct ble_hci_ev_le_subev_biginfo_adv_report *ev; + struct ble_hci_ev *hci_ev; + + if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_BIGINFO_ADV_REPORT)) { + return; + } + + hci_ev = ble_transport_alloc_evt(1); + if (!hci_ev) { + return; + } + + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*ev); + ev = (void *) hci_ev->data; + + ev->subev_code = BLE_HCI_LE_SUBEV_BIGINFO_ADV_REPORT; + ev->sync_handle = htole16(ble_ll_sync_get_handle(sm)); + ble_ll_sync_parse_biginfo_to_ev(ev, biginfo, biginfo_len); + + ble_ll_hci_event_send(hci_ev); +} +#endif + static void ble_ll_sync_send_per_adv_rpt(struct ble_ll_sync_sm *sm, struct os_mbuf *rxpdu, int8_t rssi, int8_t tx_power, int datalen, @@ -705,7 +771,7 @@ ble_ll_sync_send_per_adv_rpt(struct ble_ll_sync_sm *sm, struct os_mbuf *rxpdu, ev->rssi = rssi; ev->cte_type = 0xff; - ev->data_len = min(max_data_len, datalen - offset); + ev->data_len = MIN(max_data_len, datalen - offset); /* adjust event length */ hci_ev->length += ev->data_len; @@ -786,7 +852,7 @@ ble_ll_sync_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) ble_ll_rx_pdu_in(rxpdu); } else { STATS_INC(ble_ll_stats, sync_rx_buf_err); - ble_ll_event_send(&g_ble_ll_sync_sm_current->sync_ev_end); + ble_ll_event_add(&g_ble_ll_sync_sm_current->sync_ev_end); } /* PHY is disabled here */ @@ -809,7 +875,7 @@ ble_ll_sync_wfr_timer_exp(void) STATS_INC(ble_ll_stats, sync_missed_err); ble_ll_sync_current_sm_over(); - ble_ll_event_send(&sm->sync_ev_end); + ble_ll_event_add(&sm->sync_ev_end); } /** @@ -826,7 +892,7 @@ ble_ll_sync_halt(void) ble_ll_sync_current_sm_over(); if (sm) { - ble_ll_event_send(&sm->sync_ev_end); + ble_ll_event_add(&sm->sync_ev_end); } } @@ -881,6 +947,26 @@ ble_ll_sync_parse_aux_ptr(const uint8_t *buf, uint8_t *chan, uint32_t *offset, *phy = (aux_ptr_field >> 21) & 0x07; } +static void +ble_ll_sync_sched_set(struct ble_ll_sched_item *sch, uint32_t start_ticks, + uint8_t start_rem_us, uint32_t offset, uint8_t phy_mode) +{ + uint32_t duration_us; + uint32_t duration; + + if (offset > 0) { + ble_ll_tmr_add(&start_ticks, &start_rem_us, offset); + } + + duration_us = ble_ll_pdu_us(MYNEWT_VAL(BLE_LL_SCHED_SCAN_SYNC_PDU_LEN), + phy_mode); + duration = ble_ll_tmr_u2t(duration_us); + + sch->start_time = start_ticks - g_ble_ll_sched_offset_ticks; + sch->remainder = start_rem_us; + sch->end_time = start_ticks + duration; +} + static int ble_ll_sync_schedule_chain(struct ble_ll_sync_sm *sm, struct ble_mbuf_hdr *hdr, const uint8_t *aux) @@ -915,8 +1001,10 @@ ble_ll_sync_schedule_chain(struct ble_ll_sync_sm *sm, struct ble_mbuf_hdr *hdr, sm->flags |= BLE_LL_SYNC_SM_FLAG_CHAIN; - return ble_ll_sched_sync(&sm->sch, hdr->beg_cputime, hdr->rem_usecs, - offset, sm->phy_mode); + ble_ll_sync_sched_set(&sm->sch, hdr->beg_cputime, hdr->rem_usecs, offset, + sm->phy_mode); + + return ble_ll_sched_sync(&sm->sch); } static void @@ -965,7 +1053,8 @@ ble_ll_sync_check_failed(struct ble_ll_sync_sm *sm) static bool ble_ll_sync_check_acad(struct ble_ll_sync_sm *sm, - const uint8_t *acad, uint8_t acad_len) + const uint8_t *acad, uint8_t acad_len, + const uint8_t **biginfo, uint8_t *biginfo_len) { const struct ble_ll_acad_channel_map_update_ind *chmu; unsigned int ad_len; @@ -997,20 +1086,32 @@ ble_ll_sync_check_acad(struct ble_ll_sync_sm *sm, /* Channels Mask (37 bits) * TODO should we check this? */ - sm->chanmap_new[0] = chmu->map[0]; - sm->chanmap_new[1] = chmu->map[1]; - sm->chanmap_new[2] = chmu->map[2]; - sm->chanmap_new[3] = chmu->map[3]; - sm->chanmap_new[4] = chmu->map[4] & 0x1f; + sm->chan_map_new[0] = chmu->map[0]; + sm->chan_map_new[1] = chmu->map[1]; + sm->chan_map_new[2] = chmu->map[2]; + sm->chan_map_new[3] = chmu->map[3]; + sm->chan_map_new[4] = chmu->map[4] & 0x1f; /* drop if channel map is invalid */ - if (ble_ll_utils_calc_num_used_chans(sm->chanmap_new) == 0) { + if (ble_ll_utils_chan_map_used_get(sm->chan_map_new) == 0) { return false; } - sm->chanmap_new_instant = le16toh(chmu->instant); + sm->chan_map_new_instant = le16toh(chmu->instant); sm->flags |= BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP; break; + +#if MYNEWT_VAL(BLE_LL_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + case BLE_LL_ACAD_BIGINFO: + if ((ad_len - 1 == BLE_LL_SYNC_BIGINFO_LEN) || (ad_len - 1 == BLE_LL_SYNC_BIGINFO_LEN_ENC)) { + *biginfo = &acad[2]; + *biginfo_len = ad_len - 1; + } else { + return false; + } + break; +#endif + default: break; } @@ -1036,6 +1137,8 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) uint8_t *aux = NULL; uint8_t *acad = NULL; uint8_t acad_len; + const uint8_t *biginfo = NULL; + uint8_t biginfo_len = 0; int datalen; bool reports_enabled; @@ -1101,7 +1204,7 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) } /* check ACAD, needs to be done before rxpdu is adjusted for ADV data */ - if (acad && !ble_ll_sync_check_acad(sm, acad, acad_len)) { + if (acad && !ble_ll_sync_check_acad(sm, acad, acad_len, &biginfo, &biginfo_len)) { /* we got bad packet (bad ACAD data), end event */ goto end_event; } @@ -1119,6 +1222,12 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) /* send reports from this PDU */ ble_ll_sync_send_per_adv_rpt(sm, rxpdu, hdr->rxinfo.rssi, tx_power, datalen, aux, aux_scheduled); + +#if MYNEWT_VAL(BLE_LL_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + if (biginfo) { + ble_ll_sync_send_biginfo_adv_rpt(sm, biginfo, biginfo_len); + } +#endif } /* if chain was scheduled we don't end event yet */ @@ -1130,7 +1239,7 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) } end_event: - ble_ll_event_send(&sm->sync_ev_end); + ble_ll_event_add(&sm->sync_ev_end); ble_ll_rfmgmt_release(); } @@ -1165,21 +1274,21 @@ ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust) /* update channel map if needed */ if (sm->flags & BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP) { - if (((int16_t)(sm->event_cntr - sm->chanmap_new_instant)) >= 0) { + if (((int16_t)(sm->event_cntr - sm->chan_map_new_instant)) >= 0) { /* map was verified on reception */ - sm->chanmap[0] = sm->chanmap_new[0]; - sm->chanmap[1] = sm->chanmap_new[1]; - sm->chanmap[2] = sm->chanmap_new[2]; - sm->chanmap[3] = sm->chanmap_new[3]; - sm->chanmap[4] = sm->chanmap_new[4]; - sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap); + sm->chan_map[0] = sm->chan_map_new[0]; + sm->chan_map[1] = sm->chan_map_new[1]; + sm->chan_map[2] = sm->chan_map_new[2]; + sm->chan_map[3] = sm->chan_map_new[3]; + sm->chan_map[4] = sm->chan_map_new[4]; + sm->chan_map_used = ble_ll_utils_chan_map_used_get(sm->chan_map); sm->flags &= ~BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP; } } /* Calculate channel index of next event */ sm->chan_index = ble_ll_utils_dci_csa2(sm->event_cntr, sm->channel_id, - sm->num_used_chans, sm->chanmap); + sm->chan_map_used, sm->chan_map); cur_ww = ble_ll_utils_calc_window_widening(sm->anchor_point, sm->last_anchor_point, @@ -1234,7 +1343,7 @@ ble_ll_sync_event_end(struct ble_npl_event *ev) ble_ll_scan_chk_resume(); /* Remove any end events that might be enqueued */ - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &sm->sync_ev_end); + ble_ll_event_remove(&sm->sync_ev_end); /* don't schedule next event if sync is not established nor establishing * at this point SM is no longer valid @@ -1272,9 +1381,10 @@ ble_ll_sync_event_end(struct ble_npl_event *ev) ble_ll_sync_sm_clear(sm); return; } - } while (ble_ll_sched_sync_reschedule(&sm->sch, sm->anchor_point, - sm->anchor_point_usecs, - sm->window_widening, sm->phy_mode)); + + ble_ll_sync_sched_set(&sm->sch, sm->anchor_point, + sm->anchor_point_usecs, 0, sm->phy_mode); + } while (ble_ll_sched_sync_reschedule(&sm->sch, sm->window_widening)); } void @@ -1373,12 +1483,12 @@ ble_ll_sync_info_event(struct ble_ll_scan_addr_data *addrd, sm->itvl_ticks = ble_ll_tmr_u2t_r(usecs, &sm->itvl_usecs); /* Channels Mask (37 bits) */ - sm->chanmap[0] = syncinfo[4]; - sm->chanmap[1] = syncinfo[5]; - sm->chanmap[2] = syncinfo[6]; - sm->chanmap[3] = syncinfo[7]; - sm->chanmap[4] = syncinfo[8] & 0x1f; - sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap); + sm->chan_map[0] = syncinfo[4]; + sm->chan_map[1] = syncinfo[5]; + sm->chan_map[2] = syncinfo[6]; + sm->chan_map[3] = syncinfo[7]; + sm->chan_map[4] = syncinfo[8] & 0x1f; + sm->chan_map_used = ble_ll_utils_chan_map_used_get(sm->chan_map); /* SCA (3 bits) */ sm->sca = syncinfo[8] >> 5; @@ -1410,10 +1520,12 @@ ble_ll_sync_info_event(struct ble_ll_scan_addr_data *addrd, /* Calculate channel index of first event */ sm->chan_index = ble_ll_utils_dci_csa2(sm->event_cntr, sm->channel_id, - sm->num_used_chans, sm->chanmap); + sm->chan_map_used, sm->chan_map); - if (ble_ll_sched_sync(&sm->sch, rxhdr->beg_cputime, rxhdr->rem_usecs, - offset, sm->phy_mode)) { + ble_ll_sync_sched_set(&sm->sch, rxhdr->beg_cputime, rxhdr->rem_usecs, + offset, sm->phy_mode); + + if (ble_ll_sched_sync(&sm->sch)) { return; } @@ -1560,13 +1672,13 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len) } static void -ble_ll_sync_cancel_complete_event(void) +ble_ll_sync_cancel_complete_event(void *user_data) { ble_ll_sync_est_event_failed(BLE_ERR_OPERATION_CANCELLED); } int -ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) +ble_ll_sync_cancel(void) { struct ble_ll_sync_sm *sm; os_sr_t sr; @@ -1597,7 +1709,7 @@ ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) OS_EXIT_CRITICAL(sr); /* g_ble_ll_sync_create_comp_ev will be cleared by this callback */ - *post_cmd_cb = ble_ll_sync_cancel_complete_event; + ble_ll_hci_post_cmd_cb_set(ble_ll_sync_cancel_complete_event, NULL); return BLE_ERR_SUCCESS; } @@ -1717,7 +1829,7 @@ ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len) int ble_ll_sync_list_clear(void) { - int i; + unsigned int i; if (g_ble_ll_sync_create_comp_ev) { return BLE_ERR_CMD_DISALLOWED; @@ -1945,12 +2057,12 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, sm->itvl_ticks = ble_ll_tmr_u2t_r(itvl_usecs, &sm->itvl_usecs); /* Channels Mask (37 bits) */ - sm->chanmap[0] = syncinfo[4]; - sm->chanmap[1] = syncinfo[5]; - sm->chanmap[2] = syncinfo[6]; - sm->chanmap[3] = syncinfo[7]; - sm->chanmap[4] = syncinfo[8] & 0x1f; - sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap); + sm->chan_map[0] = syncinfo[4]; + sm->chan_map[1] = syncinfo[5]; + sm->chan_map[2] = syncinfo[6]; + sm->chan_map[3] = syncinfo[7]; + sm->chan_map[4] = syncinfo[8] & 0x1f; + sm->chan_map_used = ble_ll_utils_chan_map_used_get(sm->chan_map); /* SCA (3 bits) */ sm->sca = syncinfo[8] >> 5; @@ -1978,7 +2090,7 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, /* Calculate channel index of first event */ sm->chan_index = ble_ll_utils_dci_csa2(sm->event_cntr, sm->channel_id, - sm->num_used_chans, sm->chanmap); + sm->chan_map_used, sm->chan_map); /* get anchor for specified conn event */ conn_event_count = get_le16(sync_ind + 20); @@ -2007,8 +2119,10 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, } } - if (ble_ll_sched_sync(&sm->sch, sm->anchor_point, sm->anchor_point_usecs, - offset, sm->phy_mode)) { + ble_ll_sync_sched_set(&sm->sch, sm->anchor_point, sm->anchor_point_usecs, + offset, sm->phy_mode); + + if (ble_ll_sched_sync(&sm->sch)) { /* release SM if this failed */ ble_ll_sync_transfer_received(sm, BLE_ERR_CONN_ESTABLISHMENT); memset(sm, 0, sizeof(*sm)); @@ -2075,11 +2189,11 @@ ble_ll_sync_put_syncinfo(struct ble_ll_sync_sm *syncsm, put_le16(&dptr[2], syncsm->itvl); /* Channels Mask (37 bits) */ - dptr[4] = syncsm->chanmap[0]; - dptr[5] = syncsm->chanmap[1]; - dptr[6] = syncsm->chanmap[2]; - dptr[7] = syncsm->chanmap[3]; - dptr[8] = syncsm->chanmap[4] & 0x1f; + dptr[4] = syncsm->chan_map[0]; + dptr[5] = syncsm->chan_map[1]; + dptr[6] = syncsm->chan_map[2]; + dptr[7] = syncsm->chan_map[3]; + dptr[8] = syncsm->chan_map[4] & 0x1f; /* SCA (3 bits) */ dptr[8] |= syncsm->sca << 5; @@ -2186,32 +2300,30 @@ ble_ll_sync_transfer(const uint8_t *cmdbuf, uint8_t len, if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) { rc = BLE_ERR_UNK_ADV_INDENT; - OS_EXIT_CRITICAL(sr); - goto done; + goto exit_crit; } handle = le16toh(cmd->conn_handle); if (handle > 0xeff) { rc = BLE_ERR_INV_HCI_CMD_PARMS; - OS_EXIT_CRITICAL(sr); - goto done; + goto exit_crit; } connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; - OS_EXIT_CRITICAL(sr); - goto done; + goto exit_crit; } /* Allow initiate LL procedure only if remote supports it. */ if (!ble_ll_conn_rem_feature_check(connsm, BLE_LL_FEAT_SYNC_TRANS_RECV)) { rc = BLE_ERR_UNSUPP_REM_FEATURE; - goto done; + goto exit_crit; } rc = ble_ll_sync_send_sync_ind(sm, connsm, cmd->service_data); +exit_crit: OS_EXIT_CRITICAL(sr); done: rsp->conn_handle = cmd->conn_handle; @@ -2227,7 +2339,7 @@ done: void ble_ll_sync_rmvd_from_sched(struct ble_ll_sync_sm *sm) { - ble_ll_event_send(&sm->sync_ev_end); + ble_ll_event_add(&sm->sync_ev_end); } bool @@ -2244,7 +2356,7 @@ ble_ll_sync_enabled(void) void ble_ll_sync_reset(void) { - int i; + unsigned int i; for (i = 0; i < BLE_LL_SYNC_CNT; i++) { ble_ll_sync_sm_clear(&g_ble_ll_sync_sm[i]); @@ -2270,7 +2382,7 @@ ble_ll_sync_reset(void) void ble_ll_sync_init(void) { - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { g_ble_ll_sync_adv_list[i].adv_sid = 0xff; diff --git a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_utils.c b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_utils.c index a2507ad2..9fa32f8f 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_utils.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/src/ble_ll_utils.c @@ -32,10 +32,9 @@ static const uint16_t g_ble_sca_ppm_tbl[8] = { 500, 250, 150, 100, 75, 50, 30, 20 }; -uint32_t -ble_ll_utils_calc_access_addr(void) +int +ble_ll_utils_verify_aa(uint32_t aa) { - uint32_t aa; uint16_t aa_low; uint16_t aa_high; uint32_t temp; @@ -47,105 +46,175 @@ ble_ll_utils_calc_access_addr(void) uint8_t ones; int tmp; - /* Calculate a random access address */ - aa = 0; - while (1) { - /* Get two, 16-bit random numbers */ - aa_low = ble_ll_rand() & 0xFFFF; - aa_high = ble_ll_rand() & 0xFFFF; + aa_low = aa & 0xffff; + aa_high = aa >> 16; - /* All four bytes cannot be equal */ - if (aa_low == aa_high) { - continue; - } + /* All four bytes cannot be equal */ + if (aa_low == aa_high) { + return 0; + } - /* Upper 6 bits must have 2 transitions */ - tmp = (int16_t)aa_high >> 10; - if (__builtin_popcount(tmp ^ (tmp >> 1)) < 2) { - continue; - } + /* Upper 6 bits must have 2 transitions */ + tmp = (int16_t)aa_high >> 10; + if (__builtin_popcount(tmp ^ (tmp >> 1)) < 2) { + return 0; + } - /* Cannot be access address or be 1 bit different */ - aa = aa_high; - aa = (aa << 16) | aa_low; - bits_diff = 0; - temp = aa ^ BLE_ACCESS_ADDR_ADV; - for (mask = 0x00000001; mask != 0; mask <<= 1) { - if (mask & temp) { - ++bits_diff; - if (bits_diff > 1) { - break; - } + /* Cannot be access address or be 1 bit different */ + aa = aa_high; + aa = (aa << 16) | aa_low; + bits_diff = 0; + temp = aa ^ BLE_ACCESS_ADDR_ADV; + for (mask = 0x00000001; mask != 0; mask <<= 1) { + if (mask & temp) { + ++bits_diff; + if (bits_diff > 1) { + break; } } - if (bits_diff <= 1) { - continue; - } + } + if (bits_diff <= 1) { + return 0; + } - /* Cannot have more than 24 transitions */ - transitions = 0; - consecutive = 1; - ones = 0; - mask = 0x00000001; - while (mask < 0x80000000) { - prev_bit = aa & mask; - mask <<= 1; - if (mask & aa) { - if (prev_bit == 0) { - ++transitions; - consecutive = 1; - } else { - ++consecutive; - } + /* Cannot have more than 24 transitions */ + transitions = 0; + consecutive = 1; + ones = 0; + mask = 0x00000001; + while (mask < 0x80000000) { + prev_bit = aa & mask; + mask <<= 1; + if (mask & aa) { + if (prev_bit == 0) { + ++transitions; + consecutive = 1; } else { - if (prev_bit == 0) { - ++consecutive; - } else { - ++transitions; - consecutive = 1; - } + ++consecutive; } - - if (prev_bit) { - ones++; + } else { + if (prev_bit == 0) { + ++consecutive; + } else { + ++transitions; + consecutive = 1; } + } - /* 8 lsb should have at least three 1 */ - if (mask == 0x00000100 && ones < 3) { - break; - } + if (prev_bit) { + ones++; + } - /* 16 lsb should have no more than 11 transitions */ - if (mask == 0x00010000 && transitions > 11) { - break; - } + /* 8 lsb should have at least three 1 */ + if (mask == 0x00000100 && ones < 3) { + break; + } - /* This is invalid! */ - if (consecutive > 6) { - /* Make sure we always detect invalid sequence below */ - mask = 0; - break; - } + /* 16 lsb should have no more than 11 transitions */ + if (mask == 0x00010000 && transitions > 11) { + break; + } + + /* This is invalid! */ + if (consecutive > 6) { + /* Make sure we always detect invalid sequence below */ + mask = 0; + break; + } + } + + /* Invalid sequence found */ + if (mask != 0x80000000) { + return 0; + } + + /* Cannot be more than 24 transitions */ + if (transitions > 24) { + return 0; + } + + return 1; +} + +uint32_t +ble_ll_utils_calc_aa(void) +{ + uint32_t aa; + + do { + aa = ble_ll_rand(); + } while (!ble_ll_utils_verify_aa(aa)); + + return aa; +} + +uint32_t +ble_ll_utils_calc_seed_aa(void) +{ + uint32_t seed_aa; + + while (1) { + seed_aa = ble_ll_rand(); + + /* saa(19) == saa(15) */ + if (!!(seed_aa & (1 << 19)) != !!(seed_aa & (1 << 15))) { + continue; + } + + /* saa(22) = saa(16) */ + if (!!(seed_aa & (1 << 22)) != !!(seed_aa & (1 << 16))) { + continue; + } + + /* saa(22) != saa(15) */ + if (!!(seed_aa & (1 << 22)) == !!(seed_aa & (1 << 15))) { + continue; } - /* Invalid sequence found */ - if (mask != 0x80000000) { + /* saa(25) == 0 */ + if (seed_aa & (1 << 25)) { continue; } - /* Cannot be more than 24 transitions */ - if (transitions > 24) { + /* saa(23) == 1 */ + if (!(seed_aa & (1 << 23))) { continue; } - /* We have a valid access address */ break; } - return aa; + + return seed_aa; +} + +uint32_t +ble_ll_utils_calc_big_aa(uint32_t seed_aa, uint32_t n) +{ + uint32_t d; + uint32_t dw; + + /* Core 5.3, Vol 6, Part B, 2.1.2 */ + /* TODO simplify? */ + d = ((35 * n) + 42) % 128; + dw = (!!(d & (1 << 0)) << 31) | + (!!(d & (1 << 0)) << 30) | + (!!(d & (1 << 0)) << 29) | + (!!(d & (1 << 0)) << 28) | + (!!(d & (1 << 0)) << 27) | + (!!(d & (1 << 0)) << 26) | + (!!(d & (1 << 1)) << 25) | + (!!(d & (1 << 6)) << 24) | + (!!(d & (1 << 1)) << 23) | + (!!(d & (1 << 5)) << 21) | + (!!(d & (1 << 4)) << 20) | + (!!(d & (1 << 3)) << 18) | + (!!(d & (1 << 2)) << 17); + + return seed_aa ^ dw; } uint8_t -ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap) +ble_ll_utils_chan_map_remap(const uint8_t *chan_map, uint8_t remap_index) { uint8_t cntr; uint8_t mask; @@ -160,7 +229,7 @@ ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap) chan = 0; cntr = 0; for (i = 0; i < BLE_LL_CHMAP_LEN; i++) { - usable_chans = chanmap[i]; + usable_chans = chan_map[i]; if (usable_chans != 0) { mask = 0x01; for (j = 0; j < 8; j++) { @@ -182,23 +251,10 @@ ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap) } uint8_t -ble_ll_utils_calc_num_used_chans(const uint8_t *chan_map) +ble_ll_utils_chan_map_used_get(const uint8_t *chan_map) { - uint32_t u32 = 0; - uint32_t num_used_chans = 0; - unsigned idx; - - for (idx = 0; idx < 37; idx++) { - if ((idx % 8) == 0) { - u32 = chan_map[idx / 8]; - } - if (u32 & 1) { - num_used_chans++; - } - u32 >>= 1; - } - - return num_used_chans; + return __builtin_popcountll(((uint64_t)(chan_map[4] & 0x1f) << 32) | + get_le32(chan_map)); } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) @@ -356,7 +412,7 @@ ble_ll_utils_dci_csa2(uint16_t counter, uint16_t chan_id, uint16_t ble_ll_utils_dci_iso_event(uint16_t counter, uint16_t chan_id, - uint16_t *prn_sub_lu, uint8_t num_used_chans, + uint16_t *prn_sub_lu, uint8_t chan_map_used, const uint8_t *chan_map, uint16_t *remap_idx) { uint16_t prn_s; @@ -368,7 +424,7 @@ ble_ll_utils_dci_iso_event(uint16_t counter, uint16_t chan_id, *prn_sub_lu = prn_s; - chan_idx = ble_ll_utils_csa2_calc_chan_idx(prn_e, num_used_chans, chan_map, + chan_idx = ble_ll_utils_csa2_calc_chan_idx(prn_e, chan_map_used, chan_map, remap_idx); return chan_idx; @@ -376,7 +432,7 @@ ble_ll_utils_dci_iso_event(uint16_t counter, uint16_t chan_id, uint16_t ble_ll_utils_dci_iso_subevent(uint16_t chan_id, uint16_t *prn_sub_lu, - uint8_t num_used_chans, const uint8_t *chan_map, + uint8_t chan_map_used, const uint8_t *chan_map, uint16_t *remap_idx) { uint16_t prn_sub_se; @@ -389,10 +445,10 @@ ble_ll_utils_dci_iso_subevent(uint16_t chan_id, uint16_t *prn_sub_lu, /* Core 5.3, Vol 6, Part B, 4.5.8.3.6 (enjoy!) */ /* TODO optimize this somehow */ - d = max(1, max(min(3, num_used_chans - 5), - min(11, (num_used_chans - 10) / 2))); + d = MAX(1, MAX(MIN(3, chan_map_used - 5), + MIN(11, (chan_map_used - 10) / 2))); *remap_idx = (*remap_idx + d + prn_sub_se * - (num_used_chans - 2 * d + 1) / 65536) % num_used_chans; + (chan_map_used - 2 * d + 1) / 65536) % chan_map_used; chan_idx = ble_ll_utils_csa2_remap2chan(*remap_idx, chan_map); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/syscfg.defunct.yml b/lib/bt/host/nimble/nimble/nimble/controller/syscfg.defunct.yml index da338458..23986128 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/syscfg.defunct.yml +++ b/lib/bt/host/nimble/nimble/nimble/controller/syscfg.defunct.yml @@ -42,6 +42,34 @@ syscfg.defs: description: use BLE_LL_SCAN_AUX_SEGMENT_CNT value: 0 deprecated: 1 + BLE_LL_MFRG_ID: + description: use BLE_LL_MANUFACTURER_ID + value: 0x0B65 + deprecated: 1 + BLE_LL_PA: + description: use BLE_FEM_PA + value: 0 + deprecated: 1 + BLE_LL_PA_GPIO: + description: use BLE_FEM_PA_GPIO + value: -1 + deprecated: 1 + BLE_LL_PA_TURN_ON_US: + description: use BLE_FEM_PA_TURN_ON_US + value: 1 + deprecated: 1 + BLE_LL_LNA: + description: use BLE_FEM_LNA + value: 0 + deprecated: 1 + BLE_LL_LNA_GPIO: + description: use BLE_FEM_LNA_GPIO + value: -1 + deprecated: 1 + BLE_LL_LNA_TURN_ON_US: + description: use BLE_FEM_LNA_TURN_ON_US + value: 1 + deprecated: 1 # defunct settings (to be removed eventually) BLE_DEVICE: diff --git a/lib/bt/host/nimble/nimble/nimble/controller/syscfg.hbd.yml b/lib/bt/host/nimble/nimble/nimble/controller/syscfg.hbd.yml index d5a05e14..ee5a86e9 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/syscfg.hbd.yml +++ b/lib/bt/host/nimble/nimble/nimble/controller/syscfg.hbd.yml @@ -23,3 +23,5 @@ syscfg.defs: device. It can be initialized and used by Windows 10 to some extent. value: 0 + restrictions: + - '(BLE_TRANSPORT_EVT_SIZE == 257) if 1' diff --git a/lib/bt/host/nimble/nimble/nimble/controller/syscfg.yml b/lib/bt/host/nimble/nimble/nimble/controller/syscfg.yml index 6ff7bdb3..f02b04df 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/syscfg.yml +++ b/lib/bt/host/nimble/nimble/nimble/controller/syscfg.yml @@ -69,16 +69,24 @@ syscfg.defs: may be rounded up or down depending on used radio. value: '0' + BLE_LL_TX_PWR_MAX_DBM: + description: > + Maximum allowed transmit power level (in dBm). This limits maximum + power to specified value (including FEM and/or host compensation). + Useful for ensuring selected power class of device. Defaults to + maximum allowed by specification (Power Class 1). + value: '20' + BLE_LL_NUM_COMP_PKT_ITVL_MS: description: > Determines the interval at which the controller will send the number of completed packets event to the host. Rate is in milliseconds. value: 2000 - BLE_LL_MFRG_ID: + BLE_LL_MANUFACTURER_ID: description: > - Manufacturer ID. Should be set to unique ID per manufacturer. - value: '0xFFFF' + Manufacturer ID, as assigned by Bluetooth SIG + value: MYNEWT_VAL(BLE_LL_MFRG_ID) # Configuration items for the number of duplicate advertisers and the # number of advertisers from which we have heard a scan response. @@ -132,11 +140,15 @@ syscfg.defs: BLE_LL_CONN_INIT_MAX_TX_BYTES: description: > Used to set the initial maximum transmit PDU size in a - connection. If this is set to a value greater than 27, - the controller will automatically attempt to do the - data length update procedure. The host can always tell - the controller to update this value. + connection. The host can always tell the controller to update this + value. value: '27' + BLE_LL_CONN_INIT_AUTO_DLE: + description: > + If BLE_LL_CONN_INIT_MAX_TX_BYTES is set to value greater than 27 + controller will automatically attempt to do the data length update + procedure. + value: 1 # The number of slots that will be allocated to each connection BLE_LL_CONN_INIT_SLOTS: @@ -351,6 +363,13 @@ syscfg.defs: restrictions: - 'BLE_LL_CFG_FEAT_LL_ISO if 1' + BLE_LL_PERIODIC_ADV_SYNC_BIGINFO_REPORTS: + description: > + This option is used to enable/disable support for + handling BIGInfo data + value: MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + experimental: 1 + BLE_LL_SCAN_AUX_SEGMENT_CNT: description: > Number of auxiliary advertising segments that can be scanned @@ -406,22 +425,69 @@ syscfg.defs: line number where assertion occured. value: MYNEWT_VAL(BLE_LL_VND_EVENT_ON_ASSERT) - BLE_LL_PA: - description: Enable PA support + BLE_FEM_PA: + description: Enable FEM PA support + value: MYNEWT_VAL(BLE_LL_PA) + BLE_FEM_PA_GAIN: + description: PA fixed TX gain (in dBm). + value: 0 + BLE_FEM_PA_GAIN_TUNABLE: + description: > + PA TX gain is tunable and not constant. If enabled + ble_fem_pa_tx_power_set() and ble_fem_pa_tx_power_round() + shall be implemented (see ble_fem.h for details). value: 0 - BLE_LL_PA_GPIO: + BLE_FEM_PA_GPIO: description: > GPIO pin number to control PA. Pin is set to high state when PA should be enabled. - value: -1 - BLE_LL_LNA: + value: MYNEWT_VAL(BLE_LL_PA_GPIO) + BLE_FEM_PA_TURN_ON_US: + description: > + Time required for PA to turn on, in microseconds. + value: MYNEWT_VAL(BLE_LL_PA_TURN_ON_US) + BLE_FEM_LNA: description: Enable LNA support + value: MYNEWT_VAL(BLE_LL_LNA) + BLE_FEM_LNA_GAIN: + description: LNA fixed RX gain (in dBm). + value: 0 + BLE_FEM_LNA_GAIN_TUNABLE: + description: > + LNA RX gain is tunable and not constant. If enabled + ble_fem_lna_rx_gain() shall be implemented (see ble_fem.h for + details). value: 0 - BLE_LL_LNA_GPIO: + BLE_FEM_LNA_GPIO: description: > GPIO pin number to control LNA. Pin is set to high state when LNA should be enabled. - value: -1 + value: MYNEWT_VAL(BLE_LL_LNA_GPIO) + BLE_FEM_LNA_TURN_ON_US: + description: > + Time required for LNA to turn on, in microseconds. + value: MYNEWT_VAL(BLE_LL_LNA_TURN_ON_US) + BLE_FEM_ANTENNA: + description: > + Enable support for runtime antenna selection in FEM. + value: 0 + + BLE_LL_ISO: + description: > + Enable support for isochronous data. + This enables common code (e.g. ISOAL) for all types of isochronous + data, particular ISO features have to be enabled separately. + restrictions: + - (BLE_VERSION >= 52) if 1 + value: 0 + state: experimental + BLE_LL_ISO_BROADCASTER: + description: > + Enable support for Isochronous Broadcasting state. + restrictions: + - BLE_LL_ISO if 1 + value: 0 + state: experimental BLE_LL_SYSINIT_STAGE: description: > @@ -454,6 +520,12 @@ syscfg.defs: while rfmgmt is active. value: -1 + BLE_LL_EXT: + description: > + Enables API to support external (i.e. non-native to LL) state for + NimBLE LL and scheduler. See ble_ll_ext.h. + experimental: 1 + value: 0 # Below settings allow to change scheduler timings. These should be left at # default values unless you know what you are doing! BLE_LL_SCHED_AUX_MAFS_DELAY: @@ -493,6 +565,20 @@ syscfg.defs: range: 1..257 value: 32 + BLE_LL_CONN_EVENT_END_MARGIN: + description: > + Extra time needed for scheduling next connection event. Setting this + value results in ending connection event sooner (in microseconds) + which gives more time to schedule next event. This value should be + tuned only after measuring performance as depends on various factors + like build optimisation, cache, clock speed etc. + value: 0 + + BLE_LL_STACK_SIZE: + description: > + This is the stack size for LL task. + value: 120 + syscfg.vals.BLE_LL_CFG_FEAT_LL_EXT_ADV: BLE_LL_CFG_FEAT_LE_CSA2: 1 BLE_HW_WHITELIST_ENABLE: 0 @@ -500,14 +586,14 @@ syscfg.vals.BLE_LL_CFG_FEAT_LL_EXT_ADV: # Enable vendor event on assert in standalone build to make failed assertions in # controller code visible when connected to external host -syscfg.vals.!BLE_HOST: +syscfg.vals.'!BLE_HOST && !BABBLESIM': BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 syscfg.restrictions: - BLE_TRANSPORT_LL == "native" - BLE_LL_PUBLIC_DEV_ADDR <= 0xffffffffffff - - BLE_LL_PA == 0 || BLE_LL_PA_GPIO >= 0 - - BLE_LL_LNA == 0 || BLE_LL_LNA_GPIO >= 0 + - BLE_FEM_PA == 0 || BLE_FEM_PA_GPIO >= 0 + - BLE_FEM_LNA == 0 || BLE_FEM_LNA_GPIO >= 0 $import: # defunct and deprecated settings diff --git a/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_aa_test.c b/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_aa_test.c new file mode 100644 index 00000000..4d64d87a --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_aa_test.c @@ -0,0 +1,103 @@ +/* + * 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 +#include +#include + +TEST_CASE_SELF(ble_ll_aa_test_1) +{ + uint32_t seed_aa; + uint32_t aa; + + seed_aa = 0x78e52493; + + /* BIG Control */ + aa = ble_ll_utils_calc_big_aa(seed_aa, 0); + TEST_ASSERT(aa == 0x7a412493); + + /* BISes */ + aa = ble_ll_utils_calc_big_aa(seed_aa, 1); + TEST_ASSERT(aa == 0x85e32493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 2); + TEST_ASSERT(aa == 0x79d52493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 3); + TEST_ASSERT(aa == 0x86752493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 4); + TEST_ASSERT(aa == 0x7a572493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 5); + TEST_ASSERT(aa == 0x85f12493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 6); + TEST_ASSERT(aa == 0x79d32493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 7); + TEST_ASSERT(aa == 0x86732493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 8); + TEST_ASSERT(aa == 0x7b652493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 9); + TEST_ASSERT(aa == 0x85c72493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 10); + TEST_ASSERT(aa == 0x78e12493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 11); + TEST_ASSERT(aa == 0x86412493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 12); + TEST_ASSERT(aa == 0x7b632493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 13); + TEST_ASSERT(aa == 0x85d52493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 14); + TEST_ASSERT(aa == 0x78f72493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 15); + TEST_ASSERT(aa == 0x86572493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 16); + TEST_ASSERT(aa == 0x7b712493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 17); + TEST_ASSERT(aa == 0x85d32493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 18); + TEST_ASSERT(aa == 0x78c52493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 19); + TEST_ASSERT(aa == 0x87652493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 20); + TEST_ASSERT(aa == 0x7b472493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 21); + TEST_ASSERT(aa == 0x84e12493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 22); + TEST_ASSERT(aa == 0x78c32493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 23); + TEST_ASSERT(aa == 0x87632493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 24); + TEST_ASSERT(aa == 0x7b552493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 25); + TEST_ASSERT(aa == 0x84f72493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 26); + TEST_ASSERT(aa == 0x78d12493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 27); + TEST_ASSERT(aa == 0x87712493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 28); + TEST_ASSERT(aa == 0x7b532493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 29); + TEST_ASSERT(aa == 0x84c52493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 30); + TEST_ASSERT(aa == 0x79e72493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 31); + TEST_ASSERT(aa == 0x87472493); +} + +TEST_SUITE(ble_ll_aa_test_suite) +{ + ble_ll_aa_test_1(); +} diff --git a/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_crypto_test.c b/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_crypto_test.c new file mode 100644 index 00000000..a2e727a0 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_crypto_test.c @@ -0,0 +1,147 @@ +/* + * 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 +#include +#include + +TEST_CASE_SELF(ble_ll_crypto_test_h6) { + const uint8_t w[] = { + 0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, + 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b + }; + const uint8_t key_id[] = { 0x6c, 0x65, 0x62, 0x72 }; + const uint8_t ok[] = { + 0x2d, 0x9a, 0xe1, 0x02, 0xe7, 0x6d, 0xc9, 0x1c, + 0xe8, 0xd3, 0xa9, 0xe2, 0x80, 0xb1, 0x63, 0x99 + }; + uint8_t out[16]; + int rc; + + rc = ble_ll_crypto_h6(w, key_id, out); + TEST_ASSERT(rc == 0); + + rc = memcmp(out, ok, 16); + TEST_ASSERT(rc == 0); +} + +TEST_CASE_SELF(ble_ll_crypto_test_h7) { + const uint8_t salt[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x6D, 0x70, 0x31 + }; + const uint8_t w[] = { + 0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, + 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b + }; + const uint8_t ok[] = { + 0xfb, 0x17, 0x35, 0x97, 0xc6, 0xa3, 0xc0, 0xec, + 0xd2, 0x99, 0x8c, 0x2a, 0x75, 0xa5, 0x70, 0x11 + }; + uint8_t out[16]; + int rc; + + rc = ble_ll_crypto_h7(salt, w, out); + TEST_ASSERT(rc == 0); + + rc = memcmp(out, ok, 16); + TEST_ASSERT(rc == 0); +} + +TEST_CASE_SELF(ble_ll_crypto_test_h8) { + const uint8_t k[] = { + 0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, + 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b + }; + const uint8_t s[] = { + 0x15, 0x36, 0xd1, 0x8d, 0xe3, 0xd2, 0x0d, 0xf9, + 0x9b, 0x70, 0x44, 0xc1, 0x2f, 0x9e, 0xd5, 0xba + }; + const uint8_t key_id[] = { 0xcc, 0x03, 0x01, 0x48 }; + const uint8_t ok[] = { + 0xe5, 0xe5, 0xbe, 0xba, 0xae, 0x72, 0x28, 0xe7, + 0x22, 0xa3, 0x89, 0x04, 0xed, 0x35, 0x0f, 0x6d + }; + uint8_t out[16]; + int rc; + + rc = ble_ll_crypto_h8(k, s, key_id, out); + TEST_ASSERT(rc == 0); + + rc = memcmp(out, ok, 16); + TEST_ASSERT(rc == 0); +} + +TEST_CASE_SELF(ble_ll_crypto_test_gskd) { + const uint8_t broadcast_code[] = { + 0x00, 0x00, 0x00, 0x00, 0x65, 0x73, 0x75, 0x6f, + 0x48, 0x20, 0x65, 0x6e, 0x72, 0xb8, 0xc3, 0x42 + }; + const uint8_t gskd[] = { + 0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a, + 0x90, 0x0a, 0xfc, 0xfb, 0xee, 0xd4, 0xe7, 0x2a + }; + const uint8_t big1[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x42, 0x49, 0x47, 0x31 + }; + const uint8_t big2[] = { 0x42, 0x49, 0x47, 0x32 }; + const uint8_t big3[] = { 0x42, 0x49, 0x47, 0x33 }; + const uint8_t ok_igltk[] = { + 0x4c, 0x0d, 0xd7, 0x4c, 0x2b, 0x19, 0xaa, 0x95, + 0xd8, 0x98, 0x23, 0x85, 0x5f, 0x10, 0x01, 0xb8 + }; + const uint8_t ok_gltk[] = { + 0xc4, 0xcd, 0x4b, 0x83, 0x49, 0xb5, 0xa1, 0x8a, + 0x02, 0xde, 0x66, 0x20, 0x90, 0x17, 0xae, 0xd3 + }; + const uint8_t ok_gsk[] = { + 0xbe, 0x2a, 0x16, 0xfc, 0x7a, 0xc4, 0x64, 0xe7, + 0x52, 0x30, 0x1b, 0xcc, 0xc8, 0x18, 0x81, 0x2c + }; + uint8_t igltk[16]; + uint8_t gltk[16]; + uint8_t gsk[16]; + int rc; + + rc = ble_ll_crypto_h7(big1, broadcast_code, igltk); + TEST_ASSERT(rc == 0); + + rc = memcmp(igltk, ok_igltk, 16); + TEST_ASSERT(rc == 0); + + rc = ble_ll_crypto_h6(igltk, big2, gltk); + TEST_ASSERT(rc == 0); + + rc = memcmp(gltk, ok_gltk, 16); + TEST_ASSERT(rc == 0); + + rc = ble_ll_crypto_h8(gltk, gskd, big3, gsk); + TEST_ASSERT(rc == 0); + + rc = memcmp(gsk, ok_gsk, 16); + TEST_ASSERT(rc == 0); +} + +TEST_SUITE(ble_ll_crypto_test_suite) { + ble_ll_crypto_test_h6(); + ble_ll_crypto_test_h7(); + ble_ll_crypto_test_h8(); + ble_ll_crypto_test_gskd(); +} diff --git a/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_csa2_test.c b/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_csa2_test.c index 566500e3..7939367e 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_csa2_test.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_csa2_test.c @@ -17,13 +17,10 @@ * under the License. */ -#include -#include -#include "testutil/testutil.h" -#include "controller/ble_ll_test.h" -#include "controller/ble_ll_conn.h" -#include "controller/ble_ll_utils.h" -#include "ble_ll_csa2_test.h" +#include +#include +#include +#include TEST_CASE_SELF(ble_ll_csa2_test_1) { @@ -37,8 +34,7 @@ TEST_CASE_SELF(ble_ll_csa2_test_1) */ memset(&conn, 0, sizeof(conn)); - - CONN_F_CSA2_SUPP(&conn) = 1; + conn.flags.csa2 = 1; /* * based on sample data from CoreSpec 5.0 Vol 6 Part C 3.1 @@ -47,12 +43,12 @@ TEST_CASE_SELF(ble_ll_csa2_test_1) conn.channel_id = ((0x8e89bed6 & 0xffff0000) >> 16) ^ (0x8e89bed6 & 0x0000ffff); - conn.num_used_chans = 37; - conn.chanmap[0] = 0xff; - conn.chanmap[1] = 0xff; - conn.chanmap[2] = 0xff; - conn.chanmap[3] = 0xff; - conn.chanmap[4] = 0x1f; + conn.chan_map_used = 37; + conn.chan_map[0] = 0xff; + conn.chan_map[1] = 0xff; + conn.chan_map[2] = 0xff; + conn.chan_map[3] = 0xff; + conn.chan_map[4] = 0x1f; conn.event_cntr = 1; rc = ble_ll_conn_calc_dci(&conn, 0); @@ -79,8 +75,7 @@ TEST_CASE_SELF(ble_ll_csa2_test_2) */ memset(&conn, 0, sizeof(conn)); - - CONN_F_CSA2_SUPP(&conn) = 1; + conn.flags.csa2 = 1; /* * based on sample data from CoreSpec 5.0 Vol 6 Part C 3.2 @@ -89,12 +84,12 @@ TEST_CASE_SELF(ble_ll_csa2_test_2) conn.channel_id = ((0x8e89bed6 & 0xffff0000) >> 16) ^ (0x8e89bed6 & 0x0000ffff); - conn.num_used_chans = 9; - conn.chanmap[0] = 0x00; - conn.chanmap[1] = 0x06; - conn.chanmap[2] = 0xe0; - conn.chanmap[3] = 0x00; - conn.chanmap[4] = 0x1e; + conn.chan_map_used = 9; + conn.chan_map[0] = 0x00; + conn.chan_map[1] = 0x06; + conn.chan_map[2] = 0xe0; + conn.chan_map[3] = 0x00; + conn.chan_map[4] = 0x1e; conn.event_cntr = 6; rc = ble_ll_conn_calc_dci(&conn, 0); @@ -112,7 +107,7 @@ TEST_CASE_SELF(ble_ll_csa2_test_2) TEST_CASE_SELF(ble_ll_csa2_test_3) { uint8_t chan_map[5]; - uint8_t num_used_chans; + uint8_t chan_map_used; uint16_t chan_id; uint16_t prn_sub_lu; uint16_t chan_idx; @@ -124,86 +119,86 @@ TEST_CASE_SELF(ble_ll_csa2_test_3) chan_map[2] = 0xff; chan_map[3] = 0xff; chan_map[4] = 0x1f; - num_used_chans = ble_ll_utils_calc_num_used_chans(chan_map); - TEST_ASSERT(num_used_chans == 37); + chan_map_used = ble_ll_utils_chan_map_used_get(chan_map); + TEST_ASSERT(chan_map_used == 37); chan_id = 0x305f; - chan_idx = ble_ll_utils_dci_iso_event(0, chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_event(0, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 56857); TEST_ASSERT(chan_idx == 25); TEST_ASSERT(remap_idx == 25); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 11710); TEST_ASSERT(chan_idx == 1); TEST_ASSERT(remap_idx == 1); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 16649); TEST_ASSERT(chan_idx == 16); TEST_ASSERT(remap_idx == 16); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 38198); TEST_ASSERT(chan_idx == 36); TEST_ASSERT(remap_idx == 36); - chan_idx = ble_ll_utils_dci_iso_event(1, chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_event(1, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 1685); TEST_ASSERT(chan_idx == 20); TEST_ASSERT(remap_idx == 20); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 20925); TEST_ASSERT(chan_idx == 36); TEST_ASSERT(remap_idx == 36); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 11081); TEST_ASSERT(chan_idx == 12); TEST_ASSERT(remap_idx == 12); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 48920); TEST_ASSERT(chan_idx == 34); TEST_ASSERT(remap_idx == 34); - chan_idx = ble_ll_utils_dci_iso_event(2, chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_event(2, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 38301); TEST_ASSERT(chan_idx == 6); TEST_ASSERT(remap_idx == 6); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 6541); TEST_ASSERT(chan_idx == 18); TEST_ASSERT(remap_idx == 18); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 14597); TEST_ASSERT(chan_idx == 32); TEST_ASSERT(remap_idx == 32); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 62982); TEST_ASSERT(chan_idx == 21); TEST_ASSERT(remap_idx == 21); - chan_idx = ble_ll_utils_dci_iso_event(3, chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_event(3, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 27475); TEST_ASSERT(chan_idx == 21); TEST_ASSERT(remap_idx == 21); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 40400); TEST_ASSERT(chan_idx == 4); TEST_ASSERT(remap_idx == 4); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 30015); TEST_ASSERT(chan_idx == 22); TEST_ASSERT(remap_idx == 22); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 49818); TEST_ASSERT(chan_idx == 8); TEST_ASSERT(remap_idx == 8); @@ -214,66 +209,66 @@ TEST_CASE_SELF(ble_ll_csa2_test_3) chan_map[2] = 0xe0; chan_map[3] = 0x00; chan_map[4] = 0x1e; - num_used_chans = ble_ll_utils_calc_num_used_chans(chan_map); - TEST_ASSERT(num_used_chans == 9); + chan_map_used = ble_ll_utils_chan_map_used_get(chan_map); + TEST_ASSERT(chan_map_used == 9); chan_id = 0x305f; - chan_idx = ble_ll_utils_dci_iso_event(6, chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_event(6, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 10975); TEST_ASSERT(chan_idx == 23); TEST_ASSERT(remap_idx == 4); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 14383); TEST_ASSERT(chan_idx == 35); TEST_ASSERT(remap_idx == 7); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 28946); TEST_ASSERT(chan_idx == 21); TEST_ASSERT(remap_idx == 2); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 61038); TEST_ASSERT(chan_idx == 36); TEST_ASSERT(remap_idx == 8); - chan_idx = ble_ll_utils_dci_iso_event(7, chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_event(7, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 5490); TEST_ASSERT(chan_idx == 9); TEST_ASSERT(remap_idx == 0); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 4108); TEST_ASSERT(chan_idx == 22); TEST_ASSERT(remap_idx == 3); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 45462); TEST_ASSERT(chan_idx == 36); TEST_ASSERT(remap_idx == 8); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 64381); TEST_ASSERT(chan_idx == 33); TEST_ASSERT(remap_idx == 5); - chan_idx = ble_ll_utils_dci_iso_event(8, chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_event(8, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 46970); TEST_ASSERT(chan_idx == 34); TEST_ASSERT(remap_idx == 6); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 7196); TEST_ASSERT(chan_idx == 9); TEST_ASSERT(remap_idx == 0); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 33054); TEST_ASSERT(chan_idx == 33); TEST_ASSERT(remap_idx == 5); - chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, num_used_chans, chan_map, &remap_idx); + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); TEST_ASSERT((prn_sub_lu ^ chan_id) == 42590); TEST_ASSERT(chan_idx == 10); TEST_ASSERT(remap_idx == 1); diff --git a/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_test.c b/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_test.c index ee089afe..2b36cb1f 100644 --- a/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_test.c +++ b/lib/bt/host/nimble/nimble/nimble/controller/test/src/ble_ll_test.c @@ -17,19 +17,22 @@ * under the License. */ -#include "sysinit/sysinit.h" -#include "syscfg/syscfg.h" -#include "controller/ble_ll_test.h" -#include "os/os.h" -#include "testutil/testutil.h" -#include "ble_ll_csa2_test.h" +#include +#include #if MYNEWT_VAL(SELFTEST) +TEST_SUITE_DECL(ble_ll_aa_test_suite); +TEST_SUITE_DECL(ble_ll_crypto_test_suite); +TEST_SUITE_DECL(ble_ll_csa2_test_suite); + int main(int argc, char **argv) { + ble_ll_aa_test_suite(); + ble_ll_crypto_test_suite(); ble_ll_csa2_test_suite(); + return tu_any_failed; } diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_hw.c b/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_hw.c index a2724b68..195dcd35 100644 --- a/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_hw.c +++ b/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_hw.c @@ -23,7 +23,7 @@ #include "nimble/ble.h" #include "controller/ble_hw.h" #include "CMAC.h" -#include "cmac_driver/cmac_shared.h" +#include #include "tinycrypt/aes.h" static struct tc_aes_key_sched_struct g_ctx; diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_phy.c b/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_phy.c index 1e6a3c99..938455bb 100644 --- a/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_phy.c +++ b/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_phy.c @@ -27,7 +27,7 @@ #include "nimble/ble.h" #include "mcu/mcu.h" #include "mcu/cmac_timer.h" -#include "cmac_driver/cmac_shared.h" +#include #include "controller/ble_phy.h" #include "controller/ble_ll.h" #include "stats/stats.h" @@ -310,6 +310,7 @@ static bool ble_phy_rx_start_isr(void); static void ble_phy_rx_setup_fields(void); static void ble_phy_rx_setup_xcvr(void); static void ble_phy_mode_apply(uint8_t phy_mode); +static int ble_phy_get_cur_phy(void); void FIELD_IRQHandler(void) @@ -523,7 +524,7 @@ ble_phy_rx_start_isr(void) /* Read the latched RSSI value */ ble_hdr->rxinfo.rssi = ble_rf_get_rssi(); #if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) - g_cmac_shared_data.debug.last_rx_rssi = ble_hdr->rxinfo.rssi; + g_cmac_shm_debugdata.last_rx_rssi = ble_hdr->rxinfo.rssi; #endif /* Count rx starts */ @@ -1012,7 +1013,7 @@ ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode) g_ble_phy_data.frame_offset_rxtx = g_ble_phy_frame_offset_rxtx[rxtx]; } -int +static int ble_phy_get_cur_phy(void) { #if (BLE_LL_BT5_PHY_SUPPORTED == 1) @@ -1327,7 +1328,7 @@ ble_phy_rx_setup_xcvr(void) g_ble_phy_data.phy_rx_started = 0; } -int +static int ble_phy_rx(void) { MCU_DIAG_SER('R'); @@ -1597,19 +1598,12 @@ ble_phy_rx_enc_start(uint8_t len) } void -ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master) +ble_phy_encrypt_enable(const uint8_t *key) { struct ble_phy_encrypt_obj *enc; enc = &g_ble_phy_encrypt_data; memcpy(enc->key, key, 16); - memcpy(&enc->b0[6], iv, 8); - put_le32(&enc->b0[1], pkt_counter); - enc->b0[5] = is_master ? 0x80 : 0; - memcpy(&enc->ai[6], iv, 8); - put_le32(&enc->ai[1], pkt_counter); - enc->ai[5] = enc->b0[5]; g_ble_phy_data.phy_encrypted = 1; @@ -1630,14 +1624,25 @@ ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, } void -ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) +ble_phy_encrypt_iv_set(const uint8_t *iv) { struct ble_phy_encrypt_obj *enc; enc = &g_ble_phy_encrypt_data; - put_le32(&enc->b0[1], pkt_counter); - enc->b0[5] = dir ? 0x80 : 0; - put_le32(&enc->ai[1], pkt_counter); + memcpy(&enc->b0[6], iv, 8); + memcpy(&enc->ai[6], iv, 8); +} + + +void +ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit) +{ + struct ble_phy_encrypt_obj *enc; + + enc = &g_ble_phy_encrypt_data; + put_le32(&enc->b0[1], counter); + enc->b0[5] = dir_bit ? 0x80 : 0; + put_le32(&enc->ai[1], counter); enc->ai[5] = enc->b0[5]; CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_SW_REQ_PBUF_CLR_Msk; @@ -1651,11 +1656,11 @@ ble_phy_encrypt_disable(void) #endif int -ble_phy_txpwr_set(int dbm) +ble_phy_tx_power_set(int dbm) { #if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) - if (g_cmac_shared_data.debug.tx_power_override != INT8_MAX) { - ble_rf_set_tx_power(g_cmac_shared_data.debug.tx_power_override); + if (g_cmac_shm_debugdata.tx_power_ovr_enable) { + ble_rf_set_tx_power(g_cmac_shm_debugdata.tx_power_ovr); } else { ble_rf_set_tx_power(dbm); } @@ -1667,16 +1672,11 @@ ble_phy_txpwr_set(int dbm) } int -ble_phy_txpower_round(int dbm) +ble_phy_tx_power_round(int dbm) { return 0; } -void -ble_phy_set_rx_pwr_compensation(int8_t compensation) -{ -} - int ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crc_init) { @@ -1697,6 +1697,12 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crc_init) return 0; } +uint8_t +ble_phy_chan_get(void) +{ + return g_ble_phy_data.channel; +} + void ble_phy_restart_rx(void) { diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_rf.c b/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_rf.c index 806f4ea8..f9756ec6 100644 --- a/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_rf.c +++ b/lib/bt/host/nimble/nimble/nimble/drivers/dialog_cmac/src/ble_rf.c @@ -23,7 +23,7 @@ #include "mcu/mcu.h" #include "mcu/cmac_timer.h" #include "controller/ble_phy.h" -#include "cmac_driver/cmac_shared.h" +#include #include "ble_rf_priv.h" #define RF_CALIBRATION_0 (0x01) @@ -206,8 +206,7 @@ ble_rf_rfcu_apply_recommended_settings(void) static void ble_rf_rfcu_apply_settings(void) { - ble_rf_apply_trim(g_cmac_shared_data.trim.rfcu, - g_cmac_shared_data.trim.rfcu_len); + ble_rf_apply_trim(g_cmac_shm_trim.rfcu, g_cmac_shm_trim.rfcu_len); ble_rf_rfcu_apply_recommended_settings(); } @@ -234,6 +233,9 @@ ble_rf_synth_is_enabled(void) static void ble_rf_synth_apply_recommended_settings(void) { + if (mcu_chip_variant_get() == MCU_CHIP_VARIANT_GF) { + set_reg32_mask(0x40022034, 0x00000018, 0x0215807B); + } set_reg32_mask(0x40022048, 0x0000000c, 0x000000d5); set_reg32_mask(0x40022050, 0x00000300, 0x00000300); set_reg16_mask(0x40022024, 0x0001, 0x0001); @@ -242,8 +244,7 @@ ble_rf_synth_apply_recommended_settings(void) static void ble_rf_synth_apply_settings(void) { - ble_rf_apply_trim(g_cmac_shared_data.trim.synth, - g_cmac_shared_data.trim.synth_len); + ble_rf_apply_trim(g_cmac_shm_trim.synth, g_cmac_shm_trim.synth_len); ble_rf_synth_apply_recommended_settings(); } @@ -337,7 +338,11 @@ ble_rf_calibration_1(void) set_reg32(0x40020000, 0x0f168820); set_reg32_bits(0x40022000, 0x00000001, 0); set_reg32_bits(0x4002101c, 0x00001e00, 0); - set_reg32_bits(0x4002001c, 0x0000003f, 47); + if (mcu_chip_variant_get() == MCU_CHIP_VARIANT_TSMC) { + set_reg32_bits(0x4002001c, 0x0000003f, 47); + } else { + set_reg32_bits(0x4002001c, 0x0000003f, 44); + } set_reg8(0x40020006, 1); set_reg32(0x40020020, 16); set_reg32_bits(0x4002003c, 0x00000800, 1); @@ -495,8 +500,8 @@ ble_rf_calibrate_int(uint8_t mask) __enable_irq(); #if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) - g_cmac_shared_data.debug.cal_res_1 = g_ble_phy_rf_data.cal_res_1; - g_cmac_shared_data.debug.cal_res_2 = g_ble_phy_rf_data.cal_res_2; + g_cmac_shm_debugdata.cal_res_1 = g_ble_phy_rf_data.cal_res_1; + g_cmac_shm_debugdata.cal_res_2 = g_ble_phy_rf_data.cal_res_2; #endif } @@ -539,25 +544,27 @@ ble_rf_init(void) static bool done = false; uint32_t val; + assert(mcu_chip_variant_get()); + ble_rf_disable(); if (done) { return; } - val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu_mode1, - g_cmac_shared_data.trim.rfcu_mode1_len, + val = ble_rf_find_trim_reg(g_cmac_shm_trim.rfcu_mode1, + g_cmac_shm_trim.rfcu_mode1_len, 0x4002004c); g_ble_phy_rf_data.trim_val1_tx_1 = val; - val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu_mode2, - g_cmac_shared_data.trim.rfcu_mode2_len, + val = ble_rf_find_trim_reg(g_cmac_shm_trim.rfcu_mode2, + g_cmac_shm_trim.rfcu_mode2_len, 0x4002004c); g_ble_phy_rf_data.trim_val1_tx_2 = val; if (!g_ble_phy_rf_data.trim_val1_tx_1 || !g_ble_phy_rf_data.trim_val1_tx_2) { - val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu, - g_cmac_shared_data.trim.rfcu_len, + val = ble_rf_find_trim_reg(g_cmac_shm_trim.rfcu, + g_cmac_shm_trim.rfcu_len, 0x4002004c); if (!val) { val = 0x0300; @@ -566,8 +573,8 @@ ble_rf_init(void) g_ble_phy_rf_data.trim_val1_tx_2 = val; } - val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.synth, - g_cmac_shared_data.trim.synth_len, + val = ble_rf_find_trim_reg(g_cmac_shm_trim.synth, + g_cmac_shm_trim.synth_len, 0x40022038); if (!val) { val = 0x0198ff03; @@ -577,10 +584,10 @@ ble_rf_init(void) set_reg32_bits((uint32_t)&g_ble_phy_rf_data.trim_val2_tx, 0x0001ff00, 0x87); #if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) - g_cmac_shared_data.debug.trim_val1_tx_1 = g_ble_phy_rf_data.trim_val1_tx_1; - g_cmac_shared_data.debug.trim_val1_tx_2 = g_ble_phy_rf_data.trim_val1_tx_2; - g_cmac_shared_data.debug.trim_val2_tx = g_ble_phy_rf_data.trim_val2_tx; - g_cmac_shared_data.debug.trim_val2_rx = g_ble_phy_rf_data.trim_val2_rx; + g_cmac_shm_debugdata.trim_val1_tx_1 = g_ble_phy_rf_data.trim_val1_tx_1; + g_cmac_shm_debugdata.trim_val1_tx_2 = g_ble_phy_rf_data.trim_val1_tx_2; + g_cmac_shm_debugdata.trim_val2_tx = g_ble_phy_rf_data.trim_val2_tx; + g_cmac_shm_debugdata.trim_val2_rx = g_ble_phy_rf_data.trim_val2_rx; #endif ble_rf_rfcu_enable(); diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/include/nrf21540/nrf21540.h b/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/include/nrf21540/nrf21540.h new file mode 100644 index 00000000..54efc854 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/include/nrf21540/nrf21540.h @@ -0,0 +1,36 @@ +/* + * 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 _NRF21540_H +#define _NRF21540_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int nrf21540_mode_set(uint8_t mode); + +#ifdef __cplusplus +} +#endif + +#endif /* _NRF21540_H */ diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/pkg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/pkg.yml new file mode 100644 index 00000000..c6dd5f55 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/pkg.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +pkg.name: nimble/drivers/fem/nrf21540 +pkg.description: Driver for nRF21540 front-end module +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.apis: + - ble_fem_pa + - ble_fem_lna + - ble_fem_antenna + +pkg.init: + nrf21540_init: 999 diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/src/nrf21540.c b/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/src/nrf21540.c new file mode 100644 index 00000000..b70a66e7 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/src/nrf21540.c @@ -0,0 +1,143 @@ +/* + * 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 +#include +#include +#include +#include + +static void +nrf21540_pdn_set(int state) +{ + int pin; + + pin = MYNEWT_VAL(NRF21540_PIN_PDN); + hal_gpio_write(pin, state); +} + +int +nrf21540_mode_set(uint8_t mode) +{ +#ifdef MYNEWT_VAL_NRF21540_PIN_MODE + int pin; + + pin = MYNEWT_VAL(NRF21540_PIN_MODE); + hal_gpio_init_out(pin, mode); + + return 0; +#else + return -1; +#endif +} + +void +ble_fem_pa_init(void) +{ + nrf21540_pdn_set(0); +} + +void +ble_fem_pa_enable(void) +{ + nrf21540_pdn_set(1); +} + +void +ble_fem_pa_disable(void) +{ + nrf21540_pdn_set(0); +} + +void +ble_fem_lna_init(void) +{ +} + +void +ble_fem_lna_enable(void) +{ + nrf21540_pdn_set(1); +} + +void +ble_fem_lna_disable(void) +{ + nrf21540_pdn_set(0); +} + +int +ble_fem_antenna(uint8_t port) +{ +#ifdef MYNEWT_VAL_NRF21540_PIN_ANT_SEL + int pin; + + pin = MYNEWT_VAL(NRF21540_PIN_ANT_SEL); + switch (port) { + case 0: + case 1: + hal_gpio_write(pin, 0); + break; + case 2: + hal_gpio_write(pin, 1); + break; + default: + return -1; + } + + return 0; +#else + return -1; +#endif +} + +void +nrf21540_init(void) +{ + int pin; + + pin = MYNEWT_VAL(NRF21540_PIN_PDN); + assert(pin >= 0); + hal_gpio_init_out(pin, 0); + +#ifdef MYNEWT_VAL_NRF21540_PIN_ANT_SEL + pin = MYNEWT_VAL(NRF21540_PIN_ANT_SEL); + assert(pin >= 0); + switch (MYNEWT_VAL(NRF21540_ANTENNA_PORT)) { + case 1: + hal_gpio_init_out(pin, 0); + break; + case 2: + hal_gpio_init_out(pin, 1); + break; + default: + assert(0); + } +#endif + +#ifdef MYNEWT_VAL_NRF21540_PIN_MODE + pin = MYNEWT_VAL(NRF21540_PIN_MODE); + assert(pin >= 0); + if (MYNEWT_VAL_CHOICE(NRF21540_TX_GAIN_PRESET, POUTB)) { + hal_gpio_init_out(pin, 1); + } else { + hal_gpio_init_out(pin, 0); + } +#endif +} diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/syscfg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/syscfg.yml new file mode 100644 index 00000000..13e5f17a --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/nrf21540/syscfg.yml @@ -0,0 +1,45 @@ +# 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. +# + +syscfg.defs: + NRF21540_PIN_PDN: + description: > + GPIO pin number to control PDN signal. + value: + restrictions: $notnull + NRF21540_PIN_ANT_SEL: + description: > + GPIO pin number to control ANT_SEL signal. + value: + NRF21540_PIN_MODE: + description: > + GPIO pin number to control MODE signal. + value: + NRF21540_ANTENNA_PORT: + description: > + Selects antenna port, valid only if ANT_SEL pin is configured. + range: 1, 2 + value: 1 + NRF21540_TX_GAIN_PRESET: + description: > + Selects TX gain preset, valid only if MODE pin is configured. + choices: + - none + - POUTA + - POUTB + value: none diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/include/sky66112/sky66112.h b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/include/sky66112/sky66112.h new file mode 100644 index 00000000..4b995b61 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/include/sky66112/sky66112.h @@ -0,0 +1,42 @@ +/* + * 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 _SKY66112_H +#define _SKY66112_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void sky66112_tx_hp_mode(uint8_t enabled); +void sky66112_rx_bypass(uint8_t enabled); +void sky66112_tx_bypass(uint8_t enabled); + +#if MYNEWT_VAL_CHOICE(SKY66112_ANTENNA_PORT, runtime) +uint8_t sky66112_default_antenna_get(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SKY66112_H */ diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/pkg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/pkg.yml new file mode 100644 index 00000000..822cfaa8 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/pkg.yml @@ -0,0 +1,32 @@ +# +# 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. +# + +pkg.name: nimble/drivers/fem/sky66112 +pkg.description: Driver for SKY66112 front-end module +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.apis: + - ble_fem_pa + - ble_fem_lna + - ble_fem_antenna +pkg.deps: + - nimble/controller + +pkg.init: + sky66112_init: 999 diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/src/sky66112.c b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/src/sky66112.c new file mode 100644 index 00000000..615055c7 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/src/sky66112.c @@ -0,0 +1,201 @@ +/* + * 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 +#include +#include "syscfg/syscfg.h" +#include "hal/hal_gpio.h" +#include "controller/ble_fem.h" + +static struct { + uint8_t rx_bypass : 1; + uint8_t tx_bypass : 1; +} sky66112_config = { + .rx_bypass = MYNEWT_VAL(SKY66112_RX_BYPASS), + .tx_bypass = MYNEWT_VAL(SKY66112_TX_BYPASS), +}; + +#if !MYNEWT_VAL_CHOICE(SKY66112_ANTENNA_PORT, runtime) +static uint8_t +sky66112_default_antenna_get(void) +{ + if (MYNEWT_VAL_CHOICE(SKY66112_ANTENNA_PORT, ANT2)) { + return 2; + } else { + return 1; + } +} +#endif + +static void +sky66112_bypass(uint8_t enabled) +{ + /* this is called only if bypass is enabled which means CPS PIN is + * correctly set and there is no need to check it here. + */ + hal_gpio_write(MYNEWT_VAL(SKY66112_PIN_CPS), enabled); +} + +void +ble_fem_pa_init(void) +{ + sky66112_tx_hp_mode(MYNEWT_VAL(SKY66112_TX_HP_MODE)); + sky66112_tx_bypass(0); +#if MYNEWT_VAL(BLE_FEM_ANTENNA) + ble_fem_antenna(0); +#endif +} + +void +ble_fem_pa_enable(void) +{ + if (sky66112_config.tx_bypass) { + sky66112_bypass(1); + } +} + +void +ble_fem_pa_disable(void) +{ + if (sky66112_config.tx_bypass) { + sky66112_bypass(0); + } +} + +void +ble_fem_lna_init(void) +{ + sky66112_rx_bypass(0); +#if MYNEWT_VAL(BLE_FEM_ANTENNA) + ble_fem_antenna(0); +#endif +} + +void +ble_fem_lna_enable(void) +{ + if (sky66112_config.rx_bypass) { + sky66112_bypass(1); + } +} + +void +ble_fem_lna_disable(void) +{ + if (sky66112_config.rx_bypass) { + sky66112_bypass(0); + } +} + +void +sky66112_tx_hp_mode(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66112_PIN_CHL); + + if (pin >= 0) { + hal_gpio_write(pin, enabled); + } +} + +int +ble_fem_antenna(uint8_t port) +{ + int pin = MYNEWT_VAL(SKY66112_PIN_SEL); + uint8_t ant; + + if (pin >= 0) { + switch (port) { + case 0: + ant = sky66112_default_antenna_get(); + assert(ant == 1 || ant == 2); + return ble_fem_antenna(ant); + case 1: + hal_gpio_write(pin, 0); + break; + case 2: + hal_gpio_write(pin, 1); + break; + default: + return -1; + } + } + + return 0; +} + +void +sky66112_rx_bypass(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66112_PIN_CPS); + + if (pin >= 0) { + sky66112_config.rx_bypass = enabled; + sky66112_bypass(enabled); + } +} + +void +sky66112_tx_bypass(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66112_PIN_CPS); + + if (pin >= 0) { + sky66112_config.tx_bypass = enabled; + sky66112_bypass(enabled); + } +} + +void +sky66112_init(void) +{ + int pin; + + /* Use CRX and CTX to enable sleep mode */ + pin = MYNEWT_VAL(SKY66112_PIN_CSD); + if (pin >= 0) { + hal_gpio_init_out(pin, 1); + } + + /* Set default tx power mode */ + pin = MYNEWT_VAL(SKY66112_PIN_CHL); + if (pin >= 0) { + hal_gpio_init_out(pin, MYNEWT_VAL(SKY66112_TX_HP_MODE)); + } + + /* Disable bypass, we'll enable it when needed */ + pin = MYNEWT_VAL(SKY66112_PIN_CPS); + if (pin >= 0) { + hal_gpio_init_out(pin, 0); + } + + /* configure default antenna */ + pin = MYNEWT_VAL(SKY66112_PIN_SEL); + if (pin >= 0) { + switch (sky66112_default_antenna_get()) { + case 1: + hal_gpio_init_out(pin, 0); + break; + case 2: + hal_gpio_init_out(pin, 1); + break; + default: + assert(0); + } + } +} diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/syscfg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/syscfg.yml new file mode 100644 index 00000000..120fd4e5 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66112/syscfg.yml @@ -0,0 +1,76 @@ +# 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. +# + +syscfg.defs: + SKY66112_PIN_CSD: + description: > + GPIO pin number to control CSD signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_PIN_CPS: + description: > + GPIO pin number to control CPS signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_PIN_CHL: + description: > + GPIO pin number to control CHL signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_PIN_SEL: + description: > + GPIO pin number to control SEL signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_TX_HP_MODE: + description: > + Enables high-power mode for TX. + Only valid if CHL signal is controller by driver. + value: 0 + SKY66112_TX_BYPASS: + description: > + Enables bypass for TX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + SKY66112_RX_BYPASS: + description: > + Enables bypass for RX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + SKY66112_ANTENNA_PORT: + description: > + Selects which antenna port should be enabled. If 'runtime' is + selected sky66112_default_antenna_get() (see sky66112/sky66112.h) + shall be implemeneted by application. + choices: + - ANT1 + - ANT2 + - runtime + value: ANT1 + +syscfg.vals.!BLE_FEM_PA: + # Enable TX bypass by default if PA is disabled + SKY66112_TX_BYPASS: 1 + +syscfg.vals.!BLE_FEM_LNA: + # Enable RX bypass by default if LNA is disabled + SKY66112_RX_BYPASS: 1 diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/include/sky66403/sky66403.h b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/include/sky66403/sky66403.h new file mode 100644 index 00000000..a9dc99ba --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/include/sky66403/sky66403.h @@ -0,0 +1,42 @@ +/* + * 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 _SKY66403_H +#define _SKY66403_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void sky66403_tx_linear_mode(uint8_t enabled); +void sky66403_rx_bypass(uint8_t enabled); +void sky66403_tx_bypass(uint8_t enabled); + +#if MYNEWT_VAL_CHOICE(SKY66403_ANTENNA_PORT, runtime) +uint8_t sky66403_default_antenna_get(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SKY66403_H */ diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/pkg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/pkg.yml new file mode 100644 index 00000000..d119cf12 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/pkg.yml @@ -0,0 +1,32 @@ +# +# 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. +# + +pkg.name: nimble/drivers/fem/sky66403 +pkg.description: Driver for SKY66403 front-end module +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.apis: + - ble_fem_pa + - ble_fem_lna + - ble_fem_antenna +pkg.deps: + - nimble/controller + +pkg.init: + sky66403_init: 999 diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/src/sky66403.c b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/src/sky66403.c new file mode 100644 index 00000000..1aa87d14 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/src/sky66403.c @@ -0,0 +1,201 @@ +/* + * 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 +#include +#include +#include +#include + +static struct { + uint8_t rx_bypass : 1; + uint8_t tx_bypass : 1; +} sky66403_config = { + .rx_bypass = MYNEWT_VAL(SKY66403_RX_BYPASS), + .tx_bypass = MYNEWT_VAL(SKY66403_TX_BYPASS), +}; + +#if !MYNEWT_VAL_CHOICE(SKY66403_ANTENNA_PORT, runtime) +static uint8_t +sky66403_default_antenna_get(void) +{ + if (MYNEWT_VAL_CHOICE(SKY66403_ANTENNA_PORT, ANT2)) { + return 2; + } else { + return 1; + } +} +#endif + +static void +sky66403_bypass(uint8_t enabled) +{ + /* this is called only if bypass is enabled which means CPS PIN is + * correctly set and there is no need to check it here. + */ + hal_gpio_write(MYNEWT_VAL(SKY66403_PIN_CPS), enabled); +} + +void +ble_fem_pa_init(void) +{ + sky66403_tx_linear_mode(MYNEWT_VAL(SKY66403_TX_LINEAR_MODE)); + sky66403_tx_bypass(0); +#if MYNEWT_VAL(BLE_FEM_ANTENNA) + ble_fem_antenna(0); +#endif +} + +void +ble_fem_pa_enable(void) +{ + if (sky66403_config.tx_bypass) { + sky66403_bypass(1); + } +} + +void +ble_fem_pa_disable(void) +{ + if (sky66403_config.tx_bypass) { + sky66403_bypass(0); + } +} + +void +ble_fem_lna_init(void) +{ + sky66403_rx_bypass(0); +#if MYNEWT_VAL(BLE_FEM_ANTENNA) + ble_fem_antenna(0); +#endif +} + +void +ble_fem_lna_enable(void) +{ + if (sky66403_config.rx_bypass) { + sky66403_bypass(1); + } +} + +void +ble_fem_lna_disable(void) +{ + if (sky66403_config.rx_bypass) { + sky66403_bypass(0); + } +} + +void +sky66403_tx_linear_mode(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66403_PIN_CHL); + + if (pin >= 0) { + hal_gpio_write(pin, enabled); + } +} + +int +ble_fem_antenna(uint8_t port) +{ + int pin = MYNEWT_VAL(SKY66403_PIN_SEL); + uint8_t ant; + + if (pin >= 0) { + switch (port) { + case 0: + ant = sky66403_default_antenna_get(); + assert(ant == 1 || ant == 2); + return ble_fem_antenna(ant); + case 1: + hal_gpio_write(pin, 0); + break; + case 2: + hal_gpio_write(pin, 1); + break; + default: + return -1; + } + } + + return 0; +} + +void +sky66403_rx_bypass(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66403_PIN_CPS); + + if (pin >= 0) { + sky66403_config.rx_bypass = enabled; + sky66403_bypass(enabled); + } +} + +void +sky66403_tx_bypass(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66403_PIN_CPS); + + if (pin >= 0) { + sky66403_config.tx_bypass = enabled; + sky66403_bypass(enabled); + } +} + +void +sky66403_init(void) +{ + int pin; + + /* Use CRX and CTX to enable sleep mode */ + pin = MYNEWT_VAL(SKY66403_PIN_CSD); + if (pin >= 0) { + hal_gpio_init_out(pin, 1); + } + + /* Set default tx power mode */ + pin = MYNEWT_VAL(SKY66403_PIN_CHL); + if (pin >= 0) { + hal_gpio_init_out(pin, MYNEWT_VAL(SKY66403_TX_LINEAR_MODE)); + } + + /* Disable bypass, we'll enable it when needed */ + pin = MYNEWT_VAL(SKY66403_PIN_CPS); + if (pin >= 0) { + hal_gpio_init_out(pin, 0); + } + + /* configure default antenna */ + pin = MYNEWT_VAL(SKY66403_PIN_SEL); + if (pin >= 0) { + switch (sky66403_default_antenna_get()) { + case 1: + hal_gpio_init_out(pin, 0); + break; + case 2: + hal_gpio_init_out(pin, 1); + break; + default: + assert(0); + } + } +} diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/syscfg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/syscfg.yml new file mode 100644 index 00000000..def2da51 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/fem/sky66403/syscfg.yml @@ -0,0 +1,76 @@ +# 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. +# + +syscfg.defs: + SKY66403_PIN_CSD: + description: > + GPIO pin number to control CSD signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66403_PIN_CPS: + description: > + GPIO pin number to control CPS signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66403_PIN_CHL: + description: > + GPIO pin number to control CHL signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66403_PIN_SEL: + description: > + GPIO pin number to control SEL signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66403_TX_LINEAR_MODE: + description: > + Enables linear mode for TX. + Only valid if CHL signal is controller by driver. + value: 0 + SKY66403_TX_BYPASS: + description: > + Enables bypass for TX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + SKY66403_RX_BYPASS: + description: > + Enables bypass for RX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + SKY66403_ANTENNA_PORT: + description: > + Selects which antenna port should be enabled. If 'runtime' is + selected SKY66403_default_antenna_get() (see SKY66403/SKY66403.h) + shall be implemeneted by application. + choices: + - ANT1 + - ANT2 + - runtime + value: ANT1 + +syscfg.vals.!BLE_FEM_PA: + # Enable TX bypass by default if PA is disabled + SKY66403_TX_BYPASS: 1 + +syscfg.vals.!BLE_FEM_LNA: + # Enable RX bypass by default if LNA is disabled + SKY66403_RX_BYPASS: 1 diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/native/src/ble_phy.c b/lib/bt/host/nimble/nimble/nimble/drivers/native/src/ble_phy.c index f9ab0fcb..4609c286 100644 --- a/lib/bt/host/nimble/nimble/nimble/drivers/native/src/ble_phy.c +++ b/lib/bt/host/nimble/nimble/nimble/drivers/native/src/ble_phy.c @@ -165,7 +165,7 @@ ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) struct os_mbuf_pkthdr *pkthdr; /* Better be aligned */ - assert(((uint32_t)dptr & 3) == 0); + assert(((uintptr_t)dptr & 3) == 0); pkthdr = OS_MBUF_PKTHDR(rxpdu); rem_bytes = pkthdr->omp_len; @@ -342,24 +342,18 @@ ble_phy_restart_rx(void) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/** - * Called to enable encryption at the PHY. Note that this state will persist - * in the PHY; in other words, if you call this function you have to call - * disable so that future PHY transmits/receives will not be encrypted. - * - * @param pkt_counter - * @param iv - * @param key - * @param is_master - */ void -ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master) +ble_phy_encrypt_enable(const uint8_t *key) +{ +} + +void +ble_phy_encrypt_iv_set(const uint8_t *iv) { } void -ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) +ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit) { } @@ -464,7 +458,7 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) * @return int 0: success; anything else is an error */ int -ble_phy_txpwr_set(int dbm) +ble_phy_tx_power_set(int dbm) { /* Check valid range */ assert(dbm <= BLE_PHY_MAX_PWR_DBM); @@ -492,7 +486,8 @@ ble_phy_txpwr_set(int dbm) * * @return int Rounded power in dBm */ -int ble_phy_txpower_round(int dbm) +int +ble_phy_tx_power_round(int dbm) { /* "Rail" power level if outside supported range */ if (dbm > BLE_XCVR_TX_PWR_MAX_DBM) { @@ -514,7 +509,7 @@ int ble_phy_txpower_round(int dbm) * @return int The current PHY transmit power, in dBm */ int -ble_phy_txpwr_get(void) +ble_phy_tx_power_get(void) { return g_ble_phy_data.phy_txpwr_dbm; } @@ -556,6 +551,12 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) return 0; } +uint8_t +ble_phy_chan_get(void) +{ + return g_ble_phy_data.phy_chan; +} + /** * Disable the PHY. This will do the following: * -> Turn off all phy interrupts. diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/pkg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/pkg.yml index 816a5635..9311093b 100644 --- a/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/pkg.yml +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/pkg.yml @@ -29,3 +29,6 @@ pkg.apis: ble_driver pkg.deps: - nimble - nimble/controller + +# allows to override nimble/controller settings +pkg.subpriority: 1 diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/src/ble_hw.c b/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/src/ble_hw.c index 437efd4f..fb6e844b 100644 --- a/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/src/ble_hw.c +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/src/ble_hw.c @@ -88,11 +88,17 @@ ble_hw_get_public_addr(ble_addr_t *addr) int ble_hw_get_static_addr(ble_addr_t *addr) { + uint32_t addr_high; + uint32_t addr_low; int rc; if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) { - memcpy(addr->val, (void *)&NRF_FICR->DEVICEADDR[0], 4); - memcpy(&addr->val[4], (void *)&NRF_FICR->DEVICEADDR[1], 2); + addr_low = NRF_FICR->DEVICEADDR[0]; + addr_high = NRF_FICR->DEVICEADDR[1]; + + memcpy(addr->val, &addr_low, 4); + memcpy(&addr->val[4], &addr_high, 2); + addr->val[5] |= 0xc0; addr->type = BLE_ADDR_RANDOM; rc = 0; diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/src/ble_phy.c b/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/src/ble_phy.c index d3bc3c2e..c3a523dc 100644 --- a/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/src/ble_phy.c +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/src/ble_phy.c @@ -22,6 +22,8 @@ #include #include "syscfg/syscfg.h" #include "os/os.h" +/* Keep os_cputime explicitly to enable build on non-Mynewt platforms */ +#include "os/os_cputime.h" #include "ble/xcvr.h" #include "nimble/ble.h" #include "nimble/nimble_opt.h" @@ -45,6 +47,12 @@ #error LE Coded PHY cannot be enabled on nRF51 #endif +static uint32_t +ble_phy_mode_pdu_start_off(int phy_mode) +{ + return 40; +} + /* XXX: 4) Make sure RF is higher priority interrupt than schedule */ /* @@ -94,7 +102,6 @@ struct ble_phy_obj uint8_t phy_privacy; uint8_t phy_tx_pyld_len; uint8_t *rxdptr; - int8_t rx_pwr_compensation; uint32_t phy_aar_scratch; uint32_t phy_access_address; struct ble_mbuf_hdr rxhdr; @@ -618,8 +625,7 @@ ble_phy_rx_end_isr(void) /* Set RSSI and CRC status flag in header */ ble_hdr = &g_ble_phy_data.rxhdr; assert(NRF_RADIO->EVENTS_RSSIEND != 0); - ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->RSSISAMPLE) + - g_ble_phy_data.rx_pwr_compensation; + ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->RSSISAMPLE); dptr = g_ble_phy_data.rxdptr; @@ -847,8 +853,6 @@ ble_phy_init(void) /* Set phy channel to an invalid channel so first set channel works */ g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS; - g_ble_phy_data.rx_pwr_compensation = 0; - /* Toggle peripheral power to reset (just in case) */ NRF_RADIO->POWER = 0; NRF_RADIO->POWER = 1; @@ -979,24 +983,10 @@ ble_phy_rx(void) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/** - * Called to enable encryption at the PHY. Note that this state will persist - * in the PHY; in other words, if you call this function you have to call - * disable so that future PHY transmits/receives will not be encrypted. - * - * @param pkt_counter - * @param iv - * @param key - * @param is_master - */ void -ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master) +ble_phy_encrypt_enable(const uint8_t *key) { memcpy(g_nrf_ccm_data.key, key, 16); - g_nrf_ccm_data.pkt_counter = pkt_counter; - memcpy(g_nrf_ccm_data.iv, iv, 8); - g_nrf_ccm_data.dir_bit = is_master; g_ble_phy_data.phy_encrypted = 1; /* Encryption uses LFLEN=5, S1LEN = 3. */ @@ -1010,10 +1000,16 @@ ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, } void -ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) +ble_phy_encrypt_iv_set(const uint8_t *iv) +{ + memcpy(g_nrf_ccm_data.iv, iv, 8); +} + +void +ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit) { - g_nrf_ccm_data.pkt_counter = pkt_counter; - g_nrf_ccm_data.dir_bit = dir; + g_nrf_ccm_data.pkt_counter = counter; + g_nrf_ccm_data.dir_bit = dir_bit; } void @@ -1254,7 +1250,7 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) * @return int 0: success; anything else is an error */ int -ble_phy_txpwr_set(int dbm) +ble_phy_tx_power_set(int dbm) { /* Check valid range */ assert(dbm <= BLE_PHY_MAX_PWR_DBM); @@ -1283,7 +1279,8 @@ ble_phy_txpwr_set(int dbm) * * @return int Rounded power in dBm */ -int ble_phy_txpower_round(int dbm) +int +ble_phy_tx_power_round(int dbm) { /* "Rail" power level if outside supported range */ if (dbm > NRF_TX_PWR_MAX_DBM) { @@ -1305,17 +1302,11 @@ int ble_phy_txpower_round(int dbm) * @return int The current PHY transmit power, in dBm */ int -ble_phy_txpwr_get(void) +ble_phy_tx_power_get(void) { return g_ble_phy_data.phy_txpwr_dbm; } -void -ble_phy_set_rx_pwr_compensation(int8_t compensation) -{ - g_ble_phy_data.rx_pwr_compensation = compensation; -} - /** * ble phy setchan * @@ -1374,6 +1365,12 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) return 0; } +uint8_t +ble_phy_chan_get(void) +{ + return g_ble_phy_data.phy_chan; +} + /** * Stop the timer used to count microseconds when using RTC for cputime */ diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/syscfg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/syscfg.yml new file mode 100644 index 00000000..451742a6 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf51/syscfg.yml @@ -0,0 +1,21 @@ +# 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. +# + + +syscfg.vals.!BLE_LL_CFG_FEAT_LL_EXT_ADV: + BLE_LL_STACK_SIZE: 96 diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf52/pkg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/nrf52/pkg.yml index a1ff457e..c9745261 100644 --- a/lib/bt/host/nimble/nimble/nimble/drivers/nrf52/pkg.yml +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf52/pkg.yml @@ -18,14 +18,5 @@ # pkg.name: nimble/drivers/nrf52 -pkg.description: BLE driver for nRF52 systems. -pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" -pkg.keywords: - - ble - - bluetooth - -pkg.apis: ble_driver -pkg.deps: - - nimble - - nimble/controller +pkg.type: transient +pkg.link: "@apache-mynewt-nimble/nimble/drivers/nrf5x" diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5340/pkg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5340/pkg.yml index 3ff44212..794697e9 100644 --- a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5340/pkg.yml +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5340/pkg.yml @@ -18,14 +18,5 @@ # pkg.name: nimble/drivers/nrf5340 -pkg.description: BLE driver for nRF5340 systems. -pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" -pkg.keywords: - - ble - - bluetooth - -pkg.apis: ble_driver -pkg.deps: - - nimble - - nimble/controller +pkg.type: transient +pkg.link: "@apache-mynewt-nimble/nimble/drivers/nrf5x" diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/include/ble/xcvr.h b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/include/ble/xcvr.h new file mode 100644 index 00000000..bb2da568 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/include/ble/xcvr.h @@ -0,0 +1,61 @@ +/* + * 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 H_BLE_XCVR_ +#define H_BLE_XCVR_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define XCVR_RX_RADIO_RAMPUP_USECS (40) +#define XCVR_TX_RADIO_RAMPUP_USECS (40) + +/* We need to account for the RTC compare issue, we want it to be 5 ticks. + * In case FEM turn on time is more than radio enable (i.e. 2 ticks) we want + * to add 1 more tick to compensate for additional delay. + * + * TODO this file should be refactored... + */ +#if (MYNEWT_VAL(BLE_FEM_PA) && (MYNEWT_VAL(BLE_FEM_PA_TURN_ON_US) > 60)) || \ + (MYNEWT_VAL(BLE_FEM_LNA) && (MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US) > 60)) +#define XCVR_PROC_DELAY_USECS (183) +#else +#define XCVR_PROC_DELAY_USECS (153) +#endif +#define XCVR_RX_START_DELAY_USECS (XCVR_RX_RADIO_RAMPUP_USECS) +#define XCVR_TX_START_DELAY_USECS (XCVR_TX_RADIO_RAMPUP_USECS) +#define XCVR_TX_SCHED_DELAY_USECS \ + (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS) +#define XCVR_RX_SCHED_DELAY_USECS \ + (XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS) + +/* + * Define HW whitelist size. This is the total possible whitelist size; + * not necessarily the size that will be used (may be smaller) + */ +#define BLE_HW_WHITE_LIST_SIZE (8) + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_XCVR_ */ diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/pkg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/pkg.yml new file mode 100644 index 00000000..b99e6692 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/pkg.yml @@ -0,0 +1,36 @@ +# +# 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. +# + +pkg.name: nimble/drivers/nrf5x +pkg.description: PHY for nRF52 and nRF53 series +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + +pkg.apis: ble_driver +pkg.deps: + - nimble + - nimble/controller + +pkg.ign_dirs.'MCU_TARGET=="nRF5340_NET"': + - nrf52 +pkg.ign_dirs.'MCU_TARGET!="nRF5340_NET"': + - nrf53 diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/ble_hw.c b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/ble_hw.c new file mode 100644 index 00000000..9a46fa6c --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/ble_hw.c @@ -0,0 +1,519 @@ +/* + * 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 +#include +#include +#include "syscfg/syscfg.h" +#include "os/os.h" +#include "ble/xcvr.h" +#include "nimble/ble.h" +#include "nimble/nimble_opt.h" +#include "nrfx.h" +#include "controller/ble_hw.h" +#if MYNEWT +#include "mcu/cmsis_nvic.h" +#else +#ifdef NRF52_SERIES +#include "core_cm4.h" +#endif +#include +#endif +#include "os/os_trace_api.h" +#include +#include "hal/nrf_ecb.h" + +/* Total number of resolving list elements */ +#define BLE_HW_RESOLV_LIST_SIZE (16) + +/* We use this to keep track of which entries are set to valid addresses */ +static uint8_t g_ble_hw_whitelist_mask; + +/* Random number generator isr callback */ +ble_rng_isr_cb_t g_ble_rng_isr_cb; + +#if BABBLESIM +extern void tm_tick(void); +#endif + +/* If LL privacy is enabled, allocate memory for AAR */ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + +/* The NRF51 supports up to 16 IRK entries */ +#if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16) +#define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)) +#else +#define NRF_IRK_LIST_ENTRIES (16) +#endif + +/* NOTE: each entry is 16 bytes long. */ +uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4]; + +/* Current number of IRK entries */ +uint8_t g_nrf_num_irks; + +#endif + +/* Returns public device address or -1 if not present */ +int +ble_hw_get_public_addr(ble_addr_t *addr) +{ + uint32_t addr_high; + uint32_t addr_low; + +#if MYNEWT_VAL(BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR) + /* + * The BMD-345 modules are preprogrammed from the factory with a unique public + * The Bluetooth device address stored in the CUSTOMER[0] and CUSTOMER[1] + * registers of the User Information Configuration Registers (UICR). + * The Bluetooth device address consists of the IEEE Organizationally Unique + * Identifier (OUI) combined with the hexadecimal digits that are printed on + * a 2D barcode and in human-readable text on the module label.The Bluetooth + * device address is stored in little endian format. The most significant + * bytes of the CUSTOMER[1] register are 0xFF to complete the 32-bit register. + */ + + /* Copy into device address. We can do this because we know platform */ + addr_low = NRF_UICR->CUSTOMER[0]; + addr_high = NRF_UICR->CUSTOMER[1]; +#else + /* Does FICR have a public address */ + if ((NRF_FICR->DEVICEADDRTYPE & 1) != 0) { + return -1; + } + + /* Copy into device address. We can do this because we know platform */ + addr_low = NRF_FICR->DEVICEADDR[0]; + addr_high = NRF_FICR->DEVICEADDR[1]; +#endif + + memcpy(addr->val, &addr_low, 4); + memcpy(&addr->val[4], &addr_high, 2); + addr->type = BLE_ADDR_PUBLIC; + + return 0; +} + +/* Returns random static address or -1 if not present */ +int +ble_hw_get_static_addr(ble_addr_t *addr) +{ + uint32_t addr_high; + uint32_t addr_low; + int rc; + + if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) { + addr_low = NRF_FICR->DEVICEADDR[0]; + addr_high = NRF_FICR->DEVICEADDR[1]; + + memcpy(addr->val, &addr_low, 4); + memcpy(&addr->val[4], &addr_high, 2); + + addr->val[5] |= 0xc0; + addr->type = BLE_ADDR_RANDOM; + rc = 0; + } else { + rc = -1; + } + + return rc; +} + +/** + * Clear the whitelist + * + * @return int + */ +void +ble_hw_whitelist_clear(void) +{ + NRF_RADIO->DACNF = 0; + g_ble_hw_whitelist_mask = 0; +} + +/** + * Add a device to the hw whitelist + * + * @param addr + * @param addr_type + * + * @return int 0: success, BLE error code otherwise + */ +int +ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type) +{ + int i; + uint32_t mask; + + /* Find first ununsed device address match element */ + mask = 0x01; + for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) { + if ((mask & g_ble_hw_whitelist_mask) == 0) { + NRF_RADIO->DAB[i] = get_le32(addr); + NRF_RADIO->DAP[i] = get_le16(addr + 4); + if (addr_type == BLE_ADDR_RANDOM) { + NRF_RADIO->DACNF |= (mask << 8); + } + g_ble_hw_whitelist_mask |= mask; + return BLE_ERR_SUCCESS; + } + mask <<= 1; + } + + return BLE_ERR_MEM_CAPACITY; +} + +/** + * Remove a device from the hw whitelist + * + * @param addr + * @param addr_type + * + */ +void +ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type) +{ + int i; + uint8_t cfg_addr; + uint16_t dap; + uint16_t txadd; + uint32_t dab; + uint32_t mask; + + /* Find first ununsed device address match element */ + dab = get_le32(addr); + dap = get_le16(addr + 4); + txadd = NRF_RADIO->DACNF >> 8; + mask = 0x01; + for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) { + if (mask & g_ble_hw_whitelist_mask) { + if ((dab == NRF_RADIO->DAB[i]) && (dap == NRF_RADIO->DAP[i])) { + cfg_addr = txadd & mask; + if (addr_type == BLE_ADDR_RANDOM) { + if (cfg_addr != 0) { + break; + } + } else { + if (cfg_addr == 0) { + break; + } + } + } + } + mask <<= 1; + } + + if (i < BLE_HW_WHITE_LIST_SIZE) { + g_ble_hw_whitelist_mask &= ~mask; + NRF_RADIO->DACNF &= ~mask; + } +} + +/** + * Returns the size of the whitelist in HW + * + * @return int Number of devices allowed in whitelist + */ +uint8_t +ble_hw_whitelist_size(void) +{ + return BLE_HW_WHITE_LIST_SIZE; +} + +/** + * Enable the whitelisted devices + */ +void +ble_hw_whitelist_enable(void) +{ + /* Enable the configured device addresses */ + NRF_RADIO->DACNF |= g_ble_hw_whitelist_mask; +} + +/** + * Disables the whitelisted devices + */ +void +ble_hw_whitelist_disable(void) +{ + /* Disable all whitelist devices */ + NRF_RADIO->DACNF &= 0x0000ff00; +} + +/** + * Boolean function which returns true ('1') if there is a match on the + * whitelist. + * + * @return int + */ +int +ble_hw_whitelist_match(void) +{ + return (int)NRF_RADIO->EVENTS_DEVMATCH; +} + +/* Encrypt data */ +int +ble_hw_encrypt_block(struct ble_encryption_block *ecb) +{ + int rc; + uint32_t end; + uint32_t err; + + /* Stop ECB */ + nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STOPECB); + /* XXX: does task stop clear these counters? Anyway to do this quicker? */ + NRF_ECB->EVENTS_ENDECB = 0; + NRF_ECB->EVENTS_ERRORECB = 0; + NRF_ECB->ECBDATAPTR = (uint32_t)ecb; + + /* Start ECB */ + nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STARTECB); + + /* Wait till error or done */ + rc = 0; + while (1) { + end = NRF_ECB->EVENTS_ENDECB; + err = NRF_ECB->EVENTS_ERRORECB; + if (end || err) { + if (err) { + rc = -1; + } + break; + } +#if BABBLESIM + tm_tick(); +#endif + } + + return rc; +} + +/** + * Random number generator ISR. + */ +static void +ble_rng_isr(void) +{ + uint8_t rnum; + + os_trace_isr_enter(); + + /* No callback? Clear and disable interrupts */ + if (g_ble_rng_isr_cb == NULL) { + nrf_rng_int_disable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK); + NRF_RNG->EVENTS_VALRDY = 0; + (void)NRF_RNG->SHORTS; + os_trace_isr_exit(); + return; + } + + /* If there is a value ready grab it */ + if (NRF_RNG->EVENTS_VALRDY) { + NRF_RNG->EVENTS_VALRDY = 0; + rnum = (uint8_t)NRF_RNG->VALUE; + (*g_ble_rng_isr_cb)(rnum); + } + + os_trace_isr_exit(); +} + +/** + * Initialize the random number generator + * + * @param cb + * @param bias + * + * @return int + */ +int +ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias) +{ + /* Set bias */ + if (bias) { + NRF_RNG->CONFIG = 1; + } else { + NRF_RNG->CONFIG = 0; + } + + /* If we were passed a function pointer we need to enable the interrupt */ + if (cb != NULL) { +#ifndef RIOT_VERSION + NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1); +#endif +#if MYNEWT + NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr); +#else + ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr); +#endif + NVIC_EnableIRQ(RNG_IRQn); + g_ble_rng_isr_cb = cb; + } + + return 0; +} + +/** + * Start the random number generator + * + * @return int + */ +int +ble_hw_rng_start(void) +{ + os_sr_t sr; + + /* No need for interrupt if there is no callback */ + OS_ENTER_CRITICAL(sr); + NRF_RNG->EVENTS_VALRDY = 0; + + if (g_ble_rng_isr_cb) { + nrf_rng_int_enable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK); + } + nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_START); + OS_EXIT_CRITICAL(sr); + + return 0; +} + +/** + * Stop the random generator + * + * @return int + */ +int +ble_hw_rng_stop(void) +{ + os_sr_t sr; + + /* No need for interrupt if there is no callback */ + OS_ENTER_CRITICAL(sr); + nrf_rng_int_disable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK); + nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_STOP); + NRF_RNG->EVENTS_VALRDY = 0; + OS_EXIT_CRITICAL(sr); + + return 0; +} + +/** + * Read the random number generator. + * + * @return uint8_t + */ +uint8_t +ble_hw_rng_read(void) +{ + uint8_t rnum; + + /* Wait for a sample */ + while (NRF_RNG->EVENTS_VALRDY == 0) { + } + + NRF_RNG->EVENTS_VALRDY = 0; + rnum = (uint8_t)NRF_RNG->VALUE; + + return rnum; +} + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) +/** + * Clear the resolving list + * + * @return int + */ +void +ble_hw_resolv_list_clear(void) +{ + g_nrf_num_irks = 0; +} + +/** + * Add a device to the hw resolving list + * + * @param irk Pointer to IRK to add + * + * @return int 0: success, BLE error code otherwise + */ +int +ble_hw_resolv_list_add(uint8_t *irk) +{ + uint32_t *nrf_entry; + + /* Find first ununsed device address match element */ + if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) { + return BLE_ERR_MEM_CAPACITY; + } + + /* Copy into irk list */ + nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks]; + memcpy(nrf_entry, irk, 16); + + /* Add to total */ + ++g_nrf_num_irks; + return BLE_ERR_SUCCESS; +} + +/** + * Remove a device from the hw resolving list + * + * @param index Index of IRK to remove + */ +void +ble_hw_resolv_list_rmv(int index) +{ + uint32_t *irk_entry; + + if (index < g_nrf_num_irks) { + --g_nrf_num_irks; + irk_entry = &g_nrf_irk_list[index]; + if (g_nrf_num_irks > index) { + memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index)); + } + } +} + +/** + * Returns the size of the resolving list. NOTE: this returns the maximum + * allowable entries in the HW. Configuration options may limit this. + * + * @return int Number of devices allowed in resolving list + */ +uint8_t +ble_hw_resolv_list_size(void) +{ + return BLE_HW_RESOLV_LIST_SIZE; +} + +/** + * Called to determine if the address received was resolved. + * + * @return int Negative values indicate unresolved address; positive values + * indicate index in resolving list of resolved address. + */ +int +ble_hw_resolv_list_match(void) +{ + if (NRF_AAR->ENABLE && NRF_AAR->EVENTS_END && NRF_AAR->EVENTS_RESOLVED) { + return (int)NRF_AAR->STATUS; + } + + return -1; +} +#endif diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/ble_phy.c b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/ble_phy.c new file mode 100644 index 00000000..481ed619 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/ble_phy.c @@ -0,0 +1,2326 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "syscfg/syscfg.h" +#include "os/os.h" +/* Keep os_cputime explicitly to enable build on non-Mynewt platforms */ +#include "os/os_cputime.h" +#include "ble/xcvr.h" +#include "nimble/ble.h" +#include "nimble/nimble_opt.h" +#include "nimble/nimble_npl.h" +#include "controller/ble_phy.h" +#include "controller/ble_phy_trace.h" +#include "controller/ble_ll.h" +#include "nrfx.h" +#if MYNEWT +#ifdef NRF52_SERIES +#include +#endif +#ifdef NRF53_SERIES +#include +#endif +#include "mcu/cmsis_nvic.h" +#include "hal/hal_gpio.h" +#else +#include +#ifdef NRF52_SERIES +#include "core_cm4.h" +#endif +#endif +#include +#include "phy_priv.h" + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) +#if !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) && \ + !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52811) && \ + !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF5340_NET) +#error LE Coded PHY can only be enabled on nRF52811, nRF52840 or nRF5340 +#endif +#endif + +#if BABBLESIM +extern void tm_tick(void); +#endif + +#include + +/* + * NOTE: This code uses a couple of PPI channels so care should be taken when + * using PPI somewhere else. + * + * Pre-programmed channels: CH20, CH21, CH23, CH25, CH31 + * Regular channels: CH4, CH5 and optionally CH6, CH7, CH17, CH18, CH19 + * - CH4 = cancel wfr timer on address match + * - CH5 = disable radio on wfr timer expiry + * - CH6 = PA/LNA control (enable) + * - CH7 = PA/LNA control (disable) + * - CH17 = (optional) gpio debug for radio ramp-up + * - CH18 = (optional) gpio debug for wfr timer RX enabled + * - CH19 = (optional) gpio debug for wfr timer radio disabled + * + */ + +/* XXX: 4) Make sure RF is higher priority interrupt than schedule */ + +/* + * XXX: Maximum possible transmit time is 1 msec for a 60ppm crystal + * and 16ms for a 30ppm crystal! We need to limit PDU size based on + * crystal accuracy. Look at this in the spec. + */ + +/* XXX: private header file? */ +extern uint8_t g_nrf_num_irks; +extern uint32_t g_nrf_irk_list[]; + +/* To disable all radio interrupts */ +#define NRF_RADIO_IRQ_MASK_ALL (0x34FF) + +/* + * We configure the nrf with a 1 byte S0 field, 8 bit length field, and + * zero bit S1 field. The preamble is 8 bits long. + */ +#define NRF_LFLEN_BITS (8) +#define NRF_S0LEN (1) +#define NRF_S1LEN_BITS (0) +#define NRF_CILEN_BITS (2) +#define NRF_TERMLEN_BITS (3) + +/* Maximum length of frames */ +#define NRF_MAXLEN (255) +#define NRF_BALEN (3) /* For base address of 3 bytes */ + +/* NRF_RADIO->PCNF0 configuration values */ +#define NRF_PCNF0 (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | \ + (RADIO_PCNF0_S1INCL_Msk) | \ + (NRF_S0LEN << RADIO_PCNF0_S0LEN_Pos) | \ + (NRF_S1LEN_BITS << RADIO_PCNF0_S1LEN_Pos) +#define NRF_PCNF0_1M (NRF_PCNF0) | \ + (RADIO_PCNF0_PLEN_8bit << RADIO_PCNF0_PLEN_Pos) +#define NRF_PCNF0_2M (NRF_PCNF0) | \ + (RADIO_PCNF0_PLEN_16bit << RADIO_PCNF0_PLEN_Pos) +#define NRF_PCNF0_CODED (NRF_PCNF0) | \ + (RADIO_PCNF0_PLEN_LongRange << RADIO_PCNF0_PLEN_Pos) | \ + (NRF_CILEN_BITS << RADIO_PCNF0_CILEN_Pos) | \ + (NRF_TERMLEN_BITS << RADIO_PCNF0_TERMLEN_Pos) + +/* BLE PHY data structure */ +struct ble_phy_obj +{ + uint8_t phy_stats_initialized; + int8_t phy_txpwr_dbm; + uint8_t phy_chan; + uint8_t phy_state; + uint8_t phy_transition; + uint8_t phy_transition_late; + uint8_t phy_rx_started; + uint8_t phy_encrypted; +#if PHY_USE_HEADERMASK_WORKAROUND + uint8_t phy_headermask; + uint8_t phy_headerbyte; +#endif + uint8_t phy_privacy; + uint8_t phy_tx_pyld_len; + uint8_t phy_cur_phy_mode; + uint8_t phy_tx_phy_mode; + uint8_t phy_rx_phy_mode; + uint8_t phy_bcc_offset; + uint32_t phy_aar_scratch; + uint32_t phy_access_address; + struct ble_mbuf_hdr rxhdr; + void *txend_arg; + ble_phy_tx_end_func txend_cb; + uint32_t phy_start_cputime; +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) + uint16_t tifs; +#endif + + uint16_t txtx_time_us; + uint8_t txtx_time_anchor; +}; +static struct ble_phy_obj g_ble_phy_data; + +/* XXX: if 27 byte packets desired we can make this smaller */ +/* Global transmit/receive buffer */ +static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; +static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) +/* Make sure word-aligned for faster copies */ +static uint32_t g_ble_phy_enc_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; +#endif + +/* RF center frequency for each channel index (offset from 2400 MHz) */ +static const uint8_t g_ble_phy_chan_freq[BLE_PHY_NUM_CHANS] = { + 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, /* 0-9 */ + 24, 28, 30, 32, 34, 36, 38, 40, 42, 44, /* 10-19 */ + 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, /* 20-29 */ + 66, 68, 70, 72, 74, 76, 78, 2, 26, 80, /* 30-39 */ +}; + +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +/* packet start offsets (in usecs) */ +static const uint16_t g_ble_phy_mode_pkt_start_off[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 40, + [BLE_PHY_MODE_2M] = 24, + [BLE_PHY_MODE_CODED_125KBPS] = 376, + [BLE_PHY_MODE_CODED_500KBPS] = 376 +}; +#endif + +/* Various radio timings */ +/* Radio ramp-up times in usecs (fast mode) */ +#define BLE_PHY_T_TXENFAST (XCVR_TX_RADIO_RAMPUP_USECS) +#define BLE_PHY_T_RXENFAST (XCVR_RX_RADIO_RAMPUP_USECS) + +#if BABBLESIM +/* delay between EVENTS_READY and start of tx */ +static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 1, + [BLE_PHY_MODE_2M] = 1, +}; +/* delay between EVENTS_END and end of txd packet */ +static const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 1, + [BLE_PHY_MODE_2M] = 1, +}; +/* delay between rxd access address (w/ TERM1 for coded) and EVENTS_ADDRESS */ +static const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 9, + [BLE_PHY_MODE_2M] = 5, +}; +/* delay between end of rxd packet and EVENTS_END */ +static const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 9, + [BLE_PHY_MODE_2M] = 5, +}; +#else +/* delay between EVENTS_READY and start of tx */ +static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 4, + [BLE_PHY_MODE_2M] = 3, + [BLE_PHY_MODE_CODED_125KBPS] = 5, + [BLE_PHY_MODE_CODED_500KBPS] = 5 +}; +/* delay between EVENTS_END and end of txd packet */ +static const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 4, + [BLE_PHY_MODE_2M] = 3, + [BLE_PHY_MODE_CODED_125KBPS] = 9, + [BLE_PHY_MODE_CODED_500KBPS] = 3 +}; +/* delay between rxd access address (w/ TERM1 for coded) and EVENTS_ADDRESS */ +static const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 6, + [BLE_PHY_MODE_2M] = 2, + [BLE_PHY_MODE_CODED_125KBPS] = 17, + [BLE_PHY_MODE_CODED_500KBPS] = 17 +}; +/* delay between end of rxd packet and EVENTS_END */ +static const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 6, + [BLE_PHY_MODE_2M] = 2, + [BLE_PHY_MODE_CODED_125KBPS] = 27, + [BLE_PHY_MODE_CODED_500KBPS] = 22 +}; +#endif + +/* Statistics */ +STATS_SECT_START(ble_phy_stats) + STATS_SECT_ENTRY(phy_isrs) + STATS_SECT_ENTRY(tx_good) + STATS_SECT_ENTRY(tx_fail) + STATS_SECT_ENTRY(tx_late) + STATS_SECT_ENTRY(tx_bytes) + STATS_SECT_ENTRY(rx_starts) + STATS_SECT_ENTRY(rx_aborts) + STATS_SECT_ENTRY(rx_valid) + STATS_SECT_ENTRY(rx_crc_err) + STATS_SECT_ENTRY(rx_late) + STATS_SECT_ENTRY(radio_state_errs) + STATS_SECT_ENTRY(rx_hw_err) + STATS_SECT_ENTRY(tx_hw_err) +STATS_SECT_END +STATS_SECT_DECL(ble_phy_stats) ble_phy_stats; + +STATS_NAME_START(ble_phy_stats) + STATS_NAME(ble_phy_stats, phy_isrs) + STATS_NAME(ble_phy_stats, tx_good) + STATS_NAME(ble_phy_stats, tx_fail) + STATS_NAME(ble_phy_stats, tx_late) + STATS_NAME(ble_phy_stats, tx_bytes) + STATS_NAME(ble_phy_stats, rx_starts) + STATS_NAME(ble_phy_stats, rx_aborts) + STATS_NAME(ble_phy_stats, rx_valid) + STATS_NAME(ble_phy_stats, rx_crc_err) + STATS_NAME(ble_phy_stats, rx_late) + STATS_NAME(ble_phy_stats, radio_state_errs) + STATS_NAME(ble_phy_stats, rx_hw_err) + STATS_NAME(ble_phy_stats, tx_hw_err) +STATS_NAME_END(ble_phy_stats) + +/* + * NOTE: + * Tested the following to see what would happen: + * -> NVIC has radio irq enabled (interrupt # 1, mask 0x2). + * -> Set up nrf to receive. Clear ADDRESS event register. + * -> Enable ADDRESS interrupt on nrf5 by writing to INTENSET. + * -> Enable RX. + * -> Disable interrupts globally using OS_ENTER_CRITICAL(). + * -> Wait until a packet is received and the ADDRESS event occurs. + * -> Call ble_phy_disable(). + * + * At this point I wanted to see the state of the cortex NVIC. The IRQ + * pending bit was TRUE for the radio interrupt (as expected) as we never + * serviced the radio interrupt (interrupts were disabled). + * + * What was unexpected was this: without clearing the pending IRQ in the NVIC, + * when radio interrupts were re-enabled (address event bit in INTENSET set to + * 1) and the radio ADDRESS event register read 1 (it was never cleared after + * the first address event), the radio did not enter the ISR! I would have + * expected that if the following were true, an interrupt would occur: + * -> NVIC ISER bit set to TRUE + * -> NVIC ISPR bit reads TRUE, meaning interrupt is pending. + * -> Radio peripheral interrupts are enabled for some event (or events). + * -> Corresponding event register(s) in radio peripheral read 1. + * + * Not sure what the end result of all this is. We will clear the pending + * bit in the NVIC just to be sure when we disable the PHY. + */ + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + +/* + * Per nordic, the number of bytes needed for scratch is 16 + MAX_PKT_SIZE. + * However, when I used a smaller size it still overwrote the scratchpad. Until + * I figure this out I am just going to allocate 67 words so we have enough + * space for 267 bytes of scratch. I used 268 bytes since not sure if this + * needs to be aligned and burning a byte is no big deal. + */ +//#define NRF_ENC_SCRATCH_WORDS (((MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE) + 16) + 3) / 4) +#define NRF_ENC_SCRATCH_WORDS (67) + +static uint32_t g_nrf_encrypt_scratchpad[NRF_ENC_SCRATCH_WORDS]; + +struct nrf_ccm_data +{ + uint8_t key[16]; + uint64_t pkt_counter; + uint8_t dir_bit; + uint8_t iv[8]; +} __attribute__((packed)); + +struct nrf_ccm_data g_nrf_ccm_data; +#endif + +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) + +/* Packet start offset (in usecs). This is the preamble plus access address. + * For LE Coded PHY this also includes CI and TERM1. */ +static uint32_t +ble_phy_mode_pdu_start_off(int phy_mode) +{ + return g_ble_phy_mode_pkt_start_off[phy_mode]; +} + +#if NRF52_ERRATA_191_ENABLE_WORKAROUND +static bool +ble_phy_mode_is_coded(uint8_t phy_mode) +{ + return (phy_mode == BLE_PHY_MODE_CODED_125KBPS) || + (phy_mode == BLE_PHY_MODE_CODED_500KBPS); +} + +static void +phy_nrf52_errata_191(uint8_t new_phy_mode) +{ + bool from_coded = ble_phy_mode_is_coded(g_ble_phy_data.phy_cur_phy_mode); + bool to_coded = ble_phy_mode_is_coded(new_phy_mode); + + /* [191] RADIO: High packet error rate in BLE Long Range mode + * Should be applied only if switching to/from LE Coded, no need to apply + * on each mode change. + */ + if (from_coded == to_coded) { + return; + } + + if (to_coded) { + *(volatile uint32_t *)0x40001740 = + ((*((volatile uint32_t *)0x40001740)) & 0x7fff00ff) | + 0x80000000 | (((uint32_t)(196)) << 8); + } else { + *(volatile uint32_t *) 0x40001740 = + ((*((volatile uint32_t *) 0x40001740)) & 0x7fffffff); + } +} +#endif + +static void +ble_phy_mode_apply(uint8_t phy_mode) +{ + if (phy_mode == g_ble_phy_data.phy_cur_phy_mode) { + return; + } + +#if NRF52_ERRATA_191_ENABLE_WORKAROUND + if (nrf52_errata_191()) { + phy_nrf52_errata_191(phy_mode); + } +#endif + + switch (phy_mode) { + case BLE_PHY_MODE_1M: + NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); +#endif + NRF_RADIO->PCNF0 = NRF_PCNF0_1M; + break; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) + case BLE_PHY_MODE_2M: + NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_2Mbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0084); +#endif + NRF_RADIO->PCNF0 = NRF_PCNF0_2M; + break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + case BLE_PHY_MODE_CODED_125KBPS: + NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR125Kbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); +#endif + NRF_RADIO->PCNF0 = NRF_PCNF0_CODED; + break; + case BLE_PHY_MODE_CODED_500KBPS: + NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR500Kbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); +#endif + NRF_RADIO->PCNF0 = NRF_PCNF0_CODED; + break; +#endif + default: + assert(0); + } + + g_ble_phy_data.phy_cur_phy_mode = phy_mode; +} + +void +ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode) +{ + g_ble_phy_data.phy_tx_phy_mode = tx_phy_mode; + g_ble_phy_data.phy_rx_phy_mode = rx_phy_mode; +} +#else +static uint32_t +ble_phy_mode_pdu_start_off(int phy_mode) +{ + return 40; +} +#endif + +static int +ble_phy_get_cur_phy(void) +{ +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) + switch (g_ble_phy_data.phy_cur_phy_mode) { + case BLE_PHY_MODE_1M: + return BLE_PHY_1M; + case BLE_PHY_MODE_2M: + return BLE_PHY_2M; + case BLE_PHY_MODE_CODED_125KBPS: + case BLE_PHY_MODE_CODED_500KBPS: + return BLE_PHY_CODED; + default: + assert(0); + return -1; + } +#else + return BLE_PHY_1M; +#endif +} + +/** + * Copies the data from the phy receive buffer into a mbuf chain. + * + * @param dptr Pointer to receive buffer + * @param rxpdu Pointer to already allocated mbuf chain + * + * NOTE: the packet header already has the total mbuf length in it. The + * lengths of the individual mbufs are not set prior to calling. + * + */ +void +ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) +{ + uint32_t rem_len; + uint32_t copy_len; + uint32_t block_len; + uint32_t block_rem_len; + void *dst; + void *src; + struct os_mbuf * om; + + /* Better be aligned */ + assert(((uint32_t)dptr & 3) == 0); + + block_len = rxpdu->om_omp->omp_databuf_len; + rem_len = OS_MBUF_PKTHDR(rxpdu)->omp_len; + src = dptr; + + /* + * Setup for copying from first mbuf which is shorter due to packet header + * and extra leading space + */ + copy_len = block_len - rxpdu->om_pkthdr_len - 4; + om = rxpdu; + dst = om->om_data; + + while (true) { + /* + * Always copy blocks of length aligned to word size, only last mbuf + * will have remaining non-word size bytes appended. + */ + block_rem_len = copy_len; + copy_len = min(copy_len, rem_len); + copy_len &= ~3; + + dst = om->om_data; + om->om_len = copy_len; + rem_len -= copy_len; + block_rem_len -= copy_len; + +#if BABBLESIM + memcpy(dst, src, copy_len); + dst += copy_len; + src += copy_len; +#else + __asm__ volatile (".syntax unified \n" + " mov r4, %[len] \n" + " b 2f \n" + "1: ldr r3, [%[src], %[len]] \n" + " str r3, [%[dst], %[len]] \n" + "2: subs %[len], #4 \n" + " bpl 1b \n" + " adds %[src], %[src], r4 \n" + " adds %[dst], %[dst], r4 \n" + : [dst] "+r" (dst), [src] "+r" (src), + [len] "+r" (copy_len) + : + : "r3", "r4", "memory" + ); +#endif + + if ((rem_len < 4) && (block_rem_len >= rem_len)) { + break; + } + + /* Move to next mbuf */ + om = SLIST_NEXT(om, om_next); + copy_len = block_len; + } + + /* Copy remaining bytes, if any, to last mbuf */ + om->om_len += rem_len; + +#if BABBLESIM + memcpy(dst, src, rem_len); +#else + __asm__ volatile (".syntax unified \n" + " b 2f \n" + "1: ldrb r3, [%[src], %[len]] \n" + " strb r3, [%[dst], %[len]] \n" + "2: subs %[len], #1 \n" + " bpl 1b \n" + : [len] "+r" (rem_len) + : [dst] "r" (dst), [src] "r" (src) + : "r3", "memory" + ); +#endif + + /* Copy header */ + memcpy(BLE_MBUF_HDR_PTR(rxpdu), &g_ble_phy_data.rxhdr, + sizeof(struct ble_mbuf_hdr)); +} + +/** + * Called when we want to wait if the radio is in either the rx or tx + * disable states. We want to wait until that state is over before doing + * anything to the radio + */ +static void +nrf_wait_disabled(void) +{ + uint32_t state; + + state = NRF_RADIO->STATE; + if (state != RADIO_STATE_STATE_Disabled) { + if ((state == RADIO_STATE_STATE_RxDisable) || + (state == RADIO_STATE_STATE_TxDisable)) { + /* This will end within a short time (6 usecs). Just poll */ + while (NRF_RADIO->STATE == state) { + /* If this fails, something is really wrong. Should last + * no more than 6 usecs */ +#if BABBLESIM + tm_tick(); +#endif + } + } + } +} + +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) +void +ble_phy_tifs_set(uint16_t tifs) +{ + g_ble_phy_data.tifs = tifs; +} +#endif + +/** + * + * + */ +static int +ble_phy_set_start_time(uint32_t cputime, uint8_t rem_us, bool tx) +{ + uint32_t next_cc; + uint32_t cur_cc; + uint32_t cntr; + uint32_t delta; + int radio_rem_us; +#if PHY_USE_FEM + int fem_rem_us = 0; +#endif + int rem_us_corr; + int min_rem_us; + + /* Calculate rem_us for radio and FEM enable. The result may be a negative + * value, but we'll adjust later. + */ + if (tx) { + radio_rem_us = rem_us - BLE_PHY_T_TXENFAST - + g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; +#if PHY_USE_FEM_PA + fem_rem_us = rem_us - MYNEWT_VAL(BLE_FEM_PA_TURN_ON_US); +#endif + } else { + radio_rem_us = rem_us - BLE_PHY_T_TXENFAST; +#if PHY_USE_FEM_LNA + fem_rem_us = rem_us - MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US); +#endif + } + +#if PHY_USE_FEM + min_rem_us = min(radio_rem_us, fem_rem_us); +#else + min_rem_us = radio_rem_us; +#endif + + /* We need to adjust rem_us values, so they are >=1 for TIMER0 compare + * event to be triggered. + * + * If FEM is not enabled, calculated rem_us is -45<=rem_us<=-15 since we + * only had to adjust earlier for ramp-up and txdelay, i.e. 40+5=45us in + * worst case, so we adjust by 1 or 2 tick(s) only. + * + * If FEM is enabled, turn on time may be a bit longer, so we also allow to + * adjust by 3 ticks so up to 90us which should be enough. If needed, we + * can extend this by another tick but having FEM with turn on time >90us + * means transition may become tricky. + */ + + if ((PHY_USE_FEM) && (min_rem_us <= -61)) { + cputime -= 3; + rem_us_corr = 91; + } else if (min_rem_us <= -30) { + /* rem_us is -60..-30 */ + cputime -= 2; + rem_us_corr = 61; + } else { + /* rem_us is -29..0 */ + cputime -= 1; + rem_us_corr = 30; + } + + /* + * Can we set the RTC compare to start TIMER0? We can do it if: + * a) Current compare value is not N+1 or N+2 ticks from current + * counter. + * b) The value we want to set is not at least N+2 from current + * counter. + * + * NOTE: since the counter can tick 1 while we do these calculations we + * need to account for it. + */ + next_cc = cputime & 0xffffff; + cur_cc = NRF_RTC0->CC[0]; + cntr = NRF_RTC0->COUNTER; + + delta = (cur_cc - cntr) & 0xffffff; + if ((delta <= 3) && (delta != 0)) { + return -1; + } + delta = (next_cc - cntr) & 0xffffff; + if ((delta & 0x800000) || (delta < 3)) { + return -1; + } + + /* Clear and set TIMER0 to fire off at proper time */ + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR); + nrf_timer_cc_set(NRF_TIMER0, 0, radio_rem_us + rem_us_corr); + NRF_TIMER0->EVENTS_COMPARE[0] = 0; +#if PHY_USE_FEM + if (fem_rem_us) { + nrf_timer_cc_set(NRF_TIMER0, 2, fem_rem_us + rem_us_corr); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + } +#endif + + /* Set RTC compare to start TIMER0 */ + NRF_RTC0->EVENTS_COMPARE[0] = 0; + nrf_rtc_cc_set(NRF_RTC0, 0, next_cc); + nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); + + /* Enable PPI */ +#if PHY_USE_FEM + if (fem_rem_us) { + if (tx) { +#if PHY_USE_FEM_PA + phy_fem_enable_pa(); +#endif + } else { +#if PHY_USE_FEM_LNA + phy_fem_enable_lna(); +#endif + } + } +#endif + phy_ppi_rtc0_compare0_to_timer0_start_enable(); + + /* Store the cputime at which we set the RTC */ + g_ble_phy_data.phy_start_cputime = cputime; + + return 0; +} + +static int +ble_phy_set_start_now(void) +{ + os_sr_t sr; + uint32_t now; + uint32_t radio_rem_us; +#if PHY_USE_FEM_LNA + uint32_t fem_rem_us; +#endif + + OS_ENTER_CRITICAL(sr); + + /* We need to set TIMER0 compare registers to at least 1 as otherwise + * compare event won't be triggered. Event (FEM/radio) that have to be + * triggered first is set to 1, other event is set to 1+diff. + * + * Note that this is only used for rx, so only need to handle LNA. + */ + +#if PHY_USE_FEM_LNA + if (MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US) > BLE_PHY_T_RXENFAST) { + radio_rem_us = 1 + MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US) - + BLE_PHY_T_RXENFAST; + fem_rem_us = 1; + } else { + radio_rem_us = 1; + fem_rem_us = 1 + BLE_PHY_T_RXENFAST - + MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US); + } +#else + radio_rem_us = 1; +#endif + + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR); + nrf_timer_cc_set(NRF_TIMER0, 0, radio_rem_us); + NRF_TIMER0->EVENTS_COMPARE[0] = 0; +#if PHY_USE_FEM_LNA + nrf_timer_cc_set(NRF_TIMER0, 2, fem_rem_us); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; +#endif + + /* + * Set RTC compare to start TIMER0. We need to set it to at least N+2 ticks + * from current value to guarantee triggering compare event, but let's set + * it to N+3 to account for possible extra tick on RTC0 during these + * operations. + */ + now = os_cputime_get32(); + NRF_RTC0->EVENTS_COMPARE[0] = 0; + nrf_rtc_cc_set(NRF_RTC0, 0, (now + 3) & 0xffffff); + nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); + +#if PHY_USE_FEM_LNA + phy_fem_enable_lna(); +#endif + + /* Enable PPI */ + phy_ppi_rtc0_compare0_to_timer0_start_enable(); + + /* + * Store the cputime at which we set the RTC + * + * XXX Compare event may be triggered on previous CC value (if it was set to + * less than N+2) so in rare cases actual start time may be 2 ticks earlier + * than what we expect. Since this is only used on RX, it may cause AUX scan + * to be scheduled 1 or 2 ticks too late so we'll miss it - it's acceptable + * for now. + */ + g_ble_phy_data.phy_start_cputime = now + 3; + + OS_EXIT_CRITICAL(sr); + + return 0; +} + +/** + * Function is used to set PPI so that we can time out waiting for a reception + * to occur. This happens for two reasons: we have sent a packet and we are + * waiting for a response (txrx should be set to ENABLE_TXRX) or we are + * starting a connection event and we are a slave and we are waiting for the + * master to send us a packet (txrx should be set to ENABLE_RX). + * + * NOTE: when waiting for a txrx turn-around, wfr_usecs is not used as there + * is no additional time to wait; we know when we should receive the address of + * the received frame. + * + * @param txrx Flag denoting if this wfr is a txrx turn-around or not. + * @param tx_phy_mode phy mode for last TX (only valid for TX->RX) + * @param wfr_usecs Amount of usecs to wait. + */ +void +ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) +{ + uint32_t end_time; + uint8_t phy; + uint16_t tifs; + + phy = g_ble_phy_data.phy_cur_phy_mode; + +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) + tifs = g_ble_phy_data.tifs; +#else + tifs = BLE_LL_IFS; +#endif + + if (txrx == BLE_PHY_WFR_ENABLE_TXRX) { + /* RX shall start exactly T_IFS after TX end captured in CC[2] */ + end_time = NRF_TIMER0->CC[2] + tifs; + /* Adjust for delay between EVENT_END and actual TX end time */ + end_time += g_ble_phy_t_txenddelay[tx_phy_mode]; + /* Wait a bit longer due to allowed active clock accuracy */ + end_time += 2; + /* + * It's possible that we'll capture PDU start time at the end of timer + * cycle and since wfr expires at the beginning of calculated timer + * cycle it can be almost 1 usec too early. Let's compensate for this + * by waiting 1 usec more. + */ + end_time += 1; + } else { + /* + * RX shall start no later than wfr_usecs after RX enabled. + * CC[0] is the time of RXEN so adjust for radio ram-up. + * Do not add jitter since this is already covered by LL. + */ + end_time = NRF_TIMER0->CC[0] + BLE_PHY_T_RXENFAST + wfr_usecs; + } + + /* + * Note: on LE Coded EVENT_ADDRESS is fired after TERM1 is received, so + * we are actually calculating relative to start of packet payload + * which is fine. + */ + + /* Adjust for receiving access address since this triggers EVENT_ADDRESS */ + end_time += ble_phy_mode_pdu_start_off(phy); + /* Adjust for delay between actual access address RX and EVENT_ADDRESS */ + end_time += g_ble_phy_t_rxaddrdelay[phy]; + + /* wfr_secs is the time from rxen until timeout */ + nrf_timer_cc_set(NRF_TIMER0, 3, end_time); + NRF_TIMER0->EVENTS_COMPARE[3] = 0; + + /* Enable wait for response PPI */ + phy_ppi_wfr_enable(); + + /* + * It may happen that if CPU is halted for a brief moment (e.g. during flash + * erase or write), TIMER0 already counted past CC[3] and thus wfr will not + * fire as expected. In case this happened, let's just disable PPIs for wfr + * and trigger wfr manually (i.e. disable radio). + * + * Note that the same applies to RX start time set in CC[0] but since it + * should fire earlier than wfr, fixing wfr is enough. + * + * CC[1] is only used as a reference on RX start, we do not need it here so + * it can be used to read TIMER0 counter. + */ + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE1); + if (NRF_TIMER0->CC[1] > NRF_TIMER0->CC[3]) { + phy_ppi_wfr_disable(); + nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE); + } +} + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) +static uint32_t +ble_phy_get_ccm_datarate(void) +{ +#if BLE_LL_BT5_PHY_SUPPORTED + switch (g_ble_phy_data.phy_cur_phy_mode) { + case BLE_PHY_MODE_1M: + return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos; + case BLE_PHY_MODE_2M: + return CCM_MODE_DATARATE_2Mbit << CCM_MODE_DATARATE_Pos; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + case BLE_PHY_MODE_CODED_125KBPS: + return CCM_MODE_DATARATE_125Kbps << CCM_MODE_DATARATE_Pos; + case BLE_PHY_MODE_CODED_500KBPS: + return CCM_MODE_DATARATE_500Kbps << CCM_MODE_DATARATE_Pos; +#endif + } + + assert(0); + return 0; +#else + return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos; +#endif +} +#endif + +/** + * Setup transceiver for receive. + */ +static void +ble_phy_rx_xcvr_setup(void) +{ + uint8_t *dptr; + + dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; + dptr += 3; + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + if (g_ble_phy_data.phy_encrypted) { + NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0]; + NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; + NRF_CCM->OUTPTR = (uint32_t)dptr; + NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; + NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | CCM_MODE_MODE_Decryption | + ble_phy_get_ccm_datarate(); + NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data; + NRF_CCM->SHORTS = 0; + NRF_CCM->EVENTS_ERROR = 0; + NRF_CCM->EVENTS_ENDCRYPT = 0; + nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN); + phy_ppi_radio_address_to_ccm_crypt_enable(); + } else { + NRF_RADIO->PACKETPTR = (uint32_t)dptr; + } +#else + NRF_RADIO->PACKETPTR = (uint32_t)dptr; +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (g_ble_phy_data.phy_privacy) { + NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled; + NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; + NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch; + NRF_AAR->EVENTS_END = 0; + NRF_AAR->EVENTS_RESOLVED = 0; + NRF_AAR->EVENTS_NOTRESOLVED = 0; + } else { + if (g_ble_phy_data.phy_encrypted == 0) { + NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled; + } + } +#endif + + /* Turn off trigger TXEN on output compare match and AAR on bcmatch */ + phy_ppi_timer0_compare0_to_radio_txen_disable(); + phy_ppi_radio_bcmatch_to_aar_start_disable(); + + /* Reset the rx started flag. Used for the wait for response */ + g_ble_phy_data.phy_rx_started = 0; + g_ble_phy_data.phy_state = BLE_PHY_STATE_RX; + +#if BLE_LL_BT5_PHY_SUPPORTED + /* + * On Coded PHY there are CI and TERM1 fields before PDU starts so we need + * to take this into account when setting up BCC. + */ + if (g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_125KBPS || + g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_500KBPS) { + g_ble_phy_data.phy_bcc_offset = 5; + } else { + g_ble_phy_data.phy_bcc_offset = 0; + } +#else + g_ble_phy_data.phy_bcc_offset = 0; +#endif + + /* I want to know when 1st byte received (after address) */ + nrf_radio_bcc_set(NRF_RADIO, 8 + g_ble_phy_data.phy_bcc_offset); /* in bits */ + NRF_RADIO->EVENTS_ADDRESS = 0; + NRF_RADIO->EVENTS_DEVMATCH = 0; + NRF_RADIO->EVENTS_BCMATCH = 0; + NRF_RADIO->EVENTS_RSSIEND = 0; + NRF_RADIO->EVENTS_CRCOK = 0; + NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | + RADIO_SHORTS_READY_START_Msk | + RADIO_SHORTS_ADDRESS_BCSTART_Msk | + RADIO_SHORTS_ADDRESS_RSSISTART_Msk | + RADIO_SHORTS_DISABLED_RSSISTOP_Msk; + + nrf_radio_int_enable(NRF_RADIO, RADIO_INTENSET_ADDRESS_Msk | + RADIO_INTENSET_DISABLED_Msk); +} + +/** + * Called from interrupt context when the transmit ends + * + */ +static void +ble_phy_tx_end_isr(void) +{ + uint8_t tx_phy_mode; + uint8_t was_encrypted; + uint8_t transition; + uint32_t rx_time; + uint32_t tx_time; +#if PHY_USE_FEM + uint32_t fem_time; +#endif + uint32_t radio_time; + uint16_t tifs; + + /* Store PHY on which we've just transmitted smth */ + tx_phy_mode = g_ble_phy_data.phy_cur_phy_mode; + + /* If this transmission was encrypted we need to remember it */ + was_encrypted = g_ble_phy_data.phy_encrypted; + (void)was_encrypted; + + /* Better be in TX state! */ + assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + /* + * XXX: not sure what to do. We had a HW error during transmission. + * For now I just count a stat but continue on like all is good. + */ + if (was_encrypted) { + if (NRF_CCM->EVENTS_ERROR) { + STATS_INC(ble_phy_stats, tx_hw_err); + NRF_CCM->EVENTS_ERROR = 0; + } + } +#endif + +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) + tifs = g_ble_phy_data.tifs; + g_ble_phy_data.tifs = BLE_LL_IFS; +#else + tifs = BLE_LL_IFS; +#endif + transition = g_ble_phy_data.phy_transition; + + if (g_ble_phy_data.txend_cb) { + g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); + } + + if (transition == BLE_PHY_TRANSITION_TX_RX) { +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) + ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode); +#endif + + /* Packet pointer needs to be reset. */ + ble_phy_rx_xcvr_setup(); + + ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, tx_phy_mode, 0); + + /* Schedule RX exactly T_IFS after TX end captured in CC[2] */ + rx_time = NRF_TIMER0->CC[2] + tifs; + /* Adjust for delay between EVENT_END and actual TX end time */ + rx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; + /* Start listening a bit earlier due to allowed active clock accuracy */ + rx_time -= 2; + +#if PHY_USE_FEM_LNA + fem_time = rx_time - MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US); + nrf_timer_cc_set(NRF_TIMER0, 2, fem_time); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + phy_fem_enable_lna(); +#endif + + radio_time = rx_time - BLE_PHY_T_RXENFAST; + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + phy_ppi_timer0_compare0_to_radio_rxen_enable(); + + /* In case TIMER0 did already count past CC[0] and/or CC[2], radio + * and/or LNA may not be enabled. In any case we won't be stuck since + * wfr will cancel rx if needed. + * + * FIXME failing to enable LNA may result in unexpected RSSI drop in + * case we still rxd something, so perhaps we could check it here + */ + } else if (transition == BLE_PHY_TRANSITION_TX_TX) { + if (g_ble_phy_data.txtx_time_anchor) { + /* Schedule next TX relative to current TX end. TX end timestamp is + * captured in CC[2]. + */ + tx_time = NRF_TIMER0->CC[2] + g_ble_phy_data.txtx_time_us; + } else { + /* Schedule next TX relative to current TX start. AA timestamp is + * captured in CC[1], we need to adjust for sync word to get TX + * start. + */ + tx_time = NRF_TIMER0->CC[1] - ble_ll_pdu_syncword_us(tx_phy_mode) + + g_ble_phy_data.txtx_time_us; + /* Adjust for delay between EVENT_ADDRESS and actual address TX time */ + /* FIXME assume this is the same as EVENT_END to end, but we should + * measure this to be sure */ + tx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; + } + + /* Adjust for delay between EVENT_END and actual TX end time */ + tx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; + +#if PHY_USE_FEM_PA + fem_time = tx_time - MYNEWT_VAL(BLE_FEM_PA_TURN_ON_US); +#endif + + /* Adjust for delay between EVENT_READY and actual TX start time */ + tx_time -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; + + radio_time = tx_time - BLE_PHY_T_TXENFAST; + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + phy_ppi_timer0_compare0_to_radio_txen_enable(); + +#if PHY_USE_FEM_PA + nrf_timer_cc_set(NRF_TIMER0, 2, fem_time); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + phy_fem_enable_pa(); +#endif + + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3); + if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) { + phy_ppi_timer0_compare0_to_radio_txen_disable(); + g_ble_phy_data.phy_transition_late = 1; + } + } else { + /* + * XXX: not sure we need to stop the timer here all the time. Or that + * it should be stopped here. + */ + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); + NRF_TIMER0->TASKS_SHUTDOWN = 1; + phy_ppi_wfr_disable(); + phy_ppi_timer0_compare0_to_radio_txen_disable(); + phy_ppi_rtc0_compare0_to_timer0_start_disable(); + assert(transition == BLE_PHY_TRANSITION_NONE); + } +} + +static inline uint8_t +ble_phy_get_cur_rx_phy_mode(void) +{ + uint8_t phy; + + phy = g_ble_phy_data.phy_cur_phy_mode; + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + /* + * For Coded PHY mode can be set to either codings since actual coding is + * set in packet header. However, here we need actual coding of received + * packet as this determines pipeline delays so need to figure this out + * using CI field. + */ + if ((phy == BLE_PHY_MODE_CODED_125KBPS) || + (phy == BLE_PHY_MODE_CODED_500KBPS)) { + phy = NRF_RADIO->PDUSTAT & RADIO_PDUSTAT_CISTAT_Msk ? + BLE_PHY_MODE_CODED_500KBPS : + BLE_PHY_MODE_CODED_125KBPS; + } +#endif + + return phy; +} + +static void +ble_phy_rx_end_isr(void) +{ + int rc; + uint8_t *dptr; + uint8_t crcok; + uint32_t tx_time; +#if PHY_USE_FEM_PA + uint32_t fem_time; +#endif + uint32_t radio_time; + uint16_t tifs; + struct ble_mbuf_hdr *ble_hdr; + bool is_late; + + /* Disable automatic RXEN */ + phy_ppi_timer0_compare0_to_radio_rxen_disable(); + + /* Set RSSI and CRC status flag in header */ + ble_hdr = &g_ble_phy_data.rxhdr; + assert(NRF_RADIO->EVENTS_RSSIEND != 0); + ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->RSSISAMPLE); + + dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; + dptr += 3; + + /* Count PHY crc errors and valid packets */ + crcok = NRF_RADIO->EVENTS_CRCOK; + if (!crcok) { + STATS_INC(ble_phy_stats, rx_crc_err); + } else { + STATS_INC(ble_phy_stats, rx_valid); + ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + if (g_ble_phy_data.phy_encrypted) { + while (NRF_CCM->EVENTS_ENDCRYPT == 0) { + /* Make sure CCM finished */ + }; + + /* Only set MIC failure flag if frame is not zero length */ + if ((dptr[1] != 0) && (NRF_CCM->MICSTATUS == 0)) { + ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE; + } + + /* + * XXX: not sure how to deal with this. This should not + * be a MIC failure but we should not hand it up. I guess + * this is just some form of rx error and that is how we + * handle it? For now, just set CRC error flags + */ + if (NRF_CCM->EVENTS_ERROR) { + STATS_INC(ble_phy_stats, rx_hw_err); + ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; + } + } +#endif + } + +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) + ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode); +#endif + + /* + * Let's schedule TX now and we will just cancel it after processing RXed + * packet if we don't need TX. + * + * We need this to initiate connection in case AUX_CONNECT_REQ was sent on + * LE Coded S8. In this case the time we process RXed packet is roughly the + * same as the limit when we need to have TX scheduled (i.e. TIMER0 and PPI + * armed) so we may simply miss the slot and set the timer in the past. + * + * When TX is scheduled in advance, we may event process packet a bit longer + * during radio ramp-up - this gives us extra 40 usecs which is more than + * enough. + */ + +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) + tifs = g_ble_phy_data.tifs; + g_ble_phy_data.tifs = BLE_LL_IFS; +#else + tifs = BLE_LL_IFS; +#endif + + /* Schedule TX exactly T_IFS after RX end captured in CC[2] */ + tx_time = NRF_TIMER0->CC[2] + tifs; + /* Adjust for delay between actual RX end time and EVENT_END */ + tx_time -= g_ble_phy_t_rxenddelay[ble_hdr->rxinfo.phy_mode]; + +#if PHY_USE_FEM_PA + fem_time = tx_time - MYNEWT_VAL(BLE_FEM_PA_TURN_ON_US); +#endif + + /* Adjust for delay between EVENT_READY and actual TX start time */ + tx_time -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; + + radio_time = tx_time - BLE_PHY_T_TXENFAST; + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + phy_ppi_timer0_compare0_to_radio_txen_enable(); + +#if PHY_USE_FEM_PA + nrf_timer_cc_set(NRF_TIMER0, 2, fem_time); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + phy_fem_enable_pa(); +#endif + + /* Need to check if TIMER0 did not already count past CC[0] and/or CC[2], so + * we're not stuck waiting for events in case radio and/or PA was not + * started. If event was triggered we're fine regardless of timer value. + * + * Note: CC[3] is used only for wfr which we do not need here. + */ + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3); + is_late = (NRF_TIMER0->CC[3] > radio_time) && !NRF_TIMER0->EVENTS_COMPARE[0]; +#if PHY_USE_FEM_PA + is_late = is_late || + ((NRF_TIMER0->CC[3] > fem_time) && !NRF_TIMER0->EVENTS_COMPARE[2]); +#endif + if (is_late) { + phy_ppi_timer0_compare0_to_radio_txen_disable(); + g_ble_phy_data.phy_transition_late = 1; + } + + /* + * XXX: This is a horrible ugly hack to deal with the RAM S1 byte + * that is not sent over the air but is present here. Simply move the + * data pointer to deal with it. Fix this later. + */ + dptr[2] = dptr[1]; + dptr[1] = dptr[0]; + rc = ble_ll_rx_end(dptr + 1, ble_hdr); + if (rc < 0) { + ble_phy_disable(); + } +} + +static bool +ble_phy_rx_start_isr(void) +{ + int rc; + uint32_t state; + uint32_t usecs; + uint32_t pdu_usecs; + uint32_t ticks; + struct ble_mbuf_hdr *ble_hdr; + uint8_t *dptr; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + int adva_offset; +#endif + + dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; + + /* Clear events and clear interrupt */ + NRF_RADIO->EVENTS_ADDRESS = 0; + nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_ADDRESS_Msk); + + /* Clear wfr timer channels */ + phy_ppi_wfr_disable(); + + /* Initialize the ble mbuf header */ + ble_hdr = &g_ble_phy_data.rxhdr; + ble_hdr->rxinfo.flags = ble_ll_state_get(); + ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; + ble_hdr->rxinfo.handle = 0; + ble_hdr->rxinfo.phy = ble_phy_get_cur_phy(); + ble_hdr->rxinfo.phy_mode = ble_phy_get_cur_rx_phy_mode(); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + ble_hdr->rxinfo.user_data = NULL; +#endif + + /* + * Calculate accurate packets start time (with remainder) + * + * We may start receiving packet somewhere during preamble in which case + * it is possible that actual transmission started before TIMER0 was + * running - need to take this into account. + */ + ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime; + + usecs = NRF_TIMER0->CC[1]; + pdu_usecs = ble_phy_mode_pdu_start_off(ble_hdr->rxinfo.phy_mode) + + g_ble_phy_t_rxaddrdelay[ble_hdr->rxinfo.phy_mode]; + if (usecs < pdu_usecs) { + g_ble_phy_data.phy_start_cputime--; + usecs += 30; + } + usecs -= pdu_usecs; + + ticks = os_cputime_usecs_to_ticks(usecs); + usecs -= os_cputime_ticks_to_usecs(ticks); + if (usecs == 31) { + usecs = 0; + ++ticks; + } + + ble_hdr->beg_cputime += ticks; + ble_hdr->rem_usecs = usecs; + + /* XXX: I wonder if we always have the 1st byte. If we need to wait for + * rx chain delay, it could be 18 usecs from address interrupt. The + nrf52 may be able to get here early. */ + /* Wait to get 1st byte of frame */ + while (1) { + state = NRF_RADIO->STATE; + if (NRF_RADIO->EVENTS_BCMATCH != 0) { + break; + } + + /* + * If state is disabled, we should have the BCMATCH. If not, + * something is wrong! + */ + if (state == RADIO_STATE_STATE_Disabled) { + nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); + NRF_RADIO->SHORTS = 0; + return false; + } + +#if BABBLESIM + tm_tick(); +#endif + } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + /* + * If privacy is enabled and received PDU has TxAdd bit set (i.e. random + * address) we try to resolve address using AAR. + */ + if (g_ble_phy_data.phy_privacy && (dptr[3] & 0x40)) { + /* + * AdvA is located at 4th octet in RX buffer (after S0, length an S1 + * fields). In case of extended advertising PDU we need to add 2 more + * octets for extended header. + */ + adva_offset = (dptr[3] & 0x0f) == 0x07 ? 2 : 0; + NRF_AAR->ADDRPTR = (uint32_t)(dptr + 3 + adva_offset); + + /* Trigger AAR after last bit of AdvA is received */ + NRF_RADIO->EVENTS_BCMATCH = 0; + phy_ppi_radio_bcmatch_to_aar_start_enable(); + nrf_radio_bcc_set(NRF_RADIO, (BLE_LL_PDU_HDR_LEN + adva_offset + + BLE_DEV_ADDR_LEN) * 8 + g_ble_phy_data.phy_bcc_offset); + } +#endif + + /* Call Link Layer receive start function */ + rc = ble_ll_rx_start(dptr + 3, + g_ble_phy_data.phy_chan, + &g_ble_phy_data.rxhdr); + if (rc >= 0) { + /* Set rx started flag and enable rx end ISR */ + g_ble_phy_data.phy_rx_started = 1; + } else { + /* Disable PHY */ + ble_phy_disable(); + STATS_INC(ble_phy_stats, rx_aborts); + } + + /* Count rx starts */ + STATS_INC(ble_phy_stats, rx_starts); + + return true; +} + +static void +ble_phy_isr(void) +{ + uint32_t irq_en; + + os_trace_isr_enter(); + + /* Read irq register to determine which interrupts are enabled */ + irq_en = NRF_RADIO->INTENSET; + + /* + * NOTE: order of checking is important! Possible, if things get delayed, + * we have both an ADDRESS and DISABLED interrupt in rx state. If we get + * an address, we disable the DISABLED interrupt. + */ + + /* We get this if we have started to receive a frame */ + if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) { + /* + * wfr timer is calculated to expire at the exact time we should start + * receiving a packet (with 1 usec precision) so it is possible it will + * fire at the same time as EVENT_ADDRESS. If this happens, radio will + * be disabled while we are waiting for EVENT_BCCMATCH after 1st byte + * of payload is received and ble_phy_rx_start_isr() will fail. In this + * case we should not clear DISABLED irq mask so it will be handled as + * regular radio disabled event below. In other case radio was disabled + * on purpose and there's nothing more to handle so we can clear mask. + */ + if (ble_phy_rx_start_isr()) { + irq_en &= ~RADIO_INTENCLR_DISABLED_Msk; + } + } + + /* Handle disabled event. This is enabled for both TX and RX. On RX, we + * need to check phy_rx_started flag to make sure we actually were receiving + * a PDU, otherwise this is due to wfr. + */ + if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) { + BLE_LL_ASSERT(NRF_RADIO->EVENTS_END || + ((g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) && + !g_ble_phy_data.phy_rx_started)); + NRF_RADIO->EVENTS_END = 0; + NRF_RADIO->EVENTS_DISABLED = 0; + nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_DISABLED_Msk); + + switch (g_ble_phy_data.phy_state) { + case BLE_PHY_STATE_RX: +#if MYNEWT_VAL(BLE_FEM_LNA) + phy_ppi_fem_disable(); + ble_fem_lna_disable(); +#endif + if (g_ble_phy_data.phy_rx_started) { + ble_phy_rx_end_isr(); + } else { + ble_ll_wfr_timer_exp(NULL); + } + break; + case BLE_PHY_STATE_TX: +#if MYNEWT_VAL(BLE_FEM_PA) + phy_ppi_fem_disable(); + ble_fem_pa_disable(); +#endif + ble_phy_tx_end_isr(); + break; + default: + BLE_LL_ASSERT(0); + } + } + + g_ble_phy_data.phy_transition_late = 0; + + /* Count # of interrupts */ + STATS_INC(ble_phy_stats, phy_isrs); + + os_trace_isr_exit(); +} + +#if PHY_USE_HEADERMASK_WORKAROUND +static void +ble_phy_ccm_isr(void) +{ + volatile uint8_t *tx_buf = (uint8_t *)g_ble_phy_tx_buf; + + if (NRF_CCM->EVENTS_ENDKSGEN) { + while (tx_buf[0] == 0xff); + tx_buf[0] = g_ble_phy_data.phy_headerbyte; + NRF_CCM->INTENCLR = CCM_INTENCLR_ENDKSGEN_Msk; + } +} +#endif + +/** + * ble phy init + * + * Initialize the PHY. + * + * @return int 0: success; PHY error code otherwise + */ +int +ble_phy_init(void) +{ + int rc; + + /* Default phy to use is 1M */ + g_ble_phy_data.phy_cur_phy_mode = BLE_PHY_MODE_1M; + g_ble_phy_data.phy_tx_phy_mode = BLE_PHY_MODE_1M; + g_ble_phy_data.phy_rx_phy_mode = BLE_PHY_MODE_1M; + + /* Set phy channel to an invalid channel so first set channel works */ + g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS; + +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) + g_ble_phy_data.tifs = BLE_LL_IFS; +#endif + + /* Toggle peripheral power to reset (just in case) */ + nrf_radio_power_set(NRF_RADIO, false); + nrf_radio_power_set(NRF_RADIO, true); + +#ifdef NRF53_SERIES + /* Errata 158: load trim values after toggling power */ + for (uint32_t index = 0; index < 32ul && + NRF_FICR_NS->TRIMCNF[index].ADDR != 0xFFFFFFFFul; index++) { + if (((uint32_t)NRF_FICR_NS->TRIMCNF[index].ADDR & 0xFFFFF000ul) == (volatile uint32_t)NRF_RADIO_NS) { + *((volatile uint32_t *)NRF_FICR_NS->TRIMCNF[index].ADDR) = NRF_FICR_NS->TRIMCNF[index].DATA; + } + } + + *(volatile uint32_t *)(NRF_RADIO_NS_BASE + 0x774) = + (*(volatile uint32_t* )(NRF_RADIO_NS_BASE + 0x774) & 0xfffffffe) | 0x01000000; +#if NRF53_ERRATA_16_ENABLE_WORKAROUND + if (nrf53_errata_16()) { + /* [16] RADIO: POWER register is not functional */ + NRF_RADIO_NS->SUBSCRIBE_TXEN = 0; + NRF_RADIO_NS->SUBSCRIBE_RXEN = 0; + NRF_RADIO_NS->SUBSCRIBE_DISABLE = 0; + } +#endif +#endif + + /* Disable all interrupts */ + nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); + + /* Set configuration registers */ + NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit; + NRF_RADIO->PCNF0 = NRF_PCNF0; + + /* XXX: should maxlen be 251 for encryption? */ + NRF_RADIO->PCNF1 = NRF_MAXLEN | + (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) | + (NRF_BALEN << RADIO_PCNF1_BALEN_Pos) | + RADIO_PCNF1_WHITEEN_Msk; + + /* Enable radio fast ramp-up */ + NRF_RADIO->MODECNF0 |= (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos) & + RADIO_MODECNF0_RU_Msk; + + /* Set logical address 1 for TX and RX */ + NRF_RADIO->TXADDRESS = 0; + NRF_RADIO->RXADDRESSES = (1 << 0); + + /* Configure the CRC registers */ + NRF_RADIO->CRCCNF = (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos) | RADIO_CRCCNF_LEN_Three; + + /* Configure BLE poly */ + NRF_RADIO->CRCPOLY = 0x0000065B; + + /* Configure IFS */ + NRF_RADIO->TIFS = BLE_LL_IFS; + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + nrf_ccm_int_disable(NRF_CCM, 0xffffffff); + NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; + NRF_CCM->EVENTS_ERROR = 0; + memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad)); + +#if PHY_USE_HEADERMASK_WORKAROUND + NVIC_SetVector(CCM_AAR_IRQn, (uint32_t)ble_phy_ccm_isr); + NVIC_EnableIRQ(CCM_AAR_IRQn); + NRF_CCM->INTENCLR = CCM_INTENCLR_ENDKSGEN_Msk;; +#endif +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + g_ble_phy_data.phy_aar_scratch = 0; + NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; + nrf_aar_int_disable(NRF_AAR, 0xffffffff); + NRF_AAR->EVENTS_END = 0; + NRF_AAR->EVENTS_RESOLVED = 0; + NRF_AAR->EVENTS_NOTRESOLVED = 0; + NRF_AAR->NIRK = 0; +#endif + + /* TIMER0 setup for PHY when using RTC */ + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); + NRF_TIMER0->TASKS_SHUTDOWN = 1; + NRF_TIMER0->BITMODE = 3; /* 32-bit timer */ + NRF_TIMER0->MODE = 0; /* Timer mode */ + NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ + + phy_ppi_init(); + +#if PHY_USE_DEBUG + phy_debug_init(); +#endif +#if PHY_USE_FEM + phy_fem_init(); +#endif + + /* Set isr in vector table and enable interrupt */ +#ifndef RIOT_VERSION +#ifdef FREERTOS + NVIC_SetPriority(RADIO_IRQn, 5); +#else + NVIC_SetPriority(RADIO_IRQn, 0); +#endif +#endif +#if MYNEWT + NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr); +#else + ble_npl_hw_set_isr(RADIO_IRQn, ble_phy_isr); +#endif + NVIC_EnableIRQ(RADIO_IRQn); + + /* Register phy statistics */ + if (!g_ble_phy_data.phy_stats_initialized) { + rc = stats_init_and_reg(STATS_HDR(ble_phy_stats), + STATS_SIZE_INIT_PARMS(ble_phy_stats, + STATS_SIZE_32), + STATS_NAME_INIT_PARMS(ble_phy_stats), + "ble_phy"); + assert(rc == 0); + + g_ble_phy_data.phy_stats_initialized = 1; + } + + return 0; +} + +/** + * Puts the phy into receive mode. + * + * @return int 0: success; BLE Phy error code otherwise + */ +static int +ble_phy_rx(void) +{ + /* + * Check radio state. + * + * In case radio is now disabling we'll wait for it to finish, but if for + * any reason it's just in idle state we proceed with RX as usual since + * nRF52 radio can ramp-up from idle state as well. + * + * Note that TX and RX states values are the same except for 3rd bit so we + * can make a shortcut here when checking for idle state. + */ + nrf_wait_disabled(); + if ((NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) && + ((NRF_RADIO->STATE & 0x07) != RADIO_STATE_STATE_RxIdle)) { + ble_phy_disable(); + STATS_INC(ble_phy_stats, radio_state_errs); + return BLE_PHY_ERR_RADIO_STATE; + } + + /* Make sure all interrupts are disabled */ + nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); + + /* Clear events prior to enabling receive */ + NRF_RADIO->EVENTS_END = 0; + NRF_RADIO->EVENTS_DISABLED = 0; + + /* Setup for rx */ + ble_phy_rx_xcvr_setup(); + + return 0; +} + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) +void +ble_phy_encrypt_enable(const uint8_t *key) +{ + memcpy(g_nrf_ccm_data.key, key, 16); + g_ble_phy_data.phy_encrypted = 1; + NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled; + NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled; +#ifdef NRF5340_XXAA + NRF_CCM->HEADERMASK = BLE_LL_PDU_HEADERMASK_DATA; +#endif +#if PHY_USE_HEADERMASK_WORKAROUND + g_ble_phy_data.phy_headermask = BLE_LL_PDU_HEADERMASK_DATA; +#endif +} + +void +ble_phy_encrypt_header_mask_set(uint8_t mask) +{ +#ifdef NRF5340_XXAA + NRF_CCM->HEADERMASK = mask; +#endif +#if PHY_USE_HEADERMASK_WORKAROUND + g_ble_phy_data.phy_headermask = mask; +#endif +} + +void +ble_phy_encrypt_iv_set(const uint8_t *iv) +{ + memcpy(g_nrf_ccm_data.iv, iv, 8); +} + +void +ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit) +{ + g_nrf_ccm_data.pkt_counter = counter; + g_nrf_ccm_data.dir_bit = dir_bit; +} + +void +ble_phy_encrypt_disable(void) +{ + phy_ppi_radio_address_to_ccm_crypt_disable(); + nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_STOP); + NRF_CCM->EVENTS_ERROR = 0; + NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled; + + g_ble_phy_data.phy_encrypted = 0; +} +#endif + +void +ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg) +{ + /* Set transmit end callback and arg */ + g_ble_phy_data.txend_cb = txend_cb; + g_ble_phy_data.txend_arg = arg; +} + +/** + * Called to set the start time of a transmission. + * + * This function is called to set the start time when we are not going from + * rx to tx automatically. + * + * NOTE: care must be taken when calling this function. The channel should + * already be set. + * + * @param cputime This is the tick at which the 1st bit of the preamble + * should be transmitted + * @param rem_usecs This is used only when the underlying timing uses a 32.768 + * kHz crystal. It is the # of usecs from the cputime tick + * at which the first bit of the preamble should be + * transmitted. + * @return int + */ +int +ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) +{ + int rc; + + ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_TX, cputime, rem_usecs); + +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) + ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode); +#endif + + /* XXX: This should not be necessary, but paranoia is good! */ + /* Clear timer0 compare to RXEN since we are transmitting */ + phy_ppi_timer0_compare0_to_radio_rxen_disable(); + + if (ble_phy_set_start_time(cputime, rem_usecs, true) != 0) { + STATS_INC(ble_phy_stats, tx_late); + ble_phy_disable(); + rc = BLE_PHY_ERR_TX_LATE; + } else { + /* Enable PPI to automatically start TXEN */ + phy_ppi_timer0_compare0_to_radio_txen_enable(); + rc = 0; + } + + return rc; +} + +/** + * Called to set the start time of a reception + * + * This function acts a bit differently than transmit. If we are late getting + * here we will still attempt to receive. + * + * NOTE: care must be taken when calling this function. The channel should + * already be set. + * + * @param cputime + * + * @return int + */ +int +ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) +{ + bool late = false; + int rc = 0; + + ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_RX, cputime, rem_usecs); + +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) + ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode); +#endif + + /* XXX: This should not be necessary, but paranoia is good! */ + /* Clear timer0 compare to TXEN since we are transmitting */ + phy_ppi_timer0_compare0_to_radio_txen_disable(); + + if (ble_phy_set_start_time(cputime, rem_usecs, false) != 0) { + STATS_INC(ble_phy_stats, rx_late); + + /* We're late so let's just try to start RX as soon as possible */ + ble_phy_set_start_now(); + + late = true; + } + + /* Enable PPI to automatically start RXEN */ + phy_ppi_timer0_compare0_to_radio_rxen_enable(); + + /* Start rx */ + rc = ble_phy_rx(); + + /* + * If we enabled receiver but were late, let's return proper error code so + * caller can handle this. + */ + if (!rc && late) { + rc = BLE_PHY_ERR_RX_LATE; + } + + return rc; +} + +int +ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) +{ + int rc; + uint8_t *dptr; + uint8_t *pktptr; + uint8_t payload_len; + uint8_t hdr_byte; + uint32_t state; + uint32_t shortcuts; + + if (g_ble_phy_data.phy_transition_late) { + ble_phy_disable(); + STATS_INC(ble_phy_stats, tx_late); + return BLE_PHY_ERR_TX_LATE; + } + + /* + * This check is to make sure that the radio is not in a state where + * it is moving to disabled state. If so, let it get there. + */ + nrf_wait_disabled(); + + /* + * XXX: Although we may not have to do this here, I clear all the PPI + * that should not be used when transmitting. Some of them are only enabled + * if encryption and/or privacy is on, but I dont care. Better to be + * paranoid, and if you are going to clear one, might as well clear them + * all. + */ + phy_ppi_wfr_disable(); + phy_ppi_radio_bcmatch_to_aar_start_disable(); + phy_ppi_radio_address_to_ccm_crypt_disable(); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + if (g_ble_phy_data.phy_encrypted) { + dptr = (uint8_t *)&g_ble_phy_enc_buf[0]; + pktptr = (uint8_t *)&g_ble_phy_tx_buf[0]; + NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; + NRF_CCM->INPTR = (uint32_t)dptr; + NRF_CCM->OUTPTR = (uint32_t)pktptr; + NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; + NRF_CCM->EVENTS_ERROR = 0; + NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | ble_phy_get_ccm_datarate(); + NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data; + } else { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; +#endif + dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; + pktptr = dptr; + } +#else + dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; + pktptr = dptr; +#endif + + /* Set PDU payload */ + payload_len = pducb(&dptr[3], pducb_arg, &hdr_byte); + + /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */ + dptr[0] = hdr_byte; + dptr[1] = payload_len; + dptr[2] = 0; + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + /* Start key-stream generation and encryption (via short) */ + if (g_ble_phy_data.phy_encrypted) { +#if PHY_USE_HEADERMASK_WORKAROUND + if (g_ble_phy_data.phy_headermask != BLE_LL_PDU_HEADERMASK_DATA) { + g_ble_phy_data.phy_headerbyte = dptr[0]; + dptr[0] &= g_ble_phy_data.phy_headermask; + g_ble_phy_tx_buf[0] = 0xffffffff; + NRF_CCM->EVENTS_ENDKSGEN = 0; + NRF_CCM->INTENSET = CCM_INTENSET_ENDKSGEN_Msk; + } +#endif + nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN); + } +#endif + + NRF_RADIO->PACKETPTR = (uint32_t)pktptr; + + /* Clear the ready, end and disabled events */ + NRF_RADIO->EVENTS_READY = 0; + NRF_RADIO->EVENTS_END = 0; + NRF_RADIO->EVENTS_DISABLED = 0; + + /* Enable shortcuts for transmit start/end. */ + shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk; + NRF_RADIO->SHORTS = shortcuts; + nrf_radio_int_enable(NRF_RADIO, RADIO_INTENSET_DISABLED_Msk); + + /* Set the PHY transition */ + g_ble_phy_data.phy_transition = end_trans; + + /* Set transmitted payload length */ + g_ble_phy_data.phy_tx_pyld_len = payload_len; + + /* If we already started transmitting, abort it! */ + state = NRF_RADIO->STATE; + if (state != RADIO_STATE_STATE_Tx) { + /* Set phy state to transmitting and count packet statistics */ + g_ble_phy_data.phy_state = BLE_PHY_STATE_TX; + STATS_INC(ble_phy_stats, tx_good); + STATS_INCN(ble_phy_stats, tx_bytes, payload_len + BLE_LL_PDU_HDR_LEN); + rc = BLE_ERR_SUCCESS; + } else { + ble_phy_disable(); + STATS_INC(ble_phy_stats, tx_late); + rc = BLE_PHY_ERR_RADIO_STATE; + } + + return rc; +} + +/** + * ble phy txpwr set + * + * Set the transmit output power (in dBm). + * + * NOTE: If the output power specified is within the BLE limits but outside + * the chip limits, we "rail" the power level so we dont exceed the min/max + * chip values. + * + * @param dbm Power output in dBm. + * + * @return int 0: success; anything else is an error + */ +int +ble_phy_tx_power_set(int dbm) +{ + /* Get actual TX power supported by radio */ + dbm = phy_txpower_round(dbm); + + phy_txpower_set(dbm); + g_ble_phy_data.phy_txpwr_dbm = dbm; + + return 0; +} + +/** + * ble phy txpwr round + * + * Get the rounded transmit output power (in dBm). + * + * @param dbm Power output in dBm. + * + * @return int Rounded power in dBm + */ +int +ble_phy_tx_power_round(int dbm) +{ + return phy_txpower_round(dbm); +} + +/** + * ble phy set access addr + * + * Set access address. + * + * @param access_addr Access address + * + * @return int 0: success; PHY error code otherwise + */ +static int +ble_phy_set_access_addr(uint32_t access_addr) +{ + NRF_RADIO->BASE0 = (access_addr << 8); + NRF_RADIO->PREFIX0 = (NRF_RADIO->PREFIX0 & 0xFFFFFF00) | (access_addr >> 24); + + g_ble_phy_data.phy_access_address = access_addr; + +#if NRF52_ERRATA_102_ENABLE_WORKAROUND || \ + NRF52_ERRATA_106_ENABLE_WORKAROUND || \ + NRF52_ERRATA_107_ENABLE_WORKAROUND +#ifndef BABBLESIM + if (nrf52_errata_102() || nrf52_errata_106() || nrf52_errata_107()) { + /* [102] RADIO: PAYLOAD/END events delayed or not triggered after ADDRESS + * [106] RADIO: Higher CRC error rates for some access addresses + * [107] RADIO: Immediate address match for access addresses containing MSBs 0x00 + */ + *(volatile uint32_t *)0x40001774 = + ((*(volatile uint32_t *)0x40001774) & 0xfffffffe) | 0x01000000; + } +#endif +#endif + + return 0; +} + +/** + * ble phy txpwr get + * + * Get the transmit power. + * + * @return int The current PHY transmit power, in dBm + */ +int +ble_phy_tx_power_get(void) +{ + return g_ble_phy_data.phy_txpwr_dbm; +} + +/** + * ble phy setchan + * + * Sets the logical frequency of the transceiver. The input parameter is the + * BLE channel index (0 to 39, inclusive). The NRF frequency register works like + * this: logical frequency = 2400 + FREQ (MHz). + * + * Thus, to get a logical frequency of 2402 MHz, you would program the + * FREQUENCY register to 2. + * + * @param chan This is the Data Channel Index or Advertising Channel index + * + * @return int 0: success; PHY error code otherwise + */ +int +ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) +{ + assert(chan < BLE_PHY_NUM_CHANS); + + /* Check for valid channel range */ + if (chan >= BLE_PHY_NUM_CHANS) { + return BLE_PHY_ERR_INV_PARAM; + } + + /* Set current access address */ + ble_phy_set_access_addr(access_addr); + + /* Configure crcinit */ + NRF_RADIO->CRCINIT = crcinit; + + /* Set the frequency and the data whitening initial value */ + g_ble_phy_data.phy_chan = chan; + NRF_RADIO->FREQUENCY = g_ble_phy_chan_freq[chan]; + NRF_RADIO->DATAWHITEIV = chan; + + return 0; +} + +uint8_t +ble_phy_chan_get(void) +{ + return g_ble_phy_data.phy_chan; +} + +/** + * Stop the timer used to count microseconds when using RTC for cputime + */ +static void +ble_phy_stop_usec_timer(void) +{ + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); + NRF_TIMER0->TASKS_SHUTDOWN = 1; + nrf_rtc_event_disable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); +} + +/** + * ble phy disable irq and ppi + * + * This routine is to be called when reception was stopped due to either a + * wait for response timeout or a packet being received and the phy is to be + * restarted in receive mode. Generally, the disable routine is called to stop + * the phy. + */ +static void +ble_phy_disable_irq_and_ppi(void) +{ + nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); + NRF_RADIO->SHORTS = 0; + nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE); + phy_ppi_disable(); + NVIC_ClearPendingIRQ(RADIO_IRQn); + g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE; +} + +void +ble_phy_restart_rx(void) +{ + ble_phy_stop_usec_timer(); + ble_phy_disable_irq_and_ppi(); + + ble_phy_set_start_now(); + /* Enable PPI to automatically start RXEN */ + phy_ppi_timer0_compare0_to_radio_rxen_enable(); + + ble_phy_rx(); +} + +/** + * ble phy disable + * + * Disables the PHY. This should be called when an event is over. It stops + * the usec timer (if used), disables interrupts, disables the RADIO, disables + * PPI and sets state to idle. + */ +void +ble_phy_disable(void) +{ + ble_phy_trace_void(BLE_PHY_TRACE_ID_DISABLE); + +#if PHY_USE_HEADERMASK_WORKAROUND + NRF_CCM->INTENCLR = CCM_INTENCLR_ENDKSGEN_Msk; +#endif + + ble_phy_stop_usec_timer(); + ble_phy_disable_irq_and_ppi(); + + g_ble_phy_data.phy_transition_late = 0; + +#if PHY_USE_FEM + phy_fem_disable(); +#endif +} + +/* Gets the current access address */ +uint32_t ble_phy_access_addr_get(void) +{ + return g_ble_phy_data.phy_access_address; +} + +/** + * Return the phy state + * + * @return int The current PHY state. + */ +int +ble_phy_state_get(void) +{ + return g_ble_phy_data.phy_state; +} + +/** + * Called to see if a reception has started + * + * @return int + */ +int +ble_phy_rx_started(void) +{ + return g_ble_phy_data.phy_rx_started; +} + +/** + * Return the transceiver state + * + * @return int transceiver state. + */ +uint8_t +ble_phy_xcvr_state_get(void) +{ + uint32_t state; + state = NRF_RADIO->STATE; + return (uint8_t)state; +} + +/** + * Called to return the maximum data pdu payload length supported by the + * phy. For this chip, if encryption is enabled, the maximum payload is 27 + * bytes. + * + * @return uint8_t Maximum data channel PDU payload size supported + */ +uint8_t +ble_phy_max_data_pdu_pyld(void) +{ + return BLE_LL_DATA_PDU_MAX_PYLD; +} + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) +void +ble_phy_resolv_list_enable(void) +{ + NRF_AAR->NIRK = (uint32_t)g_nrf_num_irks; + g_ble_phy_data.phy_privacy = 1; +} + +void +ble_phy_resolv_list_disable(void) +{ + g_ble_phy_data.phy_privacy = 0; +} +#endif + +#if MYNEWT_VAL(BLE_LL_DTM) +void ble_phy_enable_dtm(void) +{ + /* When DTM is enabled we need to disable whitening as per + * Bluetooth v5.0 Vol 6. Part F. 4.1.1 + */ + NRF_RADIO->PCNF1 &= ~RADIO_PCNF1_WHITEEN_Msk; +} + +void ble_phy_disable_dtm(void) +{ + /* Enable whitening */ + NRF_RADIO->PCNF1 |= RADIO_PCNF1_WHITEEN_Msk; +} +#endif + +void +ble_phy_rfclk_enable(void) +{ +#if MYNEWT || defined(RIOT_VERSION) +#ifdef NRF52_SERIES + nrf52_clock_hfxo_request(); +#endif +#ifdef NRF53_SERIES + nrf5340_net_clock_hfxo_request(); +#endif +#else + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART); +#endif +} + +void +ble_phy_rfclk_disable(void) +{ +#if MYNEWT || defined(RIOT_VERSION) +#ifdef NRF52_SERIES + nrf52_clock_hfxo_release(); +#endif +#ifdef NRF53_SERIES + nrf5340_net_clock_hfxo_release(); +#endif +#else + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP); +#endif +} + +void +ble_phy_tifs_txtx_set(uint16_t usecs, uint8_t anchor) +{ + g_ble_phy_data.txtx_time_us = usecs; + g_ble_phy_data.txtx_time_anchor = anchor; +} diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/ble_phy_trace.c b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/ble_phy_trace.c new file mode 100644 index 00000000..93b2eb32 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/ble_phy_trace.c @@ -0,0 +1,44 @@ +/* + * 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 +#include "syscfg/syscfg.h" +#include "os/os_trace_api.h" + +#if MYNEWT_VAL(BLE_PHY_SYSVIEW) + +static os_trace_module_t g_ble_phy_trace_mod; +uint32_t ble_phy_trace_off; + +static void +ble_phy_trace_module_send_desc(void) +{ + os_trace_module_desc(&g_ble_phy_trace_mod, "0 phy_set_tx cputime=%u usecs=%u"); + os_trace_module_desc(&g_ble_phy_trace_mod, "1 phy_set_rx cputime=%u usecs=%u"); + os_trace_module_desc(&g_ble_phy_trace_mod, "2 phy_disable"); +} + +void +ble_phy_trace_init(void) +{ + ble_phy_trace_off = + os_trace_module_register(&g_ble_phy_trace_mod, "ble_phy", 3, + ble_phy_trace_module_send_desc); +} +#endif diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf52/phy.c b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf52/phy.c new file mode 100644 index 00000000..30a19966 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf52/phy.c @@ -0,0 +1,220 @@ +/* + * 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 +#include +#include +#include "../phy_priv.h" + +#if PHY_USE_DEBUG +void +phy_debug_init(void) +{ +#if PHY_USE_DEBUG_1 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_1, + MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); + + nrf_ppi_channel_endpoint_setup(NRF_PPI, 17, + (uint32_t)&(NRF_RADIO->EVENTS_READY), + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_1])); + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH17_Msk); + + /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */ + nrf_ppi_fork_endpoint_setup(NRF_PPI, 20, + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_1])); + nrf_ppi_fork_endpoint_setup(NRF_PPI, 21, + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_1])); +#endif + +#if PHY_USE_DEBUG_2 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_2, + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); + + /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */ + nrf_ppi_fork_endpoint_setup(NRF_PPI, 26, + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_2])); + nrf_ppi_fork_endpoint_setup(NRF_PPI, 27, + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_2])); +#endif + +#if PHY_USE_DEBUG_3 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_3, MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); + +#if NRF52840_XXAA + nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, + (uint32_t)&(NRF_RADIO->EVENTS_RXREADY), + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_3])); +#else + nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, + (uint32_t)&(NRF_RADIO->EVENTS_READY), + (uint32_t)&(NRF_GPIOTE->TASKS_SET[GIDX_DEBUG_3])); +#endif + nrf_ppi_channel_endpoint_setup(NRF_PPI, 19, + (uint32_t)&(NRF_RADIO->EVENTS_DISABLED), + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3])); + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk); + + /* CH[4] and CH[5] are always on for wfr */ + nrf_ppi_fork_endpoint_setup(NRF_PPI, 4, + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3])); + nrf_ppi_fork_endpoint_setup(NRF_PPI, 5, + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3])); +#endif +} +#endif /* PHY_USE_DEBUG */ + +#if PHY_USE_FEM +void +phy_fem_init(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_FEM_PA_GPIO)); +#else + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_FEM_LNA_GPIO)); +#endif + NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM]); + NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM]); +#else +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM_PA, MYNEWT_VAL(BLE_FEM_PA_GPIO)); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + phy_gpiote_configure(PHY_GPIOTE_FEM_LNA, MYNEWT_VAL(BLE_FEM_LNA_GPIO)); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif /* PHY_USE_FEM_SINGLE_GPIO */ + + NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[2]); + NRF_PPI->CH[7].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED); + + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} + +#if PHY_USE_FEM_PA +void +phy_fem_enable_pa(void) +{ + ble_fem_pa_enable(); + +#if !PHY_USE_FEM_SINGLE_GPIO + /* Switch FEM channels to control PA */ + NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM_PA]); + NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA]); +#endif + + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} +#endif + +#if PHY_USE_FEM_LNA +void +phy_fem_enable_lna(void) +{ + ble_fem_lna_enable(); + +#if !PHY_USE_FEM_SINGLE_GPIO + /* Switch FEM channels to control LNA */ + NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM_LNA]); + NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA]); +#endif + + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} +#endif + +void +phy_fem_disable(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1; +#else +#if PHY_USE_FEM_PA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif +} +#endif /* PHY_USE_FEM */ + +void +phy_ppi_init(void) +{ + /* radio_address_to_timer0_capture1 */ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH26_Msk); + /* radio_end_to_timer0_capture2 */ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH27_Msk); + + /* + * PPI setup. + * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used + * to cancel the wait for response timer. + * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait + * for response timer. + */ + nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL4, + (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS), + (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3])); + nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL5, + (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]), + (uint32_t)&(NRF_RADIO->TASKS_DISABLE)); +} + +void +phy_txpower_set(int8_t dbm) +{ + NRF_RADIO->TXPOWER = dbm; +} + +int8_t +phy_txpower_round(int8_t dbm) +{ + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm; + } + + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; +} diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h new file mode 100644 index 00000000..a77b7183 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h @@ -0,0 +1,113 @@ +/* + * 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 H_PHY_PPI_ +#define H_PHY_PPI_ + +#include + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk); +} + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH31_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH23_Msk); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH23_Msk); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH25_Msk); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH25_Msk); +} + +static inline void +phy_ppi_wfr_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); +} + +static inline void +phy_ppi_wfr_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); +} + +static inline void +phy_ppi_fem_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} + +static inline void +phy_ppi_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | + PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk | + PPI_CHEN_CH20_Msk | PPI_CHEN_CH21_Msk | + PPI_CHEN_CH23_Msk | PPI_CHEN_CH25_Msk | + PPI_CHEN_CH31_Msk); +} + +#endif /* H_PHY_PPI_ */ diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf53/phy.c b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf53/phy.c new file mode 100644 index 00000000..ceda769b --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf53/phy.c @@ -0,0 +1,312 @@ +/* + * 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 +#include +#include +#include "../phy_priv.h" + +/* + * When the radio is operated on high voltage (see VREQCTRL - Voltage request + * control on page 62 for how to control voltage), the output power is increased + * by 3 dB. I.e. if the TXPOWER value is set to 0 dBm and high voltage is + * requested using VREQCTRL, the output power will be +3 + * */ +#define NRF_TXPOWER_VREQH 3 + +#if PHY_USE_DEBUG +void +phy_debug_init(void) +{ +#if PHY_USE_DEBUG_1 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_1, + MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); + + NRF_RADIO->PUBLISH_READY = DPPI_CH_PUB(RADIO_EVENTS_READY); + NRF_DPPIC->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_READY); + + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(RADIO_EVENTS_READY); +#endif + +#if PHY_USE_DEBUG_2 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_2, + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); + + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(RADIO_EVENTS_END); +#endif + +#if PHY_USE_DEBUG_3 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_3, MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); + + NRF_RADIO->PUBLISH_RXREADY = DPPI_CH_PUB(RADIO_EVENTS_READY); + NRF_RADIO->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED); + NRF_DPPIC->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_RXREADY) | + DPPI_CH_MASK(RADIO_EVENTS_DISABLED); + + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_RXREADY); + + /* TODO figure out how (if?) to subscribe task to multiple DPPI channels + * Currently only last one is working. Also using multiple GPIOTE for same + * PIN doesn't work... + */ + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); + +#endif +} +#endif /* PHY_USE_DEBUG */ + +#if PHY_USE_FEM +void +phy_fem_init() +{ + /* We can keep clear tasks subscribed and published channels always enabled, + * it's enough to just (un)subscribe set tasks when needed. + * TODO: check if this affects power consumption + */ + + NRF_TIMER0->PUBLISH_COMPARE[2] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_2); + NRF_RADIO->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED); + +#if PHY_USE_FEM_SINGLE_GPIO +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_FEM_PA_GPIO)); +#else + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_FEM_LNA_GPIO)); +#endif + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM] = + DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1; +#else +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM_PA, MYNEWT_VAL(BLE_FEM_PA_GPIO)); + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM_PA] = + DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + phy_gpiote_configure(PHY_GPIOTE_FEM_LNA, MYNEWT_VAL(BLE_FEM_LNA_GPIO)); + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif /* PHY_USE_FEM_SINGLE_GPIO */ + + NRF_DPPIC->CHENSET = DPPI_CH_MASK_FEM; +} + +#if PHY_USE_FEM_PA +void +phy_fem_enable_pa(void) +{ + ble_fem_pa_enable(); + +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#else + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#endif +} +#endif + +#if PHY_USE_FEM_LNA +void +phy_fem_enable_lna(void) +{ + ble_fem_lna_enable(); + +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#else + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#endif +} +#endif + +void +phy_fem_disable(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1; +#else +#if PHY_USE_FEM_PA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif +} +#endif /* PHY_USE_FEM */ + +void +phy_ppi_init(void) +{ + /* Publish events */ + NRF_TIMER0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_0); + NRF_TIMER0->PUBLISH_COMPARE[3] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_3); + NRF_RADIO->PUBLISH_END = DPPI_CH_PUB(RADIO_EVENTS_END); + NRF_RADIO->PUBLISH_BCMATCH = DPPI_CH_PUB(RADIO_EVENTS_BCMATCH); + NRF_RADIO->PUBLISH_ADDRESS = DPPI_CH_PUB(RADIO_EVENTS_ADDRESS); + NRF_RTC0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(RTC0_EVENTS_COMPARE_0); + + /* Enable channels we publish on */ + NRF_DPPIC->CHENSET = DPPI_CH_ENABLE_ALL; + + /* radio_address_to_timer0_capture1 */ + NRF_TIMER0->SUBSCRIBE_CAPTURE[1] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + /* radio_end_to_timer0_capture2 */ + NRF_TIMER0->SUBSCRIBE_CAPTURE[2] = DPPI_CH_SUB(RADIO_EVENTS_END); +} + +void +phy_txpower_set(int8_t dbm) +{ +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + switch (dbm) { + case ((int8_t)RADIO_TXPOWER_TXPOWER_0dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm) + NRF_TXPOWER_VREQH: + NRF_VREQCTRL->VREGRADIO.VREQH = 1; + dbm -= NRF_TXPOWER_VREQH; + break; + default: + NRF_VREQCTRL->VREGRADIO.VREQH = 0; + break; + } +#endif + + NRF_RADIO->TXPOWER = dbm; +} + +int8_t +phy_txpower_round(int8_t dbm) +{ +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + /* +3 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_0dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_0dBm) + NRF_TXPOWER_VREQH; + } + + /* +2 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) + NRF_TXPOWER_VREQH; + } + + /* +1 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) + NRF_TXPOWER_VREQH; + } +#endif + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg3dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg3dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm; + } + +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + /* -9 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) + NRF_TXPOWER_VREQH; + } +#endif + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm; + } + +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + /* -13 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) + NRF_TXPOWER_VREQH; + } +#endif + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm; + } + +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + /* -17 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) + NRF_TXPOWER_VREQH; + } +#endif + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm; + } + +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + /* -37 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm) + NRF_TXPOWER_VREQH; + } +#endif + + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; +} diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h new file mode 100644 index 00000000..6412f327 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h @@ -0,0 +1,159 @@ +/* + * 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 H_PHY_PPI_ +#define H_PHY_PPI_ + +#define DPPI_CH_PUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31)) +#define DPPI_CH_SUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31)) +#define DPPI_CH_UNSUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (0 << 31)) +#define DPPI_CH_MASK(_ch) (1 << (DPPI_CH_ ## _ch)) + +/* Channels 0..5 are always used. + * Channels 6 and 7 are used for PA/LNA (optionally). + * Channels 7..9 are used for GPIO debugging (optionally). + */ + +#define DPPI_CH_TIMER0_EVENTS_COMPARE_0 0 +#define DPPI_CH_TIMER0_EVENTS_COMPARE_3 1 +#define DPPI_CH_RADIO_EVENTS_END 2 +#define DPPI_CH_RADIO_EVENTS_BCMATCH 3 +#define DPPI_CH_RADIO_EVENTS_ADDRESS 4 +#define DPPI_CH_RTC0_EVENTS_COMPARE_0 5 +#define DPPI_CH_TIMER0_EVENTS_COMPARE_2 6 +#define DPPI_CH_RADIO_EVENTS_DISABLED 7 +#define DPPI_CH_RADIO_EVENTS_READY 8 +#define DPPI_CH_RADIO_EVENTS_RXREADY 9 + +#define DPPI_CH_ENABLE_ALL (DPPIC_CHEN_CH0_Msk | DPPIC_CHEN_CH1_Msk | \ + DPPIC_CHEN_CH2_Msk | DPPIC_CHEN_CH3_Msk | \ + DPPIC_CHEN_CH4_Msk | DPPIC_CHEN_CH5_Msk) + +#define DPPI_CH_MASK_FEM (DPPI_CH_MASK(TIMER0_EVENTS_COMPARE_2) | \ + DPPI_CH_MASK(RADIO_EVENTS_DISABLED)) + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_enable(void) +{ + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_SUB(RTC0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_0); + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_enable(void) +{ + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_disable(void) +{ + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_enable(void) +{ + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_disable(void) +{ + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_enable(void) +{ + NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_disable(void) +{ + NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_enable(void) +{ + NRF_AAR->SUBSCRIBE_START = DPPI_CH_SUB(RADIO_EVENTS_BCMATCH); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_disable(void) +{ + NRF_AAR->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); +} + +static inline void +phy_ppi_wfr_enable(void) +{ + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_wfr_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_fem_disable(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +#else +#if PHY_USE_FEM_PA + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); +#endif +#if PHY_USE_FEM_LNA + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); +#endif +#endif +} + +static inline void +phy_ppi_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_0); + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); + NRF_AAR->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); + NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + + phy_ppi_fem_disable(); +} + +#endif /* H_PHY_PPI_ */ \ No newline at end of file diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/phy_priv.h b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/phy_priv.h new file mode 100644 index 00000000..db0664da --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/src/phy_priv.h @@ -0,0 +1,96 @@ +/* + * 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 H_PHY_PRIV_ +#define H_PHY_PRIV_ + +#include +#include +#include + + +#if defined(NRF52840_XXAA) && MYNEWT_VAL(BLE_PHY_NRF52_HEADERMASK_WORKAROUND) +#define PHY_USE_HEADERMASK_WORKAROUND 1 +#endif + +#define PHY_USE_DEBUG_1 (MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0) +#define PHY_USE_DEBUG_2 (MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0) +#define PHY_USE_DEBUG_3 (MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0) +#define PHY_USE_DEBUG (PHY_USE_DEBUG_1 || PHY_USE_DEBUG_2 || PHY_USE_DEBUG_3) + +#define PHY_USE_FEM_PA (MYNEWT_VAL(BLE_FEM_PA) != 0) +#define PHY_USE_FEM_LNA (MYNEWT_VAL(BLE_FEM_LNA) != 0) +#define PHY_USE_FEM (PHY_USE_FEM_PA || PHY_USE_FEM_LNA) +#define PHY_USE_FEM_SINGLE_GPIO \ + (PHY_USE_FEM && (!PHY_USE_FEM_PA || !PHY_USE_FEM_LNA || \ + (MYNEWT_VAL(BLE_FEM_PA_GPIO) == \ + MYNEWT_VAL(BLE_FEM_LNA_GPIO)))) + +/* GPIOTE indexes, start assigning from last one */ +#define PHY_GPIOTE_DEBUG_1 (8 - PHY_USE_DEBUG_1) +#define PHY_GPIOTE_DEBUG_2 (PHY_GPIOTE_DEBUG_1 - PHY_USE_DEBUG_2) +#define PHY_GPIOTE_DEBUG_3 (PHY_GPIOTE_DEBUG_2 - PHY_USE_DEBUG_3) +#if PHY_USE_FEM_SINGLE_GPIO +#define PHY_GPIOTE_FEM (PHY_GPIOTE_DEBUG_3 - PHY_USE_FEM) +#else +#define PHY_GPIOTE_FEM_PA (PHY_GPIOTE_DEBUG_3 - PHY_USE_FEM_PA) +#define PHY_GPIOTE_FEM_LNA (PHY_GPIOTE_FEM_PA - PHY_USE_FEM_LNA) +#endif + +static inline void +phy_gpiote_configure(int idx, int pin) +{ + nrf_gpio_cfg_output(pin); + nrf_gpiote_task_configure(NRF_GPIOTE, idx, pin, NRF_GPIOTE_POLARITY_NONE, + NRF_GPIOTE_INITIAL_VALUE_LOW); + nrf_gpiote_task_enable(NRF_GPIOTE, idx); +} + +#if PHY_USE_DEBUG +void phy_debug_init(void); +#endif + +#if PHY_USE_FEM +void phy_fem_init(void); +#if PHY_USE_FEM_PA +void phy_fem_enable_pa(void); +#endif +#if PHY_USE_FEM_LNA +void phy_fem_enable_lna(void); +#endif +void phy_fem_disable(void); +#endif + +void phy_ppi_init(void); + +#ifdef NRF52_SERIES +#include "nrf52/phy_ppi.h" +#endif + +void phy_txpower_set(int8_t dbm); +int8_t phy_txpower_round(int8_t dbm); + +#ifdef NRF52_SERIES +#include "nrf52/phy_ppi.h" +#endif +#ifdef NRF53_SERIES +#include "nrf53/phy_ppi.h" +#endif + +#endif /* H_PHY_PRIV_ */ diff --git a/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/syscfg.yml b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/syscfg.yml new file mode 100644 index 00000000..07c9042f --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/drivers/nrf5x/syscfg.yml @@ -0,0 +1,86 @@ +# 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. +# + +syscfg.defs: + BLE_PHY_VARIABLE_TIFS: + description: > + Enables API to set custom T_ifs (inter-frame spacing) for each + transition. T_ifs is reset to default value after each transition. + When disabled, 150us is always used which enables some build-time + optimizations by compiler. + experimental: 1 + value: 0 + + BLE_PHY_SYSVIEW: + description: > + Enable SystemView tracing module for radio driver. + value: 0 + + BLE_PHY_DBG_TIME_TXRXEN_READY_PIN: + description: > + When set to proper GPIO pin number, this pin will be set + to high state when radio is enabled using PPI channels + 20 or 21 and back to low state on radio EVENTS_READY. + This can be used to measure radio ram-up time. + value: -1 + + BLE_PHY_DBG_TIME_ADDRESS_END_PIN: + description: > + When set to proper GPIO pin number, this pin will be set + to high state on radio EVENTS_ADDRESS and back to low state + on radio EVENTS_END. + This can be used to measure radio pipeline delays. + value: -1 + + BLE_PHY_DBG_TIME_WFR_PIN: + description: > + When set to proper GPIO pin number, this pin will be set + to high state on radio EVENTS_RXREADY and back to low + state when wfr timer expires. + This can be used to check if wfr is calculated properly. + value: -1 + + BLE_PHY_NRF52_HEADERMASK_WORKAROUND: + description: > + This enables workaround for lack of HEADERMASK register on some + nRF52 family MCUs (notably nRF52840) which is required for enabling + encryption for ISO PDUs. + Note: this requires exclusive access to CCM_AAR interrupt and only + works for TX (i.e. ISO Broadcaster). + value: 0 + + BLE_PHY_NRF5340_VDDH: + description: > + This indicates if VDDH pin of nRF5340 is connected to external + power source. If connected PHY driver will make use of high voltage + operation mode for additional TX power levels (+3, +2, +1, -9, -13, + -17, -37). + value: 0 + + BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR: + description: > + Ublox BMD-345 modules come with public address preprogrammed + in UICR register. If enabled public address will be read from + custom UICR instead of FICR register. + value: 0 + +syscfg.restrictions: + # code supports turn on times up to 90us due to some optimizations, but it + # should be enough for most (all?) cases + - "!BLE_FEM_PA || BLE_FEM_PA_TURN_ON_US <= 90" + - "!BLE_FEM_LNA || BLE_FEM_LNA_TURN_ON_US <= 90" diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_att.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_att.h index f8241051..a4665aa3 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_att.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_att.h @@ -32,29 +32,82 @@ extern "C" { #endif +/** Chained memory buffer. */ struct os_mbuf; +/** + * @defgroup ble_att_uuids Attribute Protocol (ATT) UUIDs + * @{ + */ +/** UUID for a primary service. */ #define BLE_ATT_UUID_PRIMARY_SERVICE 0x2800 + +/** UUID for a secondary service. */ #define BLE_ATT_UUID_SECONDARY_SERVICE 0x2801 + +/** UUID for an include definition. */ #define BLE_ATT_UUID_INCLUDE 0x2802 + +/** UUID for a characteristic. */ #define BLE_ATT_UUID_CHARACTERISTIC 0x2803 +/** @} */ + +/** + * @defgroup ble_att_err_codes Attribute Protocol (ATT) Error Codes + * @{ + */ + +/** The attribute handle given was not valid on this server */ #define BLE_ATT_ERR_INVALID_HANDLE 0x01 + +/** The attribute cannot be read. */ #define BLE_ATT_ERR_READ_NOT_PERMITTED 0x02 + +/** The attribute cannot be written. */ #define BLE_ATT_ERR_WRITE_NOT_PERMITTED 0x03 + +/** The attribute PDU was invalid. */ #define BLE_ATT_ERR_INVALID_PDU 0x04 + +/** The attribute requires authentication before it can be read or written. */ #define BLE_ATT_ERR_INSUFFICIENT_AUTHEN 0x05 + +/** ATT Server does not support the request received from the client. */ #define BLE_ATT_ERR_REQ_NOT_SUPPORTED 0x06 + +/** Offset specified was past the end of the attribute. */ #define BLE_ATT_ERR_INVALID_OFFSET 0x07 + +/** The attribute requires authorization before it can be read or written. */ #define BLE_ATT_ERR_INSUFFICIENT_AUTHOR 0x08 + +/** Too many prepare writes have been queued. */ #define BLE_ATT_ERR_PREPARE_QUEUE_FULL 0x09 + +/** No attribute found within the given attribute handle range. */ #define BLE_ATT_ERR_ATTR_NOT_FOUND 0x0a + +/** The attribute cannot be read using the ATT_READ_BLOB_REQ PDU. */ #define BLE_ATT_ERR_ATTR_NOT_LONG 0x0b + +/** The Encryption Key Size used for encrypting this link is too short. */ #define BLE_ATT_ERR_INSUFFICIENT_KEY_SZ 0x0c + +/** The attribute value length is invalid for the operation. */ #define BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN 0x0d + +/** The attribute request that was requested has encountered an error that was unlikely, + * and therefore could not be completed as requested. */ #define BLE_ATT_ERR_UNLIKELY 0x0e + +/** The attribute requires encryption before it can be read or written */ #define BLE_ATT_ERR_INSUFFICIENT_ENC 0x0f + +/** The attribute type is not a supported grouping attribute as defined by a higher layer specification. */ #define BLE_ATT_ERR_UNSUPPORTED_GROUP 0x10 + +/**Insufficient Resources to complete the request. */ #define BLE_ATT_ERR_INSUFFICIENT_RES 0x11 #define BLE_ATT_ERR_DB_OUT_OF_SYNC 0x12 #define BLE_ATT_ERR_VALUE_NOT_ALLOWED 0x13 @@ -69,57 +122,145 @@ struct os_mbuf; /** Error Response. */ #define BLE_ATT_OP_ERROR_RSP 0x01 + +/** MTU Request. */ #define BLE_ATT_OP_MTU_REQ 0x02 + +/** MTU Response. */ #define BLE_ATT_OP_MTU_RSP 0x03 + +/** Find Information Request. */ #define BLE_ATT_OP_FIND_INFO_REQ 0x04 + +/** Find Information Response. */ #define BLE_ATT_OP_FIND_INFO_RSP 0x05 + +/** Find By Type Value Request. */ #define BLE_ATT_OP_FIND_TYPE_VALUE_REQ 0x06 + +/** Find By Type Value Response. */ #define BLE_ATT_OP_FIND_TYPE_VALUE_RSP 0x07 + +/** Read By Type Request. */ #define BLE_ATT_OP_READ_TYPE_REQ 0x08 + +/** Read By Type Response. */ #define BLE_ATT_OP_READ_TYPE_RSP 0x09 + +/** Read Request. */ #define BLE_ATT_OP_READ_REQ 0x0a + +/** Read Response. */ #define BLE_ATT_OP_READ_RSP 0x0b + +/** Read Blob Request. */ #define BLE_ATT_OP_READ_BLOB_REQ 0x0c + +/** Read Blob Response. */ #define BLE_ATT_OP_READ_BLOB_RSP 0x0d + +/** Read Multiple Request. */ #define BLE_ATT_OP_READ_MULT_REQ 0x0e + +/** Read Multiple Response. */ #define BLE_ATT_OP_READ_MULT_RSP 0x0f + +/** Read By Group Type Request. */ #define BLE_ATT_OP_READ_GROUP_TYPE_REQ 0x10 + +/** Read By Group Type Response. */ #define BLE_ATT_OP_READ_GROUP_TYPE_RSP 0x11 + +/** Write Request. */ #define BLE_ATT_OP_WRITE_REQ 0x12 + +/** Write Response. */ #define BLE_ATT_OP_WRITE_RSP 0x13 + +/** Prepare Write Request. */ #define BLE_ATT_OP_PREP_WRITE_REQ 0x16 + +/** Prepare Write Response. */ #define BLE_ATT_OP_PREP_WRITE_RSP 0x17 + +/** Execute Write Request. */ #define BLE_ATT_OP_EXEC_WRITE_REQ 0x18 + +/** Execute Write Response. */ #define BLE_ATT_OP_EXEC_WRITE_RSP 0x19 + /** Read Multiple Variable Lenght Request */ #define BLE_ATT_OP_READ_MULT_VAR_REQ 0x20 /** Read Multiple Variable Lenght Response */ #define BLE_ATT_OP_READ_MULT_VAR_RSP 0x21 +/** Notify Request. */ #define BLE_ATT_OP_NOTIFY_REQ 0x1b + +/** Indicate Request. */ #define BLE_ATT_OP_INDICATE_REQ 0x1d + +/** Indicate Response. */ #define BLE_ATT_OP_INDICATE_RSP 0x1e + +/** Write Command. */ #define BLE_ATT_OP_WRITE_CMD 0x52 #define BLE_ATT_OP_SIGNED_WRITE_CMD 0xD2 +/** @} */ + +/** Maximum length of an Attribute Protocol (ATT) attribute. */ #define BLE_ATT_ATTR_MAX_LEN 512 +/** + * @defgroup ble_att_flags Attribute Protocol (ATT) Flags + * @{ + */ + +/** Read permission flag. */ #define BLE_ATT_F_READ 0x01 + +/** Write permission flag. */ #define BLE_ATT_F_WRITE 0x02 + +/** Read encrypted permission flag. */ #define BLE_ATT_F_READ_ENC 0x04 + +/** Read authenticated permission flag. */ #define BLE_ATT_F_READ_AUTHEN 0x08 + +/** Read authorized permission flag. */ #define BLE_ATT_F_READ_AUTHOR 0x10 + +/** Write encrypted permission flag. */ #define BLE_ATT_F_WRITE_ENC 0x20 + +/** Write authenticated permission flag. */ #define BLE_ATT_F_WRITE_AUTHEN 0x40 + +/** Write authorized permission flag. */ #define BLE_ATT_F_WRITE_AUTHOR 0x80 +/** Read and write permission flag. */ #define HA_FLAG_PERM_RW (BLE_ATT_F_READ | BLE_ATT_F_WRITE) +/** @} */ + +/** + * @defgroup ble_att_access_op_codes Attribute Protocol (ATT) Access Operation Codes + * @{ + */ + +/** Access operation: Read. */ #define BLE_ATT_ACCESS_OP_READ 1 + +/** Access operation: Write. */ #define BLE_ATT_ACCESS_OP_WRITE 2 +/** @} */ + /** Default ATT MTU. Also the minimum. */ #define BLE_ATT_MTU_DFLT 23 diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_dtm.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_dtm.h new file mode 100644 index 00000000..cd01a23b --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_dtm.h @@ -0,0 +1,126 @@ +/* + * 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 H_BLE_DTM_ +#define H_BLE_DTM_ + +#include +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file ble_dtm.h + * + * @brief DTM (Direct Test Mode) + * + * This header file provides the interface and data structures for working with + * the Direct Test Mode (DTM) functionality in a BLE (Bluetooth Low Energy) host. + * DTM allows for testing and validation of the BLE radio performance by enabling + * custom transmission and reception of data packets. + * + * @defgroup bt_host_dtm Bluetooth Host Direct Test Mode + * @ingroup bt_host + * @{ + */ + +/** + * @struct ble_dtm_rx_params + * @brief Parameters for DTM RX test. + * + * This structure represents the parameters for a Direct Test Mode (DTM) receiver test. + */ +struct ble_dtm_rx_params { + /** The channel to use for the RX test. */ + uint8_t channel; + + /** The PHY to use for the RX test. */ + uint8_t phy; + + /** The modulation index to use for the RX test. */ + uint8_t modulation_index; +}; + +/** + * @brief Start a Direct Test Mode (DTM) receiver test. + * + * This function starts a DTM RX test with the provided parameters. + * + * @param params The parameters for the DTM RX test. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_dtm_rx_start(const struct ble_dtm_rx_params *params); + +/** + * @struct ble_dtm_tx_params + * @brief Parameters for DTM TX test. + * + * This structure represents the parameters for a Direct Test Mode (DTM) transmitter test. + */ +struct ble_dtm_tx_params { + /** The channel to use for the TX test. */ + uint8_t channel; + + /** The length of the data for the TX test. */ + uint8_t test_data_len; + + /** The payload to use for the TX test. */ + uint8_t payload; + + /** The PHY to use for the TX test. */ + uint8_t phy; +}; + +/** + * @brief Start a Direct Test Mode (DTM) transmitter test. + * + * This function starts a DTM TX test with the provided parameters. + * + * @param params The parameters for the DTM TX test. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_dtm_tx_start(const struct ble_dtm_tx_params *params); + +/** + * @brief Stops a Direct Test Mode (DTM) test and retrieves the number of transmitted packets. + * + * This function sends a command to the Bluetooth controller to stop the currently running DTM test. + * It retrieves the number of packets transmitted during the test and stores it in the provided `num_packets` variable. + * + * @param num_packets Pointer to a `uint16_t` variable to store the number of transmitted packets. + * If an error occurs, the value will be set to 0. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_dtm_stop(uint16_t *num_packets); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_esp_gap.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_esp_gap.h index e0977f48..705f29a9 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_esp_gap.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_esp_gap.h @@ -112,6 +112,28 @@ int ble_gap_wl_read_size(uint8_t *size); */ int ble_gap_host_check_status(void); +/** + * This API is called to get local used address and address type. + * + * @param addr On success, locally used address will be stored here. + * + * @return 0 on success; nonzero on failure. +*/ +int ble_gap_get_local_used_addr(ble_addr_t *addr); + +/** + * This API is called to get ADV data for a specific type. + + * + * @param adv_data Pointer of ADV data which to be resolved. + * @param adv_type Finding ADV data type. + * @param adv_data_len Total length of Advertising data. + * @param length Return the length of ADV data not including type. + * + * @return Pointer of type specific ADV data. + */ +uint8_t* ble_resolve_adv_data(const uint8_t *adv_data, uint8_t adv_type, uint8_t adv_data_len , uint8_t * length); + #if MYNEWT_VAL(BLE_HCI_VS) #if MYNEWT_VAL(BLE_POWER_CONTROL) diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_gap.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_gap.h index 6ddc5a3b..ebab72b8 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_gap.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_gap.h @@ -153,12 +153,14 @@ struct hci_conn_update; #define BLE_GAP_EVENT_PERIODIC_TRANSFER 24 #define BLE_GAP_EVENT_PATHLOSS_THRESHOLD 25 #define BLE_GAP_EVENT_TRANSMIT_POWER 26 -#define BLE_GAP_EVENT_SUBRATE_CHANGE 27 -#define BLE_GAP_EVENT_VS_HCI 28 -#define BLE_GAP_EVENT_REATTEMPT_COUNT 29 -#define BLE_GAP_EVENT_AUTHORIZE 30 -#define BLE_GAP_EVENT_TEST_UPDATE 31 - +#define BLE_GAP_EVENT_PARING_COMPLETE 27 +#define BLE_GAP_EVENT_SUBRATE_CHANGE 28 +#define BLE_GAP_EVENT_VS_HCI 29 +#define BLE_GAP_EVENT_BIGINFO_REPORT 30 +#define BLE_GAP_EVENT_REATTEMPT_COUNT 31 +#define BLE_GAP_EVENT_AUTHORIZE 32 +#define BLE_GAP_EVENT_TEST_UPDATE 33 +#define BLE_GAP_EVENT_DATA_LEN_CHG 34 /* DTM events */ #define BLE_GAP_DTM_TX_START_EVT 0 @@ -850,6 +852,8 @@ struct ble_gap_event { struct { /** The handle of the relevant connection. */ uint16_t conn_handle; + /** Peer identity address */ + ble_addr_t peer_id_addr; } identity_resolved; /** @@ -1022,6 +1026,54 @@ struct ble_gap_event { } periodic_transfer; #endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + /** + * Represents a periodic advertising sync transfer received. Valid for + * the following event types: + * o BLE_GAP_EVENT_BIGINFO_REPORT + */ + struct { + /** Synchronization handle */ + uint16_t sync_handle; + + /** Number of present BISes */ + uint8_t bis_cnt; + + /** Number of SubEvents */ + uint8_t nse; + + /** ISO Interval */ + uint16_t iso_interval; + + /** Burst Number */ + uint8_t bn; + + /** Pre-Transmission Offset */ + uint8_t pto; + + /** Immediate Repetition Count */ + uint8_t irc; + + /** Maximum PDU size */ + uint16_t max_pdu; + + /** Maximum SDU size */ + uint16_t max_sdu; + + /** Service Data Unit Interval */ + uint32_t sdu_interval; + + /** BIG PHY */ + uint8_t phy; + + /** Framing of BIS Data PDUs */ + uint8_t framing : 1; + + /** Encryption */ + uint8_t encryption : 1; + } biginfo_report; +#endif + #if MYNEWT_VAL(BLE_POWER_CONTROL) /** * Represents a change in either local transmit power or remote transmit @@ -1069,6 +1121,24 @@ struct ble_gap_event { int8_t delta; } transmit_power; #endif + /** + * Represents a received Pairing Complete message + * + * Valid for the following event types: + * o BLE_GAP_EVENT_PARING_COMPLETE + */ + struct { + /** + * Indicates the result of the encryption state change attempt; + * o 0: the encrypted state was successfully updated; + * o BLE host error code: the encryption state change attempt + * failed for the specified reason. + */ + int status; + + /** The handle of the relevant connection. */ + uint16_t conn_handle; + } pairing_complete; #if MYNEWT_VAL(BLE_CONN_SUBRATING) /** @@ -1174,8 +1244,31 @@ struct ble_gap_event { * Valid only for BLE_GAP_DTM_END_EVT * shall be 0 for a transmitter. */ - uint8_t num_pkt; + uint16_t num_pkt; } dtm_state; + + /** + * Represent an event for LE Data length change + * + * Valid for the following event types: + * o BLE_GAP_EVENT_DATA_LEN_CHG + */ + struct { + /* Connection handle */ + uint16_t conn_handle; + + /* Max Tx Payload octotes */ + uint16_t max_tx_octets; + + /* Max Tx Time */ + uint16_t max_tx_time; + + /* Max Rx payload octet */ + uint16_t max_rx_octets; + + /* Max Rx Time */ + uint16_t max_rx_time; + } data_len_chg; }; }; @@ -1226,6 +1319,7 @@ struct ble_gap_multi_conn_params { #endif // MYNEWT_VAL(OPTIMIZE_MULTI_CONN) typedef int ble_gap_event_fn(struct ble_gap_event *event, void *arg); +typedef int ble_gap_conn_foreach_handle_fn(uint16_t conn_handle, void *arg); #define BLE_GAP_CONN_MODE_NON 0 #define BLE_GAP_CONN_MODE_DIR 1 @@ -1633,7 +1727,7 @@ int ble_gap_ext_adv_active(uint8_t instance); /** @brief Periodic advertising parameters */ struct ble_gap_periodic_adv_params { /** If include TX power in advertising PDU */ - unsigned int include_tx_power:1; + unsigned int include_tx_power : 1; /** Minimum advertising interval in 1.25ms units, if 0 stack use sane * defaults @@ -2248,17 +2342,57 @@ int ble_gap_update_params(uint16_t conn_handle, * Configure LE Data Length in controller (OGF = 0x08, OCF = 0x0022). * * @param conn_handle Connection handle. - * @param tx_octets The preferred value of payload octets that the Controller - * should use for a new connection (Range - * 0x001B-0x00FB). - * @param tx_time The preferred maximum number of microseconds that the local Controller - * should use to transmit a single link layer packet - * (Range 0x0148-0x4290). + * @param tx_octets The preferred value of payload octets that the + * Controller should use for a new connection + * (Range 0x001B-0x00FB). + * @param tx_time The preferred maximum number of microseconds that + * the local Controller should use to transmit a single + * link layer packet (Range 0x0148-0x4290). * * @return 0 on success, * other error code on failure. */ -int ble_gap_set_data_len(uint16_t conn_handle, uint16_t tx_octets, uint16_t tx_time); +int ble_gap_set_data_len(uint16_t conn_handle, uint16_t tx_octets, + uint16_t tx_time); + +/** + * Read LE Suggested Default Data Length in controller + * (OGF = 0x08, OCF = 0x0024). + * + * @param out_sugg_max_tx_octets The Host's suggested value for the + * Controller's maximum transmitted number of + * payload octets in LL Data PDUs to be used + * for new connections. (Range 0x001B-0x00FB). + * @param out_sugg_max_tx_time The Host's suggested value for the + * Controller's maximum packet transmission + * time for packets containing LL Data PDUs to + * be used for new connections. + * (Range 0x0148-0x4290). + * + * @return 0 on success, + * other error code on failure. + */ +int ble_gap_read_sugg_def_data_len(uint16_t *out_sugg_max_tx_octets, + uint16_t *out_sugg_max_tx_time); + +/** + * Configure LE Suggested Default Data Length in controller + * (OGF = 0x08, OCF = 0x0024). + * + * @param sugg_max_tx_octets The Host's suggested value for the Controller's + * maximum transmitted number of payload octets in + * LL Data PDUs to be used for new connections. + * (Range 0x001B-0x00FB). + * @param sugg_max_tx_time The Host's suggested value for the Controller's + * maximum packet transmission time for packets + * containing LL Data PDUs to be used for new + * connections. (Range 0x0148-0x4290). + * + * @return 0 on success, + * other error code on failure. + */ +int ble_gap_write_sugg_def_data_len(uint16_t sugg_max_tx_octets, + uint16_t sugg_max_tx_time); /** * Read LE Suggested Default Data Length in controller (OGF = 0x08, OCF = 0x0024). @@ -2534,8 +2668,8 @@ int ble_gap_set_default_subrate(uint16_t subrate_min, uint16_t subrate_max, uint int ble_gap_subrate_req(uint16_t conn_handle, uint16_t subrate_min, uint16_t subrate_max, - uint16_t max_latency, uint16_t cont_num, - uint16_t supervision_timeout); + uint16_t max_latency, uint16_t cont_num, + uint16_t supervision_timeout); #endif /** * Event listener structure diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_gatt.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_gatt.h index a1679b36..c2facf29 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_gatt.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_gatt.h @@ -40,49 +40,154 @@ struct ble_hs_conn; struct ble_att_error_rsp; struct ble_hs_cfg; +/** + * @defgroup ble_gatt_register_op_codes Generic Attribute Profile (GATT) Registration Operation Codes + * @{ + */ + +/** GATT Service registration. */ #define BLE_GATT_REGISTER_OP_SVC 1 + +/** GATT Characteristic registration. */ #define BLE_GATT_REGISTER_OP_CHR 2 + +/** GATT Descriptor registration. */ #define BLE_GATT_REGISTER_OP_DSC 3 +/** @} */ + +/** + * @defgroup ble_gatt_uuid Generic Attribute Profile (GATT) Service and Descriptor UUIDs + * @{ + */ + +/** GATT service 16-bit UUID. */ #define BLE_GATT_SVC_UUID16 0x1801 + +/** GATT Client Characteristic Configuration descriptor 16-bit UUID. */ #define BLE_GATT_DSC_CLT_CFG_UUID16 0x2902 #define BLE_GATT_DSC_CLT_PRE_FMT16 0x2904 #define BLE_GATT_DSC_CLT_AGG_FMT16 0x2905 +/** @} */ + +/** + * @defgroup ble_gatt_chr_properties Generic Attribute Profile (GATT) Characteristic Properties + * @{ + */ + +/** Characteristic property: Broadcast. */ #define BLE_GATT_CHR_PROP_BROADCAST 0x01 + +/** Characteristic property: Read. */ #define BLE_GATT_CHR_PROP_READ 0x02 + +/** Characteristic property: Write Without Response. */ #define BLE_GATT_CHR_PROP_WRITE_NO_RSP 0x04 + +/** Characteristic property: Write. */ #define BLE_GATT_CHR_PROP_WRITE 0x08 + +/** Characteristic property: Notify. */ #define BLE_GATT_CHR_PROP_NOTIFY 0x10 + +/** Characteristic property: Indicate. */ #define BLE_GATT_CHR_PROP_INDICATE 0x20 + +/** Characteristic property: Authenticated Signed Write. */ #define BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE 0x40 + +/** Characteristic property: Extended Properties. */ #define BLE_GATT_CHR_PROP_EXTENDED 0x80 +/** @} */ + +/** @defgroup ble_gatt_access_op_codes Generic Attribute Profile (GATT) Access Operation Codes + * @{ + */ + +/** GATT attribute access operation: Read characteristic. */ #define BLE_GATT_ACCESS_OP_READ_CHR 0 + +/** GATT attribute access operation: Write characteristic. */ #define BLE_GATT_ACCESS_OP_WRITE_CHR 1 + +/** GATT attribute access operation: Read descriptor. */ #define BLE_GATT_ACCESS_OP_READ_DSC 2 + +/** GATT attribute access operation: Write descriptor. */ #define BLE_GATT_ACCESS_OP_WRITE_DSC 3 +/** @} */ + +/** + * @defgroup ble_gatt_chr_flags Generic Attribute Profile (GATT) Characteristic Flags + * @{ + */ + +/** GATT Characteristic Flag: Broadcast. */ #define BLE_GATT_CHR_F_BROADCAST 0x0001 + +/** GATT Characteristic Flag: Read. */ #define BLE_GATT_CHR_F_READ 0x0002 + +/** GATT Characteristic Flag: Write without Response. */ #define BLE_GATT_CHR_F_WRITE_NO_RSP 0x0004 + +/** GATT Characteristic Flag: Write. */ #define BLE_GATT_CHR_F_WRITE 0x0008 + +/** GATT Characteristic Flag: Notify. */ #define BLE_GATT_CHR_F_NOTIFY 0x0010 + +/** GATT Characteristic Flag: Indicate. */ #define BLE_GATT_CHR_F_INDICATE 0x0020 + +/** GATT Characteristic Flag: Authenticated Signed Writes. */ #define BLE_GATT_CHR_F_AUTH_SIGN_WRITE 0x0040 + +/** GATT Characteristic Flag: Reliable Writes. */ #define BLE_GATT_CHR_F_RELIABLE_WRITE 0x0080 + +/** GATT Characteristic Flag: Auxiliary Writes. */ #define BLE_GATT_CHR_F_AUX_WRITE 0x0100 + +/** GATT Characteristic Flag: Read Encrypted. */ #define BLE_GATT_CHR_F_READ_ENC 0x0200 + +/** GATT Characteristic Flag: Read Authenticated. */ #define BLE_GATT_CHR_F_READ_AUTHEN 0x0400 + +/** GATT Characteristic Flag: Read Authorized. */ #define BLE_GATT_CHR_F_READ_AUTHOR 0x0800 + +/** GATT Characteristic Flag: Write Encrypted. */ #define BLE_GATT_CHR_F_WRITE_ENC 0x1000 + +/** GATT Characteristic Flag: Write Authenticated. */ #define BLE_GATT_CHR_F_WRITE_AUTHEN 0x2000 + +/** GATT Characteristic Flag: Write Authorized. */ #define BLE_GATT_CHR_F_WRITE_AUTHOR 0x4000 + +/** @} */ + +/** + * @defgroup ble_gatt_service_types Generic Attribute Profile (GATT) Service Types + * @{ + */ + +/** GATT Service Type: End of Services. */ #define BLE_GATT_SVC_TYPE_END 0 + +/** GATT Service Type: Primary Service. */ #define BLE_GATT_SVC_TYPE_PRIMARY 1 + +/** GATT Service Type: Secondary Service. */ #define BLE_GATT_SVC_TYPE_SECONDARY 2 +/** @} */ /** * Client Presentation Format * GATT Format Types @@ -282,38 +387,72 @@ struct ble_hs_cfg; #define BLE_GATT_CHR_BT_SIG_DESC_EXTERNAL 0x0110 /*** @client. */ +/** Represents a GATT error. */ struct ble_gatt_error { + /** The GATT status code indicating the type of error. */ uint16_t status; + + /** The attribute handle associated with the error. */ uint16_t att_handle; }; +/** Represents a GATT Service. */ struct ble_gatt_svc { + /** The start handle of the GATT service. */ uint16_t start_handle; + + /** The end handle of the GATT service. */ uint16_t end_handle; + + /** The UUID of the GATT service. */ ble_uuid_any_t uuid; }; + +/** Represents a GATT attribute. */ struct ble_gatt_attr { + /** The handle of the GATT attribute. */ uint16_t handle; + + /** The offset of the data within the attribute. */ uint16_t offset; + + /** Pointer to the data buffer represented by an os_mbuf. */ struct os_mbuf *om; }; + +/** Represents a GATT characteristic. */ struct ble_gatt_chr { + /** The handle of the GATT characteristic definition. */ uint16_t def_handle; + + /** The handle of the GATT characteristic value. */ uint16_t val_handle; + + /** The properties of the GATT characteristic. */ uint8_t properties; + + /** The UUID of the GATT characteristic. */ ble_uuid_any_t uuid; }; + +/** Represents a GATT descriptor. */ struct ble_gatt_dsc { + /** The handle of the GATT descriptor. */ uint16_t handle; + + /** The UUID of the GATT descriptor. */ ble_uuid_any_t uuid; }; +/** Function prototype for the GATT MTU exchange callback. */ typedef int ble_gatt_mtu_fn(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t mtu, void *arg); + +/** Function prototype for the GATT service discovery callback. */ typedef int ble_gatt_disc_svc_fn(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, @@ -329,6 +468,17 @@ typedef int ble_gatt_attr_fn(uint16_t conn_handle, struct ble_gatt_attr *attr, void *arg); +/** + * The host will free the attribute mbuf automatically after the callback is + * executed. The application can take ownership of the mbuf and prevent it + * from being freed by assigning NULL to attr->om. + */ +typedef int ble_gatt_attr_mult_fn(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + uint8_t num_attrs, + void *arg); + /** * The host will free the attribute mbufs automatically after the callback is * executed. The application can take ownership of the mbufs and prevent them @@ -339,10 +489,12 @@ typedef int ble_gatt_reliable_attr_fn(uint16_t conn_handle, struct ble_gatt_attr *attrs, uint8_t num_attrs, void *arg); +/** Function prototype for the GATT characteristic callback. */ typedef int ble_gatt_chr_fn(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *chr, void *arg); +/** Function prototype for the GATT descriptor callback. */ typedef int ble_gatt_dsc_fn(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t chr_val_handle, @@ -382,7 +534,7 @@ int ble_gattc_disc_all_svcs(uint16_t conn_handle, * * @param conn_handle The connection over which to execute the * procedure. - * @param service_uuid128 The 128-bit UUID of the service to discover. + * @param uuid The 128-bit UUID of the service to discover. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -442,7 +594,7 @@ int ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle, * the service definition handle). * @param end_handle The handle to end the search at (generally the * last handle in the service). - * @param chr_uuid128 The 128-bit UUID of the characteristic to + * @param uuid The 128-bit UUID of the characteristic to * discover. * @param cb The function to call to report procedure status * updates; null for no callback. @@ -460,9 +612,9 @@ int ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle, * * @param conn_handle The connection over which to execute the * procedure. - * @param chr_val_handle The handle of the characteristic value + * @param start_handle The handle of the characteristic value * attribute. - * @param chr_end_handle The last handle in the characteristic + * @param end_handle The last handle in the characteristic * definition. * @param cb The function to call to report procedure status * updates; null for no callback. @@ -500,6 +652,8 @@ int ble_gattc_read(uint16_t conn_handle, uint16_t attr_handle, * handle of the service definition). * @param end_handle The last handle to search (generally the * last handle in the service definition). + * @param uuid The 128-bit UUID of the characteristic to + * read. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -517,6 +671,8 @@ int ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle, * @param conn_handle The connection over which to execute the * procedure. * @param handle The handle of the characteristic value to read. + * @param offset The offset within the characteristic value to + * start reading. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -545,6 +701,10 @@ int ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, uint8_t num_handles, ble_gatt_attr_fn *cb, void *cb_arg); +int ble_gattc_read_mult_var(uint16_t conn_handle, const uint16_t *handles, + uint8_t num_handles, ble_gatt_attr_mult_fn *cb, + void *cb_arg); + /** * Initiates GATT procedure: Write Without Response. This function consumes * the supplied mbuf regardless of the outcome. @@ -553,7 +713,7 @@ int ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param txom The value to write to the characteristic. + * @param om The value to write to the characteristic. * * @return 0 on success; nonzero on failure. */ @@ -568,8 +728,8 @@ int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle, * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param value The value to write to the characteristic. - * @param value_len The number of bytes to write. + * @param data The value to write to the characteristic. + * @param data_len The number of bytes to write. * * @return 0 on success; nonzero on failure. */ @@ -599,7 +759,7 @@ int ble_gattc_signed_write(uint16_t conn_handle, uint16_t attr_handle, * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param txom The value to write to the characteristic. + * @param om The value to write to the characteristic. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -618,8 +778,8 @@ int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param value The value to write to the characteristic. - * @param value_len The number of bytes to write. + * @param data The value to write to the characteristic. + * @param data_len The number of bytes to write. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -639,7 +799,8 @@ int ble_gattc_write_flat(uint16_t conn_handle, uint16_t attr_handle, * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param txom The value to write to the characteristic. + * @param offset The offset at which to begin writing the value. + * @param om The value to write to the characteristic. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -681,9 +842,9 @@ int ble_gattc_write_reliable(uint16_t conn_handle, * * @param conn_handle The connection over which to execute the * procedure. - * @param chr_val_handle The attribute handle to indicate in the + * @param att_handle The attribute handle to indicate in the * outgoing notification. - * @param txom The value to write to the characteristic. + * @param om The value to write to the characteristic. * * @return 0 on success; nonzero on failure. */ @@ -756,16 +917,21 @@ int ble_gatts_indicate(uint16_t conn_handle, uint16_t chr_val_handle); */ int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle); +/** Initialize the BLE GATT client. */ int ble_gattc_init(void); /*** @server. */ struct ble_gatt_access_ctxt; + +/** Type definition for GATT access callback function. */ typedef int ble_gatt_access_fn(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); +/** Type definition for GATT characteristic flags. */ typedef uint16_t ble_gatt_chr_flags; +/** Represents the definition of a GATT characteristic. */ struct ble_gatt_chr_def { /** * Pointer to characteristic UUID; use BLE_UUIDxx_DECLARE macros to declare @@ -805,6 +971,7 @@ struct ble_gatt_chr_def { struct ble_gatt_cpfd *cpfd; }; +/** Represents the definition of a GATT service. */ struct ble_gatt_svc_def { /** * One of the following: @@ -834,6 +1001,7 @@ struct ble_gatt_svc_def { const struct ble_gatt_chr_def *characteristics; }; +/** Represents the definition of a GATT descriptor. */ struct ble_gatt_dsc_def { /** * Pointer to descriptor UUID; use BLE_UUIDxx_DECLARE macros to declare @@ -1013,6 +1181,7 @@ struct ble_gatt_register_ctxt { }; }; +/** Type definition for GATT registration callback function. */ typedef void ble_gatt_register_fn(struct ble_gatt_register_ctxt *ctxt, void *arg); @@ -1146,7 +1315,7 @@ int ble_gatts_find_chr(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid, * @param svc_uuid The UUID of the grandparent service. * @param chr_uuid The UUID of the parent characteristic. * @param dsc_uuid The UUID of the descriptor ro look up. - * @param out_handle On success, populated with the handle + * @param out_dsc_handle On success, populated with the handle * of the descriptor attribute. Pass null if * you don't need this value. * @@ -1158,6 +1327,7 @@ int ble_gatts_find_chr(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid, int ble_gatts_find_dsc(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid, uint16_t *out_dsc_handle); +/** Type definition for GATT service iteration callback function. */ typedef void (*ble_gatt_svc_foreach_fn)(const struct ble_gatt_svc_def *svc, uint16_t handle, uint16_t end_group_handle, diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs.h index 734f6181..4eba4b44 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs.h @@ -50,6 +50,7 @@ extern "C" { #endif +/** Represents an infinite value for timeouts or durations. */ #define BLE_HS_FOREVER INT32_MAX /** Connection handle not present */ @@ -67,36 +68,97 @@ extern "C" { * @{ */ +/** Operation failed and should be retried later. */ #define BLE_HS_EAGAIN 1 + +/** Operation already in progress. */ #define BLE_HS_EALREADY 2 + +/** Invalid parameter. */ #define BLE_HS_EINVAL 3 + +/** Message too long. */ #define BLE_HS_EMSGSIZE 4 + +/** No such entry. */ #define BLE_HS_ENOENT 5 + +/** Out of memory. */ #define BLE_HS_ENOMEM 6 + +/** Not connected. */ #define BLE_HS_ENOTCONN 7 + +/** Not supported. */ #define BLE_HS_ENOTSUP 8 + +/** Application error. */ #define BLE_HS_EAPP 9 + +/** Bad data. */ #define BLE_HS_EBADDATA 10 + +/** Operating System error. */ #define BLE_HS_EOS 11 + +/** Controller error. */ #define BLE_HS_ECONTROLLER 12 + +/** Operation timed out. */ #define BLE_HS_ETIMEOUT 13 + +/** Operation completed. */ #define BLE_HS_EDONE 14 + +/** Resource busy. */ #define BLE_HS_EBUSY 15 + +/** Operation rejected. */ #define BLE_HS_EREJECT 16 + +/** Unknown error. */ #define BLE_HS_EUNKNOWN 17 + +/** Role error. */ #define BLE_HS_EROLE 18 + +/** HCI operation timed out. */ #define BLE_HS_ETIMEOUT_HCI 19 + +/** Out of memory to handle an event. */ #define BLE_HS_ENOMEM_EVT 20 + +/** No valid address. */ #define BLE_HS_ENOADDR 21 + +/** Not synchronized with the controller. */ #define BLE_HS_ENOTSYNCED 22 + +/** Authentication error. */ #define BLE_HS_EAUTHEN 23 + +/** Authorization error. */ #define BLE_HS_EAUTHOR 24 + +/** Encryption error. */ #define BLE_HS_EENCRYPT 25 + +/** Invalid encryption key size. */ #define BLE_HS_EENCRYPT_KEY_SZ 26 + +/** Storage capacity exceeded. */ #define BLE_HS_ESTORE_CAP 27 + +/** Storage operation failed. */ #define BLE_HS_ESTORE_FAIL 28 + +/** Operation was preempted. */ #define BLE_HS_EPREEMPTED 29 + +/** Operation disabled. */ #define BLE_HS_EDISABLED 30 + +/** Operation stalled. */ #define BLE_HS_ESTALLED 31 /** Error base for ATT errors */ @@ -168,6 +230,25 @@ extern "C" { /** KeyboardDisplay Only IO capability */ #define BLE_HS_IO_KEYBOARD_DISPLAY 0x04 +/** + * @} + */ + +/** + * @brief LE key distribution + * @defgroup bt_host_key_dist LE key distribution + * + * @{ + */ + +/** Distibute LTK */ +#define BLE_HS_KEY_DIST_ENC_KEY 0x01 + +/** Distribute IRK */ +#define BLE_HS_KEY_DIST_ID_KEY 0x02 + +/** CSRK distibution and LinkKey are not supported */ + /** * @} */ @@ -260,6 +341,9 @@ struct ble_hs_cfg { */ ble_hs_sync_fn *sync_cb; + /** Callback to handle generation of security keys */ + ble_store_gen_key_fn *store_gen_key_cb; + /* XXX: These need to go away. Instead, the nimble host package should * require the host-store API (not yet implemented).. */ @@ -286,6 +370,7 @@ struct ble_hs_cfg { void *store_status_arg; }; +/** Configuration structure for the NimBLE Host stack. */ extern struct ble_hs_cfg ble_hs_cfg; /** diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_hci.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_hci.h index 56f8bcc4..5b28d999 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_hci.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_hci.h @@ -87,6 +87,21 @@ int ble_hs_hci_read_chan_map(uint16_t conn_handle, uint8_t *out_chan_map); */ int ble_hs_hci_set_chan_class(const uint8_t *chan_map); +/** + * Reads random data into buffer from controller. + * This allows to use BLE controller as a source of true random data. + * + * @param dst Destination buffer. + * @param len Destination buffer length. + * + * @return 0 on success; + * A BLE host HCI return code if the controller + * rejected the request; + * A BLE host core return code on unexpected + * error. + */ +int ble_hs_hci_util_rand(void *dst, int len); + #if MYNEWT_VAL(BLE_HCI_VS) /** * Send an arbitrary HCI command to the controller. diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_log.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_log.h index 7b90eaf9..a89b1e66 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_log.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_log.h @@ -20,6 +20,19 @@ #ifndef H_BLE_HS_LOG_ #define H_BLE_HS_LOG_ +/** + * @file ble_hs_log.h + * + * @brief Bluetooth Host Log + * + * This header file defines macros and functions used for logging messages + * within the BLE Host Stack. + * + * @defgroup bt_host_log Bluetooth Host Log + * @ingroup bt_host + * @{ + */ + #include "modlog/modlog.h" #include "log/log.h" @@ -34,20 +47,62 @@ extern "C" { struct os_mbuf; +/** + * @brief Macro for logging messages at a specified log level. + * + * The BLE_HS_LOG macro allows logging messages with different severity levels, + * such as DEBUG, INFO, WARN, ERROR or CRITICAL. + * + * @param lvl The log level of the message. + * @param ... The format string and additional arguments for the log message. + */ #define BLE_HS_LOG(lvl, ...) \ BLE_HS_LOG_ ## lvl(__VA_ARGS__) +/** + * @brief Macro for logging a Bluetooth address at a specified log level. + * + * The BLE_HS_LOG_ADDR macro allows logging Bluetooth addresses in the format + * "XX:XX:XX:XX:XX:XX" at different severity levels, such as DEBUG, INFO, WARN, ERROR or CRITICAL. + * + * @param lvl The log level of the message. + * @param addr The Bluetooth address to be logged. + */ #define BLE_HS_LOG_ADDR(lvl, addr) \ BLE_HS_LOG_ ## lvl("%02x:%02x:%02x:%02x:%02x:%02x", \ (addr)[5], (addr)[4], (addr)[3], \ (addr)[2], (addr)[1], (addr)[0]) +/** + * @brief Logs the content of an `os_mbuf` structure. + * + * This function iterates over each byte in the provided `os_mbuf` and logs its + * value in hexadecimal format using the `BLE_HS_LOG` macro with the log level + * set to DEBUG. + * + * @param om The `os_mbuf` to log. + */ void ble_hs_log_mbuf(const struct os_mbuf *om); + +/** + * @brief Logs the content of a flat buffer. + * + * This function iterates over each byte in the provided buffer and logs its + * value in hexadecimal format using the `BLE_HS_LOG` macro with the log level + * set to DEBUG. + * + * @param data Pointer to the buffer to log. + * @param len Length of the buffer. + */ void ble_hs_log_flat_buf(const void *data, int len); #ifdef __cplusplus } #endif +/** + * @} + */ + #endif diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_pvcy.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_pvcy.h index 4b6c39d8..0e2fefca 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_pvcy.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_pvcy.h @@ -69,6 +69,7 @@ void ble_hs_resolv_deinit(void); #endif int ble_hs_pvcy_set_resolve_enabled(int enable); +void ble_hs_set_rpa_timeout(uint16_t timeout); #ifdef __cplusplus } diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_stop.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_stop.h index e4feb62b..8b3ebd3f 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_stop.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_hs_stop.h @@ -20,6 +20,13 @@ #ifndef H_BLE_HS_STOP_ #define H_BLE_HS_STOP_ +/** + * @brief Bluetooth Host Stop API + * @defgroup bt_hs_stop Bluetooth Host Stop + * @ingroup bt_host + * @{ + */ + /** @typedef ble_hs_stop_fn * @brief Callback function; reports the result of a host stop procedure. * @@ -38,8 +45,13 @@ typedef void ble_hs_stop_fn(int status, void *arg); * This should be used as an opaque structure and not modified manually. */ struct ble_hs_stop_listener { + /** The callback function to be called when the stop procedure completes. */ ble_hs_stop_fn *fn; + + /** An optional argument to be passed to the callback function. */ void *arg; + + /** Singly-linked list entry. */ SLIST_ENTRY(ble_hs_stop_listener) link; }; @@ -67,4 +79,8 @@ struct ble_hs_stop_listener { int ble_hs_stop(struct ble_hs_stop_listener *listener, ble_hs_stop_fn *fn, void *arg); +/** +* @} +*/ + #endif diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_l2cap.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_l2cap.h index aef9682c..f836e97c 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_l2cap.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_l2cap.h @@ -17,6 +17,20 @@ * under the License. */ +/** + * @file ble_l2cap.h + * + * @brief L2CAP (Logical Link Control and Adaptation Protocol) API + * + * This header file provides the public API for interacting with the L2CAP layer of the BLE + * (Bluetooth Low Energy) stack. L2CAP is responsible for managing logical channels between + * two connected BLE devices. + * + * @defgroup bt_host_l2cap Bluetooth Host Logical Link Control and Adaptation Protocol + * @ingroup bt_host + * @{ + */ + #ifndef H_BLE_L2CAP_ #define H_BLE_L2CAP_ @@ -25,89 +39,311 @@ extern "C" { #endif +/** + * @brief L2CAP Signaling Connection Parameters Update Request. + * + * This structure represents a request to update the L2CAP connection parameters. + */ struct ble_l2cap_sig_update_req; + +/** + * @brief BLE Host Connection structure. + * + * This structure represents a connection between the BLE host and a remote device. + */ struct ble_hs_conn; +/** + * @defgroup ble_l2cap_channel_ids Channel Identifiers + * @{ + */ +/** Attribute Protocol (ATT) CID. */ #define BLE_L2CAP_CID_ATT 4 + +/** L2CAP LE Signaling CID. */ #define BLE_L2CAP_CID_SIG 5 + +/** Security Manager (SM) CID. */ #define BLE_L2CAP_CID_SM 6 +/** @} */ + +/** + * @defgroup ble_l2cap_signaling_op_codes Signaling Commands Operation Codes + * @{ + */ + +/** Reject */ #define BLE_L2CAP_SIG_OP_REJECT 0x01 + +/** Connect Request */ #define BLE_L2CAP_SIG_OP_CONNECT_REQ 0x02 + +/** Connect Response */ #define BLE_L2CAP_SIG_OP_CONNECT_RSP 0x03 + +/** Configuration Request */ #define BLE_L2CAP_SIG_OP_CONFIG_REQ 0x04 + +/** Configuration Response */ #define BLE_L2CAP_SIG_OP_CONFIG_RSP 0x05 + +/** Disconnect Request */ #define BLE_L2CAP_SIG_OP_DISCONN_REQ 0x06 + +/** Disconnect Response */ #define BLE_L2CAP_SIG_OP_DISCONN_RSP 0x07 + +/** Echo Request */ #define BLE_L2CAP_SIG_OP_ECHO_REQ 0x08 + +/** Echo Response */ #define BLE_L2CAP_SIG_OP_ECHO_RSP 0x09 + +/** Information Request */ #define BLE_L2CAP_SIG_OP_INFO_REQ 0x0a + +/** Information Response */ #define BLE_L2CAP_SIG_OP_INFO_RSP 0x0b + +/** Create Channel Request */ #define BLE_L2CAP_SIG_OP_CREATE_CHAN_REQ 0x0c + +/** Create Channel Response */ #define BLE_L2CAP_SIG_OP_CREATE_CHAN_RSP 0x0d + +/** Move Channel Request */ #define BLE_L2CAP_SIG_OP_MOVE_CHAN_REQ 0x0e + +/** Move Channel Response */ #define BLE_L2CAP_SIG_OP_MOVE_CHAN_RSP 0x0f + +/** Move Channel Confirmation Request */ #define BLE_L2CAP_SIG_OP_MOVE_CHAN_CONF_REQ 0x10 + +/** Move Channel Confirmation Response */ #define BLE_L2CAP_SIG_OP_MOVE_CHAN_CONF_RSP 0x11 + +/** Update Request */ #define BLE_L2CAP_SIG_OP_UPDATE_REQ 0x12 + +/** Update Response */ #define BLE_L2CAP_SIG_OP_UPDATE_RSP 0x13 + +/** LE Credit Based Connection Request */ #define BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_REQ 0x14 + +/** LE Credit Based Connection Response */ #define BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_RSP 0x15 + +/** Credit Based Flow Control Credit */ #define BLE_L2CAP_SIG_OP_FLOW_CTRL_CREDIT 0x16 + +/** Credit Based Connection Request */ #define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_REQ 0x17 + +/** Credit Based Connection Response */ #define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_RSP 0x18 + +/** Credit Based Reconfiguration Request */ #define BLE_L2CAP_SIG_OP_CREDIT_RECONFIG_REQ 0x19 + +/** Credit Based Reconfiguration Response */ #define BLE_L2CAP_SIG_OP_CREDIT_RECONFIG_RSP 0x1A + +/** Signaling Command Maximum Value */ #define BLE_L2CAP_SIG_OP_MAX 0x1B +/** @} */ + +/** + * @defgroup ble_l2cap_signaling_err_codes Signaling Commands Error Codes + * @{ + */ + +/** Command Not Understood */ #define BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD 0x0000 + +/** Maximum Transmission Unit (MTU) Exceeded */ #define BLE_L2CAP_SIG_ERR_MTU_EXCEEDED 0x0001 + +/** Invalid CID */ #define BLE_L2CAP_SIG_ERR_INVALID_CID 0x0002 +/** @} */ + +/** + * @defgroup ble_l2cap_coc_err_codes Connection-Oriented Channels (CoC) Error Codes + * @{ + */ + +/** Connection Success */ #define BLE_L2CAP_COC_ERR_CONNECTION_SUCCESS 0x0000 + +/** Unknown LE Protocol/Service Multiplexer (PSM) */ #define BLE_L2CAP_COC_ERR_UNKNOWN_LE_PSM 0x0002 + +/** No Resources */ #define BLE_L2CAP_COC_ERR_NO_RESOURCES 0x0004 + +/** Insufficient Authentication */ #define BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHEN 0x0005 + +/** Insufficient Authorization */ #define BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHOR 0x0006 + +/** Insufficient Key Size */ #define BLE_L2CAP_COC_ERR_INSUFFICIENT_KEY_SZ 0x0007 + +/** Insufficient Encryption */ #define BLE_L2CAP_COC_ERR_INSUFFICIENT_ENC 0x0008 + +/** Invalid Source CID */ #define BLE_L2CAP_COC_ERR_INVALID_SOURCE_CID 0x0009 + +/** Source CID Already Used */ #define BLE_L2CAP_COC_ERR_SOURCE_CID_ALREADY_USED 0x000A + +/** Unacceptable Parameters */ #define BLE_L2CAP_COC_ERR_UNACCEPTABLE_PARAMETERS 0x000B + +/** Invalid Parameters */ #define BLE_L2CAP_COC_ERR_INVALID_PARAMETERS 0x000C +/** @} */ + +/** + * @defgroup ble_l2cap_reconfig_err_codes Channel Reconfiguration Error Codes + * @{ + */ + +/** Reconfiguration Succeeded */ #define BLE_L2CAP_ERR_RECONFIG_SUCCEED 0x0000 + +/** Reduction of Maximum Transmission Unit (MTU) Not Allowed */ #define BLE_L2CAP_ERR_RECONFIG_REDUCTION_MTU_NOT_ALLOWED 0x0001 + +/** Reduction of Maximum Packet Size (MPS) Not Allowed */ #define BLE_L2CAP_ERR_RECONFIG_REDUCTION_MPS_NOT_ALLOWED 0x0002 + +/** Invalid Destination CID */ #define BLE_L2CAP_ERR_RECONFIG_INVALID_DCID 0x0003 -#define BLE_L2CAP_ERR_RECONFIG_UNACCAPTED_PARAM 0x0004 +/** Unaccepted Parameters */ +#define BLE_L2CAP_ERR_RECONFIG_UNACCEPTED_PARAM 0x0004 + +/** @} */ + +/** + * @defgroup ble_l2cap_coc_event_types Connection-Oriented Channel (CoC) Event Types + * @{ + */ + +/** CoC Connected */ #define BLE_L2CAP_EVENT_COC_CONNECTED 0 + +/** CoC Disconnected */ #define BLE_L2CAP_EVENT_COC_DISCONNECTED 1 + +/** CoC Accept */ #define BLE_L2CAP_EVENT_COC_ACCEPT 2 + +/** CoC Data Received */ #define BLE_L2CAP_EVENT_COC_DATA_RECEIVED 3 + +/** CoC Transmission Unstalled */ #define BLE_L2CAP_EVENT_COC_TX_UNSTALLED 4 + +/** CoC Reconfiguration Completed */ #define BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED 5 + +/** CoC Peer Reconfigured */ #define BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED 6 +/** @} */ + + +/** + * @brief Function signature for L2CAP signaling update event callback. + * + * This function is used to handle signaling update events in the L2CAP layer, + * such as changes in connection parameters. + * + * @param conn_handle The connection handle associated with the signaling update event. + * @param status The status of the signaling update event. + * @param arg A pointer to additional arguments passed to the callback function. + */ typedef void ble_l2cap_sig_update_fn(uint16_t conn_handle, int status, void *arg); +/** + * @brief Represents the signaling update in L2CAP. + * + * This structure holds the parameters required for initiating a signaling update in the L2CAP layer. + * It defines the connection interval, slave latency, and supervision timeout multiplier for the update. + */ struct ble_l2cap_sig_update_params { + /** + * The minimum desired connection interval in increments of 1.25 ms. + * This value defines the lower bound for the connection interval range. + */ uint16_t itvl_min; + + /** + * The maximum desired connection interval in increments of 1.25 ms. + * This value defines the upper bound for the connection interval range. + */ uint16_t itvl_max; + + /** + * The desired number of connection events that a slave device can skip. + * It specifies the maximum allowed latency between consecutive connection events. + */ uint16_t slave_latency; + + /** + * The desired supervision timeout multiplier. + * The supervision timeout defines the time limit for detecting the loss of a connection. + * This value is multiplied by the connection interval to determine the supervision timeout duration. + */ uint16_t timeout_multiplier; }; +/** + * @brief Initiate an L2CAP connection update procedure. + * + * This function initiates an L2CAP connection update procedure for the specified connection handle. + * The update procedure is used to modify the connection parameters, such as interval, latency, and timeout. + * + * @param conn_handle The connection handle of the L2CAP connection. + * + * @param params A pointer to a structure containing the desired update parameters. + * This includes the new connection interval, slave latency, and + * supervision timeout multiplier. + * + * @param cb The callback function to be called when the update request completes. + * The function signature for the callback is defined by `ble_l2cap_sig_update_fn`. + * + * @param cb_arg An optional argument to be passed to the callback function. + * + * @return 0 on success; + * A non-zero value on failure. + */ int ble_l2cap_sig_update(uint16_t conn_handle, struct ble_l2cap_sig_update_params *params, ble_l2cap_sig_update_fn *cb, void *cb_arg); +/** + * @brief Structure representing a L2CAP channel. + * + * It is used to maintain the state and track the properties of an L2CAP channel + * during its lifecycle. + */ struct ble_l2cap_chan; /** - * Represents a L2CAP-related event. + * @brief Represents a L2CAP-related event. + * * When such an event occurs, the host notifies the application by passing an * instance of this structure to an application-specified callback. */ @@ -234,33 +470,161 @@ struct ble_l2cap_event { }; }; +/** + * @brief Represents information about an L2CAP channel. + * + * This structure is typically used to retrieve or provide information about an existing L2CAP channel. + */ struct ble_l2cap_chan_info { + /** Source Channel Identifier. */ uint16_t scid; + + /** Destination Channel Identifier. */ uint16_t dcid; + + /** Local L2CAP Maximum Transmission Unit. */ uint16_t our_l2cap_mtu; + + /** Peer L2CAP Maximum Transmission Unit. */ uint16_t peer_l2cap_mtu; + + /** Protocol/Service Multiplexer of the channel. */ uint16_t psm; + + /** Local CoC Maximum Transmission Unit. */ uint16_t our_coc_mtu; + + /** Peer CoC Maximum Transmission Unit. */ uint16_t peer_coc_mtu; }; +/** + * @brief Function pointer type for handling L2CAP events. + * + * @param event A pointer to the L2CAP event structure. + * @param arg A pointer to additional arguments passed to the callback function. + * + * @return Integer value representing the status or result of the event handling. + */ typedef int ble_l2cap_event_fn(struct ble_l2cap_event *event, void *arg); - +/** + * @brief Get the connection handle associated with an L2CAP channel. + * + * This function retrieves the connection handle associated with the specified L2CAP channel. + * + * @param chan A pointer to the L2CAP channel structure. + * + * @return The connection handle associated with the L2CAP channel on success; + * A Bluetooth Host Error Code on failure: + * BLE_HS_CONN_HANDLE_NONE: if the provided channel pointer is NULL. + */ uint16_t ble_l2cap_get_conn_handle(struct ble_l2cap_chan *chan); + +/** + * @brief Create an L2CAP server. + * + * This function creates an L2CAP server with the specified Protocol/Service Multiplexer (PSM) and Maximum + * Transmission Unit (MTU) size. The server is used to accept incoming L2CAP connections from remote clients. + * When a connection request is received, the provided callback function will be invoked with the corresponding + * event information. + * + * @param psm The Protocol/Service Multiplexer (PSM) for the server. + * @param mtu The Maximum Transmission Unit (MTU) size for the server. + * @param cb Pointer to the callback function to be invoked when a connection request is received. + * @param cb_arg An optional argument to be passed to the callback function. + * + * @return 0 on success; + * A non-zero value on failure. + */ int ble_l2cap_create_server(uint16_t psm, uint16_t mtu, ble_l2cap_event_fn *cb, void *cb_arg); +/** + * @brief Initiate an L2CAP connection. + * + * This function initiates an L2CAP connection to a remote device with the specified connection handle, + * Protocol/Service Multiplexer (PSM), Maximum Transmission Unit (MTU) size, and receive SDU buffer. + * When the connection is established or if there is an error during the connection process, the provided + * callback function will be invoked with the corresponding event information. + * + * @param conn_handle The connection handle for the remote device. + * @param psm The Protocol/Service Multiplexer (PSM) for the connection. + * @param mtu The Maximum Transmission Unit (MTU) size for the connection. + * @param sdu_rx Pointer to the receive Service Data Unit (SDU) buffer. + * @param cb Pointer to the callback function to be invoked when the connection is established. + * @param cb_arg An optional argument to be passed to the callback function. + * + * @return 0 on success; + * A non-zero value on failure. + */ int ble_l2cap_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu, struct os_mbuf *sdu_rx, ble_l2cap_event_fn *cb, void *cb_arg); + +/** + * @brief Disconnect an L2CAP channel. + * + * This function disconnects the specified L2CAP channel by sending a disconnect signal. + * + * @param chan Pointer to the L2CAP channel structure representing the channel to disconnect. + * + * @return 0 on success; + * A non-zero value on failure. + */ int ble_l2cap_disconnect(struct ble_l2cap_chan *chan); + +/** + * @brief Send an SDU (Service Data Unit) over an L2CAP channel. + * + * This function sends an SDU over the specified L2CAP channel. The SDU is encapsulated + * in L2CAP frames and transmitted to the remote device. + * + * @param chan Pointer to the L2CAP channel structure representing the channel to send the SDU on. + * @param sdu_tx Pointer to the os_mbuf structure containing the SDU (Service Data Unit) to send. + * + * @return 0 on success; + * BLE_HS_ESTALLED: if there was not enough credits available to send whole SDU. + * The application needs to wait for the event 'BLE_L2CAP_EVENT_COC_TX_UNSTALLED' + * before being able to transmit more data; + * Another non-zero value on failure. + */ int ble_l2cap_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_tx); + +/** + * @brief Check if the L2CAP channel is ready to receive an SDU. + * + * This function checks if the specified L2CAP channel is ready to receive an SDU (Service Data Unit). + * It can be used to determine if the channel is in a state where it can accept incoming data. + * + * @param chan Pointer to the L2CAP channel structure to check. + * @param sdu_rx Pointer to the os_mbuf structure to receive the incoming SDU. + * + * @return 0 if the channel is ready to receive an SDU; + * A non-zero value on failure. + */ int ble_l2cap_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx); + +/** + * @brief Get information about an L2CAP channel. + * + * This function retrieves information about the specified L2CAP channel and populates + * the provided `ble_l2cap_chan_info` structure with the channel's details. + * + * @param chan Pointer to the L2CAP channel structure to retrieve information from. + * @param chan_info Pointer to the `ble_l2cap_chan_info` structure to populate with channel information. + * + * @return 0 on success; + * A non-zero value on failure. + */ int ble_l2cap_get_chan_info(struct ble_l2cap_chan *chan, struct ble_l2cap_chan_info *chan_info); #ifdef __cplusplus } #endif +/** + * @} + */ + #endif diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_sm.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_sm.h index ceebb856..ff381cf2 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_sm.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_sm.h @@ -27,6 +27,7 @@ extern "C" { #endif +#define BLE_SM_ERR_SUCCESS 0x00 #define BLE_SM_ERR_PASSKEY 0x01 #define BLE_SM_ERR_OOB 0x02 #define BLE_SM_ERR_AUTHREQ 0x03 @@ -41,7 +42,8 @@ extern "C" { #define BLE_SM_ERR_NUMCMP 0x0c #define BLE_SM_ERR_ALREADY 0x0d #define BLE_SM_ERR_CROSS_TRANS 0x0e -#define BLE_SM_ERR_MAX_PLUS_1 0x0f +#define BLE_SM_ERR_KEY_REJ 0x0f +#define BLE_SM_ERR_MAX_PLUS_1 0x10 #define BLE_SM_PAIR_ALG_JW 0 #define BLE_SM_PAIR_ALG_PASSKEY 1 diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_store.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_store.h index 66d29b0c..732f4ff0 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_store.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_store.h @@ -57,14 +57,6 @@ struct ble_store_key_sec { */ ble_addr_t peer_addr; - /** Key by ediv; ediv_rand_present=0 means don't key off ediv. */ - uint16_t ediv; - - /** Key by rand_num; ediv_rand_present=0 means don't key off rand_num. */ - uint64_t rand_num; - - unsigned ediv_rand_present:1; - /** Number of results to skip; 0 means retrieve the first match. */ uint8_t idx; }; @@ -77,6 +69,7 @@ struct ble_store_key_sec { */ struct ble_store_value_sec { ble_addr_t peer_addr; + uint16_t bond_count; uint8_t key_size; uint16_t ediv; @@ -244,6 +237,42 @@ struct ble_store_status_event { }; }; +/* Generate LTK, EDIT and Rand */ +#define BLE_STORE_GEN_KEY_LTK 0x01 +/* Generate IRK */ +#define BLE_STORE_GEN_KEY_IRK 0x02 +/* Generate CSRK */ +#define BLE_STORE_GEN_KEY_CSRK 0x03 + +struct ble_store_gen_key { + union { + uint8_t ltk_periph[16]; + uint8_t irk[16]; + uint8_t csrk[16]; + }; + uint16_t ediv; + uint64_t rand; +}; + +/** + * Generates key required by security module. + * This can be used to use custom routines to generate keys instead of simply + * randomizing them. + * + * \p conn_handle is set to \p BLE_HS_CONN_HANDLE_NONE if key is not requested + * for a specific connection (e.g. an IRK). + * + * @param key Key that shall be generated. + * @param gen_key Storage for generated key. + * @param conn_handle Connection handle for which keys are generated. + * + * @return 0 if keys were generated successfully + * Other nonzero on error. + */ +typedef int ble_store_gen_key_fn(uint8_t key, + struct ble_store_gen_key *gen_key, + uint16_t conn_handle); + /** * Searches the store for an object matching the specified criteria. If a * match is found, it is read from the store and the dst parameter is populated diff --git a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_uuid.h b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_uuid.h index cc368368..54d2b5e2 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_uuid.h +++ b/lib/bt/host/nimble/nimble/nimble/host/include/host/ble_uuid.h @@ -56,30 +56,55 @@ typedef struct { /** 16-bit UUID */ typedef struct { + /** Generic UUID structure */ ble_uuid_t u; + + /** 16-bit UUID value */ uint16_t value; } ble_uuid16_t; /** 32-bit UUID */ typedef struct { + /** Generic UUID structure */ ble_uuid_t u; + + /** 32-bit UUID value */ uint32_t value; } ble_uuid32_t; /** 128-bit UUID */ typedef struct { + /** Generic UUID structure */ ble_uuid_t u; + + /** 128-bit UUID value */ uint8_t value[16]; } ble_uuid128_t; /** Universal UUID type, to be used for any-UUID static allocation */ typedef union { + /** Generic UUID structure */ ble_uuid_t u; + + /** 16-bit UUID structure */ ble_uuid16_t u16; + + /** 32-bit UUID structure */ ble_uuid32_t u32; + + /** 128-bit UUID structure */ ble_uuid128_t u128; } ble_uuid_any_t; +/** + * @brief Macro for initializing a 16-bit UUID. + * + * This macro initializes a 16-bit UUID with the provided value. + * + * @param uuid16 The value of the 16-bit UUID. + * + * @return The initialized 16-bit UUID structure. + */ #define BLE_UUID16_INIT(uuid16) \ { \ .u = { \ @@ -88,6 +113,15 @@ typedef union { .value = (uuid16), \ } +/** + * @brief Macro for initializing a 32-bit UUID. + * + * This macro initializes a 32-bit UUID with the provided value. + * + * @param uuid32 The value of the 32-bit UUID. + * + * @return The initialized 32-bit UUID structure. + */ #define BLE_UUID32_INIT(uuid32) \ { \ .u = { \ @@ -104,21 +138,63 @@ typedef union { .value = { uuid128 }, \ } +/** + * @brief Macro for declaring a pointer to a 16-bit UUID structure initialized with a specific 16-bit UUID value. + * + * @param uuid16 The 16-bit UUID value to initialize the structure with. + * + * @return Pointer to a `ble_uuid_t` structure. + */ #define BLE_UUID16_DECLARE(uuid16) \ ((ble_uuid_t *) (&(ble_uuid16_t) BLE_UUID16_INIT(uuid16))) +/** + * @brief Macro for declaring a pointer to a 32-bit UUID structure initialized with a specific 32-bit UUID value. + * + * @param uuid32 The 32-bit UUID value to initialize the structure with. + * + * @return Pointer to a `ble_uuid_t` structure. + */ #define BLE_UUID32_DECLARE(uuid32) \ ((ble_uuid_t *) (&(ble_uuid32_t) BLE_UUID32_INIT(uuid32))) +/** + * @brief Macro for declaring a pointer to a 128-bit UUID structure initialized with specific 128-bit UUID values. + * + * @param uuid128 The 128-bit UUID value to initialize the structure with. + * + * @return Pointer to a `ble_uuid_t` structure. + */ #define BLE_UUID128_DECLARE(uuid128...) \ ((ble_uuid_t *) (&(ble_uuid128_t) BLE_UUID128_INIT(uuid128))) +/** + * @brief Macro for casting a pointer to a `ble_uuid_t` structure to a pointer to 16-bit UUID structure. + * + * @param u Pointer to a `ble_uuid_t` structure. + * + * @return Pointer to a `ble_uuid16_t` structure. + */ #define BLE_UUID16(u) \ ((ble_uuid16_t *) (u)) +/** + * @brief Macro for casting a pointer to a `ble_uuid_t` structure to a pointer to 32-bit UUID structure. + * + * @param u Pointer to a `ble_uuid_t` structure. + * + * @return Pointer to a `ble_uuid32_t` structure. + */ #define BLE_UUID32(u) \ ((ble_uuid32_t *) (u)) +/** + * @brief Macro for casting a pointer to a `ble_uuid_t` structure to a pointer to 128-bit UUID structure. + * + * @param u Pointer to a `ble_uuid_t` structure. + * + * @return Pointer to a `ble_uuid128_t` structure. + */ #define BLE_UUID128(u) \ ((ble_uuid128_t *) (u)) @@ -168,6 +244,25 @@ void ble_uuid_copy(ble_uuid_any_t *dst, const ble_uuid_t *src); */ char *ble_uuid_to_str(const ble_uuid_t *uuid, char *dst); +/** + * @brief Converts the specified UUID string to ble_uuid_any_t representation. + * If the UUID is recognised as Bluetooth SIG UUID, it will provide its + * 32-bit or 16-bit representation. + * + * Example 128-bit string representations: + * o "12345678-1234-1234-1234-123456789abc" + * o "12345678123412341234123456789abc" + * + * @param uuid Destination UUID. + * @param str The source string UUID. + * + * @return 0 on success, + * BLE_HS_EINVAL if the specified UUID string has wrong size or + * contains disallowed characters. + */ +int +ble_uuid_from_str(ble_uuid_any_t *uuid, const char *str); + /** @brief Converts the specified 16-bit UUID to a uint16_t. * * @param uuid The source UUID to convert. diff --git a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/adv_legacy.c b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/adv_legacy.c index c3a526e0..ec45e808 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/adv_legacy.c +++ b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/adv_legacy.c @@ -48,7 +48,7 @@ static int adv_initialized = false; /* TinyCrypt PRNG consumes a lot of stack space, so we need to have * an increased call stack whenever it's used. */ -#if MYNEWT +#ifdef MYNEWT OS_TASK_STACK_DEFINE(g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); struct os_task adv_task; #endif @@ -69,7 +69,7 @@ static inline void adv_send(struct os_mbuf *buf) struct bt_data ad; int err; - adv_int = max(adv_int_min, + adv_int = MAX(adv_int_min, BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit)); #if MYNEWT_VAL(BLE_CONTROLLER) duration = ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) * @@ -222,7 +222,7 @@ void bt_mesh_adv_init(void) ble_npl_eventq_init(&bt_mesh_adv_queue); -#if MYNEWT +#ifdef MYNEWT os_task_init(&adv_task, "mesh_adv", mesh_adv_thread, NULL, MYNEWT_VAL(BLE_MESH_ADV_TASK_PRIO), OS_WAIT_FOREVER, g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); diff --git a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/cfg_cli.c b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/cfg_cli.c index 773bafa7..2a68b40a 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/cfg_cli.c +++ b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/cfg_cli.c @@ -52,7 +52,7 @@ static int comp_data_status(struct bt_mesh_model *model, if (param->page) { *(param->page) = net_buf_simple_pull_u8(buf); } - to_copy = min(net_buf_simple_tailroom(param->comp), buf->om_len); + to_copy = MIN(net_buf_simple_tailroom(param->comp), buf->om_len); net_buf_simple_add_mem(param->comp, buf->om_data, to_copy); bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); diff --git a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/cfg_srv.c b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/cfg_srv.c index e84bb742..d7b3c62c 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/cfg_srv.c +++ b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/cfg_srv.c @@ -2050,7 +2050,7 @@ static int mod_app_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - struct os_mbuf *msg = NET_BUF_SIMPLE(max(BT_MESH_MODEL_BUF_LEN(OP_VND_MOD_APP_LIST, + struct os_mbuf *msg = NET_BUF_SIMPLE(MAX(BT_MESH_MODEL_BUF_LEN(OP_VND_MOD_APP_LIST, 9 + KEY_LIST_LEN), BT_MESH_MODEL_BUF_LEN(OP_SIG_MOD_APP_LIST, 9 + KEY_LIST_LEN))); diff --git a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/glue.c b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/glue.c index 9d331ca4..5bce3d8d 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/glue.c +++ b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/glue.c @@ -61,7 +61,7 @@ bt_hex(const void *buf, size_t len) str = hexbufs[curbuf++]; curbuf %= ARRAY_SIZE(hexbufs); - len = min(len, (sizeof(hexbufs[0]) - 1) / 2); + len = MIN(len, (sizeof(hexbufs[0]) - 1) / 2); for (i = 0; i < len; i++) { str[i * 2] = hex[b[i] >> 4]; diff --git a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/light_model.c b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/light_model.c index e7199519..5f0af485 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/light_model.c +++ b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/light_model.c @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "syscfg/syscfg.h" diff --git a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/lpn.c b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/lpn.c index 1d2f229e..6e164c13 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/lpn.c +++ b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/lpn.c @@ -32,7 +32,7 @@ #endif #define LPN_RECV_DELAY MYNEWT_VAL(BLE_MESH_LPN_RECV_DELAY) -#define SCAN_LATENCY min(MYNEWT_VAL(BLE_MESH_LPN_SCAN_LATENCY), \ +#define SCAN_LATENCY MIN(MYNEWT_VAL(BLE_MESH_LPN_SCAN_LATENCY), \ LPN_RECV_DELAY) #define FRIEND_REQ_RETRY_TIMEOUT K_SECONDS(MYNEWT_VAL(BLE_MESH_LPN_RETRY_TIMEOUT)) @@ -152,12 +152,12 @@ static int32_t poll_timeout(struct bt_mesh_lpn *lpn) { /* If we're waiting for segment acks keep polling at high freq */ if (bt_mesh_tx_in_progress()) { - return min(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1)); + return MIN(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1)); } if (lpn->poll_timeout < POLL_TIMEOUT_MAX(lpn)) { lpn->poll_timeout *= 2; - lpn->poll_timeout = min(lpn->poll_timeout, + lpn->poll_timeout = MIN(lpn->poll_timeout, POLL_TIMEOUT_MAX(lpn)); } @@ -1000,7 +1000,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, } /* Set initial poll timeout */ - lpn->poll_timeout = min(POLL_TIMEOUT_MAX(lpn), + lpn->poll_timeout = MIN(POLL_TIMEOUT_MAX(lpn), POLL_TIMEOUT_INIT); } diff --git a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/proxy_srv.c b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/proxy_srv.c index 9beb34a2..00af2f84 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/proxy_srv.c +++ b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/proxy_srv.c @@ -589,8 +589,8 @@ static int gatt_proxy_advertise(struct bt_mesh_subnet *sub) * 6 slices, but make sure that a slice is at least one * second long (to avoid excessive rotation). */ - max_timeout = NODE_ID_TIMEOUT / max(subnet_count, 6); - max_timeout = max(max_timeout, K_SECONDS(1)); + max_timeout = NODE_ID_TIMEOUT / MAX(subnet_count, 6); + max_timeout = MAX(max_timeout, K_SECONDS(1)); if (remaining > max_timeout || remaining < 0) { remaining = max_timeout; diff --git a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/shell.h b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/shell.h index 53cc83a2..98d3f8c6 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/shell.h +++ b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/shell.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + #ifndef __SHELL_H__ #define __SHELL_H__ diff --git a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/transport.c b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/transport.c index 80071b19..a14f657a 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/mesh/src/transport.c +++ b/lib/bt/host/nimble/nimble/nimble/host/mesh/src/transport.c @@ -1015,7 +1015,7 @@ static inline int32_t ack_timeout(struct seg_rx *rx) /* Make sure we don't send more frequently than the duration for * each packet (default is 300ms). */ - return max(to, K_MSEC(400)); + return MAX(to, K_MSEC(400)); } int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, diff --git a/lib/bt/host/nimble/nimble/nimble/host/services/ans/src/ble_svc_ans.c b/lib/bt/host/nimble/nimble/nimble/host/services/ans/src/ble_svc_ans.c index df1e0764..edaf7f3c 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/services/ans/src/ble_svc_ans.c +++ b/lib/bt/host/nimble/nimble/nimble/host/services/ans/src/ble_svc_ans.c @@ -457,6 +457,7 @@ ble_svc_ans_init(void) rc = ble_gatts_add_svcs(ble_svc_ans_defs); SYSINIT_PANIC_ASSERT(rc == 0); + (void)rc; ble_svc_ans_new_alert_cat = MYNEWT_VAL(BLE_SVC_ANS_NEW_ALERT_CAT); ble_svc_ans_unr_alert_cat = MYNEWT_VAL(BLE_SVC_ANS_UNR_ALERT_CAT); diff --git a/lib/bt/host/nimble/nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h b/lib/bt/host/nimble/nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h index 3701121e..a035f9a1 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h +++ b/lib/bt/host/nimble/nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h @@ -36,10 +36,10 @@ struct ble_hs_cfg; #if MYNEWT_VAL(BLE_GATT_CACHING) #define BLE_SVC_GATT_CHR_DATABASE_HASH_UUID16 0x2b2a -uint16_t ble_svc_gatt_changed_handle(); -uint16_t ble_svc_gatt_hash_handle(); -uint16_t ble_svc_gatt_csf_handle(); -uint8_t ble_svc_gatt_get_csfs(); +uint16_t ble_svc_gatt_changed_handle(void); +uint16_t ble_svc_gatt_hash_handle(void); +uint16_t ble_svc_gatt_csf_handle(void); +uint8_t ble_svc_gatt_get_csfs(void); #endif uint8_t ble_svc_gatt_get_local_cl_supported_feat(void); diff --git a/lib/bt/host/nimble/nimble/nimble/host/services/hid/include/services/hid/ble_svc_hid.h b/lib/bt/host/nimble/nimble/nimble/host/services/hid/include/services/hid/ble_svc_hid.h index c2d0cd90..dcdf129c 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/services/hid/include/services/hid/ble_svc_hid.h +++ b/lib/bt/host/nimble/nimble/nimble/host/services/hid/include/services/hid/ble_svc_hid.h @@ -104,9 +104,9 @@ struct ble_svc_hid_params{ uint16_t ctrl_pt_handle; }; -void ble_svc_hid_init(); +void ble_svc_hid_init(void); int ble_svc_hid_add(struct ble_svc_hid_params params); -void ble_svc_hid_reset(); +void ble_svc_hid_reset(void); #endif #endif // CONFIG_BT_NIMBLE_HID_SERVICE diff --git a/lib/bt/host/nimble/nimble/nimble/host/services/hid/src/ble_svc_hid.c b/lib/bt/host/nimble/nimble/nimble/host/services/hid/src/ble_svc_hid.c index c077cb0f..e091bb3d 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/services/hid/src/ble_svc_hid.c +++ b/lib/bt/host/nimble/nimble/nimble/host/services/hid/src/ble_svc_hid.c @@ -95,7 +95,7 @@ ble_svc_hid_get_dsc(uint8_t num) } static struct ble_gatt_chr_def* -ble_svc_hid_get_chr_block() +ble_svc_hid_get_chr_block(void) { if (ble_svc_hid_chr_index >= HID_MAX_CHRS) { return NULL; @@ -106,14 +106,14 @@ ble_svc_hid_get_chr_block() /*returns current chr index */ static uint8_t -ble_svc_hid_get_curr_chr_idx() +ble_svc_hid_get_curr_chr_idx(void) { return ble_svc_hid_chr_index; } /*returns current svc index */ static uint8_t -get_curr_svc_idx() +get_curr_svc_idx(void) { return ble_svc_hid_svc_index; } @@ -138,7 +138,7 @@ find_rpt_by_handle(uint16_t handle) } static struct ble_gatt_svc_def* -ble_svc_get_svc_block() +ble_svc_get_svc_block(void) { if (ble_svc_hid_svc_index >= HID_MAX_SVC_INSTANCES) { return NULL; @@ -162,9 +162,9 @@ fill_proto_mode(uint8_t instance) .access_cb = ble_svc_hid_access, .val_handle = &hid_instances[instance].proto_mode_handle, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP | -#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2 +#if MYNEWT_VAL(BLE_SM_LVL) == 2 BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | -#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3 +#elif MYNEWT_VAL(BLE_SM_LVL) == 3 BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_WRITE_AUTHEN | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | #endif @@ -191,9 +191,9 @@ fill_boot_kbd_inp(uint8_t instance) .val_handle = &hid_instances[instance].kbd_inp_handle, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE | -#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2 +#if MYNEWT_VAL(BLE_SM_LVL) == 2 BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | -#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3 +#elif MYNEWT_VAL(BLE_SM_LVL) == 3 BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_WRITE_AUTHEN | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | #endif @@ -220,9 +220,9 @@ fill_boot_kbd_out(uint8_t instance) .val_handle = &hid_instances[instance].kbd_out_handle, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_WRITE | -#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2 +#if MYNEWT_VAL(BLE_SM_LVL) == 2 BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | -#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3 +#elif MYNEWT_VAL(BLE_SM_LVL) == 3 BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_WRITE_AUTHEN | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | #endif @@ -248,9 +248,9 @@ fill_boot_mouse_inp(uint8_t instance) .val_handle = &hid_instances[instance].mouse_inp_handle, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE | -#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2 +#if MYNEWT_VAL(BLE_SM_LVL) == 2 BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | -#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3 +#elif MYNEWT_VAL(BLE_SM_LVL) == 3 BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_WRITE_AUTHEN | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | #endif @@ -283,9 +283,9 @@ fill_rpt_map(uint8_t instance) .access_cb = ble_svc_hid_access, .val_handle = &hid_instances[instance].report_map_handle, .flags = BLE_GATT_CHR_F_READ | -#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2 +#if MYNEWT_VAL(BLE_SM_LVL) == 2 BLE_GATT_CHR_F_READ_ENC | -#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3 +#elif MYNEWT_VAL(BLE_SM_LVL) == 3 BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_READ_ENC | #endif @@ -346,9 +346,9 @@ fill_reports(uint8_t instance) break; } demo_chr.flags |= ( -#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2 +#if MYNEWT_VAL(BLE_SM_LVL) == 2 BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | -#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3 +#elif MYNEWT_VAL(BLE_SM_LVL) == 3 BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_WRITE_AUTHEN | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | #endif @@ -372,9 +372,9 @@ fill_hid_info(uint8_t instance) .access_cb = ble_svc_hid_access, .val_handle = &hid_instances[instance].hid_info_handle, .flags = BLE_GATT_CHR_F_READ | -#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2 +#if MYNEWT_VAL(BLE_SM_LVL) == 2 BLE_GATT_CHR_F_READ_ENC | -#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3 +#elif MYNEWT_VAL(BLE_SM_LVL) == 3 BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_READ_ENC | #endif @@ -395,9 +395,9 @@ fill_ctrl_pt(uint8_t instance) .access_cb = ble_svc_hid_access, .val_handle = &hid_instances[instance].ctrl_pt_handle, .flags = BLE_GATT_CHR_F_WRITE_NO_RSP | -#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2 +#if MYNEWT_VAL(BLE_SM_LVL) == 2 BLE_GATT_CHR_F_WRITE_ENC | -#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3 +#elif MYNEWT_VAL(BLE_SM_LVL) == 3 BLE_GATT_CHR_F_WRITE_AUTHEN | BLE_GATT_CHR_F_WRITE_ENC | #endif @@ -412,7 +412,7 @@ fill_ctrl_pt(uint8_t instance) * value set to zero */ static void -ble_svc_hid_end_chrs() +ble_svc_hid_end_chrs(void) { struct ble_gatt_chr_def *chr; chr = ble_svc_hid_get_chr_block(); @@ -647,7 +647,7 @@ ble_svc_hid_add(struct ble_svc_hid_params params) * with value set to 0 */ static int -ble_svc_hid_end() +ble_svc_hid_end(void) { struct ble_gatt_svc_def *svc; @@ -664,7 +664,7 @@ ble_svc_hid_end() call ble_svc_hid_reset() to reinitialize the service. */ void -ble_svc_hid_reset() +ble_svc_hid_reset(void) { ble_svc_hid_dsc_index = 0; ble_svc_hid_chr_index = 0; @@ -675,7 +675,7 @@ ble_svc_hid_reset() * Initialize the HID Service. */ void -ble_svc_hid_init() +ble_svc_hid_init(void) { int rc; diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_att.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_att.c index b612d494..91e77080 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_att.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_att.c @@ -70,6 +70,7 @@ static const struct ble_att_rx_dispatch_entry ble_att_rx_dispatch[] = { { BLE_ATT_OP_INDICATE_REQ, ble_att_svr_rx_indicate }, { BLE_ATT_OP_INDICATE_RSP, ble_att_clt_rx_indicate }, { BLE_ATT_OP_READ_MULT_VAR_REQ, ble_att_svr_rx_read_mult_var }, + { BLE_ATT_OP_READ_MULT_VAR_RSP, ble_att_clt_rx_read_mult_var }, { BLE_ATT_OP_WRITE_CMD, ble_att_svr_rx_write_no_rsp }, { BLE_ATT_OP_SIGNED_WRITE_CMD, ble_att_svr_rx_signed_write }, }; @@ -139,7 +140,7 @@ static const struct ble_att_rx_dispatch_entry * ble_att_rx_dispatch_entry_find(uint8_t op) { const struct ble_att_rx_dispatch_entry *entry; - int i; + unsigned int i; for (i = 0; i < BLE_ATT_RX_DISPATCH_SZ; i++) { entry = ble_att_rx_dispatch + i; diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_clt.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_clt.c index d8313776..2b62e27b 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_clt.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_clt.c @@ -537,7 +537,7 @@ ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) *****************************************************************************/ int ble_att_clt_tx_read_mult(uint16_t conn_handle, const uint16_t *handles, - int num_handles) + int num_handles, bool variable) { #if !NIMBLE_BLE_ATT_CLT_READ_MULT return BLE_HS_ENOTSUP; @@ -546,12 +546,15 @@ ble_att_clt_tx_read_mult(uint16_t conn_handle, const uint16_t *handles, struct ble_att_read_mult_req *req; struct os_mbuf *txom; int i; + uint8_t op; if (num_handles < 1) { return BLE_HS_EINVAL; } - req = ble_att_cmd_get(BLE_ATT_OP_READ_MULT_REQ, + op = variable ? BLE_ATT_OP_READ_MULT_VAR_REQ : BLE_ATT_OP_READ_MULT_REQ; + + req = ble_att_cmd_get(op, sizeof(req->handles[0]) * num_handles, &txom); if (req == NULL) { @@ -573,7 +576,19 @@ ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom) #endif /* Pass the Attribute Value field to GATT. */ - ble_gattc_rx_read_mult_rsp(conn_handle, 0, rxom); + ble_gattc_rx_read_mult_rsp(conn_handle, 0, rxom, false); + return 0; +} + +int +ble_att_clt_rx_read_mult_var(uint16_t conn_handle, struct os_mbuf **rxom) +{ +#if !NIMBLE_BLE_ATT_CLT_READ_MULT_VAR + return BLE_HS_ENOTSUP; +#endif + + /* Pass the Attribute Value field to GATT. */ + ble_gattc_rx_read_mult_rsp(conn_handle, 0, rxom, true); return 0; } diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_priv.h b/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_priv.h index 4b0bda17..0e723de9 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_priv.h @@ -273,8 +273,9 @@ int ble_att_clt_tx_read_blob(uint16_t conn_handle, uint16_t handle, uint16_t offset); int ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom); int ble_att_clt_tx_read_mult(uint16_t conn_handle, - const uint16_t *handles, int num_handles); + const uint16_t *handles, int num_handles, bool variable); int ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom); +int ble_att_clt_rx_read_mult_var(uint16_t conn_handle, struct os_mbuf **rxom); int ble_att_clt_tx_read_type(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, const ble_uuid_t *uuid); int ble_att_clt_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom); diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_svr.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_svr.c index b3d6feb9..f15b4b0b 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_svr.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_att_svr.c @@ -326,12 +326,18 @@ ble_att_svr_check_perms(uint16_t conn_handle, int is_read, * require it on level 4 */ if (MYNEWT_VAL(BLE_SM_SC_ONLY)) { - if (sec_state.key_size != 16 || - !sec_state.authenticated || + if (!sec_state.authenticated || !sec_state.encrypted) { - return BLE_ATT_ERR_INSUFFICIENT_KEY_SZ; + *out_att_err = BLE_ATT_ERR_INSUFFICIENT_AUTHEN; + return BLE_HS_ATT_ERR(*out_att_err); + } else if (sec_state.authenticated && + sec_state.encrypted && + sec_state.key_size != 16) { + *out_att_err = BLE_ATT_ERR_INSUFFICIENT_KEY_SZ; + return BLE_HS_ATT_ERR(*out_att_err); } } + if ((enc || authen) && !sec_state.encrypted) { ble_hs_lock(); conn = ble_hs_conn_find(conn_handle); @@ -1373,7 +1379,7 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, *rxom = NULL; os_mbuf_adj(txom, OS_MBUF_PKTLEN(txom)); - /* Allocate space for the respose base, but don't fill in the fields. They + /* Allocate space for the response base, but don't fill in the fields. They * get filled in at the end, when we know the value of the length field. */ @@ -1852,7 +1858,7 @@ done: int ble_att_svr_rx_read_mult_var(uint16_t conn_handle, struct os_mbuf **rxom) { -#if (!MYNEWT_VAL(BLE_ATT_SVR_READ_MULT) || (MYNEWT_VAL(BLE_VERSION) < 52)) +#if !MYNEWT_VAL(BLE_ATT_SVR_READ_MULT) return BLE_HS_ENOTSUP; #endif @@ -1976,6 +1982,9 @@ ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle, /* Silence warnings. */ end_group_handle = 0; + start_group_handle = 0; + + entry = NULL; *att_err = 0; *err_handle = start_handle; @@ -2451,7 +2460,6 @@ ble_att_svr_rx_signed_write(uint16_t conn_handle, struct os_mbuf **rxom) return 0; err: if(message != NULL) nimble_platform_mem_free(message); - ble_gap_terminate(conn_handle, BLE_ERR_AUTH_FAIL); return rc; } @@ -2934,7 +2942,7 @@ ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom) /* All indications shall be confirmed, but only these with required * security established shall be pass to application */ - if (MYNEWT_VAL(BLE_SM_SC_LVL) >= 2 && !sec_state.encrypted) { + if (MYNEWT_VAL(BLE_SM_LVL) >= 2 && !sec_state.encrypted) { return 0; } @@ -3025,7 +3033,7 @@ ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom) /* All indications shall be confirmed, but only these with required * security established shall be pass to application */ - if (MYNEWT_VAL(BLE_SM_SC_LVL) >= 2 && !sec_state.encrypted) { + if (MYNEWT_VAL(BLE_SM_LVL) >= 2 && !sec_state.encrypted) { goto done; } diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_dtm.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_dtm.c new file mode 100644 index 00000000..d88bee27 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_dtm.c @@ -0,0 +1,71 @@ +/* + * 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 +#include +#include +#include "ble_hs_hci_priv.h" + +int +ble_dtm_rx_start(const struct ble_dtm_rx_params *params) +{ + struct ble_hci_le_rx_test_v2_cp cmd; + + cmd.rx_chan = params->channel; + cmd.phy = params->phy; + cmd.index = params->modulation_index; + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RX_TEST_V2), + &cmd, sizeof(cmd), NULL, 0); +} + +int +ble_dtm_tx_start(const struct ble_dtm_tx_params *params) +{ + struct ble_hci_le_tx_test_v2_cp cmd; + + cmd.tx_chan = params->channel; + cmd.test_data_len = params->test_data_len; + cmd.payload = params->payload; + cmd.phy = params->phy; + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_TX_TEST_V2), + &cmd, sizeof(cmd), NULL, 0); +} + +int +ble_dtm_stop(uint16_t *num_packets) +{ + struct ble_hci_le_test_end_rp rsp; + int rc; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_TEST_END), + NULL, 0, &rsp, sizeof(rsp)); + + if (rc) { + *num_packets = 0; + } else { + *num_packets = le16toh(rsp.num_packets); + } + + return rc; +} diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_gap.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_gap.c index d50f8769..d896565e 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_gap.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_gap.c @@ -42,7 +42,7 @@ #define max(a, b) ((a) > (b) ? (a) : (b)) #endif -#if MYNEWT +#ifdef MYNEWT #include "bsp/bsp.h" #else #define bssnz_t @@ -130,13 +130,33 @@ struct ble_gap_connect_reattempt_ctxt { struct ble_gap_conn_params conn_params; ble_gap_event_fn *cb; void *cb_arg; -}; +}ble_conn_reattempt; -static struct ble_gap_connect_reattempt_ctxt ble_conn_reattempt[MYNEWT_VAL(BLE_MAX_CONNECTIONS)]; -#if MYNEWT_VAL(BLE_ROLE_CENTRAL) -static uint16_t reattempt_idx; +struct ble_gap_adv_reattempt_ctxt { + uint8_t type; + + struct ble_hs_adv_fields fields; + uint8_t own_addr_type; + ble_addr_t direct_addr; + uint8_t direct_addr_present:1 ; + int32_t duration_ms; + struct ble_gap_adv_params adv_params; + +#if MYNEWT_VAL(BLE_EXT_ADV) + uint8_t instance; + struct ble_gap_ext_adv_params params; + int8_t selected_tx_power; + uint8_t selected_tx_power_present:1; + uint8_t data[1650]; + uint16_t data_len; + int duration; + int max_events; #endif -static bool conn_cookie_enabled; + + bool retry; + ble_gap_event_fn *cb; + void *cb_arg; +}ble_adv_reattempt; #endif @@ -547,7 +567,7 @@ ble_gap_conn_find_by_addr(const ble_addr_t *addr, struct ble_hs_conn *conn; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -569,6 +589,57 @@ ble_gap_conn_find_by_addr(const ble_addr_t *addr, #endif } +int +ble_gap_conn_find_handle_by_addr(const ble_addr_t *addr, uint16_t *out_conn_handle) +{ +#if NIMBLE_BLE_CONNECT + struct ble_hs_conn *conn; + + ble_hs_lock(); + + conn = ble_hs_conn_find_by_addr(addr); + if (conn != NULL) { + *out_conn_handle = conn->bhc_handle; + } else { + *out_conn_handle = BLE_HS_CONN_HANDLE_NONE; + } + + ble_hs_unlock(); + + if (conn == NULL) { + return BLE_HS_ENOTCONN; + } + + return 0; +#else + return BLE_HS_ENOTSUP; +#endif +} + +struct foreach_handle_cb_arg { + ble_gap_conn_foreach_handle_fn *cb; + void *arg; +}; + +static int +ble_gap_conn_foreach_handle_callback(struct ble_hs_conn *conn, void *arg) +{ + struct foreach_handle_cb_arg *cb_arg = (struct foreach_handle_cb_arg *)arg; + + return cb_arg->cb(conn->bhc_handle, cb_arg->arg); +} + +void +ble_gap_conn_foreach_handle(ble_gap_conn_foreach_handle_fn *cb, void *arg) +{ + struct foreach_handle_cb_arg cb_arg = { + .cb = cb, + .arg = arg, + }; + + ble_hs_conn_foreach(ble_gap_conn_foreach_handle_callback, &cb_arg); +} + #if NIMBLE_BLE_CONNECT static int ble_gap_extract_conn_cb(uint16_t conn_handle, @@ -604,7 +675,7 @@ ble_gap_set_priv_mode(const ble_addr_t *peer_addr, uint8_t priv_mode) { #if NIMBLE_BLE_CONNECT if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } return ble_hs_pvcy_set_mode(peer_addr, priv_mode); @@ -623,7 +694,7 @@ ble_gap_read_le_phy(uint16_t conn_handle, uint8_t *tx_phy, uint8_t *rx_phy) int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -675,7 +746,7 @@ ble_gap_set_prefered_default_le_phy(uint8_t tx_phys_mask, uint8_t rx_phys_mask) } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } memset(&cmd, 0, sizeof(cmd)); @@ -709,7 +780,7 @@ ble_gap_set_prefered_le_phy(uint16_t conn_handle, uint8_t tx_phys_mask, struct ble_hs_conn *conn; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -760,6 +831,44 @@ ble_gap_set_prefered_le_phy(uint16_t conn_handle, uint8_t tx_phys_mask, #endif } +int ble_gap_get_local_used_addr(ble_addr_t *addr) +{ + uint8_t own_addr_type = 0; + const uint8_t *out_id_addr; + int rc; + + if (addr == NULL) { + return ESP_FAIL; + } + + own_addr_type = ble_gap_slave[0].our_addr_type; + + rc = ble_hs_id_addr(own_addr_type, &out_id_addr,NULL); + + if (rc == 0) { + addr->type = own_addr_type; + memcpy(addr->val, out_id_addr, BLE_DEV_ADDR_LEN); + } + + return rc; +} + +uint8_t* ble_resolve_adv_data(const uint8_t *adv_data, uint8_t adv_type, uint8_t adv_data_len , uint8_t * length) +{ + int rc = 0; + const struct ble_hs_adv_field *fields; + const uint8_t *data; + + rc = ble_hs_adv_find_field(adv_type, adv_data, adv_data_len, &fields); /*Fill adv field*/ + + if (rc == 0) { + *length = fields->length -1 ; /* minus length of type*/ + data = fields->value; /* Type specific adv data*/ + return (uint8_t*)data; + } + + return NULL; +} /***************************************************************************** * $misc * *****************************************************************************/ @@ -977,27 +1086,12 @@ ble_gap_master_connect_cancelled(void) static void ble_gap_update_notify(uint16_t conn_handle, int status); -static int -ble_gap_find_retry_conn_param(const struct ble_gap_conn_desc *conn_desc) -{ - int i; - - for(i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { - if (ble_conn_reattempt[i].peer_addr_present == 1 && memcmp(&ble_conn_reattempt[i].peer_addr, &conn_desc->peer_ota_addr, sizeof(ble_addr_t)) == 0) { - return i; - } - } - /* No matching entry found. Return invalid index */ - return MYNEWT_VAL(BLE_MAX_CONNECTIONS); -} - int ble_gap_master_connect_reattempt(uint16_t conn_handle) { struct ble_gap_snapshot snap; struct ble_gap_conn_desc conn; struct ble_gap_update_entry *entry; - int idx; int rc = BLE_HS_EUNKNOWN; snap.desc = &conn; @@ -1007,14 +1101,6 @@ ble_gap_master_connect_reattempt(uint16_t conn_handle) } if (conn.role == BLE_GAP_ROLE_MASTER) { - idx = ble_gap_find_retry_conn_param(&conn); - if (idx >= MYNEWT_VAL(BLE_MAX_CONNECTIONS)) { - return BLE_HS_EINVAL; - } - - /* XXX Connection state in host needs to be removed and cleaned - * up to validate the connection when re-attempting. */ - /* If there was a connection update in progress, indicate to the * application that it did not complete. */ @@ -1038,14 +1124,11 @@ ble_gap_master_connect_reattempt(uint16_t conn_handle) return rc; } - /* Utilize cookie to get the index updated correctly for re-attempt */ - conn_cookie_enabled = true; - - rc = ble_gap_connect(ble_conn_reattempt[idx].own_addr_type, - (ble_conn_reattempt[idx].peer_addr_present == 1 ? &ble_conn_reattempt[idx].peer_addr : NULL), - ble_conn_reattempt[idx].duration_ms, - &ble_conn_reattempt[idx].conn_params, - ble_conn_reattempt[idx].cb, + rc = ble_gap_connect(ble_conn_reattempt.own_addr_type, + (ble_conn_reattempt.peer_addr_present == 1 ? &ble_conn_reattempt.peer_addr : NULL), + ble_conn_reattempt.duration_ms, + &ble_conn_reattempt.conn_params, + ble_conn_reattempt.cb, &conn); if (rc != 0) { return rc; @@ -1067,8 +1150,66 @@ void ble_gap_reattempt_count(uint16_t conn_handle, uint8_t count) event.reattempt_cnt.count = count; event.reattempt_cnt.conn_handle = le16toh(conn_handle); + ble_gap_event_listener_call(&event); ble_gap_call_conn_event_cb(&event, handle); } + +int ble_gap_slave_adv_reattempt(void) +{ + int rc = 0; + + switch (ble_adv_reattempt.type) { + case 0: + ble_gap_adv_stop(); + + rc = ble_gap_adv_set_fields(&ble_adv_reattempt.fields); + if (rc != 0) { + return rc; + } + + rc = ble_gap_adv_start(ble_adv_reattempt.own_addr_type, + (ble_adv_reattempt.direct_addr_present == 1 ? &ble_adv_reattempt.direct_addr: NULL), + ble_adv_reattempt.duration_ms, &ble_adv_reattempt.adv_params, + ble_adv_reattempt.cb, ble_adv_reattempt.cb_arg); + if (rc != 0) { + return rc; + } + break; + + case 1: +#if MYNEWT_VAL(BLE_EXT_ADV) + ble_gap_ext_adv_stop(ble_adv_reattempt.instance); + + rc = ble_gap_ext_adv_configure(ble_adv_reattempt.instance, &ble_adv_reattempt.params, + (ble_adv_reattempt.selected_tx_power_present == 1 ? &ble_adv_reattempt.selected_tx_power : NULL), + ble_adv_reattempt.cb, ble_adv_reattempt.cb_arg); + + if (rc != 0) { + return rc; + } + + ble_adv_reattempt.retry = 1; + rc = ble_gap_ext_adv_set_data(ble_adv_reattempt.instance, + ble_hs_mbuf_from_flat(ble_adv_reattempt.data, ble_adv_reattempt.data_len)); + + if (rc != 0) { + return rc; + } + + rc = ble_gap_ext_adv_start(ble_adv_reattempt.instance, ble_adv_reattempt.duration, + ble_adv_reattempt.max_events); + if (rc != 0) + return rc; +#endif + break; + + default: + break; + } + + return rc; + +} #endif #endif @@ -1100,21 +1241,17 @@ ble_gap_disc_report(void *desc) static void ble_gap_disc_complete(void) { -#if NIMBLE_BLE_CONNECT struct ble_gap_master_state state; -#endif struct ble_gap_event event; memset(&event, 0, sizeof event); event.type = BLE_GAP_EVENT_DISC_COMPLETE; event.disc_complete.reason = 0; -#if NIMBLE_BLE_CONNECT ble_gap_master_extract_state(&state, 1); if (ble_gap_has_client(&state)) { ble_gap_call_event_cb(&event, state.cb, state.cb_arg); } -#endif ble_gap_event_listener_call(&event); } @@ -1691,6 +1828,18 @@ ble_gap_rx_adv_set_terminated(const struct ble_hci_ev_le_subev_adv_set_terminate ble_gap_adv_finished(ev->adv_handle, reason, conn_handle, ev->num_events); } +static void +ble_gap_slave_get_cb(uint8_t instance, + ble_gap_event_fn **out_cb, void **out_cb_arg) +{ + ble_hs_lock(); + + *out_cb = ble_gap_slave[instance].cb; + *out_cb_arg = ble_gap_slave[instance].cb_arg; + + ble_hs_unlock(); +} + void ble_gap_rx_scan_req_rcvd(const struct ble_hci_ev_le_subev_scan_req_rcvd *ev) { @@ -1698,7 +1847,7 @@ ble_gap_rx_scan_req_rcvd(const struct ble_hci_ev_le_subev_scan_req_rcvd *ev) ble_gap_event_fn *cb; void *cb_arg; - ble_gap_slave_extract_cb(ev->adv_handle, &cb, &cb_arg); + ble_gap_slave_get_cb(ev->adv_handle, &cb, &cb_arg); if (cb != NULL) { memset(&event, 0, sizeof event); event.type = BLE_GAP_EVENT_SCAN_REQ_RCVD; @@ -1981,6 +2130,47 @@ ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_ ble_hs_unlock(); + cb(&event, cb_arg); +} +#endif + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) +void +ble_gap_rx_biginfo_adv_rpt(const struct ble_hci_ev_le_subev_biginfo_adv_report *ev) +{ + struct ble_hs_periodic_sync *psync; + struct ble_gap_event event; + ble_gap_event_fn *cb; + void *cb_arg; + + cb = NULL; + cb_arg = NULL; + + ble_hs_lock(); + psync = ble_hs_periodic_sync_find_by_handle(le16toh(ev->sync_handle)); + if (psync) { + cb = psync->cb; + cb_arg = psync->cb_arg; + } + ble_hs_unlock(); + + memset(&event, 0, sizeof event); + + event.type = BLE_GAP_EVENT_BIGINFO_REPORT; + event.biginfo_report.sync_handle = ev->sync_handle; + event.biginfo_report.bis_cnt = ev->bis_cnt; + event.biginfo_report.nse = ev->nse; + event.biginfo_report.iso_interval = ev->iso_interval; + event.biginfo_report.bn = ev->bn; + event.biginfo_report.pto = ev->pto; + event.biginfo_report.irc = ev->irc; + event.biginfo_report.max_pdu = ev->max_pdu; + event.biginfo_report.sdu_interval = get_le24(&ev->sdu_interval[0]); + event.biginfo_report.max_sdu = ev->max_sdu; + event.biginfo_report.phy = ev->phy; + event.biginfo_report.framing = ev->framing; + event.biginfo_report.encryption = ev->encryption; + ble_gap_event_listener_call(&event); if (cb) { cb(&event, cb_arg); @@ -2232,6 +2422,25 @@ ble_gap_rx_phy_update_complete(const struct ble_hci_ev_le_subev_phy_update_compl #endif } +void +ble_gap_rx_data_len_change(const struct ble_hci_ev_le_subev_data_len_chg *ev) +{ +#if NIMBLE_BLE_CONNECT + struct ble_gap_event event; + uint16_t conn_handle = le16toh(ev->conn_handle); + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_DATA_LEN_CHG; + event.data_len_chg.max_tx_octets = le16toh(ev->max_tx_octets); + event.data_len_chg.max_rx_octets = le16toh(ev->max_rx_octets); + event.data_len_chg.max_tx_time = le16toh(ev->max_tx_time); + event.data_len_chg.max_rx_time = le16toh(ev->max_rx_time); + + ble_gap_event_listener_call(&event); + ble_gap_call_conn_event_cb(&event, conn_handle); +#endif +} + static int32_t ble_gap_master_timer(void) { @@ -2474,7 +2683,7 @@ ble_gap_wl_tx_rmv(const ble_addr_t *addr) } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } memcpy(cmd.addr, addr->val, BLE_DEV_ADDR_LEN); @@ -2501,7 +2710,7 @@ ble_gap_wl_set(const ble_addr_t *addrs, uint8_t white_list_count) STATS_INC(ble_gap_stats, wl_set); if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -2609,7 +2818,7 @@ ble_gap_adv_stop(void) int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -2834,6 +3043,23 @@ ble_gap_adv_start(uint8_t own_addr_type, const ble_addr_t *direct_addr, goto done; } +#if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT) + ble_adv_reattempt.type = 0; + ble_adv_reattempt.own_addr_type = own_addr_type; + + if (direct_addr) { + memcpy(&ble_adv_reattempt.direct_addr, direct_addr, sizeof(ble_addr_t)); + ble_adv_reattempt.direct_addr_present = 1; + } else { + ble_adv_reattempt.direct_addr_present = 0; + } + + ble_adv_reattempt.duration_ms = duration_ms; + memcpy(&ble_adv_reattempt.adv_params , adv_params, sizeof(struct ble_gap_adv_params)); + ble_adv_reattempt.cb = cb; + ble_adv_reattempt.cb_arg = cb_arg; +#endif + if (duration_ms != BLE_HS_FOREVER) { rc = ble_npl_time_ms_to_ticks(duration_ms, &duration_ticks); if (rc != 0) { @@ -2908,7 +3134,7 @@ ble_gap_adv_set_data(const uint8_t *data, int data_len) STATS_INC(ble_gap_stats, adv_set_data); if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } /* Check for valid parameters */ @@ -2936,7 +3162,7 @@ ble_gap_adv_rsp_set_data(const uint8_t *data, int data_len) uint16_t opcode; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } /* Check for valid parameters */ @@ -2965,8 +3191,11 @@ ble_gap_adv_set_fields(const struct ble_hs_adv_fields *adv_fields) int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } +#if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT) + memcpy(&ble_adv_reattempt.fields, adv_fields, sizeof( struct ble_hs_adv_fields)); +#endif rc = ble_hs_adv_set_fields(adv_fields, buf, &buf_sz, sizeof buf); if (rc != 0) { @@ -3191,7 +3420,7 @@ ble_gap_ext_adv_configure(uint8_t instance, } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } rc = ble_gap_ext_adv_params_validate(params); @@ -3199,6 +3428,23 @@ ble_gap_ext_adv_configure(uint8_t instance, return rc; } +#if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT) + ble_adv_reattempt.instance = instance; + + memcpy(&ble_adv_reattempt.params, params, sizeof(struct ble_gap_ext_adv_params)); + + if (selected_tx_power) { + ble_adv_reattempt.selected_tx_power = *selected_tx_power; + ble_adv_reattempt.selected_tx_power_present = 1 ; + } else { + ble_adv_reattempt.selected_tx_power_present = 0 ; + } + + ble_adv_reattempt.cb = cb; + + ble_adv_reattempt.cb_arg = cb_arg; +#endif + ble_hs_lock(); if (ble_gap_adv_active_instance(instance)) { @@ -3313,9 +3559,16 @@ ble_gap_ext_adv_start(uint8_t instance, int duration, int max_events) } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } +#if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT) + ble_adv_reattempt.type = 1; + ble_adv_reattempt.instance = instance; + ble_adv_reattempt.duration = duration; + ble_adv_reattempt.max_events = max_events; +#endif + ble_hs_lock(); if (!ble_gap_slave[instance].configured) { ble_hs_unlock(); @@ -3598,9 +3851,23 @@ ble_gap_ext_adv_set_data(uint8_t instance, struct os_mbuf *data) } if (!ble_hs_is_enabled()) { - rc = BLE_HS_EDISABLED; - goto done; + rc = BLE_HS_EDISABLED; + goto done; + } + +#if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT) + uint16_t len = OS_MBUF_PKTLEN(data); + + ble_adv_reattempt.type = 1; + ble_adv_reattempt.instance = instance; + + + if (!ble_adv_reattempt.retry) { + ble_hs_mbuf_to_flat(data, ble_adv_reattempt.data, len, &ble_adv_reattempt.data_len); + } else { + ble_adv_reattempt.retry = 0; } +#endif ble_hs_lock(); rc = ble_gap_ext_adv_set_data_validate(instance, data); @@ -3615,6 +3882,8 @@ ble_gap_ext_adv_set_data(uint8_t instance, struct os_mbuf *data) done: os_mbuf_free_chain(data); + data = NULL; + return rc; } @@ -3670,8 +3939,8 @@ ble_gap_ext_adv_rsp_set_data(uint8_t instance, struct os_mbuf *data) } if (!ble_hs_is_enabled()) { - rc = BLE_HS_EDISABLED; - goto done; + rc = BLE_HS_EDISABLED; + goto done; } ble_hs_lock(); @@ -3703,7 +3972,7 @@ ble_gap_ext_adv_remove(uint8_t instance) } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -3740,7 +4009,7 @@ ble_gap_ext_adv_clear(void) uint16_t opcode; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -3836,7 +4105,7 @@ ble_gap_periodic_adv_configure(uint8_t instance, } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } rc = ble_gap_periodic_adv_params_validate(params); @@ -3891,7 +4160,7 @@ ble_gap_periodic_adv_start(uint8_t instance) } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -4086,8 +4355,8 @@ int ble_gap_periodic_adv_set_data(uint8_t instance, struct os_mbuf *data) } if (!ble_hs_is_enabled()) { - rc = BLE_HS_EDISABLED; - goto done; + rc = BLE_HS_EDISABLED; + goto done; } #if MYNEWT_VAL(BLE_PERIODIC_ADV_ENH) @@ -4156,7 +4425,7 @@ ble_gap_periodic_adv_stop(uint8_t instance) } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -4216,7 +4485,7 @@ ble_gap_periodic_adv_sync_create(const ble_addr_t *addr, uint8_t adv_sid, } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -4317,7 +4586,7 @@ ble_gap_periodic_adv_sync_terminate(uint16_t sync_handle) int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -4375,7 +4644,7 @@ ble_gap_periodic_adv_sync_reporting(uint16_t sync_handle, bool enable) int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -4420,7 +4689,7 @@ ble_gap_periodic_adv_sync_transfer(uint16_t sync_handle, uint16_t conn_handle, int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -4468,7 +4737,7 @@ ble_gap_periodic_adv_sync_set_info(uint8_t instance, uint16_t conn_handle, } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -4572,7 +4841,7 @@ ble_gap_periodic_adv_sync_receive(uint16_t conn_handle, int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -4636,7 +4905,7 @@ ble_gap_add_dev_to_periodic_adv_list(const ble_addr_t *peer_addr, } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } cmd.peer_addr_type = peer_addr->type; @@ -4660,7 +4929,7 @@ ble_gap_rem_dev_from_periodic_adv_list(const ble_addr_t *peer_addr, uint8_t adv_ } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } cmd.peer_addr_type = peer_addr->type; @@ -4871,7 +5140,7 @@ ble_gap_disc_cancel(void) int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } #if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK) @@ -4972,7 +5241,7 @@ ble_gap_ext_disc(uint8_t own_addr_type, uint16_t duration, uint16_t period, STATS_INC(ble_gap_stats, discover); if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -5109,7 +5378,7 @@ ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms, struct ble_gap_ext_disc_params p = {0}; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } p.itvl = disc_params->itvl; @@ -5134,7 +5403,7 @@ ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms, STATS_INC(ble_gap_stats, discover); if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -5549,7 +5818,7 @@ ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, if (!ble_hs_is_enabled()) { rc = BLE_HS_EDISABLED; - goto done; + goto done; } if (ble_gap_is_preempted()) { @@ -5622,51 +5891,38 @@ ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, ble_gap_master.op = BLE_GAP_OP_M_CONN; #if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT) - /* ble_gap_connect_reattempt save the connection parameters */ - if ((cb_arg != NULL) && conn_cookie_enabled) { - struct ble_gap_conn_desc *conn_desc = cb_arg; - struct ble_gap_conn_desc *curr_conn_desc=NULL; - /* reattempt_idx is set to that index where corresponding conn_handle entry was made */ - for (int i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { - curr_conn_desc = ble_conn_reattempt[i].cb_arg; - if (curr_conn_desc && (conn_desc->conn_handle == curr_conn_desc->conn_handle)) { - reattempt_idx = i; - break; - } - } - /* Reset cookie_enabled flag, it will be set again by reattempt call */ - conn_cookie_enabled = false; + ble_conn_reattempt.own_addr_type = own_addr_type; + + if (peer_addr != NULL) { + ble_conn_reattempt.peer_addr_present = 1; + memcpy(&ble_conn_reattempt.peer_addr, peer_addr, sizeof(ble_addr_t)); + } else { + ble_conn_reattempt.peer_addr_present = 0; + memset(&ble_conn_reattempt.peer_addr, 0, sizeof(ble_addr_t)); } - ble_conn_reattempt[reattempt_idx].own_addr_type = own_addr_type; - memcpy(&ble_conn_reattempt[reattempt_idx].peer_addr, peer_addr, - sizeof(ble_addr_t)); - ble_conn_reattempt[reattempt_idx].duration_ms = duration_ms; + ble_conn_reattempt.duration_ms = duration_ms; if (phy_mask & BLE_GAP_LE_PHY_1M_MASK) { - memcpy(&ble_conn_reattempt[reattempt_idx].conn_params, + memcpy(&ble_conn_reattempt.conn_params, phy_1m_conn_params, sizeof(struct ble_gap_conn_params)); } if (phy_mask & BLE_GAP_LE_PHY_2M_MASK) { - memcpy(&ble_conn_reattempt[reattempt_idx].conn_params, + memcpy(&ble_conn_reattempt.conn_params, phy_2m_conn_params, sizeof(struct ble_gap_conn_params)); } if (phy_mask & BLE_GAP_LE_PHY_CODED_MASK) { - memcpy(&ble_conn_reattempt[reattempt_idx].conn_params, + memcpy(&ble_conn_reattempt.conn_params, phy_coded_conn_params, sizeof(struct ble_gap_conn_params)); } - ble_conn_reattempt[reattempt_idx].cb = cb; - ble_conn_reattempt[reattempt_idx].cb_arg = cb_arg; - /* reattempt_idx need to be within limits. This may end up being unnecessary - * operation. However, it is better to be sure as it can get tricky with - * multiple connections and client + server roles XXX*/ - reattempt_idx = (reattempt_idx + 1) % MYNEWT_VAL(BLE_MAX_CONNECTIONS); + ble_conn_reattempt.cb = cb; + ble_conn_reattempt.cb_arg = cb_arg; #endif @@ -5808,56 +6064,39 @@ ble_gap_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, memcpy(bhc_peer_addr.val, peer_addr->val, BLE_DEV_ADDR_LEN); #if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) + if (ble_host_rpa_enabled()) + { struct ble_hs_resolv_entry *rl = NULL; rl = ble_hs_resolv_list_find(bhc_peer_addr.val); - if (rl != NULL) { + if (rl != NULL && rl->rl_isrpa) { memcpy(bhc_peer_addr.val, rl->rl_peer_rpa, BLE_DEV_ADDR_LEN); bhc_peer_addr.type = rl->rl_addr_type; } + } #endif } else { memset(&bhc_peer_addr, 0, sizeof bhc_peer_addr); } #if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT) - /* ble_gap_connect_reattempt save the connection parameters */ - if ((cb_arg != NULL) && conn_cookie_enabled) { - struct ble_gap_conn_desc *conn_desc = cb_arg; - struct ble_gap_conn_desc *curr_conn_desc=NULL; - /* reattempt_idx is set to that index where corresponding conn_handle entry was made */ - for (int i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { - curr_conn_desc = ble_conn_reattempt[i].cb_arg; - if (curr_conn_desc && (conn_desc->conn_handle == curr_conn_desc->conn_handle)) { - reattempt_idx = i; - break; - } - } - /* Reset cookie_enabled flag, it will be set again by reattempt call */ - conn_cookie_enabled = false; - } - - ble_conn_reattempt[reattempt_idx].own_addr_type = own_addr_type; + ble_conn_reattempt.own_addr_type = own_addr_type; if (peer_addr != NULL) { - ble_conn_reattempt[reattempt_idx].peer_addr_present = 1; - memcpy(&ble_conn_reattempt[reattempt_idx].peer_addr, &bhc_peer_addr, + ble_conn_reattempt.peer_addr_present = 1; + memcpy(&ble_conn_reattempt.peer_addr, &bhc_peer_addr, sizeof(ble_addr_t)); } else { - ble_conn_reattempt[reattempt_idx].peer_addr_present = 0; - memset(&ble_conn_reattempt[reattempt_idx].peer_addr, 0, + ble_conn_reattempt.peer_addr_present = 0; + memset(&ble_conn_reattempt.peer_addr, 0, sizeof(ble_addr_t)); } - ble_conn_reattempt[reattempt_idx].duration_ms = duration_ms; - memcpy(&ble_conn_reattempt[reattempt_idx].conn_params, + + ble_conn_reattempt.duration_ms = duration_ms; + memcpy(&ble_conn_reattempt.conn_params, conn_params, sizeof(struct ble_gap_conn_params)); - ble_conn_reattempt[reattempt_idx].cb = cb; - ble_conn_reattempt[reattempt_idx].cb_arg = cb_arg; - - /* reattempt_idx need to be within limits. This may end up being unnecessary - * operation. However, it is better to be sure as it can get tricky with - * multiple connections and client + server roles XXX*/ - reattempt_idx = (reattempt_idx + 1) % MYNEWT_VAL(BLE_MAX_CONNECTIONS); + ble_conn_reattempt.cb = cb; + ble_conn_reattempt.cb_arg = cb_arg; #endif if (peer_addr != NULL) { @@ -6095,7 +6334,7 @@ ble_gap_terminate(uint16_t conn_handle, uint8_t hci_reason) STATS_INC(ble_gap_stats, terminate); if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -6178,7 +6417,7 @@ ble_gap_conn_cancel(void) int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -6444,7 +6683,7 @@ ble_gap_update_params(uint16_t conn_handle, } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } STATS_INC(ble_gap_stats, update); @@ -6521,24 +6760,32 @@ done: #endif } -int ble_gap_set_data_len(uint16_t conn_handle, uint16_t tx_octets, uint16_t tx_time) +int +ble_gap_set_data_len(uint16_t conn_handle, uint16_t tx_octets, + uint16_t tx_time) { return ble_hs_hci_util_set_data_len(conn_handle, tx_octets, tx_time); } -int ble_gap_read_sugg_def_data_len(uint16_t *out_sugg_max_tx_octets, uint16_t *out_sugg_max_tx_time) +int +ble_gap_read_sugg_def_data_len(uint16_t *out_sugg_max_tx_octets, + uint16_t *out_sugg_max_tx_time) { - return ble_hs_hci_util_read_sugg_def_data_len(out_sugg_max_tx_octets, out_sugg_max_tx_time); + return ble_hs_hci_util_read_sugg_def_data_len(out_sugg_max_tx_octets, + out_sugg_max_tx_time); } -int ble_gap_write_sugg_def_data_len(uint16_t sugg_max_tx_octets, uint16_t sugg_max_tx_time) +int +ble_gap_write_sugg_def_data_len(uint16_t sugg_max_tx_octets, + uint16_t sugg_max_tx_time) { - return ble_hs_hci_util_write_sugg_def_data_len(sugg_max_tx_octets, sugg_max_tx_time); + return ble_hs_hci_util_write_sugg_def_data_len(sugg_max_tx_octets, + sugg_max_tx_time); } /***************************************************************************** - * $security * - *****************************************************************************/ +* $security * +*****************************************************************************/ int ble_gap_security_initiate(uint16_t conn_handle) { @@ -6553,7 +6800,7 @@ ble_gap_security_initiate(uint16_t conn_handle) STATS_INC(ble_gap_stats, security_initiate); if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } ble_hs_lock(); @@ -6647,7 +6894,7 @@ ble_gap_pair_initiate(uint16_t conn_handle) int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } rc = ble_sm_pair_initiate(conn_handle); @@ -6668,7 +6915,7 @@ ble_gap_encryption_initiate(uint16_t conn_handle, int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } rc = ble_hs_atomic_conn_flags(conn_handle, &conn_flags); @@ -6701,7 +6948,7 @@ ble_gap_unpair(const ble_addr_t *peer_addr) union ble_store_key key; ble_addr_t *new_addr = (ble_addr_t *) peer_addr; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } if (ble_addr_cmp(peer_addr, BLE_ADDR_ANY) == 0) { @@ -6742,15 +6989,15 @@ ble_gap_unpair(const ble_addr_t *peer_addr) irk_rc = ble_hs_pvcy_remove_entry(key.sec.peer_addr.type, key.sec.peer_addr.val); if (irk_rc != 0) { - BLE_HS_LOG(ERROR, "Error while removing IRK\n"); + BLE_HS_LOG(ERROR, "Error while removing IRK , rc = %x\n",irk_rc); } } - if (value.sec.ltk_present || value.sec.irk_present) { + if (value.sec.ltk_present || value.sec.irk_present || value.sec.csrk_present) { // Delete the Peer record from store as LTK is present ltk_rc = ble_store_util_delete_peer(&key.sec.peer_addr); if (ltk_rc != 0) { - BLE_HS_LOG(ERROR, "Error while removing LTK\n"); + BLE_HS_LOG(ERROR, "Error while removing LTK , rc = %x\n",ltk_rc); } } } @@ -6760,7 +7007,7 @@ ble_gap_unpair(const ble_addr_t *peer_addr) ble_store_util_delete_peer(&key.sec.peer_addr); } else { - BLE_HS_LOG(ERROR,"No record found for the given address in ble store"); + BLE_HS_LOG(ERROR,"No record found for the given address in ble store , rc = %x\n",rc); return rc; } @@ -6781,7 +7028,7 @@ ble_gap_unpair_oldest_peer(void) int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } rc = ble_store_util_bonded_peers( @@ -6815,7 +7062,7 @@ ble_gap_unpair_oldest_except(const ble_addr_t *peer_addr) int rc, i; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } rc = ble_store_util_bonded_peers( @@ -6909,7 +7156,7 @@ ble_gap_enc_event(uint16_t conn_handle, int status, } void -ble_gap_identity_event(uint16_t conn_handle) +ble_gap_identity_event(uint16_t conn_handle, const ble_addr_t *peer_id_addr) { #if NIMBLE_BLE_SM && NIMBLE_BLE_CONNECT struct ble_gap_event event; @@ -6919,6 +7166,7 @@ ble_gap_identity_event(uint16_t conn_handle) memset(&event, 0, sizeof event); event.type = BLE_GAP_EVENT_IDENTITY_RESOLVED; event.identity_resolved.conn_handle = conn_handle; + event.identity_resolved.peer_id_addr = *peer_id_addr; ble_gap_call_conn_event_cb(&event, conn_handle); #endif } @@ -6940,6 +7188,20 @@ ble_gap_repeat_pairing_event(const struct ble_gap_repeat_pairing *rp) #endif } +void +ble_gap_pairing_complete_event(uint16_t conn_handle, int status) +{ +#if NIMBLE_BLE_SM && NIMBLE_BLE_CONNECT + struct ble_gap_event event; + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_PARING_COMPLETE; + event.pairing_complete.conn_handle = conn_handle; + event.pairing_complete.status = status; + ble_gap_call_conn_event_cb(&event, conn_handle); +#endif +} + /***************************************************************************** * $rssi * *****************************************************************************/ @@ -6950,7 +7212,7 @@ ble_gap_conn_rssi(uint16_t conn_handle, int8_t *out_rssi) int rc; if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + return BLE_HS_EDISABLED; } rc = ble_hs_hci_util_read_rssi(conn_handle, out_rssi); diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_gap_priv.h b/lib/bt/host/nimble/nimble/nimble/host/src/ble_gap_priv.h index 8be582f7..5e05b8c6 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_gap_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_gap_priv.h @@ -88,6 +88,9 @@ void ble_gap_rx_periodic_adv_rpt(const struct ble_hci_ev_le_subev_periodic_adv_r void ble_gap_rx_periodic_adv_sync_lost(const struct ble_hci_ev_le_subev_periodic_adv_sync_lost *ev); void ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev); #endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) +void ble_gap_rx_biginfo_adv_rpt(const struct ble_hci_ev_le_subev_biginfo_adv_report *ev); +#endif void ble_gap_rx_scan_req_rcvd(const struct ble_hci_ev_le_subev_scan_req_rcvd *ev); #endif void ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc); @@ -135,8 +138,9 @@ void ble_gap_subscribe_event(uint16_t conn_handle, uint16_t attr_handle, uint8_t prev_notify, uint8_t cur_notify, uint8_t prev_indicate, uint8_t cur_indicate); void ble_gap_mtu_event(uint16_t conn_handle, uint16_t cid, uint16_t mtu); -void ble_gap_identity_event(uint16_t conn_handle); +void ble_gap_identity_event(uint16_t conn_handle, const ble_addr_t *peer_id_addr); int ble_gap_repeat_pairing_event(const struct ble_gap_repeat_pairing *rp); +void ble_gap_pairing_complete_event(uint16_t conn_handle, int status); void ble_gap_vs_hci_event(const void *buf, uint8_t len); int ble_gap_authorize_event(uint16_t conn_handle, uint16_t attr_handle, int is_read); int ble_gap_master_in_progress(void); @@ -147,7 +151,6 @@ void ble_gap_preempt_done(void); int ble_gap_terminate_with_conn(struct ble_hs_conn *conn, uint8_t hci_reason); void ble_gap_reset_state(int reason); void ble_gap_conn_broken(uint16_t conn_handle, int reason); -void ble_gap_reset_state(int reason); int32_t ble_gap_timer(void); int ble_gap_init(void); @@ -161,6 +164,8 @@ int ble_gap_dbg_update_active(uint16_t conn_handle); void ble_gap_reattempt_count(uint16_t conn_handle, uint8_t count); #endif +void ble_gap_rx_data_len_change(const struct ble_hci_ev_le_subev_data_len_chg *ev); + #ifdef __cplusplus } #endif diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_gatt_priv.h b/lib/bt/host/nimble/nimble/nimble/host/src/ble_gatt_priv.h index d4c2bdd2..34c10ed1 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_gatt_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_gatt_priv.h @@ -137,7 +137,7 @@ void ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status, struct os_mbuf **rxom); void ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status, - struct os_mbuf **rxom); + struct os_mbuf **rxom, bool variable); void ble_gattc_rx_read_group_type_adata( uint16_t conn_handle, struct ble_att_read_group_type_adata *adata); void ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int rc); diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_gattc.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_gattc.c index 6b157b96..0669b6c2 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_gattc.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_gattc.c @@ -94,11 +94,12 @@ #define BLE_GATT_OP_READ_UUID 8 #define BLE_GATT_OP_READ_LONG 9 #define BLE_GATT_OP_READ_MULT 10 -#define BLE_GATT_OP_WRITE 11 -#define BLE_GATT_OP_WRITE_LONG 12 -#define BLE_GATT_OP_WRITE_RELIABLE 13 -#define BLE_GATT_OP_INDICATE 14 -#define BLE_GATT_OP_CNT 15 +#define BLE_GATT_OP_READ_MULT_VAR 11 +#define BLE_GATT_OP_WRITE 12 +#define BLE_GATT_OP_WRITE_LONG 13 +#define BLE_GATT_OP_WRITE_RELIABLE 14 +#define BLE_GATT_OP_INDICATE 15 +#define BLE_GATT_OP_CNT 16 /** Procedure stalled due to resource exhaustion. */ #define BLE_GATTC_PROC_F_STALLED 0x01 @@ -189,7 +190,9 @@ struct ble_gattc_proc { struct { uint16_t handles[MYNEWT_VAL(BLE_GATT_READ_MAX_ATTRS)]; uint8_t num_handles; + bool variable; ble_gatt_attr_fn *cb; + ble_gatt_attr_mult_fn *cb_mult; void *cb_arg; } read_mult; @@ -586,7 +589,7 @@ ble_gattc_log_read_long(struct ble_gattc_proc *proc) } static void -ble_gattc_log_read_mult(const uint16_t *handles, uint8_t num_handles) +ble_gattc_log_read_mult(const uint16_t *handles, uint8_t num_handles, bool variable) { int i; @@ -3081,7 +3084,6 @@ ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle, #if !MYNEWT_VAL(BLE_GATT_READ_UUID) return BLE_HS_ENOTSUP; #endif - /* TODO:Roshan */ struct ble_gattc_proc *proc; int rc; @@ -3322,6 +3324,73 @@ done: * $read multiple * *****************************************************************************/ +static int +ble_gattc_read_mult_cb_var(struct ble_gattc_proc *proc, int status, + uint16_t att_handle, struct os_mbuf **om) +{ + struct ble_gatt_attr attr[proc->read_mult.num_handles]; + int rc; + int i; + uint16_t attr_len; + + if (proc->read_mult.cb_mult == NULL) { + return 0; + } + + memset(attr, 0, sizeof(*attr)); + + for (i = 0; i < proc->read_mult.num_handles; i++) { + attr[i].handle = proc->read_mult.handles[i]; + attr[i].offset = 0; + if (om == NULL || OS_MBUF_PKTLEN(*om) == 0) { + continue; + } + + *om = os_mbuf_pullup(*om, 2); + assert(*om); + + attr_len = get_le16((*om)->om_data); + + os_mbuf_adj(*om, 2); + + if (attr_len > BLE_ATT_ATTR_MAX_LEN) { + /*TODO Figure out what to do here */ + break; + } + + attr[i].om = os_msys_get_pkthdr(attr_len, 0); + if (!attr[i].om) { + /*TODO Figure out what to do here */ + break; + } + + rc = os_mbuf_appendfrom(attr[i].om, *om, 0, attr_len); + if (rc) { + /*TODO Figure out what to do here */ + break; + } + + os_mbuf_adj(*om, attr_len); + } + + /*FIXME Testing assert */ + assert(i == proc->read_mult.num_handles); + + proc->read_mult.cb_mult(proc->conn_handle, + ble_gattc_error(status, att_handle), &attr[0], + i, + proc->read_mult.cb_arg); + + for (i = 0; i < proc->read_mult.num_handles; i++) { + if (attr[i].om != NULL) { + os_mbuf_free_chain(attr[i].om); + } + } + + return 0; +} + + /** * Calls a read-multiple-characteristics proc's callback with the specified * parameters. If the proc has no callback, this function is a no-op. @@ -3344,6 +3413,10 @@ ble_gattc_read_mult_cb(struct ble_gattc_proc *proc, int status, STATS_INC(ble_gattc_stats, read_mult_fail); } + if (proc->read_mult.variable) { + return ble_gattc_read_mult_cb_var(proc, status, att_handle, om); + } + attr.handle = 0; attr.offset = 0; if (om == NULL) { @@ -3400,7 +3473,7 @@ ble_gattc_read_mult_tx(struct ble_gattc_proc *proc) int rc; rc = ble_att_clt_tx_read_mult(proc->conn_handle, proc->read_mult.handles, - proc->read_mult.num_handles); + proc->read_mult.num_handles, proc->read_mult.variable); if (rc != 0) { return rc; } @@ -3409,10 +3482,11 @@ ble_gattc_read_mult_tx(struct ble_gattc_proc *proc) } -int -ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, - uint8_t num_handles, ble_gatt_attr_fn *cb, - void *cb_arg) +static int +ble_gattc_read_mult_internal(uint16_t conn_handle, const uint16_t *handles, + uint8_t num_handles, bool variable, ble_gatt_attr_fn *cb, + ble_gatt_attr_mult_fn *cb_mult, + void *cb_arg) { #if !MYNEWT_VAL(BLE_GATT_READ_MULT) return BLE_HS_ENOTSUP; @@ -3436,14 +3510,20 @@ ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, goto done; } - proc->op = BLE_GATT_OP_READ_MULT; + if (variable) { + proc->op = BLE_GATT_OP_READ_MULT_VAR; + } else { + proc->op = BLE_GATT_OP_READ_MULT; + } proc->conn_handle = conn_handle; memcpy(proc->read_mult.handles, handles, num_handles * sizeof *handles); proc->read_mult.num_handles = num_handles; + proc->read_mult.variable = variable; proc->read_mult.cb = cb; + proc->read_mult.cb_mult = cb_mult; proc->read_mult.cb_arg = cb_arg; - ble_gattc_log_read_mult(handles, num_handles); + ble_gattc_log_read_mult(handles, num_handles, variable); rc = ble_gattc_read_mult_tx(proc); if (rc != 0) { goto done; @@ -3458,6 +3538,28 @@ done: return rc; } +int +ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, + uint8_t num_handles, ble_gatt_attr_fn *cb, + void *cb_arg) +{ + return ble_gattc_read_mult_internal(conn_handle, handles, + num_handles, false, cb, NULL, cb_arg); +} + +int +ble_gattc_read_mult_var(uint16_t conn_handle, const uint16_t *handles, + uint8_t num_handles, ble_gatt_attr_mult_fn *cb, + void *cb_arg) +{ +#if MYNEWT_VAL(BLE_GATT_READ_MULT_VAR) + return ble_gattc_read_mult_internal(conn_handle, handles, num_handles, + true, NULL, cb, cb_arg); +#else + return BLE_HS_ENOTSUP; +#endif +} + /***************************************************************************** * $write no response * *****************************************************************************/ @@ -4875,16 +4977,18 @@ ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status, */ void ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status, - struct os_mbuf **om) + struct os_mbuf **om, bool variable) { #if !NIMBLE_BLE_ATT_CLT_READ_MULT return; #endif struct ble_gattc_proc *proc; + uint8_t op; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, - BLE_GATT_OP_READ_MULT); + op = variable ? BLE_GATT_OP_READ_MULT_VAR : BLE_GATT_OP_READ_MULT; + + proc = ble_gattc_extract_first_by_conn_op(conn_handle, op); if (proc != NULL) { ble_gattc_read_mult_cb(proc, status, 0, om); ble_gattc_process_status(proc, BLE_HS_EDONE); diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_gatts.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_gatts.c index 01c944d6..bec30c4e 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_gatts.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_gatts.c @@ -589,8 +589,9 @@ ble_gatts_calculate_hash(uint8_t *out_hash_key) int size; int rc; uint8_t *buf; - uint8_t key[16] = {0}; + uint8_t key[16]; + memset(key, 0, sizeof(key)); /* data with all zeroes */ rc = ble_att_get_database_size(&size); if(rc != 0) { diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs.c index def78b10..1ed13f82 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs.c @@ -31,8 +31,13 @@ #endif #include "host/ble_hs_pvcy.h" +#include "bt_common.h" +#if (BT_HCI_LOG_INCLUDED == TRUE) +#include "hci_log/bt_hci_log.h" +#endif // (BT_HCI_LOG_INCLUDED == TRUE) -#define BLE_HS_HCI_EVT_COUNT MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT) +#define BLE_HS_HCI_EVT_COUNT (MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT) + \ + MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT)) static void ble_hs_event_rx_hci_ev(struct ble_npl_event *ev); #if NIMBLE_BLE_CONNECT @@ -131,7 +136,7 @@ ble_hs_evq_set(struct ble_npl_eventq *evq) int ble_hs_locked_by_cur_task(void) { -#if MYNEWT +#ifdef MYNEWT struct os_task *owner; if (!ble_npl_os_started()) { @@ -692,6 +697,16 @@ ble_hs_rx_data(struct os_mbuf *om, void *arg) { int rc; +#if (BT_HCI_LOG_INCLUDED == TRUE) + uint16_t len = OS_MBUF_PKTHDR(om)->omp_len + 1; + uint8_t *data = (uint8_t *)malloc(len); + assert(data != NULL); + data[0] = 0x02; + os_mbuf_copydata(om, 0, len - 1, &data[1]); + bt_hci_log_record_hci_data(HCI_LOG_DATA_TYPE_C2H_ACL, &data[1], len - 1); + free(data); +#endif // (BT_HCI_LOG_INCLUDED == TRUE) + /* If flow control is enabled, mark this packet with its corresponding * connection handle. */ @@ -718,6 +733,17 @@ ble_hs_rx_data(struct os_mbuf *om, void *arg) int ble_hs_tx_data(struct os_mbuf *om) { +#if (BT_HCI_LOG_INCLUDED == TRUE) + uint16_t len = 0; + uint8_t data[MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE) + 1]; + data[0] = 0x02; + len++; + os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]); + len += OS_MBUF_PKTLEN(om); + + bt_hci_log_record_hci_data(data[0], &data[1], len - 1); +#endif + return ble_transport_to_ll_acl(om); } @@ -842,6 +868,14 @@ ble_transport_to_hs_acl_impl(struct os_mbuf *om) return ble_hs_rx_data(om, NULL); } +int +ble_transport_to_hs_iso_impl(struct os_mbuf *om) +{ + os_mbuf_free_chain(om); + + return 0; +} + void ble_transport_hs_init(void) { diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_conn.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_conn.c index 01325ad6..0af96f28 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_conn.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_conn.c @@ -503,86 +503,73 @@ ble_hs_conn_timer(void) #endif struct ble_hs_conn *conn; - ble_npl_time_t now; - int32_t next_exp_in; + ble_npl_time_t now = ble_npl_time_get(); + int32_t next_exp_in = BLE_HS_FOREVER; + int32_t next_exp_in_new; + bool next_exp_in_updated; int32_t time_diff; - uint16_t conn_handle; - for (;;) { - conn_handle = BLE_HS_CONN_HANDLE_NONE; - next_exp_in = BLE_HS_FOREVER; - now = ble_npl_time_get(); + ble_hs_lock(); - ble_hs_lock(); - - /* This loop performs one of two tasks: - * 1. Determine if any connections need to be terminated due to timeout. - * If so, break out of the loop and terminate the connection. This - * function will need to be executed again. - * 2. Otherwise, determine when the next timeout will occur. - */ - SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) { - if (!(conn->bhc_flags & BLE_HS_CONN_F_TERMINATING)) { + /* This loop performs one of two tasks: + * 1. Determine if any connections need to be terminated due to timeout. If + * so connection is disconnected. + * 2. Otherwise, determine when the next timeout will occur. + */ + SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) { + if (!(conn->bhc_flags & BLE_HS_CONN_F_TERMINATING)) { + next_exp_in_updated = false; #if MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT) != 0 - /* Check each connection's rx fragment timer. If too much time - * passes after a partial packet is received, the connection is - * terminated. - */ - if (conn->bhc_rx_chan != NULL) { - time_diff = conn->bhc_rx_timeout - now; - - if (time_diff <= 0) { - /* ACL reassembly has timed out. Remember the connection - * handle so it can be terminated after the mutex is - * unlocked. - */ - conn_handle = conn->bhc_handle; - break; - } - - /* Determine if this connection is the soonest to time out. */ - if (time_diff < next_exp_in) { - next_exp_in = time_diff; - } - } -#endif + /* Check each connection's rx fragment timer. If too much time + * passes after a partial packet is received, the connection is + * terminated. + */ + if (conn->bhc_rx_chan != NULL) { + time_diff = conn->bhc_rx_timeout - now; -#if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO - /* Check each connection's rx queued write timer. If too much - * time passes after a prep write is received, the queue is - * cleared. - */ - time_diff = ble_att_svr_ticks_until_tmo(&conn->bhc_att_svr, now); if (time_diff <= 0) { - /* ACL reassembly has timed out. Remember the connection - * handle so it can be terminated after the mutex is - * unlocked. - */ - conn_handle = conn->bhc_handle; - break; + /* ACL reassembly has timed out.*/ + ble_gap_terminate_with_conn(conn, BLE_ERR_REM_USER_CONN_TERM); + continue; } /* Determine if this connection is the soonest to time out. */ if (time_diff < next_exp_in) { - next_exp_in = time_diff; + next_exp_in_new = time_diff; + next_exp_in_updated = true; } + } #endif + +#if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO + /* Check each connection's rx queued write timer. If too much + * time passes after a prep write is received, the queue is + * cleared. + */ + time_diff = ble_att_svr_ticks_until_tmo(&conn->bhc_att_svr, now); + if (time_diff <= 0) { + /* Queued write has timed out.*/ + ble_gap_terminate_with_conn(conn, BLE_ERR_REM_USER_CONN_TERM); + continue; } - } - ble_hs_unlock(); + /* Determine if this connection is the soonest to time out. */ + if (time_diff < next_exp_in) { + next_exp_in_new = time_diff; + next_exp_in_updated = true; + } +#endif - /* If a connection has timed out, terminate it. We need to repeatedly - * call this function again to determine when the next timeout is. - */ - if (conn_handle != BLE_HS_CONN_HANDLE_NONE) { - ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); - continue; + if (next_exp_in_updated) { + next_exp_in = next_exp_in_new; + } } - - return next_exp_in; } + + ble_hs_unlock(); + + return next_exp_in; } int diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci.c index 483bed1f..b1ac4bdb 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci.c @@ -25,6 +25,10 @@ #include "ble_hs_priv.h" #include "nimble/transport.h" +#include "bt_common.h" +#if (BT_HCI_LOG_INCLUDED == TRUE) +#include "hci_log/bt_hci_log.h" +#endif // (BT_HCI_LOG_INCLUDED == TRUE) #define BLE_HCI_CMD_TIMEOUT_MS 2000 @@ -147,8 +151,8 @@ ble_hs_hci_rx_cmd_complete(const void *data, int len, const struct ble_hci_ev_command_complete_nop *nop = data; uint16_t opcode; - if (len < sizeof(*ev)) { - if (len < sizeof(*nop)) { + if (len < (int)sizeof(*ev)) { + if (len < (int)sizeof(*nop)) { return BLE_HS_ECONTROLLER; } @@ -325,14 +329,14 @@ ble_hs_hci_cmd_tx(uint16_t opcode, const void *cmd, uint8_t cmd_len, rc = ble_hs_hci_wait_for_ack(); if (rc != 0) { - BLE_HS_LOG(INFO, "HCI wait for ack returned %d \n", rc); + BLE_HS_LOG(ERROR, "HCI wait for ack returned %d \n", rc); ble_hs_sched_reset(rc); goto done; } rc = ble_hs_hci_process_ack(opcode, rsp, rsp_len, &ack); if (rc != 0) { - BLE_HS_LOG(INFO, "HCI process ack returned %d \n", rc); + BLE_HS_LOG(ERROR, "HCI process ack returned %d \n", rc); ble_hs_sched_reset(rc); goto done; } @@ -341,7 +345,7 @@ ble_hs_hci_cmd_tx(uint16_t opcode, const void *cmd, uint8_t cmd_len, /* on success we should always get full response */ if (!rc && (ack.bha_params_len != rsp_len)) { - BLE_HS_LOG(INFO, "Received status %d \n", rc); + BLE_HS_LOG(ERROR, "Received status %d \n", rc); ble_hs_sched_reset(rc); goto done; } @@ -387,6 +391,24 @@ ble_hs_hci_rx_ack(uint8_t *ack_ev) ble_npl_sem_release(&ble_hs_hci_sem); } +#if (BT_HCI_LOG_INCLUDED == TRUE) +bool host_recv_adv_packet(uint8_t *data) +{ + assert(data); + if(data[0] == BLE_HCI_EVCODE_LE_META) { + if((data[2] == BLE_HCI_LE_SUBEV_ADV_RPT) || (data[2] == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT) || + (data[2] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT) || (data[2] == BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT) +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + || (data[2] == BLE_HCI_LE_SUBEV_DISCARD_REPORT_EVT) +#endif + ) { + return true; + } + } + return false; +} +#endif // (BT_HCI_LOG_INCLUDED == TRUE) + int ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg) { @@ -397,6 +419,15 @@ ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg) BLE_HS_DBG_ASSERT(hci_ev != NULL); +#if (BT_HCI_LOG_INCLUDED == TRUE) + uint16_t len = hci_ev[1] + 3; + if (host_recv_adv_packet(hci_ev)) { + bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, &hci_ev[1], len - 2); + } else { + bt_hci_log_record_hci_data(0x04, &hci_ev[0], len - 1); + } +#endif // #if (BT_HCI_LOG_INCLUDED == TRUE) + switch (ev->opcode) { case BLE_HCI_EVCODE_COMMAND_COMPLETE: enqueue = (cmd_complete->opcode == BLE_HCI_OPCODE_NOP); diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_cmd.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_cmd.c index 45df3053..76ec034d 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_cmd.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_cmd.c @@ -24,6 +24,11 @@ #include "os/os.h" #include "nimble/hci_common.h" #include "ble_hs_priv.h" +#include "bt_common.h" +#if (BT_HCI_LOG_INCLUDED == TRUE) +#include "hci_log/bt_hci_log.h" +#endif // (BT_HCI_LOG_INCLUDED == TRUE) + /* * HCI Command Header @@ -86,6 +91,16 @@ ble_hs_hci_cmd_send(uint16_t opcode, uint8_t len, const void *cmddata) buf--; #endif +#if (BT_HCI_LOG_INCLUDED == TRUE) + uint8_t *data; +#if !(SOC_ESP_NIMBLE_CONTROLLER) && CONFIG_BT_CONTROLLER_ENABLED + data = (uint8_t *)buf + 1; +#else + data = (uint8_t *)buf; +#endif + bt_hci_log_record_hci_data(0x01, data, len + BLE_HCI_CMD_HDR_LEN); +#endif + rc = ble_hs_hci_cmd_transport((void *) buf); if (rc == 0) { diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_evt.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_evt.c index d77a4b7e..64b37f01 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_evt.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_evt.c @@ -31,10 +31,10 @@ struct ble_gap_reattempt_ctxt { ble_addr_t peer_addr; uint8_t count; -}; +}reattempt_conn; -static struct ble_gap_reattempt_ctxt reattempt_conn[MYNEWT_VAL(BLE_MAX_CONNECTIONS)]; extern int ble_gap_master_connect_reattempt(uint16_t conn_handle); +extern int ble_gap_slave_adv_reattempt(void); #ifdef CONFIG_BT_NIMBLE_MAX_CONN_REATTEMPT #define MAX_REATTEMPT_ALLOWED CONFIG_BT_NIMBLE_MAX_CONN_REATTEMPT @@ -42,13 +42,13 @@ extern int ble_gap_master_connect_reattempt(uint16_t conn_handle); #define MAX_REATTEMPT_ALLOWED 0 #endif #endif - + #if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK) -static struct ble_npl_mutex adv_list_lock; +static struct ble_npl_mutex adv_list_lock; static uint16_t ble_adv_list_count; -#define BLE_ADV_LIST_MAX_LENGTH 50 +#define BLE_ADV_LIST_MAX_LENGTH 50 #define BLE_ADV_LIST_MAX_COUNT 200 -#endif +#endif _Static_assert(sizeof (struct hci_data_hdr) == BLE_HCI_DATA_HDR_SZ, "struct hci_data_hdr must be 4 bytes"); @@ -79,6 +79,7 @@ static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_complete; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_upd_complete; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_lt_key_req; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_parm_req; +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_data_len_change; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_phy_update_complete; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_enh_conn_complete; #endif @@ -92,6 +93,9 @@ static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_rpt; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_sync_lost; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_scan_req_rcvd; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_sync_transfer; +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_biginfo_adv_report; +#endif #if MYNEWT_VAL(BLE_POWER_CONTROL) static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_pathloss_threshold; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_transmit_power_report; @@ -126,7 +130,7 @@ static const struct ble_hs_hci_evt_dispatch_entry ble_hs_hci_evt_dispatch[] = { #endif { BLE_HCI_EVCODE_HW_ERROR, ble_hs_hci_evt_hw_error }, #if MYNEWT_VAL(BLE_HCI_VS) - { BLE_HCI_EVCODE_VS_DEBUG, ble_hs_hci_evt_vs }, + { BLE_HCI_EVCODE_VS, ble_hs_hci_evt_vs }, #endif { BLE_HCI_OCF_LE_RX_TEST, ble_hs_hci_evt_rx_test }, { BLE_HCI_OCF_LE_TX_TEST, ble_hs_hci_evt_tx_test }, @@ -147,6 +151,7 @@ static ble_hs_hci_evt_le_fn * const ble_hs_hci_evt_le_dispatch[] = { [BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE] = ble_hs_hci_evt_le_conn_upd_complete, [BLE_HCI_LE_SUBEV_LT_KEY_REQ] = ble_hs_hci_evt_le_lt_key_req, [BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ] = ble_hs_hci_evt_le_conn_parm_req, + [BLE_HCI_LE_SUBEV_DATA_LEN_CHG] = ble_hs_hci_evt_le_data_len_change, [BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE] = ble_hs_hci_evt_le_enh_conn_complete, #endif [BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT] = ble_hs_hci_evt_le_dir_adv_rpt, @@ -162,6 +167,9 @@ static ble_hs_hci_evt_le_fn * const ble_hs_hci_evt_le_dispatch[] = { [BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED] = ble_hs_hci_evt_le_adv_set_terminated, [BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD] = ble_hs_hci_evt_le_scan_req_rcvd, [BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER] = ble_hs_hci_evt_le_periodic_adv_sync_transfer, +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + [BLE_HCI_LE_SUBEV_BIGINFO_ADV_REPORT] = ble_hs_hci_evt_le_biginfo_adv_report, +#endif #if MYNEWT_VAL(BLE_POWER_CONTROL) [BLE_HCI_LE_SUBEV_PATH_LOSS_THRESHOLD] = ble_hs_hci_evt_le_pathloss_threshold, [BLE_HCI_LE_SUBEV_TRANSMIT_POWER_REPORT] = ble_hs_hci_evt_le_transmit_power_report, @@ -178,7 +186,7 @@ static const struct ble_hs_hci_evt_dispatch_entry * ble_hs_hci_evt_dispatch_find(uint8_t event_code) { const struct ble_hs_hci_evt_dispatch_entry *entry; - int i; + unsigned int i; for (i = 0; i < BLE_HS_HCI_EVT_DISPATCH_SZ; i++) { entry = ble_hs_hci_evt_dispatch + i; @@ -202,22 +210,6 @@ ble_hs_hci_evt_le_dispatch_find(uint8_t event_code) return ble_hs_hci_evt_le_dispatch[event_code]; } -#if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT) -static int -ble_gap_find_reattempt_conn_idx(const struct ble_hs_conn *conn) -{ - int i; - - for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { - if (memcmp(&reattempt_conn[i].peer_addr, &conn->bhc_peer_addr, sizeof(ble_addr_t)) == 0) { - return i; - } - } - /* No matching entry found. Return invalid index */ - return MYNEWT_VAL(BLE_MAX_CONNECTIONS); -} -#endif - #if NIMBLE_BLE_CONNECT static int ble_hs_hci_evt_disconn_complete(uint8_t event_code, const void *data, @@ -238,68 +230,60 @@ ble_hs_hci_evt_disconn_complete(uint8_t event_code, const void *data, ble_hs_unlock(); #if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT) - if (ev->reason == BLE_ERR_CONN_ESTABLISHMENT) { - int rc, i, idx; + if (conn && ev->reason == BLE_ERR_CONN_ESTABLISHMENT) { uint16_t handle; + int rc; + + if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) { //slave + BLE_HS_LOG(INFO, "Reattempt advertising; reason: 0x%x, status = %x", + ev->reason, ev->status); + + ble_l2cap_sig_conn_broken(ev->conn_handle, BLE_ERR_CONN_ESTABLISHMENT); + ble_sm_connection_broken(ev->conn_handle); + ble_gatts_connection_broken(ev->conn_handle); + ble_gattc_connection_broken(ev->conn_handle); + ble_hs_flow_connection_broken(ev->conn_handle);; +#if MYNEWT_VAL(BLE_GATT_CACHING) + ble_gattc_cache_conn_broken(ev->conn_handle); +#endif + rc = ble_hs_atomic_conn_delete(ev->conn_handle); + if (rc != 0) { + return rc; + } - idx = ble_gap_find_reattempt_conn_idx(conn); - - if (idx == MYNEWT_VAL(BLE_MAX_CONNECTIONS)) { - /* This means, no matching addr exists in databse. So create a new one */ - for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { - if (reattempt_conn[i].count == 0) { - idx = i; - break; - } - } - } - - if (idx == MYNEWT_VAL(BLE_MAX_CONNECTIONS)) { - BLE_HS_LOG(DEBUG, "No space left in array "); - - for (i = 0; i < idx; i++) { - memset(&reattempt_conn[i], 0x0, sizeof(struct ble_gap_reattempt_ctxt)); - } - goto done; - } - - if (conn != NULL) { - BLE_HS_LOG(DEBUG, "Reattempt connection; reason = 0x%x, status = %d," - "reattempt count = %d ", ev->reason, ev->status, - reattempt_conn[idx].count); - if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) { - if (reattempt_conn[idx].count < MAX_REATTEMPT_ALLOWED) { - reattempt_conn[idx].count += 1; + rc = ble_gap_slave_adv_reattempt(); + if (rc != 0) { + BLE_HS_LOG(INFO, "Adv reattempt failed; rc= %d ", rc); + } - for (i = 0; i < BLE_DEV_ADDR_LEN; i++) { - reattempt_conn[idx].peer_addr.val[i] = conn->bhc_peer_addr.val[i]; - } + return 0; // Restart advertising, so don't post disconnect event - reattempt_conn[idx].peer_addr.type = conn->bhc_peer_addr.type; + } else { // master + if (reattempt_conn.count < MAX_REATTEMPT_ALLOWED ) { + /* Got for connection */ + BLE_HS_LOG(INFO, "Reattempt connection; reason = 0x%x, status = %d," + "reattempt count = %d ", ev->reason, ev->status, + reattempt_conn.count); + reattempt_conn.count += 1; - handle = le16toh(ev->conn_handle); - /* Post event to interested application */ - ble_gap_reattempt_count(handle, reattempt_conn[idx].count); + handle = le16toh(ev->conn_handle); + /* Post event to interested application */ + ble_gap_reattempt_count(handle, reattempt_conn.count); - rc = ble_gap_master_connect_reattempt(ev->conn_handle); - if (rc != 0) { - BLE_HS_LOG(DEBUG, "Master reconnect attempt failed; rc = %d", rc); - } - } else { - memset(&reattempt_conn[idx].peer_addr, 0x0, BLE_DEV_ADDR_LEN); - reattempt_conn[idx].count = 0; + rc = ble_gap_master_connect_reattempt(ev->conn_handle); + if (rc != 0) { + BLE_HS_LOG(INFO, "Master reconnect attempt failed; rc = %d", rc); } + } else { + /* Exhausted attempts */ + memset(&reattempt_conn, 0x0, sizeof (struct ble_gap_reattempt_ctxt)); } - } else { - /* Disconnect completed with some other reason than - * BLE_ERR_CONN_ESTABLISHMENT, reset the corresponding reattempt count - * */ - memset(&reattempt_conn[idx].peer_addr, 0x0, BLE_DEV_ADDR_LEN); - reattempt_conn[idx].count = 0; - } + } + } + else { + /* Normal disconnect. Reset the structure */ + memset(&reattempt_conn, 0x0, sizeof (struct ble_gap_reattempt_ctxt)); } -done: - #endif ble_gap_rx_disconn_complete(ev); @@ -401,7 +385,7 @@ ble_hs_hci_evt_num_completed_pkts(uint8_t event_code, const void *data, static int ble_hs_hci_evt_vs(uint8_t event_code, const void *data, unsigned int len) { - const struct ble_hci_ev_vs_debug *ev = data; + const struct ble_hci_ev_vs *ev = data; if (len < sizeof(*ev)) { return BLE_HS_ECONTROLLER; @@ -635,9 +619,9 @@ ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, const void *data, unsigned int len) data += sizeof(*ev); desc.direct_addr = *BLE_ADDR_ANY; - + /* BLE Queue Congestion check*/ -#if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK) +#if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK) if (ble_get_adv_list_length() > BLE_ADV_LIST_MAX_LENGTH || ble_adv_list_count > BLE_ADV_LIST_MAX_COUNT) { ble_adv_list_refresh(); } @@ -646,8 +630,8 @@ ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, const void *data, unsigned int len) for (i = 0; i < ev->num_reports; i++) { - /* Avoiding further processing, if the adv report is from the same device*/ -#if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK) + /* Avoiding further processing, if the adv report is from the same device*/ +#if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK) if (ble_check_adv_list(ev->reports[i].addr, ev->reports[i].addr_type) == true) { continue; } @@ -665,6 +649,9 @@ ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, const void *data, unsigned int len) rl = ble_hs_resolv_rpa_addr(desc.addr.val, desc.addr.type); if (rl != NULL) { + if(desc.addr.type == 1) { + rl->rl_isrpa = 1; + } memcpy(desc.addr.val, rl->rl_identity_addr, BLE_DEV_ADDR_LEN); desc.addr.type = rl->rl_addr_type; } @@ -915,6 +902,23 @@ ble_hs_hci_evt_le_periodic_adv_sync_transfer(uint8_t subevent, const void *data, return 0; } +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) +static int +ble_hs_hci_evt_le_biginfo_adv_report(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_biginfo_adv_report *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_EBADDATA; + } + + ble_gap_rx_biginfo_adv_rpt(ev); + + return 0; +} +#endif + static int ble_hs_hci_evt_le_scan_timeout(uint8_t subevent, const void *data, unsigned int len) @@ -1065,6 +1069,22 @@ ble_hs_hci_evt_le_phy_update_complete(uint8_t subevent, const void *data, return 0; } + +static int +ble_hs_hci_evt_le_data_len_change(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_data_len_chg *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + + ble_gap_rx_data_len_change(ev); + + return 0; + +} #endif int @@ -1214,8 +1234,8 @@ void ble_adv_list_init(void) ble_adv_list_count = 0; } -void ble_adv_list_deinit(void) -{ +void ble_adv_list_deinit(void) +{ struct ble_addr_list_entry *device; struct ble_addr_list_entry *temp; @@ -1233,16 +1253,16 @@ void ble_adv_list_deinit(void) void ble_adv_list_add_packet(void *data) { - struct ble_addr_list_entry *device; + struct ble_addr_list_entry *device; if (!data) { BLE_HS_LOG(ERROR, "%s data is NULL", __func__); return; } - + ble_npl_mutex_pend(&adv_list_lock, BLE_NPL_TIME_FOREVER); - device = (struct ble_addr_list_entry *)data; + device = (struct ble_addr_list_entry *)data; SLIST_INSERT_HEAD(&ble_adv_list, device, next); ble_npl_mutex_release(&adv_list_lock); @@ -1252,7 +1272,7 @@ uint32_t ble_get_adv_list_length(void) { uint32_t length = 0; struct ble_addr_list_entry *device; - + SLIST_FOREACH(device, &ble_adv_list, next) { length++; } @@ -1272,7 +1292,7 @@ void ble_adv_list_refresh(void) } ble_npl_mutex_pend(&adv_list_lock, BLE_NPL_TIME_FOREVER); - + SLIST_FOREACH_SAFE(device, &ble_adv_list, next, temp) { SLIST_REMOVE(&ble_adv_list, device, ble_addr_list_entry, next); free(device); @@ -1284,16 +1304,16 @@ void ble_adv_list_refresh(void) bool ble_check_adv_list(const uint8_t *addr, uint8_t addr_type) { struct ble_addr_list_entry *device; - struct ble_addr_list_entry *adv_packet; + struct ble_addr_list_entry *adv_packet; bool found = false; - + if (!addr) { BLE_HS_LOG(ERROR, "%s addr is NULL", __func__); return found; } ble_npl_mutex_pend(&adv_list_lock, BLE_NPL_TIME_FOREVER); - + SLIST_FOREACH(device, &ble_adv_list, next) { if (!memcmp(addr, device->addr.val, BLE_DEV_ADDR_LEN) && device->addr.type == addr_type) { found = true; diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_priv.h b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_priv.h index 9b6b0fa1..ab862dc5 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_priv.h @@ -102,6 +102,12 @@ int ble_hs_hci_util_read_adv_tx_pwr(int8_t *out_pwr); int ble_hs_hci_util_rand(void *dst, int len); int ble_hs_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi); int ble_hs_hci_util_set_random_addr(const uint8_t *addr); +int ble_hs_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets, + uint16_t tx_time); +int ble_hs_hci_util_read_sugg_def_data_len(uint16_t *out_sugg_max_tx_octets, + uint16_t *out_sugg_max_tx_time); +int ble_hs_hci_util_write_sugg_def_data_len(uint16_t sugg_max_tx_octets, + uint16_t sugg_max_tx_time); int ble_hs_hci_util_data_hdr_strip(struct os_mbuf *om, struct hci_data_hdr *out_hdr); int ble_hs_hci_evt_process(struct ble_hci_ev *ev); diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_util.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_util.c index 785951d7..573b4425 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_util.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_hci_util.c @@ -81,7 +81,7 @@ ble_hs_hci_util_rand(void *dst, int len) return rc; } - chunk_sz = min(len, sizeof(rsp)); + chunk_sz = min(len, (int)sizeof(rsp)); memcpy(u8ptr, &rsp.random_number, chunk_sz); len -= chunk_sz; @@ -184,12 +184,14 @@ ble_hs_hci_util_read_sugg_def_data_len(uint16_t *out_sugg_max_tx_octets, if (*out_sugg_max_tx_octets < BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MIN || *out_sugg_max_tx_octets > BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MAX) { - BLE_HS_LOG(WARN, "received suggested maximum tx octets is out of range\n"); + BLE_HS_LOG(WARN, + "received suggested maximum tx octets is out of range\n"); } if (*out_sugg_max_tx_time < BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MIN || *out_sugg_max_tx_time > BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MAX) { - BLE_HS_LOG(WARN, "received suggested maximum tx time is out of range\n"); + BLE_HS_LOG(WARN, + "received suggested maximum tx time is out of range\n"); } return 0; diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_id.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_id.c index dffa3af2..3fa07187 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_id.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_id.c @@ -24,6 +24,8 @@ static uint8_t ble_hs_id_pub[6]; static uint8_t ble_hs_id_rnd[6]; +static const uint8_t ble_hs_misc_null_addr[6]; + bool ble_hs_is_rpa(uint8_t *addr, uint8_t addr_type) diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_mbuf.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_mbuf.c index 649f3106..9c3cbf0a 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_mbuf.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_mbuf.c @@ -100,12 +100,12 @@ ble_hs_mbuf_l2cap_pkt(void) struct os_mbuf * ble_hs_mbuf_att_pkt(void) { - /* Prepare write request and response are the larget ATT commands which + /* Prepare write request and response are the largest ATT commands which * contain attribute data. */ - return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ + - BLE_L2CAP_HDR_SZ + - BLE_ATT_PREP_WRITE_CMD_BASE_SZ); + return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ + + BLE_L2CAP_HDR_SZ + + BLE_ATT_PREP_WRITE_CMD_BASE_SZ); } struct os_mbuf * diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_misc.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_misc.c index dfb46b74..c016ce75 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_misc.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_misc.c @@ -22,8 +22,6 @@ #include "os/os.h" #include "ble_hs_priv.h" -const uint8_t ble_hs_misc_null_addr[6]; - int ble_hs_misc_conn_chan_find(uint16_t conn_handle, uint16_t cid, struct ble_hs_conn **out_conn, diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_priv.h b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_priv.h index 8ee70033..c5781ccc 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_priv.h @@ -97,8 +97,6 @@ extern struct os_mbuf_pool ble_hs_mbuf_pool; extern uint8_t ble_hs_sync_state; extern uint8_t ble_hs_enabled_state; -extern const uint8_t ble_hs_misc_null_addr[6]; - extern uint16_t ble_hs_max_attrs; extern uint16_t ble_hs_max_services; extern uint16_t ble_hs_max_client_configs; diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_pvcy.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_pvcy.c index 08f7c462..403fd4ec 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_pvcy.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_pvcy.c @@ -29,6 +29,7 @@ static uint8_t ble_hs_pvcy_irk[16]; /** Use this as a default IRK if none gets set. */ uint8_t ble_hs_pvcy_default_irk[16]; +uint16_t rpa_timeout; static int ble_hs_pvcy_set_addr_timeout(uint16_t timeout) @@ -50,6 +51,23 @@ ble_hs_pvcy_set_addr_timeout(uint16_t timeout) &cmd, sizeof(cmd), NULL, 0); } +void ble_hs_set_rpa_timeout (uint16_t timeout) +{ + rpa_timeout = timeout; + + ble_hs_pvcy_set_addr_timeout(rpa_timeout); +} + +uint16_t ble_hs_get_rpa_timeout(void) +{ + return rpa_timeout; +} + +void ble_hs_reset_rpa_timeout(void) +{ + rpa_timeout = 0 ; +} + #if (!MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)) int ble_hs_pvcy_set_resolve_enabled(int enable) @@ -179,6 +197,7 @@ int ble_hs_pvcy_ensure_started(void) { int rc; + uint16_t rpa_timeout; if (ble_hs_pvcy_started) { return 0; @@ -189,8 +208,16 @@ ble_hs_pvcy_ensure_started(void) ble_hs_resolv_init(); #endif + /* Check if user has already set any timeout. If yes, use it */ + rpa_timeout = ble_hs_get_rpa_timeout(); + /* Set up the periodic change of our RPA. */ - rc = ble_hs_pvcy_set_addr_timeout(MYNEWT_VAL(BLE_RPA_TIMEOUT)); + if (rpa_timeout) { + rc = ble_hs_pvcy_set_addr_timeout(rpa_timeout); + } else { + rc = ble_hs_pvcy_set_addr_timeout(MYNEWT_VAL(BLE_RPA_TIMEOUT)); + } + if (rc != 0) { return rc; } diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_resolv_priv.h b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_resolv_priv.h index 5a74b942..382ac82b 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_resolv_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_resolv_priv.h @@ -35,6 +35,7 @@ struct ble_hs_resolv_entry { uint8_t rl_pseudo_id[BLE_DEV_ADDR_LEN]; uint8_t rl_local_rpa[BLE_DEV_ADDR_LEN]; uint8_t rl_peer_rpa[BLE_DEV_ADDR_LEN]; + uint8_t rl_isrpa; }; #if MYNEWT_VAL(BLE_STORE_CONFIG_PERSIST) diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_shutdown.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_shutdown.c index f29d4a66..bdd7f727 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_shutdown.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_shutdown.c @@ -17,7 +17,7 @@ * under the License. */ -#if MYNEWT +#ifdef MYNEWT #include "os/mynewt.h" #include "ble_hs_priv.h" diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_startup.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_startup.c index 68aa3695..a9c9fe79 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_startup.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_hs_startup.c @@ -260,6 +260,27 @@ ble_hs_startup_le_set_evmask_tx(void) } #endif +#if MYNEWT_VAL(BLE_POWER_CONTROL) + if (version >= BLE_HCI_VER_BCS_5_2) { + /** + * Enable the following LE events: + * 0x0000000080000000 LE Path Loss Threshold event + * 0x0000000100000000 LE Transmit Power Reporting event + */ + mask |= 0x0000000180000000; + } +#endif + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + if (version >= BLE_HCI_VER_BCS_5_2) { + /** + * Enable the following LE events: + * 0x0000000200000000 LE BIGInfo Advertising Report event + */ + mask |= 0x0000000200000000; + } +#endif + cmd.event_mask = htole64(mask); rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, @@ -328,6 +349,7 @@ ble_hs_startup_reset_tx(void) int ble_hs_startup_go(void) { + //struct ble_store_gen_key gen_key; int rc; rc = ble_hs_startup_reset_tx(); @@ -381,7 +403,22 @@ ble_hs_startup_go(void) if (rc != 0) { return rc; } +#if 0 + if (ble_hs_cfg.store_gen_key_cb) { + memset(&gen_key, 0, sizeof(gen_key)); + rc = ble_hs_cfg.store_gen_key_cb(BLE_STORE_GEN_KEY_IRK, &gen_key, + BLE_HS_CONN_HANDLE_NONE); + if (rc == 0) { + ble_hs_pvcy_set_our_irk(gen_key.irk); + } + } else { + rc = -1; + } + if (rc != 0) { + ble_hs_pvcy_set_our_irk(NULL); + } +#endif ble_hs_pvcy_set_default_irk(); ble_hs_pvcy_set_our_irk(NULL); diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap.c index 810d07b3..50fe18c6 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap.c @@ -331,10 +331,6 @@ ble_l2cap_get_mtu(struct ble_l2cap_chan *chan) * pointer to the appropriate handler gets * written here. The caller should pass the * receive buffer to this callback. - * @param out_rx_buf If a full L2CAP packet has been received, this - * will point to the entire L2CAP packet. To - * process the packet, pass this buffer to the - * receive handler (out_rx_cb). * @param out_reject_cid Indicates whether an L2CAP Command Reject * command should be sent. If this equals -1, * no reject should get sent. Otherwise, the diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_coc.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_coc.c index 1efbccf9..90d2a057 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_coc.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_coc.c @@ -35,7 +35,7 @@ static struct ble_l2cap_coc_srv_list ble_l2cap_coc_srvs; static os_membuf_t ble_l2cap_coc_srv_mem[ OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM), - sizeof (struct ble_l2cap_coc_srv)) + sizeof(struct ble_l2cap_coc_srv)) ]; static struct os_mempool ble_l2cap_coc_srv_pool; @@ -75,9 +75,9 @@ ble_l2cap_coc_srv_alloc(void) int ble_l2cap_coc_create_server(uint16_t psm, uint16_t mtu, - ble_l2cap_event_fn *cb, void *cb_arg) + ble_l2cap_event_fn *cb, void *cb_arg) { - struct ble_l2cap_coc_srv * srv; + struct ble_l2cap_coc_srv *srv; srv = ble_l2cap_coc_srv_alloc(); if (!srv) { @@ -111,7 +111,7 @@ ble_l2cap_clear_used_cid(uint32_t *cid_mask, int bit) static inline int ble_l2cap_get_first_available_bit(uint32_t *cid_mask) { - int i; + unsigned int i; int bit = 0; for (i = 0; i < BLE_HS_CONN_L2CAP_COC_CID_MASK_LEN; i++) { @@ -121,7 +121,7 @@ ble_l2cap_get_first_available_bit(uint32_t *cid_mask) * a) If bit == 0 means all the bits are used * b) this function returns 1 + index */ - bit = __builtin_ffs(~(unsigned int)(cid_mask[i])); + bit = __builtin_ffs(~(unsigned int) (cid_mask[i])); if (bit != 0) { break; } @@ -156,8 +156,8 @@ ble_l2cap_coc_srv_find(uint16_t psm) srv = NULL; STAILQ_FOREACH(cur, &ble_l2cap_coc_srvs, next) { if (cur->psm == psm) { - srv = cur; - break; + srv = cur; + break; } } @@ -183,6 +183,7 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) { int rc; struct os_mbuf **om; + struct os_mbuf *rx_sdu; struct ble_l2cap_coc_endpoint *rx; uint16_t om_total; @@ -194,10 +195,13 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) rx = &chan->coc_rx; BLE_HS_DBG_ASSERT(rx != NULL); + rx_sdu = rx->sdus[chan->coc_rx.current_sdu_idx]; + BLE_HS_DBG_ASSERT(rx_sdu != NULL); + om_total = OS_MBUF_PKTLEN(*om); /* First LE frame */ - if (OS_MBUF_PKTLEN(rx->sdu) == 0) { + if (OS_MBUF_PKTLEN(rx_sdu) == 0) { uint16_t sdu_len; rc = ble_hs_mbuf_pullup_base(om, BLE_L2CAP_SDU_SIZE); @@ -207,12 +211,15 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) sdu_len = get_le16((*om)->om_data); + BLE_HS_LOG(INFO, "First LE frame received %d, SDU len: %d\n", + om_total, sdu_len + 2); + /* We should receive payload of size sdu_len + 2 bytes of sdu_len field */ if (om_total > sdu_len + 2) { BLE_HS_LOG(ERROR, "Payload larger than expected (%d>%d)\n", om_total, sdu_len + 2); /* Disconnect peer with invalid behaviour */ - rx->sdu = NULL; + rx_sdu = NULL; rx->data_offset = 0; ble_l2cap_disconnect(chan); return BLE_HS_EBADDATA; @@ -226,12 +233,13 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) return BLE_HS_EBADDATA; } - BLE_HS_LOG(DEBUG, "sdu_len=%d, received LE frame=%d, credits=%d\n", - sdu_len, om_total, rx->credits); + BLE_HS_LOG(DEBUG, + "sdu_len=%d, received LE frame=%d, credits=%d, current_sdu_idx=%d\n", + sdu_len, om_total, rx->credits, chan->coc_rx.current_sdu_idx); - os_mbuf_adj(*om , BLE_L2CAP_SDU_SIZE); + os_mbuf_adj(*om, BLE_L2CAP_SDU_SIZE); - rc = os_mbuf_appendfrom(rx->sdu, *om, 0, om_total - BLE_L2CAP_SDU_SIZE); + rc = os_mbuf_appendfrom(rx_sdu, *om, 0, om_total - BLE_L2CAP_SDU_SIZE); if (rc != 0) { /* FIXME: User shall give us big enough buffer. * need to handle it better @@ -246,16 +254,16 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) } else { BLE_HS_LOG(DEBUG, "Continuation...received %d\n", (*om)->om_len); - if (OS_MBUF_PKTLEN(rx->sdu) + (*om)->om_len > rx->data_offset) { + if (OS_MBUF_PKTLEN(rx_sdu) + (*om)->om_len > rx->data_offset) { /* Disconnect peer with invalid behaviour */ BLE_HS_LOG(ERROR, "Payload larger than expected (%d>%d)\n", - OS_MBUF_PKTLEN(rx->sdu) + (*om)->om_len, rx->data_offset); - rx->sdu = NULL; + OS_MBUF_PKTLEN(rx_sdu) + (*om)->om_len, rx->data_offset); + rx_sdu = NULL; rx->data_offset = 0; ble_l2cap_disconnect(chan); return BLE_HS_EBADDATA; } - rc = os_mbuf_appendfrom(rx->sdu, *om, 0, om_total); + rc = os_mbuf_appendfrom(rx_sdu, *om, 0, om_total); if (rc != 0) { /* FIXME: need to handle it better */ BLE_HS_LOG(DEBUG, "Could not append data rc=%d\n", rc); @@ -265,17 +273,19 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) rx->credits--; - if (OS_MBUF_PKTLEN(rx->sdu) == rx->data_offset) { - struct os_mbuf *sdu_rx = rx->sdu; + if (OS_MBUF_PKTLEN(rx_sdu) == rx->data_offset) { + struct os_mbuf *sdu_rx = rx_sdu; BLE_HS_LOG(DEBUG, "Received sdu_len=%d, credits left=%d\n", - OS_MBUF_PKTLEN(rx->sdu), rx->credits); + OS_MBUF_PKTLEN(rx_sdu), rx->credits); /* Lets get back control to os_mbuf to application. * Since it this callback application might want to set new sdu * we need to prepare space for this. Therefore we need sdu_rx */ - rx->sdu = NULL; + rx_sdu = NULL; + chan->coc_rx.current_sdu_idx = + (chan->coc_rx.current_sdu_idx + 1) % BLE_L2CAP_SDU_BUFF_CNT; rx->data_offset = 0; ble_l2cap_event_coc_received_data(chan, sdu_rx); @@ -296,14 +306,16 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) ble_l2cap_sig_le_credits(chan->conn_handle, chan->scid, rx->credits); } - BLE_HS_LOG(DEBUG, "Received partial sdu_len=%d, credits left=%d\n", - OS_MBUF_PKTLEN(rx->sdu), rx->credits); + BLE_HS_LOG(DEBUG, + "Received partial sdu_len=%d, credits left=%d, current_sdu_idx=%d\n", + OS_MBUF_PKTLEN(rx_sdu), rx->credits, chan->coc_rx.current_sdu_idx); return 0; } void -ble_l2cap_coc_set_new_mtu_mps(struct ble_l2cap_chan *chan, uint16_t mtu, uint16_t mps) +ble_l2cap_coc_set_new_mtu_mps(struct ble_l2cap_chan *chan, uint16_t mtu, + uint16_t mps) { chan->my_coc_mps = mps; chan->coc_rx.mtu = mtu; @@ -332,7 +344,17 @@ ble_l2cap_coc_chan_alloc(struct ble_hs_conn *conn, uint16_t psm, uint16_t mtu, chan->my_coc_mps = MYNEWT_VAL(BLE_L2CAP_COC_MPS); chan->rx_fn = ble_l2cap_coc_rx_fn; chan->coc_rx.mtu = mtu; - chan->coc_rx.sdu = sdu_rx; + chan->coc_rx.sdus[0] = sdu_rx; + for (int i = 1; i < BLE_L2CAP_SDU_BUFF_CNT; i++) { + chan->coc_rx.sdus[i] = NULL; + } + chan->coc_rx.current_sdu_idx = 0; + + if (BLE_L2CAP_SDU_BUFF_CNT == 1) { + chan->coc_rx.next_sdu_alloc_idx = 0; + } else { + chan->coc_rx.next_sdu_alloc_idx = chan->coc_rx.sdus[0] == NULL ? 0 : 1; + } /* Number of credits should allow to send full SDU with on given * L2CAP MTU @@ -370,7 +392,7 @@ ble_l2cap_coc_create_srv_chan(struct ble_hs_conn *conn, uint16_t psm, static void ble_l2cap_event_coc_disconnected(struct ble_l2cap_chan *chan) { - struct ble_l2cap_event event = { }; + struct ble_l2cap_event event = {}; /* FIXME */ if (!chan->cb) { @@ -389,7 +411,7 @@ ble_l2cap_coc_cleanup_chan(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan { /* PSM 0 is used for fixed channels. */ if (chan->psm == 0) { - return; + return; } ble_l2cap_event_coc_disconnected(chan); @@ -399,14 +421,16 @@ ble_l2cap_coc_cleanup_chan(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan chan->scid - BLE_L2CAP_COC_CID_START); } - os_mbuf_free_chain(chan->coc_rx.sdu); - os_mbuf_free_chain(chan->coc_tx.sdu); + for (int i = 0; i < BLE_L2CAP_SDU_BUFF_CNT; i++) { + os_mbuf_free_chain(chan->coc_rx.sdus[i]); + } + os_mbuf_free_chain(chan->coc_tx.sdus[0]); } static void ble_l2cap_event_coc_unstalled(struct ble_l2cap_chan *chan, int status) { - struct ble_l2cap_event event = { }; + struct ble_l2cap_event event = {}; if (!chan->cb) { return; @@ -435,7 +459,7 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) /* If there is no data to send, just return success */ tx = &chan->coc_tx; - if (!tx->sdu) { + if (!tx->sdus[0]) { ble_hs_unlock(); return 0; } @@ -446,7 +470,7 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) BLE_HS_LOG(DEBUG, "Available credits %d\n", tx->credits); /* lets calculate data we are going to send */ - left_to_send = OS_MBUF_PKTLEN(tx->sdu) - tx->data_offset; + left_to_send = OS_MBUF_PKTLEN(tx->sdus[0]) - tx->data_offset; if (tx->data_offset == 0) { sdu_size_offset = BLE_L2CAP_SDU_SIZE; @@ -466,9 +490,10 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) if (tx->data_offset == 0) { /* First packet needs SDU len first. Left to send */ - uint16_t l = htole16(OS_MBUF_PKTLEN(tx->sdu)); + uint16_t l = htole16(OS_MBUF_PKTLEN(tx->sdus[0])); - BLE_HS_LOG(DEBUG, "Sending SDU len=%d\n", OS_MBUF_PKTLEN(tx->sdu)); + BLE_HS_LOG(DEBUG, "Sending SDU len=%d\n", + OS_MBUF_PKTLEN(tx->sdus[0])); rc = os_mbuf_append(txom, &l, sizeof(uint16_t)); if (rc) { rc = BLE_HS_ENOMEM; @@ -481,7 +506,7 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) * that for first packet we need to decrease data size by 2 bytes for sdu * size */ - rc = os_mbuf_appendfrom(txom, tx->sdu, tx->data_offset, + rc = os_mbuf_appendfrom(txom, tx->sdus[0], tx->data_offset, len - sdu_size_offset); if (rc) { rc = BLE_HS_ENOMEM; @@ -502,18 +527,19 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) } BLE_HS_LOG(DEBUG, "Sent %d bytes, credits=%d, to send %d bytes \n", - len, tx->credits, OS_MBUF_PKTLEN(tx->sdu)- tx->data_offset); + len, tx->credits, + OS_MBUF_PKTLEN(tx->sdus[0]) - tx->data_offset); - if (tx->data_offset == OS_MBUF_PKTLEN(tx->sdu)) { + if (tx->data_offset == OS_MBUF_PKTLEN(tx->sdus[0])) { BLE_HS_LOG(DEBUG, "Complete package sent\n"); - os_mbuf_free_chain(tx->sdu); - tx->sdu = NULL; + os_mbuf_free_chain(tx->sdus[0]); + tx->sdus[0] = NULL; tx->data_offset = 0; break; } } - if (tx->sdu) { + if (tx->sdus[0]) { /* Not complete SDU sent, wait for credits */ tx->flags |= BLE_L2CAP_COC_FLAG_STALLED; ble_hs_unlock(); @@ -531,8 +557,8 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) return 0; failed: - os_mbuf_free_chain(tx->sdu); - tx->sdu = NULL; + os_mbuf_free_chain(tx->sdus[0]); + tx->sdus[0] = NULL; os_mbuf_free_chain(txom); if (tx->flags & BLE_L2CAP_COC_FLAG_STALLED) { @@ -590,7 +616,15 @@ ble_l2cap_coc_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx) return BLE_HS_EINVAL; } - chan->coc_rx.sdu = sdu_rx; + if (chan->coc_rx.sdus[0] != NULL && + chan->coc_rx.next_sdu_alloc_idx == chan->coc_rx.current_sdu_idx && + BLE_L2CAP_SDU_BUFF_CNT != 1) { + return BLE_HS_EBUSY; + } + + chan->coc_rx.sdus[chan->coc_rx.next_sdu_alloc_idx] = sdu_rx; + chan->coc_rx.next_sdu_alloc_idx = + (chan->coc_rx.next_sdu_alloc_idx + 1) % BLE_L2CAP_SDU_BUFF_CNT; ble_hs_lock(); conn = ble_hs_conn_find_assert(chan->conn_handle); @@ -633,11 +667,11 @@ ble_l2cap_coc_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_tx) } ble_hs_lock(); - if (tx->sdu) { + if (tx->sdus[0]) { ble_hs_unlock(); return BLE_HS_EBUSY; } - tx->sdu = sdu_tx; + tx->sdus[0] = sdu_tx; /* leave the host locked on purpose when ble_l2cap_coc_continue_tx() */ @@ -650,10 +684,10 @@ ble_l2cap_coc_init(void) STAILQ_INIT(&ble_l2cap_coc_srvs); return os_mempool_init(&ble_l2cap_coc_srv_pool, - MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM), - sizeof (struct ble_l2cap_coc_srv), - ble_l2cap_coc_srv_mem, - "ble_l2cap_coc_srv_pool"); + MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM), + sizeof(struct ble_l2cap_coc_srv), + ble_l2cap_coc_srv_mem, + "ble_l2cap_coc_srv_pool"); } #endif diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_coc_priv.h b/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_coc_priv.h index 5ebdaa05..37a95b31 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_coc_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_coc_priv.h @@ -37,8 +37,14 @@ struct ble_l2cap_chan; #define BLE_L2CAP_COC_FLAG_STALLED 0x01 +#define BLE_L2CAP_SDU_BUFF_CNT (MYNEWT_VAL(BLE_L2CAP_COC_SDU_BUFF_COUNT)) + struct ble_l2cap_coc_endpoint { - struct os_mbuf *sdu; + struct os_mbuf *sdus[BLE_L2CAP_SDU_BUFF_CNT]; + /* Index for currently used sdu from sdus */ + uint16_t current_sdu_idx; + /* Index indicating free sdus slot to allocate next sdu */ + uint16_t next_sdu_alloc_idx; uint16_t mtu; uint16_t credits; uint16_t data_offset; diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_sig.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_sig.c index 05f5829f..42459179 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_sig.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_l2cap_sig.c @@ -795,14 +795,14 @@ ble_l2cap_sig_credit_base_reconfig_req_rx(uint16_t conn_handle, } if (hdr->length <= sizeof(*req)) { - rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_UNACCAPTED_PARAM); + rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_UNACCEPTED_PARAM); goto failed; } req = (struct ble_l2cap_sig_credit_base_reconfig_req *)(*om)->om_data; if ((req->mps < BLE_L2CAP_ECOC_MIN_MTU) || (req->mtu < BLE_L2CAP_ECOC_MIN_MTU)) { - rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_UNACCAPTED_PARAM); + rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_UNACCEPTED_PARAM); goto failed; } @@ -811,7 +811,7 @@ ble_l2cap_sig_credit_base_reconfig_req_rx(uint16_t conn_handle, cid_cnt = (hdr->length - sizeof(*req)) / sizeof(uint16_t); if (cid_cnt > BLE_L2CAP_MAX_COC_CONN_REQ) { - rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_UNACCAPTED_PARAM); + rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_UNACCEPTED_PARAM); goto failed; } diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_sm.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_sm.c index 48d3e440..527cd96d 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_sm.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_sm.c @@ -602,7 +602,8 @@ ble_sm_persist_keys(struct ble_sm_proc *proc) ble_hs_unlock(); if (identity_ev) { - ble_gap_identity_event(proc->conn_handle); + /* Use peer_addr since it does have proper addr type (i.e. 0/1, not 2/3) */ + ble_gap_identity_event(proc->conn_handle, &peer_addr); } authenticated = proc->flags & BLE_SM_PROC_F_AUTHENTICATED; @@ -945,7 +946,8 @@ ble_sm_chk_repeat_pairing(uint16_t conn_handle, } void -ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res) +ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res, + bool tx_fail) { struct ble_sm_proc *prev; struct ble_sm_proc *proc; @@ -991,12 +993,18 @@ ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res) } } - if (res->sm_err != 0) { + if (res->sm_err != 0 && tx_fail) { ble_sm_pair_fail_tx(conn_handle, res->sm_err); } ble_hs_unlock(); + if (res->enc_cb && + res->app_status != BLE_HS_ENOTCONN) { + /* Do not send this event on broken connection */ + ble_gap_pairing_complete_event(conn_handle, res->sm_err); + } + if (proc == NULL) { break; } @@ -1272,7 +1280,7 @@ ble_sm_enc_event_rx(uint16_t conn_handle, uint8_t evt_status, int encrypted) ble_hs_unlock(); res.bonded = bonded; - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); } void @@ -1302,15 +1310,15 @@ ble_sm_retrieve_ltk(uint16_t ediv, uint64_t rand, uint8_t peer_addr_type, struct ble_store_key_sec key_sec; int rc; - /* Tell applicaiton to look up LTK by peer address and ediv/rand pair. */ + /* Tell application to look up LTK by peer address and ediv/rand pair. */ memset(&key_sec, 0, sizeof key_sec); key_sec.peer_addr.type = peer_addr_type; memcpy(key_sec.peer_addr.val, peer_addr, 6); - key_sec.ediv = ediv; - key_sec.rand_num = rand; - key_sec.ediv_rand_present = 1; rc = ble_store_read_our_sec(&key_sec, value_sec); + if (value_sec->ediv != ediv || value_sec->rand_num != rand) { + return BLE_HS_ENOENT; + } return rc; } @@ -1493,7 +1501,7 @@ ble_sm_ltk_req_rx(const struct ble_hci_ev_le_subev_lt_key_req *ev) } } - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); return 0; } @@ -1827,10 +1835,10 @@ ble_sm_verify_auth_requirements(uint8_t cmd) return false; } } - /* Fail if Secure Connections level forces MITM protection and remote does not + /* Fail if security level forces MITM protection and remote does not * support it */ - if (MYNEWT_VAL(BLE_SM_SC_LVL) >= 3 && !(cmd & BLE_SM_PAIR_AUTHREQ_MITM)) { + if (MYNEWT_VAL(BLE_SM_LVL) >= 3 && !(cmd & BLE_SM_PAIR_AUTHREQ_MITM)) { return false; } return true; @@ -1914,7 +1922,7 @@ ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om, if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) { res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP); - } else if (MYNEWT_VAL(BLE_SM_SC_LVL) == 1) { + } else if (MYNEWT_VAL(BLE_SM_LVL) == 1) { res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP); } else if (req->max_enc_key_size < BLE_SM_PAIR_KEY_SZ_MIN) { @@ -1923,12 +1931,18 @@ ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om, } else if (req->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) { res->sm_err = BLE_SM_ERR_INVAL; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL); - } else if (MYNEWT_VAL(BLE_SM_SC_ONLY) && (req->max_enc_key_size != BLE_SM_PAIR_KEY_SZ_MAX)) { - /* Fail if Secure Connections Only mode is on and remote does not meet - * key size requirements - MITM was checked in last step - */ - res->sm_err = BLE_SM_ERR_ENC_KEY_SZ; - res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ); + } else if (MYNEWT_VAL(BLE_SM_SC_ONLY)) { + /* Fail if Secure Connections Only mode is on and remote does not + * meet key size requirements - MITM was checked in last step. + * Fail if SC is not supported by peer or key size is too small + */ + if (!(req->authreq & BLE_SM_PAIR_AUTHREQ_SC)) { + res->sm_err = BLE_SM_ERR_AUTHREQ; + res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ); + } else if (req->max_enc_key_size != BLE_SM_PAIR_KEY_SZ_MAX) { + res->sm_err = BLE_SM_ERR_ENC_KEY_SZ; + res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ); + } } else if (!ble_sm_verify_auth_requirements(req->authreq)) { res->sm_err = BLE_SM_ERR_AUTHREQ; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ); @@ -2161,6 +2175,7 @@ ble_sm_key_exch_success(struct ble_sm_proc *proc, struct ble_sm_result *res) res->app_status = 0; res->enc_cb = 1; res->bonded = bonded; + res->sm_err = BLE_SM_ERR_SUCCESS; } static void @@ -2179,6 +2194,8 @@ ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, uint8_t our_key_dist; struct os_mbuf *txom; const uint8_t *irk; + struct ble_store_gen_key gen_key; + int ltk_gen = 0; int rc; ble_sm_key_dist(proc, &init_key_dist, &resp_key_dist); @@ -2196,15 +2213,37 @@ ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, goto err; } - rc = ble_sm_gen_ltk(proc, enc_info->ltk); - if (rc != 0) { - os_mbuf_free_chain(txom); - goto err; + proc->our_keys.key_size = proc->key_size; + + if (ble_hs_cfg.store_gen_key_cb) { + memset(&gen_key, 0, sizeof(gen_key)); + rc = ble_hs_cfg.store_gen_key_cb(BLE_STORE_GEN_KEY_LTK, &gen_key, + proc->conn_handle); + if (rc == 0) { + /* Trim LRK to keysize */ + memset(gen_key.ltk_periph + proc->key_size, 0, + 16 - proc->key_size); + + proc->our_keys.ediv = gen_key.ediv; + proc->our_keys.rand_val = gen_key.rand; + memcpy(proc->our_keys.ltk, gen_key.ltk_periph, 16); + + ltk_gen = 1; + } } - /* store LTK before sending since ble_sm_tx consumes tx mbuf */ - memcpy(proc->our_keys.ltk, enc_info->ltk, 16); - proc->our_keys.key_size = proc->key_size; + if (!ltk_gen) { + rc = ble_sm_gen_ltk(proc, enc_info->ltk); + if (rc != 0) { + os_mbuf_free_chain(txom); + goto err; + } + + /* store LTK before sending since ble_sm_tx consumes tx mbuf */ + memcpy(proc->our_keys.ltk, enc_info->ltk, 16); + } else { + memcpy(enc_info->ltk, proc->our_keys.ltk, 16); + } proc->our_keys.ltk_valid = 1; rc = ble_sm_tx(proc->conn_handle, txom); @@ -2220,20 +2259,25 @@ ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, goto err; } - rc = ble_sm_gen_ediv(master_id); - if (rc != 0) { - os_mbuf_free_chain(txom); - goto err; - } - rc = ble_sm_gen_master_id_rand(master_id); - if (rc != 0) { - os_mbuf_free_chain(txom); - goto err; - } + if (!ltk_gen) { + rc = ble_sm_gen_ediv(master_id); + if (rc != 0) { + os_mbuf_free_chain(txom); + goto err; + } + rc = ble_sm_gen_master_id_rand(master_id); + if (rc != 0) { + os_mbuf_free_chain(txom); + goto err; + } + proc->our_keys.rand_val = master_id->rand_val; + proc->our_keys.ediv = master_id->ediv; + } else { + master_id->ediv = proc->our_keys.ediv; + master_id->rand_val = proc->our_keys.rand_val; + } proc->our_keys.ediv_rand_valid = 1; - proc->our_keys.rand_val = master_id->rand_val; - proc->our_keys.ediv = master_id->ediv; rc = ble_sm_tx(proc->conn_handle, txom); if (rc != 0) { @@ -2311,12 +2355,28 @@ ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, goto err; } - rc = ble_sm_gen_csrk(proc, sign_info->sig_key); - if (rc != 0) { - os_mbuf_free_chain(txom); - goto err; + if (ble_hs_cfg.store_gen_key_cb) { + memset(&gen_key, 0, sizeof(gen_key)); + rc = ble_hs_cfg.store_gen_key_cb(BLE_STORE_GEN_KEY_CSRK, &gen_key, + proc->conn_handle); + if (rc == 0) { + memcpy(proc->our_keys.csrk, gen_key.csrk, 16); + } + } else { + rc = -1; } + if (rc != 0) { + rc = ble_sm_gen_csrk(proc, sign_info->sig_key); + if (rc != 0) { + os_mbuf_free_chain(txom); + goto err; + } + + memcpy(proc->our_keys.csrk, sign_info->sig_key, 16); + } else { + memcpy(sign_info->sig_key, proc->our_keys.csrk, 16); + } proc->our_keys.csrk_valid = 1; proc->our_keys.sign_counter = 0; memcpy(proc->our_keys.csrk, sign_info->sig_key, 16); @@ -2571,6 +2631,7 @@ ble_sm_fail_rx(uint16_t conn_handle, struct os_mbuf **om, cmd = (struct ble_sm_pair_fail *)(*om)->om_data; res->app_status = BLE_HS_SM_PEER_ERR(cmd->reason); + res->sm_err = cmd->reason; } } @@ -2758,7 +2819,7 @@ ble_sm_pair_initiate(uint16_t conn_handle) } if (proc != NULL) { - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); } return res.app_status; @@ -2797,7 +2858,7 @@ ble_sm_slave_initiate(uint16_t conn_handle) ble_hs_unlock(); if (proc != NULL) { - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); } return res.app_status; @@ -2851,7 +2912,7 @@ ble_sm_enc_initiate(uint16_t conn_handle, uint8_t key_size, ble_hs_unlock(); - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); return res.app_status; } @@ -2889,7 +2950,8 @@ ble_sm_rx(struct ble_l2cap_chan *chan) memset(&res, 0, sizeof res); rx_cb(conn_handle, om, &res); - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, op == BLE_SM_OP_PAIR_FAIL ? + false : true); rc = res.app_status; } else { rc = BLE_HS_ENOTSUP; @@ -3001,7 +3063,7 @@ ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey) return rc; } - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); return res.app_status; } @@ -3014,7 +3076,7 @@ ble_sm_connection_broken(uint16_t conn_handle) res.app_status = BLE_HS_ENOTCONN; res.enc_cb = 1; - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); } int diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_sm_priv.h b/lib/bt/host/nimble/nimble/nimble/host/src/ble_sm_priv.h index f9c84663..94b57be5 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_sm_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_sm_priv.h @@ -386,7 +386,8 @@ uint8_t *ble_sm_our_pair_rand(struct ble_sm_proc *proc); uint8_t *ble_sm_peer_pair_rand(struct ble_sm_proc *proc); int ble_sm_ioact_state(uint8_t action); int ble_sm_proc_can_advance(struct ble_sm_proc *proc); -void ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res); +void ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res, + bool tx_fail); void ble_sm_confirm_advance(struct ble_sm_proc *proc); void ble_sm_ia_ra(struct ble_sm_proc *proc, uint8_t *out_iat, uint8_t *out_ia, @@ -432,7 +433,6 @@ int ble_sm_init(void); struct ble_l2cap_chan *ble_sm_create_chan(uint16_t handle); void *ble_sm_cmd_get(uint8_t opcode, size_t len, struct os_mbuf **txom); int ble_sm_tx(uint16_t conn_handle, struct os_mbuf *txom); -int ble_sm_alg_aes_cmac(const uint8_t *key, const uint8_t *in, size_t len, uint8_t *out); #ifdef __cplusplus diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_store.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_store.c index 70b074c0..d1cabfac 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_store.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_store.c @@ -299,10 +299,6 @@ ble_store_key_from_value_sec(struct ble_store_key_sec *out_key, const struct ble_store_value_sec *value) { out_key->peer_addr = value->peer_addr; - - out_key->ediv = value->ediv; - out_key->rand_num = value->rand_num; - out_key->ediv_rand_present = 1; out_key->idx = 0; } @@ -487,33 +483,32 @@ ble_store_iterate(int obj_type, /* a magic value to retrieve anything */ memset(&key, 0, sizeof(key)); switch(obj_type) { - case BLE_STORE_OBJ_TYPE_PEER_SEC: - case BLE_STORE_OBJ_TYPE_OUR_SEC: - key.sec.peer_addr = *BLE_ADDR_ANY; - pidx = &key.sec.idx; - break; - case BLE_STORE_OBJ_TYPE_CCCD: - key.cccd.peer_addr = *BLE_ADDR_ANY; - pidx = &key.cccd.idx; - break; + case BLE_STORE_OBJ_TYPE_PEER_SEC: + case BLE_STORE_OBJ_TYPE_OUR_SEC: + key.sec.peer_addr = *BLE_ADDR_ANY; + pidx = &key.sec.idx; + break; + case BLE_STORE_OBJ_TYPE_CCCD: + key.cccd.peer_addr = *BLE_ADDR_ANY; + pidx = &key.cccd.idx; + break; #if MYNEWT_VAL(ENC_ADV_DATA) - case BLE_STORE_OBJ_TYPE_ENC_ADV_DATA: - key.ead.peer_addr = *BLE_ADDR_ANY; - pidx = &key.ead.idx; - break; + case BLE_STORE_OBJ_TYPE_ENC_ADV_DATA: + key.ead.peer_addr = *BLE_ADDR_ANY; + pidx = &key.ead.idx; + break; #endif - case BLE_STORE_OBJ_TYPE_PEER_ADDR: - key.rpa_rec.peer_rpa_addr = *BLE_ADDR_ANY; - pidx = &key.rpa_rec.idx; - break; - case BLE_STORE_OBJ_TYPE_LOCAL_IRK: - key.local_irk.addr = *BLE_ADDR_ANY; - pidx = &key.local_irk.idx; - break; - - default: - BLE_HS_DBG_ASSERT(0); - return BLE_HS_EINVAL; + case BLE_STORE_OBJ_TYPE_PEER_ADDR: + key.rpa_rec.peer_rpa_addr = *BLE_ADDR_ANY; + pidx = &key.rpa_rec.idx; + break; + case BLE_STORE_OBJ_TYPE_LOCAL_IRK: + key.local_irk.addr = *BLE_ADDR_ANY; + pidx = &key.local_irk.idx; + break; + default: + BLE_HS_DBG_ASSERT(0); + return BLE_HS_EINVAL; } while (1) { @@ -564,7 +559,7 @@ ble_store_clear(void) union ble_store_key key; int obj_type; int rc; - int i; + unsigned int i; /* A zeroed key will always retrieve the first value. */ memset(&key, 0, sizeof key); diff --git a/lib/bt/host/nimble/nimble/nimble/host/src/ble_uuid.c b/lib/bt/host/nimble/nimble/nimble/host/src/ble_uuid.c index acf016a1..15f66374 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/src/ble_uuid.c +++ b/lib/bt/host/nimble/nimble/nimble/host/src/ble_uuid.c @@ -26,6 +26,10 @@ #include "ble_hs_priv.h" #include "host/ble_uuid.h" +#define BLE_UUID16_STR_MAX_LEN 6 +#define BLE_UUID32_STR_MAX_LEN 10 +#define BLE_UUID128_STR_MAX_LEN 36 + static uint8_t ble_uuid_base[16] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 @@ -40,6 +44,52 @@ static uint8_t ble_uuid_base[16] = { #define VERIFY_UUID(uuid) #endif +static int +hex2val(char c, uint8_t *value) +{ + if (c >= '0' && c <= '9') { + *value = c - '0'; + } else if (c >= 'a' && c <= 'f') { + *value = c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + *value = c - 'A' + 10; + } else { + return BLE_HS_EINVAL; + } + return 0; +} + + +static size_t +hex2bin(const char *hex, uint8_t *bin, size_t bin_len) +{ + size_t len = 0; + uint8_t tmp_val; + int rc; + + while (*hex && len < bin_len) { + rc = hex2val(*hex++, &tmp_val); + if (rc != 0) { + return 0; + } + + bin[len] = tmp_val << 4; + + if (!*hex) { + len++; + break; + } + + rc = hex2val(*hex++, &tmp_val); + if (rc != 0) { + return 0; + } + bin[len++] |= tmp_val; + } + + return len; +} + int ble_uuid_init_from_buf(ble_uuid_any_t *uuid, const void *buf, size_t len) { @@ -136,6 +186,106 @@ ble_uuid_to_str(const ble_uuid_t *uuid, char *dst) return dst; } +int +ble_uuid_from_str(ble_uuid_any_t *uuid, const char *str) +{ + uint8_t tmp_rslt = 0; + uint8_t *u8p; + const char *str_ptr; + uint16_t u16 = 0; + uint32_t u32 = 0; + int len = (int) strlen(str); + + if ((len < 4) || (len % 2 != 0)) { + return BLE_HS_EINVAL; + } + + str_ptr = &str[len - 2]; + + if (len <= BLE_UUID16_STR_MAX_LEN) { + uuid->u.type = BLE_UUID_TYPE_16; + } else if (len <= BLE_UUID32_STR_MAX_LEN) { + uuid->u.type = BLE_UUID_TYPE_32; + } else if (len <= BLE_UUID128_STR_MAX_LEN) { + uuid->u.type = BLE_UUID_TYPE_128; + } else { + return BLE_HS_EINVAL; + } + + switch (uuid->u.type) { + case BLE_UUID_TYPE_128: + uuid->u.type = BLE_UUID_TYPE_128; + u8p = uuid->u128.value; + for (int i = 0; i < 16; i++) { + if (hex2bin(str_ptr, u8p, 1) != 1) { + return BLE_HS_EINVAL; + } + + /* Check if string end */ + if (str_ptr == str) { + break; + } + + /* Remove '-' */ + if (*(str_ptr - 1) == '-') { + str_ptr--; + } + + str_ptr -= 2; + u8p++; + } + + if (memcmp(ble_uuid_base, uuid->u128.value, 12) == 0) { + uint8_t *tmp_ptr = &uuid->u128.value[12]; + uint32_t tmp_val32 = 0; + for (int i = 0; i < 4; i++) { + tmp_val32 |= ((uint32_t)(*tmp_ptr++) << 8 * i); + } + + if (tmp_val32 <= UINT16_MAX) { + uuid->u.type = BLE_UUID_TYPE_16; + uuid->u16.value = (uint16_t) tmp_val32; + } else { + uuid->u.type = BLE_UUID_TYPE_32; + uuid->u32.value = tmp_val32; + } + } + break; + case BLE_UUID_TYPE_32: + for (int i = 0; i < 4; i++) { + if (hex2bin(str_ptr, &tmp_rslt, 1) != 1) { + return BLE_HS_EINVAL; + } + u32 |= ((uint32_t) tmp_rslt) << (i * 8); + + if (str_ptr == str) { + break; + } + str_ptr -= 2; + } + uuid->u32.value = u32; + break; + case BLE_UUID_TYPE_16: + for (int i = 0; i < 2; i++) { + if (hex2bin(str_ptr, &tmp_rslt, 1) != 1) { + return BLE_HS_EINVAL; + } + u16 |= ((uint32_t) tmp_rslt) << (i * 8); + + if (str_ptr == str) { + break; + } + str_ptr -= 2; + } + uuid->u16.value = u16; + break; + default: + return BLE_HS_EINVAL; + } + + return 0; +} + uint16_t ble_uuid_u16(const ble_uuid_t *uuid) { diff --git a/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_config.c b/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_config.c index dd8a9e1f..770edfb0 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_config.c +++ b/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_config.c @@ -32,6 +32,9 @@ struct ble_store_value_sec #endif int ble_store_config_num_our_secs; +uint16_t ble_store_config_our_bond_count; +uint16_t ble_store_config_peer_bond_count; + #if MYNEWT_VAL(BLE_STORE_MAX_BONDS) struct ble_store_value_sec ble_store_config_peer_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; @@ -66,6 +69,107 @@ int ble_store_config_num_local_irks; * $sec * *****************************************************************************/ +int ble_store_config_compare_bond_count(const void *a, const void *b) { + const struct ble_store_value_sec *sec_a = (const struct ble_store_value_sec *)a; + const struct ble_store_value_sec *sec_b = (const struct ble_store_value_sec *)b; + + return sec_a->bond_count - sec_b->bond_count; +} + +/* This function gets the stored device records of OUR_SEC object type, arranges them in order of their bond count, + * and then updates them with new counts so they're in sequence. + */ +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) +int ble_restore_our_sec_nvs(void) +{ + esp_err_t err; + extern uint16_t ble_store_config_our_bond_count; + struct ble_store_value_sec temp_our_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; + int temp_count = 0; + + ble_store_config_our_bond_count = 0; + + memcpy(temp_our_secs, ble_store_config_our_secs, ble_store_config_num_our_secs * sizeof(struct ble_store_value_sec)); + temp_count = ble_store_config_num_our_secs; + + qsort(temp_our_secs, temp_count, sizeof(struct ble_store_value_sec), ble_store_config_compare_bond_count); + + for (int i = 0; i < temp_count; i++) { + + union ble_store_key key; + ble_store_key_from_value_sec(&key.sec, &temp_our_secs[i]); + + err = ble_store_config_delete(BLE_STORE_OBJ_TYPE_OUR_SEC, &key); + + if (err != ESP_OK) { + BLE_HS_LOG(DEBUG, "Error deleting from nvs"); + return err; + } + } + + for (int i = 0; i < temp_count; i++) { + + union ble_store_value val; + val.sec = temp_our_secs[i]; + + err = ble_store_config_write(BLE_STORE_OBJ_TYPE_OUR_SEC, &val); + + if (err != ESP_OK) { + BLE_HS_LOG(DEBUG, "Error writing record to NVS"); + return err; + } + } + + return 0; +} + +/* This function gets the stored device records of PEER_SEC object type, arranges them in order of their bond count, + * and then updates them with new counts so they're in sequence. + */ +int ble_restore_peer_sec_nvs(void) +{ + esp_err_t err; + extern uint16_t ble_store_config_peer_bond_count; + struct ble_store_value_sec temp_peer_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; + int temp_count = 0; + + ble_store_config_peer_bond_count = 0; + + memcpy(temp_peer_secs, ble_store_config_peer_secs, ble_store_config_num_peer_secs * sizeof(struct ble_store_value_sec)); + temp_count = ble_store_config_num_peer_secs; + + qsort(temp_peer_secs, temp_count, sizeof(struct ble_store_value_sec), ble_store_config_compare_bond_count); + + for (int i = 0; i < temp_count; i++) { + + union ble_store_key key; + ble_store_key_from_value_sec(&key.sec, &temp_peer_secs[i]); + + err = ble_store_config_delete(BLE_STORE_OBJ_TYPE_PEER_SEC, &key); + + if (err != ESP_OK) { + BLE_HS_LOG(DEBUG, "Error deleting from nvs"); + return err; + } + } + + for (int i = 0; i < temp_count; i++) { + + union ble_store_value val; + val.sec = temp_peer_secs[i]; + + err = ble_store_config_write(BLE_STORE_OBJ_TYPE_PEER_SEC, &val); + + if (err != ESP_OK) { + BLE_HS_LOG(DEBUG, "Error writing record to NVS"); + return err; + } + } + + return 0; +} +#endif + #if MYNEWT_VAL(BLE_STORE_MAX_BONDS) static void ble_store_config_print_value_sec(const struct ble_store_value_sec *sec) @@ -100,10 +204,6 @@ ble_store_config_print_key_sec(const struct ble_store_key_sec *key_sec) ble_hs_log_flat_buf(key_sec->peer_addr.val, 6); BLE_HS_LOG(DEBUG, " "); } - if (key_sec->ediv_rand_present) { - BLE_HS_LOG(DEBUG, "ediv=0x%02x rand=0x%llx ", - key_sec->ediv, key_sec->rand_num); - } } #if MYNEWT_VAL(BLE_STORE_MAX_BONDS) @@ -113,36 +213,20 @@ ble_store_config_find_sec(const struct ble_store_key_sec *key_sec, int num_value_secs) { const struct ble_store_value_sec *cur; - int skipped; int i; - skipped = 0; - - for (i = 0; i < num_value_secs; i++) { - cur = value_secs + i; - - if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { - if (ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr)) { - continue; - } + if (!ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { + if (key_sec->idx < num_value_secs) { + return key_sec->idx; } + } else if (key_sec->idx == 0) { + for (i = 0; i < num_value_secs; i++) { + cur = &value_secs[i]; - if (key_sec->ediv_rand_present) { - if (cur->ediv != key_sec->ediv) { - continue; - } - - if (cur->rand_num != key_sec->rand_num) { - continue; + if (!ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr)) { + return i; } } - - if (key_sec->idx > skipped) { - skipped++; - continue; - } - - return i; } return -1; @@ -197,11 +281,20 @@ ble_store_config_write_our_sec(const struct ble_store_value_sec *value_sec) ble_store_config_our_secs[idx] = *value_sec; + ble_store_config_our_secs[idx].bond_count = ++ble_store_config_our_bond_count; + rc = ble_store_config_persist_our_secs(); if (rc != 0) { return rc; } + if (ble_store_config_our_bond_count > (UINT16_MAX - 5)) { + rc = ble_restore_our_sec_nvs(); + if (rc != 0) { + return rc; + } + } + return 0; #else return BLE_HS_ENOENT; @@ -216,7 +309,7 @@ ble_store_config_delete_obj(void *values, int value_size, int idx, { uint8_t *dst; uint8_t *src; - int move_count; + uint8_t move_count; (*num_values)--; if (idx < *num_values) { @@ -347,10 +440,20 @@ ble_store_config_write_peer_sec(const struct ble_store_value_sec *value_sec) ble_store_config_peer_secs[idx] = *value_sec; + ble_store_config_peer_secs[idx].bond_count = ++ble_store_config_peer_bond_count; + rc = ble_store_config_persist_peer_secs(); if (rc != 0) { return rc; } + + if (ble_store_config_peer_bond_count > (UINT16_MAX - 5)) { + rc = ble_restore_peer_sec_nvs(); + if (rc != 0) { + return rc; + } + } + return 0; #else return BLE_HS_ENOENT; diff --git a/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_config_priv.h b/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_config_priv.h index cdc676e1..581cefdc 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_config_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_config_priv.h @@ -56,6 +56,10 @@ extern int ble_store_config_num_local_irks; int ble_store_config_persist_our_secs(void); int ble_store_config_persist_peer_secs(void); int ble_store_config_persist_cccds(void); +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) +int ble_restore_our_sec_nvs(void); +int ble_restore_peer_sec_nvs(void); +#endif #if MYNEWT_VAL(ENC_ADV_DATA) int ble_store_config_persist_eads(void); #endif diff --git a/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_nvs.c b/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_nvs.c index c6ad1aa0..8ae391e4 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_nvs.c +++ b/lib/bt/host/nimble/nimble/nimble/host/store/config/src/ble_store_nvs.c @@ -525,7 +525,12 @@ static int ble_nvs_restore_sec_keys(void) { esp_err_t err; + int flag = 0; + extern uint16_t ble_store_config_our_bond_count; + extern uint16_t ble_store_config_peer_bond_count; + extern int ble_store_config_compare_bond_count(const void *a, const void *b); +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) err = populate_db_from_nvs(BLE_STORE_OBJ_TYPE_OUR_SEC, ble_store_config_our_secs, &ble_store_config_num_our_secs); if (err != ESP_OK) { @@ -540,9 +545,32 @@ ble_nvs_restore_sec_keys(void) ESP_LOGE(TAG, "NVS operation failed for 'peer sec'"); return err; } + + for (int i = 0; i < MYNEWT_VAL(BLE_STORE_MAX_BONDS) - 1; i++) { + if ((ble_store_config_our_secs[i].bond_count > ble_store_config_our_secs[i+1].bond_count) + || (ble_store_config_peer_secs[i].bond_count > ble_store_config_peer_secs[i+1].bond_count)) { + flag = 1; + break; + } + } + + if (flag) { + + qsort(ble_store_config_our_secs, ble_store_config_num_our_secs, + sizeof(struct ble_store_value_sec), ble_store_config_compare_bond_count); + + qsort(ble_store_config_peer_secs, ble_store_config_num_peer_secs, + sizeof(struct ble_store_value_sec), ble_store_config_compare_bond_count); + } + + ble_store_config_our_bond_count = ble_store_config_our_secs[ble_store_config_num_our_secs - 1].bond_count; + ble_store_config_peer_bond_count = ble_store_config_peer_secs[ble_store_config_num_peer_secs - 1].bond_count; + ESP_LOGD(TAG, "ble_store_config_peer_secs restored %d bonds", ble_store_config_num_peer_secs); +#endif +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) err = populate_db_from_nvs(BLE_STORE_OBJ_TYPE_CCCD, ble_store_config_cccds, &ble_store_config_num_cccds); if (err != ESP_OK) { @@ -551,6 +579,7 @@ ble_nvs_restore_sec_keys(void) } ESP_LOGD(TAG, "ble_store_config_cccds restored %d bonds", ble_store_config_num_cccds); +#endif #if MYNEWT_VAL(ENC_ADV_DATA) err = populate_db_from_nvs(BLE_STORE_OBJ_TYPE_EAD, ble_store_config_eads, @@ -605,6 +634,7 @@ ble_nvs_restore_peer_records(void) } #endif +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) int ble_store_config_persist_cccds(void) { int nvs_count, nvs_idx; @@ -635,6 +665,7 @@ int ble_store_config_persist_cccds(void) } return 0; } +#endif #if MYNEWT_VAL(ENC_ADV_DATA) int ble_store_config_persist_eads(void) diff --git a/lib/bt/host/nimble/nimble/nimble/host/store/ram/src/ble_store_ram.c b/lib/bt/host/nimble/nimble/nimble/host/store/ram/src/ble_store_ram.c index d947ee6f..d587b8ac 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/store/ram/src/ble_store_ram.c +++ b/lib/bt/host/nimble/nimble/nimble/host/store/ram/src/ble_store_ram.c @@ -101,10 +101,6 @@ ble_store_ram_print_key_sec(const struct ble_store_key_sec *key_sec) ble_hs_log_flat_buf(key_sec->peer_addr.val, 6); BLE_HS_LOG(DEBUG, " "); } - if (key_sec->ediv_rand_present) { - BLE_HS_LOG(DEBUG, "ediv=0x%02x rand=0x%llx ", - key_sec->ediv, key_sec->rand_num); - } } #if MYNEWT_VAL(BLE_STORE_MAX_BONDS) @@ -114,36 +110,20 @@ ble_store_ram_find_sec(const struct ble_store_key_sec *key_sec, int num_value_secs) { const struct ble_store_value_sec *cur; - int skipped; int i; - skipped = 0; - - for (i = 0; i < num_value_secs; i++) { - cur = value_secs + i; - - if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { - if (ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr)) { - continue; - } + if (!ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { + if (key_sec->idx < num_value_secs) { + return key_sec->idx; } + } else if (key_sec->idx == 0) { + for (i = 0; i < num_value_secs; i++) { + cur = &value_secs[i]; - if (key_sec->ediv_rand_present) { - if (cur->ediv != key_sec->ediv) { - continue; + if (!ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr)) { + return i; } - - if (cur->rand_num != key_sec->rand_num) { - continue; - } - } - - if (key_sec->idx > skipped) { - skipped++; - continue; } - - return i; } return -1; @@ -211,7 +191,7 @@ ble_store_ram_delete_obj(void *values, int value_size, int idx, { uint8_t *dst; uint8_t *src; - int move_count; + uint8_t move_count; (*num_values)--; if (idx < *num_values) { diff --git a/lib/bt/host/nimble/nimble/nimble/host/syscfg.yml b/lib/bt/host/nimble/nimble/nimble/host/syscfg.yml index ce2acc48..eb1abdf4 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/syscfg.yml +++ b/lib/bt/host/nimble/nimble/nimble/host/syscfg.yml @@ -79,7 +79,13 @@ syscfg.defs: the required HCI and L2CAP headers fit into the smallest available MSYS blocks. value: 'MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8' - + BLE_L2CAP_COC_SDU_BUFF_COUNT: + description: > + Defines maximum number of SDU buffers in L2CAP COC endpoints. + Provides more currently available credits to receive more data packets. + value: 1 + restrictions: + - 'BLE_L2CAP_COC_SDU_BUFF_COUNT > 0' BLE_L2CAP_ENHANCED_COC: description: > Enables LE Enhanced CoC mode. @@ -103,9 +109,12 @@ syscfg.defs: requiring mode 1 level 1. value: 0 restrictions: - - 'BLE_SM_SC_LVL == 4 if 1' + - 'BLE_SM_LVL == 4 if 1' + - BLE_SM_MITM + - 'BLE_SM_SC if 1' + - '!BLE_SM_LEGACY if 1' - BLE_SM_SC_LVL: + BLE_SM_LVL: description: > Force global Secure Connections mode 1 level. This level describes requirements for pairing response/request received @@ -114,7 +123,8 @@ syscfg.defs: authentication requirements is granted - 2 - allow to pair despite MITM being on or off - 3 - allow to pair only when MITM protection is on - - 4 - allow to pair only when 128 bit key is used and MITM is on + - 4 - allow to pair only with Secure Connections and + when 128 bit key is used and MITM is on When set to 0 level is no forced and pairing is allowed for all requests/responses with valid values (for example pairing will be rejected with key longer than 128 bits). Successful pairing with @@ -234,6 +244,11 @@ syscfg.defs: Enables the Read Multiple Characteristic Values GATT procedure. (0/1) value: MYNEWT_VAL_BLE_ROLE_CENTRAL + BLE_GATT_READ_MULT_VAR: + description: > + Enables the Read Multiple Variable Characteristic Values GATT procedure. + (0/1) + value: MYNEWT_VAL_BLE_ROLE_CENTRAL BLE_GATT_WRITE_NO_RSP: description: > Enables the Write Without Response GATT procedure. (0/1) diff --git a/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_att_clt_test.c b/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_att_clt_test.c index 787d4bca..0b6d55d3 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_att_clt_test.c +++ b/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_att_clt_test.c @@ -380,7 +380,7 @@ TEST_CASE_SELF(ble_att_clt_test_tx_read_mult) conn_handle = ble_att_clt_test_misc_init(); /*** Success. */ - rc = ble_att_clt_tx_read_mult(conn_handle, ((uint16_t[]){ 1, 2 }), 2); + rc = ble_att_clt_tx_read_mult(conn_handle, ((uint16_t[]){ 1, 2 }), 2, false); TEST_ASSERT(rc == 0); om = ble_hs_test_util_prev_tx_dequeue_pullup(); @@ -392,7 +392,7 @@ TEST_CASE_SELF(ble_att_clt_test_tx_read_mult) TEST_ASSERT(get_le16(om->om_data + BLE_ATT_READ_MULT_REQ_BASE_SZ + 2) == 2); /*** Error: no handles. */ - rc = ble_att_clt_tx_read_mult(conn_handle, NULL, 0); + rc = ble_att_clt_tx_read_mult(conn_handle, NULL, 0, false); TEST_ASSERT(rc == BLE_HS_EINVAL); ble_hs_test_util_assert_mbufs_freed(NULL); diff --git a/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_sm_test_util.c b/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_sm_test_util.c index bad473f1..e3becdf8 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_sm_test_util.c +++ b/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_sm_test_util.c @@ -1671,9 +1671,6 @@ ble_sm_test_util_peer_bonding_good(int send_enc_req, TEST_ASSERT(ble_sm_test_store_obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC); TEST_ASSERT(ble_sm_test_store_key.sec.peer_addr.type == ble_hs_misc_peer_addr_type_to_id(peer_addr_type)); - TEST_ASSERT(ble_sm_test_store_key.sec.ediv_rand_present); - TEST_ASSERT(ble_sm_test_store_key.sec.ediv == ediv); - TEST_ASSERT(ble_sm_test_store_key.sec.rand_num == rand_num); TEST_ASSERT(!conn->bhc_sec_state.encrypted); TEST_ASSERT(ble_sm_num_procs() == 1); @@ -1738,9 +1735,6 @@ ble_sm_test_util_peer_bonding_bad(uint16_t ediv, uint64_t rand_num) /* Ensure the LTK request event got sent to the application. */ TEST_ASSERT(ble_sm_test_store_obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC); - TEST_ASSERT(ble_sm_test_store_key.sec.ediv_rand_present); - TEST_ASSERT(ble_sm_test_store_key.sec.ediv == ediv); - TEST_ASSERT(ble_sm_test_store_key.sec.rand_num == rand_num); TEST_ASSERT(!conn->bhc_sec_state.encrypted); diff --git a/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_uuid_test.c b/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_uuid_test.c index 786e371a..379fd1f4 100644 --- a/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_uuid_test.c +++ b/lib/bt/host/nimble/nimble/nimble/host/test/src/ble_uuid_test.c @@ -24,8 +24,75 @@ #include "host/ble_uuid.h" #include "ble_hs_test_util.h" -TEST_CASE_SELF(ble_uuid_test) -{ +#define DEBUG 0 + +#if DEBUG +#define DEBUG_PRINT(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else +#define DEBUG_PRINT(fmt, ...) +#endif + +#define TEST_UUID_128_1_STR "0329a25a-c4c4-4923-8039-4bacfa18eb72" +#define TEST_UUID_128_1 \ + 0x72, 0xeb, 0x18, 0xfa, 0xac, 0x4b, 0x39, 0x80, \ + 0x23, 0x49, 0xc4, 0xc4, 0x5a, 0xa2, 0x29, 0x03 + +#define TEST_UUID_128_2_STR "e3ec4966df944981a772985ff8d75dff" +#define TEST_UUID_128_2 \ + 0xff, 0x5d, 0xd7, 0xf8, 0x5f, 0x98, 0x72, 0xa7, \ + 0x81, 0x49, 0x94, 0xdf, 0x66, 0x49, 0xec, 0xe3 + +#define TEST_UUID_128_3_STR "00002a37-0000-1000-8000-00805f9b34fb" +#define TEST_UUID_128_3 \ + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, \ + 0x00, 0x10, 0x00, 0x00, 0x37, 0x2a, 0x00, 0x00 +#define TEST_UUID_128_3_AS_16 ((uint16_t) 0x2a37) + +#define TEST_32UUID1_STR "0x0329a25a" +#define TEST_32UUID1 ((uint32_t)0x0329a25a) + +#define TEST_32UUID2_STR "e3ec4966" +#define TEST_32UUID2 ((uint32_t)0xe3ec4966) + +#define TEST_16UUID1_STR "0x0329" +#define TEST_16UUID1 ((uint16_t)0x0329) + +#define TEST_16UUID2_STR "e3ec" +#define TEST_16UUID2 ((uint16_t)0xe3ec) + +static const ble_uuid128_t test_uuid128[4] = { + BLE_UUID128_INIT(TEST_UUID_128_1), + BLE_UUID128_INIT(TEST_UUID_128_2), + BLE_UUID128_INIT(TEST_UUID_128_3) +}; + +static const char test_str128[][100] = { + TEST_UUID_128_1_STR, + TEST_UUID_128_2_STR, + TEST_UUID_128_3_STR +}; + +static const ble_uuid32_t test_uuid32[3] = { + BLE_UUID32_INIT(TEST_32UUID1), + BLE_UUID32_INIT(TEST_32UUID2), +}; + +static const char test_str32[][100] = { + TEST_32UUID1_STR, + TEST_32UUID2_STR, +}; + +static const ble_uuid16_t test_uuid16[3] = { + BLE_UUID16_INIT(TEST_16UUID1), + BLE_UUID16_INIT(TEST_16UUID2), +}; + +static const char test_str16[][100] = { + TEST_16UUID1_STR, + TEST_16UUID2_STR, +}; + +TEST_CASE_SELF(ble_uuid_test) { uint8_t buf_16[2] = { 0x00, 0x18 }; uint8_t buf_128[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; @@ -70,7 +137,161 @@ TEST_CASE_SELF(ble_uuid_test) ble_hs_test_util_assert_mbufs_freed(NULL); } -TEST_SUITE(ble_uuid_test_suite) -{ +TEST_CASE_SELF(ble_uuid_from_string_test) { + int rc; + ble_uuid_any_t uuid128[3]; + ble_uuid_any_t uuid32[3]; + ble_uuid_any_t uuid16[3]; + + for (int i = 0; i < 2; i++) { + DEBUG_PRINT("Test 128bit: %d\n", i); + ble_uuid_from_str((ble_uuid_any_t * ) &uuid128[i], test_str128[i]); + DEBUG_PRINT("Original:\n"); + for (int j = 0; j < 16; j++) { + DEBUG_PRINT("%2x, ", test_uuid128[i].value[j]); + } + DEBUG_PRINT("\nConverted:\n"); + for (int j = 0; j < 16; j++) { + DEBUG_PRINT("%2x, ", uuid128[i].u128.value[j]); + } + DEBUG_PRINT("\n"); + DEBUG_PRINT("The same: %s\n", + ble_uuid_cmp((const ble_uuid_t *) &uuid128[i].u128, + (const ble_uuid_t *) &test_uuid128[i]) == 0 + ? "true" : "false"); + rc = ble_uuid_cmp((const ble_uuid_t *) &uuid128[i].u128, + (const ble_uuid_t *) &test_uuid128[i]); + TEST_ASSERT(rc == 0); + } + + DEBUG_PRINT("\n"); + DEBUG_PRINT("\n"); + + for (int i = 0; i < 2; i++) { + DEBUG_PRINT("Test 32bit: %d\n", i); + ble_uuid_from_str((ble_uuid_any_t * ) &uuid32[i], test_str32[i]); + DEBUG_PRINT("Original:\n"); + DEBUG_PRINT("%x, ", test_uuid32[i].value); + DEBUG_PRINT("\nConverted:\n"); + DEBUG_PRINT("%x, ", uuid32[i].u32.value); + DEBUG_PRINT("\n"); + DEBUG_PRINT("The same: %s\n", + ble_uuid_cmp((const ble_uuid_t *) &uuid32[i].u32, + (const ble_uuid_t *) &test_uuid32[i]) == 0 + ? "true" : "false"); + rc = ble_uuid_cmp((const ble_uuid_t *) &uuid32[i].u32, + (const ble_uuid_t *) &test_uuid32[i]); + TEST_ASSERT(rc == 0); + } + + DEBUG_PRINT("\n"); + DEBUG_PRINT("\n"); + + for (int i = 0; i < 2; i++) { + DEBUG_PRINT("Test 16bit: %d\n", i); + ble_uuid_from_str((ble_uuid_any_t * ) &uuid16[i], test_str16[i]); + DEBUG_PRINT("Original:\n"); + DEBUG_PRINT("%x, ", test_uuid16[i].value); + DEBUG_PRINT("\nConverted:\n"); + DEBUG_PRINT("%x, ", uuid16[i].u16.value); + DEBUG_PRINT("\n"); + DEBUG_PRINT("The same: %s\n", + ble_uuid_cmp((const ble_uuid_t *) &uuid16[i].u16, + (const ble_uuid_t *) &test_uuid16[i]) == 0 + ? "true" : "false"); + rc = ble_uuid_cmp((const ble_uuid_t *) &uuid16[i].u16, + (const ble_uuid_t *) &test_uuid16[i]); + TEST_ASSERT(rc == 0); + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_uuid_from_string_sig_test) { + int rc; + ble_uuid_any_t uuid; + + ble_uuid16_t test_uuid = BLE_UUID16_INIT(TEST_UUID_128_3_AS_16); + + DEBUG_PRINT("Test %d\n", 0); + ble_uuid_from_str(&uuid, test_str128[2]); + DEBUG_PRINT("Original:\n"); + for (int j = 0; j < 16; j++) { + DEBUG_PRINT("%2x, ", test_uuid128[2].value[j]); + } + DEBUG_PRINT("\nConverted:\n"); + DEBUG_PRINT("%x\n", uuid.u16.value); + DEBUG_PRINT("The same: %s\n", + ble_uuid_cmp((const ble_uuid_t *) &uuid.u16, + (const ble_uuid_t *) &test_uuid) == 0 ? "true" + : "false"); + rc = ble_uuid_cmp((const ble_uuid_t *)&uuid.u16, + (const ble_uuid_t *)&test_uuid); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_uuid_to_str_and_back_test) { + int rc; + ble_uuid128_t uuid = BLE_UUID128_INIT(TEST_UUID_128_1); + ble_uuid_any_t final_uuid; + char uuid_str[100]; + + ble_uuid_to_str((const ble_uuid_t *)&uuid, uuid_str); + + DEBUG_PRINT("String: %s\n", uuid_str); + + rc = ble_uuid_from_str(&final_uuid, (const char *)uuid_str); + TEST_ASSERT(rc == 0); + + rc = ble_uuid_cmp((const ble_uuid_t *)&uuid, (const ble_uuid_t *)&final_uuid.u128); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_uuid_to_str_too_short) { + int rc; + ble_uuid_any_t final_uuid; + char uuid_str[4] = "012"; + + DEBUG_PRINT("String: %s\n", uuid_str); + + rc = ble_uuid_from_str(&final_uuid, (const char *)uuid_str); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_uuid_to_str_sig_to_16_and_32) { + int rc; + ble_uuid_any_t final_uuid; + char uuid_str16[37] = "0000ffff-0000-1000-8000-00805f9b34fb"; + char uuid_str32[37] = "ffffffff-0000-1000-8000-00805f9b34fb"; + + DEBUG_PRINT("String16: %s\n", uuid_str16); + DEBUG_PRINT("String32: %s\n", uuid_str32); + + rc = ble_uuid_from_str(&final_uuid, (const char *)uuid_str16); + TEST_ASSERT(rc == 0); + TEST_ASSERT(final_uuid.u.type == BLE_UUID_TYPE_16); + TEST_ASSERT(final_uuid.u16.value == UINT16_MAX); + memset(&final_uuid, 0, sizeof(ble_uuid_any_t)); + + rc = ble_uuid_from_str(&final_uuid, (const char *)uuid_str32); + TEST_ASSERT(rc == 0); + TEST_ASSERT(final_uuid.u.type == BLE_UUID_TYPE_32); + TEST_ASSERT(final_uuid.u32.value == UINT32_MAX); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_uuid_test_suite) { ble_uuid_test(); + ble_uuid_from_string_test(); + ble_uuid_from_string_sig_test(); + ble_uuid_to_str_and_back_test(); + ble_uuid_to_str_too_short(); + ble_uuid_to_str_sig_to_16_and_32(); } diff --git a/lib/bt/host/nimble/nimble/nimble/include/nimble/ble.h b/lib/bt/host/nimble/nimble/nimble/include/nimble/ble.h index bbf22753..6979e945 100644 --- a/lib/bt/host/nimble/nimble/nimble/include/nimble/ble.h +++ b/lib/bt/host/nimble/nimble/nimble/include/nimble/ble.h @@ -101,7 +101,7 @@ struct ble_mbuf_hdr_rxinfo #define BLE_MBUF_HDR_F_EXT_ADV (0x0800) #define BLE_MBUF_HDR_F_RESOLVED (0x0400) #define BLE_MBUF_HDR_F_AUX_PTR_WAIT (0x0200) -#define BLE_MBUF_HDR_F_AUX_INVALID (0x0100) +#define BLE_MBUF_HDR_F_AUX_PTR_FAILED (0x0100) #define BLE_MBUF_HDR_F_CRC_OK (0x0080) #define BLE_MBUF_HDR_F_DEVMATCH (0x0040) #define BLE_MBUF_HDR_F_MIC_FAILURE (0x0020) @@ -118,11 +118,16 @@ struct ble_mbuf_hdr_txinfo uint16_t pyld_len; }; +struct ble_mbuf_hdr_txiso { + uint16_t packet_seq_num; +}; + struct ble_mbuf_hdr { union { struct ble_mbuf_hdr_rxinfo rxinfo; struct ble_mbuf_hdr_txinfo txinfo; + struct ble_mbuf_hdr_txiso txiso; }; uint32_t beg_cputime; uint32_t rem_usecs; @@ -146,9 +151,6 @@ struct ble_mbuf_hdr #define BLE_MBUF_HDR_SCAN_RSP_RXD(hdr) \ (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_RXD)) -#define BLE_MBUF_HDR_AUX_INVALID(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_AUX_INVALID)) - #define BLE_MBUF_HDR_WAIT_AUX(hdr) \ (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT)) diff --git a/lib/bt/host/nimble/nimble/nimble/include/nimble/hci_common.h b/lib/bt/host/nimble/nimble/nimble/include/nimble/hci_common.h index 02ee5104..76a8b871 100644 --- a/lib/bt/host/nimble/nimble/nimble/include/nimble/hci_common.h +++ b/lib/bt/host/nimble/nimble/nimble/include/nimble/hci_common.h @@ -842,112 +842,105 @@ struct ble_hci_le_set_default_periodic_sync_transfer_params_cp { #define BLE_HCI_OCF_LE_GENERATE_DHKEY_V2 (0x005E) #define BLE_HCI_OCF_LE_MODIFY_SCA (0x005F) -#if MYNEWT_VAL(BLE_ISO) #define BLE_HCI_OCF_LE_READ_ISO_TX_SYNC (0x0061) struct ble_hci_le_read_iso_tx_sync_cp { uint16_t conn_handle; } __attribute__((packed)); - struct ble_hci_le_read_iso_tx_sync_rp { uint16_t conn_handle; uint16_t packet_seq_num; - uint32_t timestamp; - uint8_t timeoffset[3]; + uint32_t tx_timestamp; + uint8_t time_offset[3]; } __attribute__((packed)); -#define BLE_HCI_LE_SET_CIG_CIS_MAX_NUM (0x1F) -#define BLE_HCI_OCF_LE_SET_CIG_PARAM (0x0062) +#define BLE_HCI_OCF_LE_SET_CIG_PARAMS (0x0062) struct ble_hci_le_cis_params { uint8_t cis_id; - uint16_t max_sdu_mtos; - uint16_t max_sdu_stom; - uint8_t phy_mtos; - uint8_t phy_stom; - uint8_t rnt_mtos; - uint8_t rnt_stom; + uint16_t max_sdu_c_to_p; + uint16_t max_sdu_p_to_c; + uint8_t phy_c_to_p; + uint8_t phy_p_to_c; + uint8_t rnt_c_to_p; + uint8_t rnt_p_to_c; } __attribute__((packed)); - struct ble_hci_le_set_cig_params_cp { uint8_t cig_id; - uint8_t sdu_interval_mtos[3]; - uint8_t sdu_interval_stom[3]; - uint8_t sca; + uint8_t sdu_interval_c_to_p[3]; + uint8_t sdu_interval_p_to_c[3]; + uint8_t worst_sca; uint8_t packing; uint8_t framing; - uint16_t max_latency_mtos; - uint16_t max_latency_stom; - uint8_t cis_cnt; - struct ble_hci_le_cis_params cis_params[0]; + uint16_t max_latency_c_to_p; + uint16_t max_latency_p_to_c; + uint8_t cis_count; + struct ble_hci_le_cis_params cis[0]; } __attribute__((packed)); - struct ble_hci_le_set_cig_params_rp { uint8_t cig_id; - uint8_t cis_cnt; - uint16_t cis_handle[0]; + uint8_t cis_count; + uint16_t conn_handle[0]; } __attribute__((packed)); -#if MYNEWT_VAL(BLE_ISO_TEST) -#define BLE_HCI_OCF_LE_SET_CIG_PARAM_TEST (0x0063) +#define BLE_HCI_OCF_LE_SET_CIG_PARAMS_TEST (0x0063) struct ble_hci_le_cis_params_test { uint8_t cis_id; uint8_t nse; - uint16_t max_sdu_mtos; - uint16_t max_sdu_stom; - uint16_t max_pdu_mtos; - uint16_t max_pdu_stom; - uint8_t phy_mtos; - uint8_t phy_stom; - uint8_t bn_mtos; - uint8_t bn_stom; + uint16_t max_sdu_c_to_p; + uint16_t max_sdu_p_to_c; + uint16_t max_pdu_c_to_p; + uint16_t max_pdu_p_to_c; + uint8_t phy_c_to_p; + uint8_t phy_p_to_c; + uint8_t bn_c_to_p; + uint8_t bn_p_to_c; } __attribute__((packed)); - struct ble_hci_le_set_cig_params_test_cp { uint8_t cig_id; - uint8_t sdu_interval_mtos[3]; - uint8_t sdu_interval_stom[3]; - uint8_t ft_mtos; - uint8_t ft_stom; + uint8_t sdu_interval_c_to_p[3]; + uint8_t sdu_interval_p_to_c[3]; + uint8_t ft_c_to_p; + uint8_t ft_p_to_c; uint16_t iso_interval; - uint8_t sca; + uint8_t worst_sca; uint8_t packing; uint8_t framing; - uint8_t cis_cnt; - struct ble_hci_le_cis_params_test cis_params[0]; + uint8_t cis_count; + struct ble_hci_le_cis_params_test cis[0]; +} __attribute__((packed)); +struct ble_hci_le_set_cig_params_test_rp { + uint8_t cig_id; + uint8_t cis_count; + uint16_t conn_handle[0]; } __attribute__((packed)); -#endif -#define BLE_HCI_LE_CREATE_CIS_MAX_CIS_NUM (0x1F) #define BLE_HCI_OCF_LE_CREATE_CIS (0x0064) struct ble_hci_le_create_cis_params { uint16_t cis_handle; uint16_t conn_handle; } __attribute__((packed)); - struct ble_hci_le_create_cis_cp { - uint8_t cis_cnt; - struct ble_hci_le_create_cis_params params[0]; + uint8_t cis_count; + struct ble_hci_le_create_cis_params cis[0]; } __attribute__((packed)); #define BLE_HCI_OCF_LE_REMOVE_CIG (0x0065) struct ble_hci_le_remove_cig_cp { uint8_t cig_id; } __attribute__((packed)); - struct ble_hci_le_remove_cig_rp { uint8_t cig_id; } __attribute__((packed)); #define BLE_HCI_OCF_LE_ACCEPT_CIS_REQ (0x0066) struct ble_hci_le_accept_cis_request_cp { - uint16_t cis_handle; + uint16_t conn_handle; } __attribute__((packed)); #define BLE_HCI_OCF_LE_REJECT_CIS_REQ (0x0067) struct ble_hci_le_reject_cis_request_cp { - uint16_t cis_handle; + uint16_t conn_handle; uint8_t reason; } __attribute__((packed)); - struct ble_hci_le_reject_cis_request_rp { uint16_t conn_handle; } __attribute__((packed)); @@ -956,11 +949,11 @@ struct ble_hci_le_reject_cis_request_rp { struct ble_hci_le_create_big_cp { uint8_t big_handle; uint8_t adv_handle; - uint8_t bis_cnt; + uint8_t num_bis; uint8_t sdu_interval[3]; uint16_t max_sdu; uint16_t max_transport_latency; - uint8_t rnt; + uint8_t rtn; uint8_t phy; uint8_t packing; uint8_t framing; @@ -968,12 +961,11 @@ struct ble_hci_le_create_big_cp { uint8_t broadcast_code[16]; } __attribute__((packed)); -#if MYNEWT_VAL(BLE_ISO_TEST) #define BLE_HCI_OCF_LE_CREATE_BIG_TEST (0x0069) struct ble_hci_le_create_big_test_cp { uint8_t big_handle; uint8_t adv_handle; - uint8_t bis_cnt; + uint8_t num_bis; uint8_t sdu_interval[3]; uint16_t iso_interval; uint8_t nse; @@ -988,7 +980,6 @@ struct ble_hci_le_create_big_test_cp { uint8_t encryption; uint8_t broadcast_code[16]; } __attribute__((packed)); -#endif #define BLE_HCI_OCF_LE_TERMINATE_BIG (0x006a) struct ble_hci_le_terminate_big_cp { @@ -996,78 +987,113 @@ struct ble_hci_le_terminate_big_cp { uint8_t reason; } __attribute__((packed)); -#define BLE_HCI_LE_BIG_CREATE_SYNC_LEN_MIN (25) #define BLE_HCI_OCF_LE_BIG_CREATE_SYNC (0x006b) struct ble_hci_le_big_create_sync_cp { uint8_t big_handle; uint16_t sync_handle; - uint8_t big_cnt; uint8_t encryption; uint8_t broadcast_code[16]; uint8_t mse; - uint16_t timeout; + uint16_t sync_timeout; + uint8_t num_bis; uint8_t bis[0]; } __attribute__((packed)); #define BLE_HCI_OCF_LE_BIG_TERMINATE_SYNC (0x006c) -struct ble_hci_le_terminate_big_sync_cp { +struct ble_hci_le_big_terminate_sync_cp { + uint8_t big_handle; +} __attribute__((packed)); +struct ble_hci_le_big_terminate_sync_rp { uint8_t big_handle; } __attribute__((packed)); -#endif #define BLE_HCI_OCF_LE_REQ_PEER_SCA (0x006d) struct ble_hci_le_request_peer_sca_cp { uint16_t conn_handle; } __attribute__((packed)); -#if MYNEWT_VAL(BLE_ISO) #define BLE_HCI_OCF_LE_SETUP_ISO_DATA_PATH (0x006e) -struct ble_hci_le_iso_setup_data_path_cp { - uint16_t iso_handle; - uint8_t direction; - uint8_t id; +struct ble_hci_le_setup_iso_data_path_cp { + uint16_t conn_handle; + uint8_t data_path_dir; + uint8_t data_path_id; uint8_t codec_id[5]; uint8_t controller_delay[3]; - uint8_t codec_conf_len; - uint8_t codec_conf[0]; + uint8_t codec_config_len; + uint8_t codec_config[0]; +} __attribute__((packed)); +struct ble_hci_le_setup_iso_data_path_rp { + uint16_t conn_handle; } __attribute__((packed)); -#define BLE_HCI_LE_REMOVE_INPUT_DATA_PATH_BIT (0x01) -#define BLE_HCI_LE_REMOVE_OUTPUT_DATA_PATH_BIT (0x02) #define BLE_HCI_OCF_LE_REMOVE_ISO_DATA_PATH (0x006f) -struct ble_hci_le_iso_remove_data_path_cp { - uint16_t iso_handle; - uint8_t direction; +struct ble_hci_le_remove_iso_data_path_cp { + uint16_t conn_handle; + uint8_t data_path_dir; +} __attribute__((packed)); +struct ble_hci_le_remove_iso_data_path_rp { + uint16_t conn_handle; } __attribute__((packed)); -#if MYNEWT_VAL(BLE_ISO_TEST) #define BLE_HCI_OCF_LE_ISO_TRANSMIT_TEST (0x0070) struct ble_hci_le_iso_transmit_test_cp { - uint16_t iso_handle; + uint16_t conn_handle; uint8_t payload_type; } __attribute__((packed)); +struct ble_hci_le_iso_transmit_test_rp { + uint16_t conn_handle; +} __attribute__((packed)); #define BLE_HCI_OCF_LE_ISO_RECEIVE_TEST (0x0071) struct ble_hci_le_iso_receive_test_cp { - uint16_t iso_handle; + uint16_t conn_handle; + uint8_t payload_type; +} __attribute__((packed)); +struct ble_hci_le_iso_receive_test_rp { + uint16_t conn_handle; } __attribute__((packed)); #define BLE_HCI_OCF_LE_ISO_READ_TEST_COUNTERS (0x0072) struct ble_hci_le_iso_read_test_counters_cp { - uint16_t iso_handle; + uint16_t conn_handle; +} __attribute__((packed)); +struct ble_hci_le_iso_read_test_counters_rp { + uint16_t conn_handle; + uint32_t received_sdu_count; + uint32_t missed_sdu_count; + uint32_t failed_sdu_count; } __attribute__((packed)); #define BLE_HCI_OCF_LE_ISO_TEST_END (0x0073) struct ble_hci_le_iso_test_end_cp { - uint16_t iso_handle; + uint16_t conn_handle; +} __attribute__((packed)); +struct ble_hci_le_iso_test_end_rp { + uint16_t conn_handle; + uint32_t received_sdu_count; + uint32_t missed_sdu_count; + uint32_t failed_sdu_count; } __attribute__((packed)); -#endif -#endif -#define BLE_HCI_OCF_LE_SET_HOST_FEAT (0x0074) -struct ble_hci_le_set_host_feat_cp { +#define BLE_HCI_OCF_LE_SET_HOST_FEATURE (0x0074) +struct ble_hci_le_set_host_feature_cp { uint8_t bit_num; - uint8_t val; + uint8_t bit_val; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_READ_ISO_LINK_QUALITY (0x0075) +struct ble_hci_le_read_iso_link_quality_cp { + uint16_t conn_handle; +} __attribute__((packed)); +struct ble_hci_le_read_iso_link_quality_rp { + uint16_t conn_handle; + uint32_t tx_unacked_pkts; + uint32_t tx_flushed_pkts; + uint32_t tx_last_subevent_pkts; + uint32_t retransmitted_pkts; + uint32_t crc_error_pkts; + uint32_t rx_unreceived_pkts; + uint32_t duplicate_pkts; } __attribute__((packed)); #define BLE_HCI_OCF_LE_ENH_READ_TRANSMIT_POWER_LEVEL (0x0076) @@ -1131,7 +1157,6 @@ struct ble_hci_le_subrate_req_cp { uint16_t conn_handle; uint16_t subrate_min; uint16_t subrate_max; - uint16_t max_latency; uint16_t cont_num; uint16_t supervision_tmo; } __attribute__((packed)); @@ -1154,27 +1179,49 @@ struct ble_hci_vs_set_tx_pwr_rp { int8_t tx_power; } __attribute__((packed)); -#define BLE_HCI_OCF_VS_CSS (0x0003) -struct ble_hci_vs_css_cp { - uint8_t opcode; -} __attribute__((packed)); -#define BLE_HCI_VS_CSS_OP_CONFIGURE 0x01 +#define BLE_HCI_OCF_VS_CSS_CONFIGURE (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0003)) struct ble_hci_vs_css_configure_cp { - uint8_t opcode; uint32_t slot_us; uint32_t period_slots; } __attribute__((packed)); -#define BLE_HCI_VS_CSS_OP_SET_NEXT_SLOT 0x02 +#define BLE_HCI_OCF_VS_CSS_ENABLE (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0004)) +struct ble_hci_vs_css_enable_cp { + uint8_t enable; +} __attribute__((packed)); +#define BLE_HCI_OCF_VS_CSS_SET_NEXT_SLOT (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0005)) struct ble_hci_vs_css_set_next_slot_cp { - uint8_t opcode; uint16_t slot_idx; } __attribute__((packed)); -#define BLE_HCI_VS_CSS_OP_SET_CONN_SLOT 0x03 +#define BLE_HCI_OCF_VS_CSS_SET_CONN_SLOT (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0006)) struct ble_hci_vs_css_set_conn_slot_cp { - uint8_t opcode; uint16_t conn_handle; uint16_t slot_idx; } __attribute__((packed)); +#define BLE_HCI_OCF_VS_CSS_READ_CONN_SLOT (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0007)) +struct ble_hci_vs_css_read_conn_slot_cp { + uint16_t conn_handle; +} __attribute__((packed)); +struct ble_hci_vs_css_read_conn_slot_rp { + uint16_t conn_handle; + uint16_t slot_idx; +} __attribute__((packed)); +#define BLE_HCI_OCF_VS_SET_DATA_LEN (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0008)) +struct ble_hci_vs_set_data_len_cp { + uint16_t conn_handle; + uint16_t tx_octets; + uint16_t tx_time; + uint16_t rx_octets; + uint16_t rx_time; +} __attribute__((packed)); +struct ble_hci_vs_set_data_len_rp { + uint16_t conn_handle; +} __attribute__((packed)); +#define BLE_HCI_OCF_VS_SET_ANTENNA (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0009)) +struct ble_hci_vs_set_antenna_cp { + uint8_t antenna; +} __attribute__((packed)); + + #define BLE_HCI_OCF_VS_DUPLICATE_EXCEPTION_LIST (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0108)) struct ble_hci_vs_duplicate_exception_list_cp { @@ -1246,8 +1293,6 @@ struct ble_hci_vs_duplicate_exception_list_cp { /* * Advertising filter policy * - * Determines how an advertiser filters scan and connection requests. - * * NONE: no filtering (default value). No whitelist used. * SCAN: process all connection requests but only scans from white list. * CONN: process all scan request but only connection requests from white list @@ -1344,10 +1389,10 @@ struct ble_hci_vs_duplicate_exception_list_cp { #define BLE_HCI_SET_DATALEN_TX_TIME_MAX (0x4290) /* --- LE read/write suggested default data length (OCF 0x0023 and 0x0024) */ -#define BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MIN (0x001b) -#define BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MAX (0x00fb) -#define BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MIN (0x0148) -#define BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MAX (0x4290) +#define BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MIN (0x001b) +#define BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MAX (0x00fb) +#define BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MIN (0x0148) +#define BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MAX (0x4290) /* --- LE read maximum default PHY (OCF 0x0030) */ #define BLE_HCI_LE_PHY_1M (1) @@ -1578,12 +1623,21 @@ struct ble_hci_ev_auth_pyld_tmo { #define BLE_HCI_EVCODE_SAM_STATUS_CHG (0x58) -#define BLE_HCI_EVCODE_VS_DEBUG (0xFF) -struct ble_hci_ev_vs_debug { +#define BLE_HCI_EVCODE_VS (0xff) +struct ble_hci_ev_vs { uint8_t id; uint8_t data[0]; } __attribute__((packed)); +#define BLE_HCI_VS_SUBEV_ID_ASSERT (0x01) +#define BLE_HCI_VS_SUBEV_ID_CSS_SLOT_CHANGED (0x02) +struct ble_hci_ev_vs_css_slot_changed { + uint16_t conn_handle; + uint16_t slot_idx; +}; + +#define BLE_HCI_VS_SUBEV_ID_LLCP_TRACE (0x17) + /* LE sub-event codes */ #define BLE_HCI_LE_SUBEV_CONN_COMPLETE (0x01) struct ble_hci_ev_le_subev_conn_complete { @@ -1814,43 +1868,43 @@ struct ble_hci_ev_le_subev_periodic_adv_sync_transfer { uint8_t aca; } __attribute__((packed)); -#define BLE_HCI_LE_SUBEV_CIS_ESTAB (0x19) +#define BLE_HCI_LE_SUBEV_CIS_ESTABLISHED (0x19) struct ble_hci_ev_le_subev_cis_established { uint8_t subev_code; uint8_t status; - uint16_t cis_handle; + uint16_t conn_handle; uint8_t cig_sync_delay[3]; uint8_t cis_sync_delay[3]; - uint8_t trans_latency_mtos[3]; - uint8_t trans_latency_stom[3]; - uint8_t phy_mtos; - uint8_t phy_stom; + uint8_t transport_latency_c_to_p[3]; + uint8_t transport_latency_p_to_c[3]; + uint8_t phy_c_to_p; + uint8_t phy_p_to_c; uint8_t nse; - uint8_t bn_mtos; - uint8_t bn_stom; - uint8_t ft_mtos; - uint8_t ft_stom; - uint16_t max_pdu_mtos; - uint16_t max_pdu_stom; + uint8_t bn_c_to_p; + uint8_t bn_p_to_c; + uint8_t ft_c_to_p; + uint8_t ft_p_to_c; + uint16_t max_pdu_c_to_p; + uint16_t max_pdu_p_to_c; uint16_t iso_interval; } __attribute__((packed)); #define BLE_HCI_LE_SUBEV_CIS_REQUEST (0x1A) struct ble_hci_ev_le_subev_cis_request { uint8_t subev_code; - uint16_t conn_handle; - uint16_t cis_handle; + uint16_t acl_conn_handle; + uint16_t cis_conn_handle; uint8_t cig_id; uint8_t cis_id; } __attribute__((packed)); -#define BLE_HCI_LE_SUBEV_BIG_COMP (0x1B) -struct ble_hci_ev_le_subev_big_complete { +#define BLE_HCI_LE_SUBEV_CREATE_BIG_COMPLETE (0x1B) +struct ble_hci_ev_le_subev_create_big_complete { uint8_t subev_code; uint8_t status; uint8_t big_handle; uint8_t big_sync_delay[3]; - uint8_t transport_latency[3]; + uint8_t transport_latency_big[3]; uint8_t phy; uint8_t nse; uint8_t bn; @@ -1858,31 +1912,31 @@ struct ble_hci_ev_le_subev_big_complete { uint8_t irc; uint16_t max_pdu; uint16_t iso_interval; - uint8_t bis_cnt; - uint16_t bis[0]; + uint8_t num_bis; + uint16_t conn_handle[0]; } __attribute__((packed)); -#define BLE_HCI_LE_SUBEV_BIG_TERMINATE_COMP (0x1C) -struct ble_hci_ev_le_subev_big_terminate_complete { +#define BLE_HCI_LE_SUBEV_TERMINATE_BIG_COMPLETE (0x1C) +struct ble_hci_ev_le_subev_terminate_big_complete { uint8_t subev_code; uint8_t big_handle; uint8_t reason; } __attribute__((packed)); -#define BLE_HCI_LE_SUBEV_BIG_SYNC_ESTAB (0x1D) +#define BLE_HCI_LE_SUBEV_BIG_SYNC_ESTABLISHED (0x1D) struct ble_hci_ev_le_subev_big_sync_established { uint8_t subev_code; uint8_t status; uint8_t big_handle; - uint8_t transport_latency[3]; + uint8_t transport_latency_big[3]; uint8_t nse; uint8_t bn; uint8_t pto; uint8_t irc; uint16_t max_pdu; uint16_t iso_interval; - uint8_t bis_cnt; - uint16_t bis_handles[0]; + uint8_t num_bis; + uint16_t conn_handle[0]; } __attribute__((packed)); #define BLE_HCI_LE_SUBEV_BIG_SYNC_LOST (0x1E) @@ -1910,13 +1964,13 @@ struct ble_hci_ev_le_subev_path_loss_threshold { #define BLE_HCI_LE_SUBEV_TRANSMIT_POWER_REPORT (0x21) struct ble_hci_ev_le_subev_transmit_power_report { - uint8_t subev_code; - uint8_t status; + uint8_t subev_code; + uint8_t status; uint16_t conn_handle; - uint8_t reason; - uint8_t phy; - int8_t transmit_power_level; - uint8_t transmit_power_level_flag; + uint8_t reason; + uint8_t phy; + int8_t transmit_power_level; + uint8_t transmit_power_level_flag; int8_t delta; } __attribute__((packed)); @@ -1949,6 +2003,11 @@ struct ble_hci_ev_le_subev_subrate_change { uint16_t supervision_tmo; } __attribute__((packed)); +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) +// LE vendor hci event +#define BLE_HCI_LE_SUBEV_DISCARD_REPORT_EVT 0XF0 +#endif // (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + /* Data buffer overflow event */ #define BLE_HCI_EVENT_ACL_BUF_OVERFLOW (0x01) @@ -1992,6 +2051,7 @@ struct ble_hci_ev_le_subev_subrate_change { #define BLE_HCI_VER_BCS_5_1 (10) #define BLE_HCI_VER_BCS_5_2 (11) #define BLE_HCI_VER_BCS_5_3 (12) +#define BLE_HCI_VER_BCS_5_4 (13) #define BLE_LMP_VER_BCS_1_0b (0) #define BLE_LMP_VER_BCS_1_1 (1) @@ -2006,6 +2066,7 @@ struct ble_hci_ev_le_subev_subrate_change { #define BLE_LMP_VER_BCS_5_1 (10) #define BLE_LMP_VER_BCS_5_2 (11) #define BLE_LMP_VER_BCS_5_3 (12) +#define BLE_LMP_VER_BCS_5_4 (13) /* selected HCI and LMP version */ #if MYNEWT_VAL(BLE_VERSION) == 50 @@ -2020,6 +2081,9 @@ struct ble_hci_ev_le_subev_subrate_change { #elif MYNEWT_VAL(BLE_VERSION) == 53 #define BLE_HCI_VER_BCS BLE_HCI_VER_BCS_5_3 #define BLE_LMP_VER_BCS BLE_LMP_VER_BCS_5_3 +#elif MYNEWT_VAL(BLE_VERSION) == 54 +#define BLE_HCI_VER_BCS BLE_HCI_VER_BCS_5_4 +#define BLE_LMP_VER_BCS BLE_LMP_VER_BCS_5_4 #endif #define BLE_HCI_DATA_HDR_SZ 4 @@ -2038,6 +2102,37 @@ struct hci_data_hdr #define BLE_HCI_PB_FIRST_FLUSH 2 #define BLE_HCI_PB_FULL 3 +#define BLE_HCI_ISO_CONN_HANDLE_MASK (0x07ff) +#define BLE_HCI_ISO_PB_FLAG_MASK (0x3000) +#define BLE_HCI_ISO_TS_FLAG_MASK (0x4000) +#define BLE_HCI_ISO_LENGTH_MASK (0x7fff) + +#define BLE_HCI_ISO_HANDLE(ch, pb, ts) ((ch) | ((pb) << 12) | ((ts) << 14)) + +#define BLE_HCI_ISO_CONN_HANDLE(h) ((h) & BLE_HCI_ISO_CONN_HANDLE_MASK) +#define BLE_HCI_ISO_PB_FLAG(h) (((h) & BLE_HCI_ISO_PB_FLAG_MASK) >> 12) +#define BLE_HCI_ISO_TS_FLAG(h) ((h) & BLE_HCI_ISO_TS_FLAG_MASK) +#define BLE_HCI_ISO_LENGTH(l) ((l) & BLE_HCI_ISO_LENGTH_MASK) + +#define BLE_HCI_ISO_PB_FIRST (0) +#define BLE_HCI_ISO_PB_CONTINUATION (1) +#define BLE_HCI_ISO_PB_COMPLETE (2) +#define BLE_HCI_ISO_PB_LAST (3) + +struct ble_hci_iso { + uint16_t handle; + uint16_t length; + uint8_t data[0]; +}; + +#define BLE_HCI_ISO_HDR_SDU_LENGTH_MASK (0x07ff) + +struct ble_hci_iso_data { + uint16_t packet_seq_num; + uint16_t sdu_len; + uint8_t data[0]; +}; + #ifdef __cplusplus } #endif diff --git a/lib/bt/host/nimble/nimble/nimble/include/nimble/nimble_opt_auto.h b/lib/bt/host/nimble/nimble/nimble/include/nimble/nimble_opt_auto.h index b9faee75..6326abf5 100644 --- a/lib/bt/host/nimble/nimble/nimble/include/nimble/nimble_opt_auto.h +++ b/lib/bt/host/nimble/nimble/nimble/include/nimble/nimble_opt_auto.h @@ -77,6 +77,10 @@ extern "C" { #define NIMBLE_BLE_ATT_CLT_READ_MULT \ (MYNEWT_VAL(BLE_GATT_READ_MULT)) +#undef NIMBLE_BLE_ATT_CLT_READ_MULT_VAR +#define NIMBLE_BLE_ATT_CLT_READ_MULT_VAR \ + (MYNEWT_VAL(BLE_GATT_READ_MULT_VAR)) + #undef NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE #define NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE \ (MYNEWT_VAL(BLE_GATT_DISC_ALL_SVCS)) diff --git a/lib/bt/host/nimble/nimble/nimble/syscfg.yml b/lib/bt/host/nimble/nimble/nimble/syscfg.yml index b91d3932..040171d3 100644 --- a/lib/bt/host/nimble/nimble/nimble/syscfg.yml +++ b/lib/bt/host/nimble/nimble/nimble/syscfg.yml @@ -68,7 +68,14 @@ syscfg.defs: restrictions: - 'BLE_PERIODIC_ADV if 1' - '(BLE_ROLE_CENTRAL || BLE_ROLE_PERIPHERAL) if 1' - + BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS: + description: > + This enables BIGInfo reports. + value: 0 + restrictions: + - 'BLE_PERIODIC_ADV if 1' + - '(BLE_VERSION >= 52) if 1' + experimental: 1 BLE_EXT_ADV_MAX_SIZE: description: > This allows to configure maximum size of advertising data and @@ -80,7 +87,7 @@ syscfg.defs: This allows to configure supported Bluetooth Core version. Some features may not be available if version is too low. Version is integer for easy comparison. - range: 50, 51, 52, 53 + range: 50, 51, 52, 53, 54 value: 50 BLE_ISO: description: > @@ -113,6 +120,10 @@ syscfg.defs: This enabled LE Power Control feature value: 0 + BLE_CONN_SUBRATING: + description: > + This enables LE Connection Subrating feature + value: 0 BLE_GATT_BLOB_TRANSFER: description: > This enables write blob feature diff --git a/lib/bt/host/nimble/nimble/nimble/transport/apollo3/src/apollo3_ble_hci.c b/lib/bt/host/nimble/nimble/nimble/transport/apollo3/src/apollo3_ble_hci.c index 34b6266d..2ed3012e 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/apollo3/src/apollo3_ble_hci.c +++ b/lib/bt/host/nimble/nimble/nimble/transport/apollo3/src/apollo3_ble_hci.c @@ -235,28 +235,9 @@ apollo3_update_wake(void) * The payload is placed into a queue and the controller is turned on. When it is ready * an interrupt will fire to handle sending a message */ -static uint8_t -apollo3_hci_write(uint8_t type, uint16_t len, uint8_t *data) +static int +apollo3_hci_write(hci_drv_write_t *write_buf) { - uint8_t *write_ptr; - hci_drv_write_t write_buf; - - /* comparison compensates for the type byte at index 0. */ - if (len > (MYNEWT_VAL(BLE_TRANSPORT_APOLLO3_MAX_TX_PACKET)-1)) { - return 0; - } - - /* Set all of the fields in the hci write structure. */ - write_buf.len = len + 1; - - write_ptr = (uint8_t *) write_buf.data; - - *write_ptr++ = type; - - for (uint32_t i = 0; i < len; i++) { - write_ptr[i] = data[i]; - } - /* Wake up the BLE controller. */ apollo3_update_wake(); @@ -265,7 +246,10 @@ apollo3_hci_write(uint8_t type, uint16_t len, uint8_t *data) os_time_delay(1); } - am_hal_ble_blocking_hci_write(ble_handle, AM_HAL_BLE_RAW, write_buf.data, write_buf.len); + if (AM_HAL_STATUS_SUCCESS != + am_hal_ble_blocking_hci_write(ble_handle, AM_HAL_BLE_RAW, write_buf->data, write_buf->len)) { + return -1; + } return 0; } @@ -273,17 +257,18 @@ apollo3_hci_write(uint8_t type, uint16_t len, uint8_t *data) static int apollo3_ble_hci_acl_tx(struct os_mbuf *om) { - struct os_mbuf *x; int rc = 0; + hci_drv_write_t write_buf; + uint8_t *ptr = (uint8_t *)write_buf.data; - x = om; - while (x) { - rc = apollo3_hci_write(HCI_H4_ACL, x->om_len, x->om_data); - if (rc < 0) { - break; - } - x = SLIST_NEXT(x, om_next); - } + *ptr = HCI_H4_ACL; + ptr++; + write_buf.len = 1; + + os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), ptr); + write_buf.len += OS_MBUF_PKTLEN(om); + + rc = apollo3_hci_write(&write_buf); os_mbuf_free_chain(om); @@ -327,9 +312,15 @@ ble_transport_to_ll_cmd_impl(void *buf) { int rc; uint8_t *cmd = buf; - int len = HCI_CMD_HDR_LEN + cmd[2]; + hci_drv_write_t write_buf; + uint8_t *ptr = (uint8_t *)write_buf.data; + + *ptr = HCI_H4_CMD; + ptr++; + write_buf.len = HCI_CMD_HDR_LEN + cmd[2] + 1; + memcpy(ptr, cmd, write_buf.len - 1); - rc = apollo3_hci_write(HCI_H4_CMD, len, cmd); + rc = apollo3_hci_write(&write_buf); ble_transport_free(cmd); diff --git a/lib/bt/host/nimble/nimble/nimble/transport/cdc/pkg.yml b/lib/bt/host/nimble/nimble/nimble/transport/cdc/pkg.yml new file mode 100644 index 00000000..3620ee14 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/transport/cdc/pkg.yml @@ -0,0 +1,34 @@ +# +# 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. +# + +pkg.name: nimble/transport/cdc +pkg.description: HCI H4 transport over CDC +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" + +pkg.deps: + - "@apache-mynewt-core/hw/hal" + - "@apache-mynewt-core/kernel/os" + - nimble + - nimble/transport/common/hci_h4 + - "@apache-mynewt-core/hw/usb/tinyusb" + - "@apache-mynewt-core/hw/usb/tinyusb/cdc" + +pkg.apis: + - ble_transport diff --git a/lib/bt/host/nimble/nimble/nimble/transport/cdc/src/cdc_hci.c b/lib/bt/host/nimble/nimble/nimble/transport/cdc/src/cdc_hci.c new file mode 100644 index 00000000..08c8f984 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/transport/cdc/src/cdc_hci.c @@ -0,0 +1,432 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CDC_HCI_LOG_LEVEL 2 + +/* State machine for assembling packets from HOST (commands and ALCs) */ +static struct hci_h4_sm cdc_hci_h4sm; + +static const struct cdc_callbacks cdc_hci_callback; + +struct usb_in_packet; +struct usb_in_queue { + STAILQ_HEAD(, usb_in_packet) queue; +}; + +static struct os_mempool usb_in_packet_pool; + +#define USB_IN_PACKET_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT) + \ + MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT) + \ + MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT) + 1) + +typedef struct cdc_hci_itf { + /* CDC Interface */ + cdc_itf_t cdc_itf; + /* ACL or Evnet packet that is currently transferred over USB */ + struct usb_in_packet *current_in_packet; + int current_in_packet_offset; + /* ACL and Event packets that are waiting to be transmitted */ + struct usb_in_queue usb_in_queue; + uint8_t rx_buffer[USBD_CDC_DATA_EP_SIZE]; +} cdc_hci_itf_t; + +static cdc_hci_itf_t cdc_hci_itf = { + .cdc_itf.callbacks = &cdc_hci_callback, + .usb_in_queue = {STAILQ_HEAD_INITIALIZER(cdc_hci_itf.usb_in_queue.queue)}, +}; + +struct usb_packet_ops { + void (*packet_free)(struct usb_in_packet *packet); + int (*packet_write)(struct usb_in_packet *packet, size_t offset); + int (*packet_size)(struct usb_in_packet *packet); +}; + +struct usb_in_packet { + STAILQ_ENTRY(usb_in_packet) next; + const struct usb_packet_ops *ops; + void *data; +}; + +static uint8_t usb_in_packet_pool_mem[OS_MEMPOOL_BYTES(USB_IN_PACKET_COUNT, sizeof(struct usb_in_packet))]; + +static void +cdc_hci_rx_cb(cdc_itf_t *itf) +{ + int ret; + uint8_t cdc_num = itf->cdc_num; + uint32_t available = tud_cdc_n_available(cdc_num); + uint32_t received = 0; + int consumed = 0; + + while ((available > 0) || (received > consumed)) { + if (consumed == received) { + consumed = 0; + received = tud_cdc_n_read(cdc_num, cdc_hci_itf.rx_buffer, min(available, sizeof(cdc_hci_itf.rx_buffer))); + available = tud_cdc_n_available(cdc_num); + } + ret = hci_h4_sm_rx(&cdc_hci_h4sm, cdc_hci_itf.rx_buffer + consumed, received - consumed); + if (ret < 0) { + tud_cdc_n_read_flush(cdc_num); + break; + } + consumed += ret; + } +} + +static void +usb_in_packet_free(struct usb_in_packet *pkt) +{ + if (pkt) { + pkt->ops->packet_free(pkt); + os_memblock_put(&usb_in_packet_pool, pkt); + } +} + +static int +usb_in_packet_write(struct usb_in_packet *pkt, int offset) +{ + return pkt->ops->packet_write(pkt, offset); +} + +static int +usb_in_packet_size(struct usb_in_packet *pkt) +{ + if (pkt) { + return pkt->ops->packet_size(pkt); + } else { + return 0; + } +} + +static void +cdc_hci_send_next_in_packet(void) +{ + int sr; + struct usb_in_packet *last_packet; + + if (cdc_hci_itf.current_in_packet == NULL || + cdc_hci_itf.current_in_packet_offset == usb_in_packet_size(cdc_hci_itf.current_in_packet)) { + OS_ENTER_CRITICAL(sr); + last_packet = cdc_hci_itf.current_in_packet; + cdc_hci_itf.current_in_packet_offset = 0; + cdc_hci_itf.current_in_packet = STAILQ_FIRST(&cdc_hci_itf.usb_in_queue.queue); + if (cdc_hci_itf.current_in_packet) { + STAILQ_REMOVE_HEAD(&cdc_hci_itf.usb_in_queue.queue, next); + } + OS_EXIT_CRITICAL(sr); + usb_in_packet_free(last_packet); + } + if (cdc_hci_itf.current_in_packet != NULL && + cdc_hci_itf.current_in_packet_offset < usb_in_packet_size(cdc_hci_itf.current_in_packet)) { + cdc_hci_itf.current_in_packet_offset += usb_in_packet_write(cdc_hci_itf.current_in_packet, + cdc_hci_itf.current_in_packet_offset); + } +} + +static void +cdc_hci_tx_complete_cb(cdc_itf_t *itf) +{ + (void)itf; + + cdc_hci_send_next_in_packet(); +} + +static void +cdc_hci_line_state_cb(cdc_itf_t *itf, bool dtr, bool rts) +{ + (void)itf; + (void)rts; + + if (dtr) { + cdc_hci_send_next_in_packet(); + } +} + +static struct usb_in_packet * +cdc_hci_get_usb_in_packet(void) +{ + struct usb_in_packet *packet = (struct usb_in_packet *)os_memblock_get(&usb_in_packet_pool); + if (packet) { + packet->data = NULL; + } + return packet; +} + +static void +cdc_hci_send_next_in_packet_from_usbd_task(void *dummy) +{ + (void)dummy; + cdc_hci_send_next_in_packet(); +} + +static void +cdc_hci_usb_in_enqueue_packet(struct usb_in_packet *pkt) +{ + int sr; + + /* Add to IN queue */ + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&cdc_hci_itf.usb_in_queue.queue, pkt, next); + OS_EXIT_CRITICAL(sr); + + usbd_defer_func(cdc_hci_send_next_in_packet_from_usbd_task, NULL, true); +} + + +/* + * Returns packet size as seen over USB + */ +static int +cdc_hci_event_packet_size(struct usb_in_packet *packet) +{ + struct ble_hci_ev *event = packet->data; + return event->length + 2 /* opcode + length */ + 1 /* H4 header */; +} + +/* + * Free Event packet that BLE stack provided to USB stack. + * Function is called once all data was sent over USB IN endpoint. + */ +static void +cdc_hci_event_packet_free(struct usb_in_packet *packet) +{ + ble_transport_free(packet->data); +} + +/* + * Write Event packed from BLE stack to USB IN endpoint. + * Flush will be called separately. + */ +static int +cdc_hci_event_packet_write(struct usb_in_packet *packet, size_t offset) +{ + uint8_t cdc_num = cdc_hci_itf.cdc_itf.cdc_num; + const uint8_t *buf = ((const uint8_t *)packet->data) - 1; + const struct ble_hci_ev *hci_ev = packet->data; + size_t h4_event_size = hci_ev->length + sizeof(struct ble_hci_ev) + 1; + size_t new_offset = offset; + + /* Write H4 Event type */ + if (new_offset == 0) { + new_offset = tud_cdc_n_write_char(cdc_num, HCI_H4_EVT); + } + /* If first byte was not written rest of the event has to wait as well */ + if (new_offset > 0) { + new_offset += tud_cdc_n_write(cdc_num, buf + new_offset, h4_event_size - new_offset); + tud_cdc_n_write_flush(cdc_num); + } + + return (int)(new_offset - offset); +} + +/* + * USB IN endpoint packet handling functions for Events + */ +static const struct usb_packet_ops event_packet_ops = { + .packet_free = cdc_hci_event_packet_free, + .packet_write = cdc_hci_event_packet_write, + .packet_size = cdc_hci_event_packet_size, +}; + +/* + * Returns packet size as seen over USB + */ +static int +cdc_hci_acl_packet_size(struct usb_in_packet *packet) +{ + struct os_mbuf *om = (struct os_mbuf *)packet->data; + /* Data size of mbuf plus one for H4 header (2) */ + return os_mbuf_len(om) + 1; +} + +/* + * Free ACL data packet that BLE stack provided to USB stack. + * Function is called once all data was sent over USB IN endpoint. + */ +static void +cdc_hci_acl_packet_free(struct usb_in_packet *packet) +{ + struct os_mbuf *om = (struct os_mbuf *)packet->data; + + os_mbuf_free_chain(om); +} + +/* + * Write ACL packed from BLE stack to USB IN endpoint. + * Code traverses mbuf to send all data. + * Flush will be called separately. + */ +static int +cdc_hci_acl_packet_write(struct usb_in_packet *packet, size_t offset) +{ + uint8_t cdc_num = cdc_hci_itf.cdc_itf.cdc_num; + struct os_mbuf *om = (struct os_mbuf *)packet->data; + struct os_mbuf *mb; + size_t new_offset = offset; + uint16_t mbuf_offset; + size_t write_size; + size_t written; + + if (om) { + if (new_offset == 0) { + /* Write H4 ACL type */ + new_offset += tud_cdc_n_write_char(cdc_num, HCI_H4_ACL); + } + + for (;;) { + mb = os_mbuf_off(om, (int)new_offset - 1, &mbuf_offset); + assert(mb); + /* mbuf_offset is == om_len when new_offset reached end of mbuf data */ + if (mb->om_len == mbuf_offset) { + break; + } + /* Chunk in current mbuf */ + write_size = mb->om_len - mbuf_offset; + written = tud_cdc_n_write(cdc_num, mb->om_data + mbuf_offset, write_size); + new_offset += written; + /* USB FIFO did not have enough space for whole mbuf, stop write for now */ + if (written < write_size) { + break; + } + } + tud_cdc_n_write_flush(cdc_num); + } + + return (int)(new_offset - offset); +} + +/* + * USB IN endpoint packet handling functions for ACL data + */ +static const struct usb_packet_ops cdc_hci_acl_packet_ops = { + .packet_free = cdc_hci_acl_packet_free, + .packet_write = cdc_hci_acl_packet_write, + .packet_size = cdc_hci_acl_packet_size, +}; + +static int +cdc_hci_frame_cb(uint8_t pkt_type, void *data) +{ + switch (pkt_type) { + case HCI_H4_CMD: + return ble_transport_to_ll_cmd(data); + case HCI_H4_ACL: + return ble_transport_to_ll_acl(data); + default: + assert(0); + break; + } + + return -1; +} + +/* + * BLE stack callback with Event to be dispatched to USB IN endpoint. + */ +int +ble_transport_to_hs_evt_impl(void *buf) +{ + struct usb_in_packet *pkt; + + assert(buf != NULL); + + pkt = cdc_hci_get_usb_in_packet(); + if (pkt == NULL) { + ble_transport_free(buf); + return BLE_ERR_MEM_CAPACITY; + } + + pkt->data = buf; + pkt->ops = &event_packet_ops; + cdc_hci_usb_in_enqueue_packet(pkt); + + return 0; +} + +/* + * BLE stack callback with ACL data to be dispatched to USB IN endpoint. + */ +int +ble_transport_to_hs_acl_impl(struct os_mbuf *om) +{ + struct usb_in_packet *pkt; + + /* If this packet is zero length, just free it */ + if (OS_MBUF_PKTLEN(om) == 0) { + os_mbuf_free_chain(om); + return 0; + } + + pkt = cdc_hci_get_usb_in_packet(); + if (pkt == NULL) { + assert(0); + return -ENOMEM; + } + + pkt->data = om; + pkt->ops = &cdc_hci_acl_packet_ops; + cdc_hci_usb_in_enqueue_packet(pkt); + + return 0; +} + +void +ble_transport_hs_init(void) +{ + int rc; + + SYSINIT_ASSERT_ACTIVE(); + + rc = os_mempool_init(&usb_in_packet_pool, + USB_IN_PACKET_COUNT, + sizeof(struct usb_in_packet), + usb_in_packet_pool_mem, + "usb_in_packet_pool"); + + SYSINIT_PANIC_ASSERT(rc == 0); + + cdc_itf_add(&cdc_hci_itf.cdc_itf); + + hci_h4_sm_init(&cdc_hci_h4sm, &hci_h4_allocs_from_hs, cdc_hci_frame_cb); +} + +static const struct cdc_callbacks cdc_hci_callback = { + .cdc_rx_cb = cdc_hci_rx_cb, + .cdc_line_coding_cb = NULL, + .cdc_line_state_cb = cdc_hci_line_state_cb, + .cdc_rx_wanted_cb = NULL, + .cdc_send_break_cb = NULL, + .cdc_tx_complete_cb = cdc_hci_tx_complete_cb, +}; + diff --git a/lib/bt/host/nimble/nimble/nimble/transport/cdc/syscfg.yml b/lib/bt/host/nimble/nimble/nimble/transport/cdc/syscfg.yml new file mode 100644 index 00000000..03366250 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/transport/cdc/syscfg.yml @@ -0,0 +1,27 @@ +# 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. +# + +syscfg.defs: + USBD_CDC_HCI_DESCRIPTOR_STRING: + description: String for CDC/HCI interface + value: + + USBD_CDC_HCI: + description: Constant value indicating package usage + value: 1 + diff --git a/lib/bt/host/nimble/nimble/nimble/transport/common/hci_h4/include/nimble/transport/hci_h4.h b/lib/bt/host/nimble/nimble/nimble/transport/common/hci_h4/include/nimble/transport/hci_h4.h index 139160a5..6ad083a0 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/common/hci_h4/include/nimble/transport/hci_h4.h +++ b/lib/bt/host/nimble/nimble/nimble/transport/common/hci_h4/include/nimble/transport/hci_h4.h @@ -31,11 +31,13 @@ typedef void *(hci_h4_alloc_cmd)(void); typedef void *(hci_h4_alloc_evt)(int); typedef struct os_mbuf *(hci_h4_alloc_acl)(void); +typedef struct os_mbuf *(hci_h4_alloc_iso)(void); struct hci_h4_allocators { hci_h4_alloc_cmd *cmd; hci_h4_alloc_acl *acl; hci_h4_alloc_evt *evt; + hci_h4_alloc_iso *iso; }; extern const struct hci_h4_allocators hci_h4_allocs_from_ll; diff --git a/lib/bt/host/nimble/nimble/nimble/transport/common/hci_h4/src/hci_h4.c b/lib/bt/host/nimble/nimble/nimble/transport/common/hci_h4/src/hci_h4.c index ffa9fa0b..5276c7e5 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/common/hci_h4/src/hci_h4.c +++ b/lib/bt/host/nimble/nimble/nimble/transport/common/hci_h4/src/hci_h4.c @@ -43,6 +43,7 @@ const struct hci_h4_allocators hci_h4_allocs_from_ll = { const struct hci_h4_allocators hci_h4_allocs_from_hs = { .cmd = ble_transport_alloc_cmd, .acl = ble_transport_alloc_acl_from_hs, + .iso = ble_transport_alloc_iso_from_hs, }; struct hci_h4_input_buffer { @@ -62,6 +63,7 @@ hci_h4_frame_start(struct hci_h4_sm *rxs, uint8_t pkt_type) rxs->min_len = 3; break; case HCI_H4_ACL: + case HCI_H4_ISO: rxs->min_len = 4; break; case HCI_H4_EVT: @@ -163,6 +165,16 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib) h4sm->exp_len = h4sm->hdr[1] + 2; break; + case HCI_H4_ISO: + assert(h4sm->allocs && h4sm->allocs->iso); + h4sm->om = h4sm->allocs->iso(); + if (!h4sm->om) { + return -1; + } + + os_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len); + h4sm->exp_len = (get_le16(&h4sm->hdr[2]) & 0x7fff) + 4; + break; default: assert(0); break; @@ -189,6 +201,7 @@ hci_h4_sm_w4_payload(struct hci_h4_sm *h4sm, } break; case HCI_H4_ACL: + case HCI_H4_ISO: assert(h4sm->om); mbuf_len = OS_MBUF_PKTLEN(h4sm->om); @@ -234,6 +247,7 @@ hci_h4_sm_completed(struct hci_h4_sm *h4sm) } 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); diff --git a/lib/bt/host/nimble/nimble/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h b/lib/bt/host/nimble/nimble/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h new file mode 100644 index 00000000..551fb93d --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h @@ -0,0 +1,99 @@ +/* + * 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_IPC_H_ +#define _HCI_IPC_H_ + +#include + +#define HCI_IPC_TYPE_CMD 0x01 +#define HCI_IPC_TYPE_ACL 0x02 +#define HCI_IPC_TYPE_EVT 0x04 +#define HCI_IPC_TYPE_EVT_DISCARDABLE 0x05 +#define HCI_IPC_TYPE_EVT_IN_CMD 0x06 +#define HCI_IPC_TYPE_ISO 0x07 + +struct __attribute__((packed)) hci_ipc_hdr { + uint8_t type; + uint16_t length; +}; + +struct hci_ipc_sm { + struct hci_ipc_hdr hdr; + uint8_t hdr_len; + uint16_t rem_len; + uint16_t buf_len; + + union { + uint8_t *buf; + struct os_mbuf *om; + }; +}; + +struct hci_ipc_shm { + uint16_t n2a_num_acl; + uint16_t n2a_num_evt; + uint16_t n2a_num_evt_disc; +}; + +void hci_ipc_init(volatile struct hci_ipc_shm *shm, struct hci_ipc_sm *sm); +int hci_ipc_rx(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len); + +extern void hci_ipc_atomic_put(volatile uint16_t *num); +extern uint16_t hci_ipc_atomic_get(volatile uint16_t *num); + +/* Just to optimize static inlines below, do not use directly! */ +extern volatile struct hci_ipc_shm *g_ipc_shm; + +static inline int +hci_ipc_get(uint8_t type) +{ + volatile struct hci_ipc_shm *shm = g_ipc_shm; + + switch (type) { + case HCI_IPC_TYPE_ACL: + return hci_ipc_atomic_get(&shm->n2a_num_acl); + case HCI_IPC_TYPE_EVT: + return hci_ipc_atomic_get(&shm->n2a_num_evt); + case HCI_IPC_TYPE_EVT_DISCARDABLE: + return hci_ipc_atomic_get(&shm->n2a_num_evt_disc); + } + + return 0; +} + +static inline void +hci_ipc_put(uint8_t type) +{ + volatile struct hci_ipc_shm *shm = g_ipc_shm; + + switch (type) { + case HCI_IPC_TYPE_ACL: + hci_ipc_atomic_put(&shm->n2a_num_acl); + break; + case HCI_IPC_TYPE_EVT: + hci_ipc_atomic_put(&shm->n2a_num_evt); + break; + case HCI_IPC_TYPE_EVT_DISCARDABLE: + hci_ipc_atomic_put(&shm->n2a_num_evt_disc); + break; + } +} + +#endif /* _HCI_IPC_H_ */ diff --git a/lib/bt/host/nimble/nimble/nimble/transport/common/hci_ipc/pkg.yml b/lib/bt/host/nimble/nimble/nimble/transport/common/hci_ipc/pkg.yml new file mode 100644 index 00000000..b66a3320 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/transport/common/hci_ipc/pkg.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +pkg.name: nimble/transport/common/hci_ipc +pkg.description: Custom HCI IPC protocol +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" + +pkg.deps: + - nimble diff --git a/lib/bt/host/nimble/nimble/nimble/transport/common/hci_ipc/src/hci_ipc.c b/lib/bt/host/nimble/nimble/nimble/transport/common/hci_ipc/src/hci_ipc.c new file mode 100644 index 00000000..613c9ce1 --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/transport/common/hci_ipc/src/hci_ipc.c @@ -0,0 +1,234 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +volatile struct hci_ipc_shm *g_ipc_shm; + +static void +hci_ipc_alloc(struct hci_ipc_sm *sm) +{ + assert(sm->hdr.type); + assert(sm->buf == NULL); + + switch (sm->hdr.type) { +#if MYNEWT_VAL(BLE_CONTROLLER) + case HCI_IPC_TYPE_CMD: + sm->buf = ble_transport_alloc_cmd(); + break; +#endif + case HCI_IPC_TYPE_ACL: +#if MYNEWT_VAL(BLE_CONTROLLER) + sm->om = ble_transport_alloc_acl_from_hs(); +#else + sm->om = ble_transport_alloc_acl_from_ll(); +#endif + break; +#if !MYNEWT_VAL(BLE_CONTROLLER) + case HCI_IPC_TYPE_EVT: + sm->buf = ble_transport_alloc_evt(0); + break; + case HCI_IPC_TYPE_EVT_DISCARDABLE: + sm->buf = ble_transport_alloc_evt(1); + break; + case HCI_IPC_TYPE_EVT_IN_CMD: + sm->buf = ble_transport_alloc_cmd(); + break; +#endif + case HCI_IPC_TYPE_ISO: +#if MYNEWT_VAL(BLE_CONTROLLER) + sm->om = ble_transport_alloc_iso_from_hs(); +#else + sm->om = ble_transport_alloc_iso_from_ll(); +#endif + break; + default: + assert(0); + break; + } + + assert(sm->buf); + + sm->rem_len = sm->hdr.length; + sm->buf_len = 0; +} + +static bool +hci_ipc_has_hdr(struct hci_ipc_sm *sm) +{ + return sm->hdr_len == sizeof(sm->hdr); +} + +static void +hci_ipc_frame(struct hci_ipc_sm *sm) +{ + assert(sm->hdr.type); + assert(sm->buf); + assert(sm->rem_len == 0); + + switch (sm->hdr.type) { +#if MYNEWT_VAL(BLE_CONTROLLER) + case HCI_IPC_TYPE_CMD: + ble_transport_to_ll_cmd(sm->buf); + break; +#endif + case HCI_IPC_TYPE_ACL: +#if MYNEWT_VAL(BLE_CONTROLLER) + ble_transport_to_ll_acl(sm->om); +#else + ble_transport_to_hs_acl(sm->om); +#endif + break; +#if !MYNEWT_VAL(BLE_CONTROLLER) + case HCI_IPC_TYPE_EVT: + case HCI_IPC_TYPE_EVT_DISCARDABLE: + case HCI_IPC_TYPE_EVT_IN_CMD: + ble_transport_to_hs_evt(sm->buf); + break; +#endif + case HCI_IPC_TYPE_ISO: +#if MYNEWT_VAL(BLE_CONTROLLER) + ble_transport_to_ll_iso(sm->om); +#else + ble_transport_to_hs_iso(sm->om); +#endif + break; + default: + assert(0); + break; + } + + sm->hdr.type = 0; + sm->hdr.length = 0; + sm->hdr_len = 0; + sm->buf_len = 0; + sm->rem_len = 0; + sm->buf = NULL; +} + +static uint16_t +hci_ipc_copy_to_hdr(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len) +{ + uint16_t rem_hdr_len; + uint8_t *p; + + if (hci_ipc_has_hdr(sm)) { + return 0; + } + + rem_hdr_len = sizeof(sm->hdr) - sm->hdr_len; + len = min(len, rem_hdr_len); + + p = (void *)&sm->hdr; + memcpy(p + sm->hdr_len, buf, len); + + sm->hdr_len += len; + + if (hci_ipc_has_hdr(sm)) { + hci_ipc_alloc(sm); + } + + return len; +} + +static uint16_t +hci_ipc_copy_to_buf(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len) +{ + int rc; + + assert(sm->hdr.type); + assert(sm->buf); + + len = min(len, sm->rem_len); + + switch (sm->hdr.type) { +#if MYNEWT_VAL(BLE_CONTROLLER) + case HCI_IPC_TYPE_CMD: +#else + case HCI_IPC_TYPE_EVT: + case HCI_IPC_TYPE_EVT_DISCARDABLE: + case HCI_IPC_TYPE_EVT_IN_CMD: +#endif + memcpy(sm->buf + sm->buf_len, buf, len); + break; + case HCI_IPC_TYPE_ACL: + case HCI_IPC_TYPE_ISO: + rc = os_mbuf_append(sm->om, buf, len); + assert(rc == 0); + break; + default: + assert(0); + break; + } + + sm->rem_len -= len; + sm->buf_len += len; + + if (sm->rem_len == 0) { + hci_ipc_frame(sm); + } + + return len; +} + +int +hci_ipc_rx(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len) +{ + uint16_t rem_len = len; + uint16_t copy_len; + + while (rem_len) { + if (hci_ipc_has_hdr(sm)) { + copy_len = hci_ipc_copy_to_buf(sm, buf, rem_len); + } else { + copy_len = hci_ipc_copy_to_hdr(sm, buf, rem_len); + } + + rem_len -= copy_len; + buf += copy_len; + } + + return len; +} + +void +hci_ipc_init(volatile struct hci_ipc_shm *shm, struct hci_ipc_sm *sm) +{ + assert(g_ipc_shm == NULL); + + g_ipc_shm = shm; + memset(sm, 0, sizeof(*sm)); + +#if MYNEWT_VAL(BLE_CONTROLLER) + while (shm->n2a_num_evt_disc == 0) { + /* Wait until app side initializes credits */ + } +#else + shm->n2a_num_acl = MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT); + shm->n2a_num_evt = MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT); + shm->n2a_num_evt_disc = MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT); +#endif +} diff --git a/lib/bt/host/nimble/nimble/nimble/transport/dialog_cmac/pkg.yml b/lib/bt/host/nimble/nimble/nimble/transport/dialog_cmac/pkg.yml index 2c02d7e7..40de98fe 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/dialog_cmac/pkg.yml +++ b/lib/bt/host/nimble/nimble/nimble/transport/dialog_cmac/pkg.yml @@ -18,16 +18,16 @@ # pkg.name: nimble/transport/dialog_cmac -pkg.description: HCI H4 transport for Dialog CMAC +pkg.description: IPC transport for Dialog CMAC pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" +pkg.homepage: "https://mynewt.apache.org/" pkg.keywords: - ble - bluetooth pkg.deps: - nimble/transport/common/hci_h4 - - nimble/transport/dialog_cmac/cmac_driver + - "@apache-mynewt-core/hw/drivers/ipc_cmac" pkg.apis: - ble_transport diff --git a/lib/bt/host/nimble/nimble/nimble/transport/dialog_cmac/src/hci_cmac.c b/lib/bt/host/nimble/nimble/nimble/transport/dialog_cmac/src/hci_cmac.c index e0702a03..164be668 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/dialog_cmac/src/hci_cmac.c +++ b/lib/bt/host/nimble/nimble/nimble/transport/dialog_cmac/src/hci_cmac.c @@ -24,9 +24,10 @@ /* to enable dser diag */ #include #endif /* BLE_CONTROLLER */ -#include +#include +#include #if !MYNEWT_VAL(BLE_CONTROLLER) -#include +#include #endif /* !BLE_CONTROLLER */ #include #include @@ -99,8 +100,8 @@ ble_transport_ll_init(void) hci_h4_sm_init(&hci_cmac_h4sm, &hci_h4_allocs_from_ll, hci_cmac_hs_frame_cb); /* We can now handle data from CMAC, initialize it */ - cmac_mbox_set_read_cb(hci_cmac_hs_mbox_read_cb); - cmac_mbox_set_write_notif_cb(hci_cmac_hs_mbox_write_notif_cb); + cmac_mbox_cb_set(hci_cmac_hs_mbox_read_cb, + hci_cmac_hs_mbox_write_notif_cb); cmac_host_init(); } #endif /* !BLE_CONTROLLER */ @@ -155,11 +156,11 @@ ble_transport_hs_init(void) hci_h4_sm_init(&hci_cmac_h4sm, &hci_h4_allocs_from_hs, hci_cmac_ll_frame_cb); /* Setup callbacks for mailboxes */ - cmac_mbox_set_read_cb(hci_cmac_ll_mbox_read_cb); - cmac_mbox_set_write_notif_cb(hci_cmac_ll_mbox_write_notif_cb); + cmac_mbox_cb_set(hci_cmac_ll_mbox_read_cb, + hci_cmac_ll_mbox_write_notif_cb); /* Synchronize with SYS */ - cmac_shared_sync(); + cmac_shm_ll_ready(); } #endif diff --git a/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport.h b/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport.h index 108ece45..b4ca3db2 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport.h +++ b/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport.h @@ -26,6 +26,9 @@ extern "C" { #include #include +#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc +#include +#endif #include #include "os/os_mempool.h" @@ -332,12 +335,17 @@ int esp_ble_hci_trans_reset(void); #endif struct os_mbuf; +/* Initialization */ +void ble_transport_init(void); + /* Allocators for supported data types */ #if !SOC_ESP_NIMBLE_CONTROLLER || !CONFIG_BT_CONTROLLER_ENABLED void *ble_transport_alloc_cmd(void); void *ble_transport_alloc_evt(int discardable); struct os_mbuf *ble_transport_alloc_acl_from_hs(void); +struct os_mbuf *ble_transport_alloc_iso_from_hs(void); struct os_mbuf *ble_transport_alloc_acl_from_ll(void); +struct os_mbuf *ble_transport_alloc_iso_from_ll(void); /* Generic deallocator for cmd/evt buffers */ void ble_transport_free(void *buf); @@ -346,14 +354,19 @@ void ble_transport_free(void *buf); /* Register put callback on acl_from_ll mbufs (for ll-hs flow control) */ int ble_transport_register_put_acl_from_ll_cb(os_mempool_put_fn *cb); -/* Send data to hs/ll side */ #if CONFIG_BT_CONTROLLER_ENABLED #define ble_transport_to_ll_acl ble_hci_trans_hs_acl_tx #define ble_transport_to_ll_cmd ble_hci_trans_hs_cmd_tx +#else +int ble_transport_to_ll_cmd(void *buf); +int ble_transport_to_ll_acl(struct os_mbuf *om); #endif +/* Send data to hs/ll side */ +int ble_transport_to_ll_iso(struct os_mbuf *om); int ble_transport_to_hs_evt(void *buf); int ble_transport_to_hs_acl(struct os_mbuf *om); +int ble_transport_to_hs_iso(struct os_mbuf *om); #ifdef __cplusplus } diff --git a/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport/monitor.h b/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport/monitor.h index 6b56f123..dc12c69c 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport/monitor.h +++ b/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport/monitor.h @@ -30,11 +30,20 @@ extern "C" { MYNEWT_VAL(BLE_MONITOR_UART)) #if BLE_MONITOR +int ble_monitor_out(int c); int ble_monitor_log(int level, const char *fmt, ...); #else static inline int +ble_monitor_out(int c) +{ + (void)c; + return 0; +} +static inline int ble_monitor_log(int level, const char *fmt, ...) { + (void)level; + (void)fmt; return 0; } @@ -50,6 +59,12 @@ ble_transport_to_ll_acl(struct os_mbuf *om) return ble_transport_to_ll_acl_impl(om); } +static inline int +ble_transport_to_ll_iso(struct os_mbuf *om) +{ + return ble_transport_to_ll_iso_impl(om); +} + static inline int ble_transport_to_hs_evt(void *buf) { @@ -61,6 +76,12 @@ ble_transport_to_hs_acl(struct os_mbuf *om) { return ble_transport_to_hs_acl_impl(om); } + +static inline int +ble_transport_to_hs_iso(struct os_mbuf *om) +{ + return ble_transport_to_hs_iso_impl(om); +} #endif /* BLE_MONITOR */ #ifdef __cplusplus diff --git a/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport/transport_ipc.h b/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport/transport_ipc.h new file mode 100644 index 00000000..8059c3ae --- /dev/null +++ b/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport/transport_ipc.h @@ -0,0 +1,49 @@ +/* + * 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 H_NIMBLE_TRANSPORT_IPC_ +#define H_NIMBLE_TRANSPORT_IPC_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* NOTE: These APIs shall only be used by IPC transports */ + +#define BLE_TRANSPORT_IPC \ + MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc +#define BLE_TRANSPORT_IPC_ON_HS \ + (BLE_TRANSPORT_IPC && !MYNEWT_VAL(BLE_CONTROLLER)) +#define BLE_TRANSPORT_IPC_ON_LL \ + (BLE_TRANSPORT_IPC && MYNEWT_VAL(BLE_CONTROLLER)) + +/* Free cmd/evt buffer sent over IPC */ +void ble_transport_ipc_free(void *buf); + +/* Get IPC type for cmd/evt buffer */ +uint8_t ble_transport_ipc_buf_evt_type_get(void *buf); + +#ifdef __cplusplus +} +#endif + +#endif /* H_NIMBLE_TRANSPORT_IPC_ */ diff --git a/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport_impl.h b/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport_impl.h index 4a316c21..d5973378 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport_impl.h +++ b/lib/bt/host/nimble/nimble/nimble/transport/include/nimble/transport_impl.h @@ -34,14 +34,10 @@ extern void ble_transport_hs_init(void); /* APIs to be implemented by HS/LL side of transports */ extern int ble_transport_to_ll_cmd_impl(void *buf); extern int ble_transport_to_ll_acl_impl(struct os_mbuf *om); +extern int ble_transport_to_ll_iso_impl(struct os_mbuf *om); extern int ble_transport_to_hs_evt_impl(void *buf); extern int ble_transport_to_hs_acl_impl(struct os_mbuf *om); - -#if MYNEWT_VAL(BLE_TRANSPORT_INT_FLOW_CTL) -/* To be implemented if transport supports internal flow control between cores */ -extern int ble_transport_int_flow_ctl_get(void); -extern void ble_transport_int_flow_ctl_put(void); -#endif +extern int ble_transport_to_hs_iso_impl(struct os_mbuf *om); #ifdef __cplusplus } diff --git a/lib/bt/host/nimble/nimble/nimble/transport/nrf5340/pkg.yml b/lib/bt/host/nimble/nimble/nimble/transport/nrf5340/pkg.yml index 73dfcf9e..be44d0f8 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/nrf5340/pkg.yml +++ b/lib/bt/host/nimble/nimble/nimble/transport/nrf5340/pkg.yml @@ -28,7 +28,7 @@ pkg.keywords: pkg.deps: - nimble - - nimble/transport/common/hci_h4 + - nimble/transport/common/hci_ipc - "@apache-mynewt-core/kernel/os" - "@apache-mynewt-core/hw/drivers/ipc_nrf5340" diff --git a/lib/bt/host/nimble/nimble/nimble/transport/nrf5340/src/nrf5340_ble_hci.c b/lib/bt/host/nimble/nimble/nimble/transport/nrf5340/src/nrf5340_ble_hci.c index fc9fec7c..7f3c5efe 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/nrf5340/src/nrf5340_ble_hci.c +++ b/lib/bt/host/nimble/nimble/nimble/transport/nrf5340/src/nrf5340_ble_hci.c @@ -19,11 +19,12 @@ #include #include +#include #include #include #include #include -#include +#include #if MYNEWT_VAL(BLE_CONTROLLER) #define IPC_TX_CHANNEL 0 @@ -33,20 +34,23 @@ #define IPC_RX_CHANNEL 0 #endif -static struct hci_h4_sm hci_nrf5340_h4sm; +static struct hci_ipc_sm g_hci_ipc_sm; static int nrf5340_ble_hci_acl_tx(struct os_mbuf *om) { - uint8_t ind = HCI_H4_ACL; + struct hci_ipc_hdr hdr; struct os_mbuf *x; int rc; - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, &ind, 1); + hdr.type = HCI_IPC_TYPE_ACL; + hdr.length = 4 + get_le16(&om->om_data[2]); + + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false); if (rc == 0) { x = om; while (x) { - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, x->om_data, x->om_len); + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, x->om_data, x->om_len, true); if (rc < 0) { break; } @@ -59,36 +63,34 @@ nrf5340_ble_hci_acl_tx(struct os_mbuf *om) return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; } +#if !MYNEWT_VAL(BLE_CONTROLLER) static int -nrf5340_ble_hci_frame_cb(uint8_t pkt_type, void *data) +nrf5340_ble_hci_iso_tx(struct os_mbuf *om) { + struct hci_ipc_hdr hdr; + struct os_mbuf *x; int rc; - switch (pkt_type) { -#if MYNEWT_VAL(BLE_CONTROLLER) - case HCI_H4_CMD: - rc = ble_transport_to_ll_cmd(data); - break; -#endif - case HCI_H4_ACL: -#if MYNEWT_VAL(BLE_CONTROLLER) - rc = ble_transport_to_ll_acl(data); -#else - rc = ble_transport_to_hs_acl(data); -#endif - break; -#if !MYNEWT_VAL(BLE_CONTROLLER) - case HCI_H4_EVT: - rc = ble_transport_to_hs_evt(data); - break; -#endif - default: - assert(0); - break; + hdr.type = HCI_IPC_TYPE_ISO; + hdr.length = 4 + get_le16(&om->om_data[2]); + + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false); + if (rc == 0) { + x = om; + while (x) { + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, x->om_data, x->om_len, true); + if (rc < 0) { + break; + } + x = SLIST_NEXT(x, om_next); + } } - return rc; + os_mbuf_free_chain(om); + + return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; } +#endif static void nrf5340_ble_hci_trans_rx(int channel, void *user_data) @@ -98,7 +100,7 @@ nrf5340_ble_hci_trans_rx(int channel, void *user_data) len = ipc_nrf5340_available_buf(channel, (void **)&buf); while (len > 0) { - len = hci_h4_sm_rx(&hci_nrf5340_h4sm, buf, len); + len = hci_ipc_rx(&g_hci_ipc_sm, buf, len); ipc_nrf5340_consume(channel, len); len = ipc_nrf5340_available_buf(channel, (void **)&buf); } @@ -116,17 +118,19 @@ nrf5340_ble_hci_init(void) int ble_transport_to_hs_evt_impl(void *buf) { - uint8_t ind = HCI_H4_EVT; - uint8_t* hci_ev = buf; - int len = 2 + hci_ev[1]; + struct hci_ipc_hdr hdr; + uint8_t *hci_ev = buf; int rc; - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, &ind, 1); + hdr.type = ble_transport_ipc_buf_evt_type_get(buf); + hdr.length = 2 + hci_ev[1]; + + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false); if (rc == 0) { - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, hci_ev, len); + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, hci_ev, hdr.length, true); } - ble_transport_free(buf); + ble_transport_ipc_free(buf); return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; } @@ -140,8 +144,9 @@ ble_transport_to_hs_acl_impl(struct os_mbuf *om) void ble_transport_hs_init(void) { - hci_h4_sm_init(&hci_nrf5340_h4sm, &hci_h4_allocs_from_hs, - nrf5340_ble_hci_frame_cb); + volatile struct hci_ipc_shm *shm = ipc_nrf5340_hci_shm_get(); + + hci_ipc_init(shm, &g_hci_ipc_sm); nrf5340_ble_hci_init(); } #endif /* BLE_CONTROLLER */ @@ -150,17 +155,19 @@ ble_transport_hs_init(void) int ble_transport_to_ll_cmd_impl(void *buf) { - uint8_t ind = HCI_H4_CMD; + struct hci_ipc_hdr hdr; uint8_t *cmd = buf; - int len = 3 + cmd[2]; int rc; - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, &ind, 1); + hdr.type = HCI_IPC_TYPE_CMD; + hdr.length = 3 + cmd[2]; + + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false); if (rc == 0) { - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, cmd, len); + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, cmd, hdr.length, true); } - ble_transport_free(buf); + ble_transport_ipc_free(buf); return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; } @@ -171,11 +178,54 @@ ble_transport_to_ll_acl_impl(struct os_mbuf *om) return nrf5340_ble_hci_acl_tx(om); } +int +ble_transport_to_ll_iso_impl(struct os_mbuf *om) +{ + return nrf5340_ble_hci_iso_tx(om); +} + void ble_transport_ll_init(void) { - hci_h4_sm_init(&hci_nrf5340_h4sm, &hci_h4_allocs_from_ll, - nrf5340_ble_hci_frame_cb); + volatile struct hci_ipc_shm *shm = ipc_nrf5340_hci_shm_get(); + + hci_ipc_init(shm, &g_hci_ipc_sm); nrf5340_ble_hci_init(); } #endif /* !BLE_CONTROLLER */ + +uint16_t +hci_ipc_atomic_get(volatile uint16_t *num) +{ + int ret; + + __asm__ volatile (".syntax unified \n" + "1: ldrexh r1, [%[addr]] \n" + " mov %[ret], r1 \n" + " cmp r1, #0 \n" + " itte ne \n" + " subne r2, r1, #1 \n" + " strexhne r1, r2, [%[addr]] \n" + " clrexeq \n" + " cmp r1, #0 \n" + " bne 1b \n" + : [ret] "=&r" (ret) + : [addr] "r" (num) + : "r1", "r2", "memory"); + + return ret; +} + +void +hci_ipc_atomic_put(volatile uint16_t *num) +{ + __asm__ volatile (".syntax unified \n" + "1: ldrexh r1, [%[addr]] \n" + " add r1, r1, #1 \n" + " strexh r2, r1, [%[addr]] \n" + " cmp r2, #0 \n" + " bne 1b \n" + : + : [addr] "r" (num) + : "r1", "r2", "memory"); +} diff --git a/lib/bt/host/nimble/nimble/nimble/transport/pkg.yml b/lib/bt/host/nimble/nimble/nimble/transport/pkg.yml index d2e653bf..30237f75 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/pkg.yml +++ b/lib/bt/host/nimble/nimble/nimble/transport/pkg.yml @@ -44,6 +44,8 @@ pkg.deps.'BLE_TRANSPORT_HS == "uart"': - nimble/transport/uart pkg.deps.'BLE_TRANSPORT_HS == "usb"': - nimble/transport/usb +pkg.deps.'BLE_TRANSPORT_HS == "cdc"': + - nimble/transport/cdc pkg.deps.'BLE_TRANSPORT_LL == "apollo3"': - nimble/transport/apollo3 pkg.deps.'BLE_TRANSPORT_LL == "uart_ll"': diff --git a/lib/bt/host/nimble/nimble/nimble/transport/socket/pkg.yml b/lib/bt/host/nimble/nimble/nimble/transport/socket/pkg.yml index fb4144d3..b64075ba 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/socket/pkg.yml +++ b/lib/bt/host/nimble/nimble/nimble/transport/socket/pkg.yml @@ -33,6 +33,3 @@ pkg.deps: pkg.apis: - ble_transport - -pkg.init: - ble_hci_sock_init: 'MYNEWT_VAL(BLE_SOCK_CLI_SYSINIT_STAGE)' diff --git a/lib/bt/host/nimble/nimble/nimble/transport/socket/src/ble_hci_socket.c b/lib/bt/host/nimble/nimble/nimble/transport/socket/src/ble_hci_socket.c index a8ea81b4..11232b01 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/socket/src/ble_hci_socket.c +++ b/lib/bt/host/nimble/nimble/nimble/transport/socket/src/ble_hci_socket.c @@ -146,7 +146,7 @@ STATS_NAME_END(hci_sock_stats) #define BLE_HCI_UART_H4_SKIP_CMD 0x81 #define BLE_HCI_UART_H4_SKIP_ACL 0x82 -#if MYNEWT +#ifdef MYNEWT #define BLE_SOCK_STACK_SIZE \ OS_STACK_ALIGN(MYNEWT_VAL(BLE_SOCK_STACK_SIZE)) @@ -334,6 +334,7 @@ ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) memcpy(&addr, &addr, sizeof(struct sockaddr_hci)); + len = 0; if (h4_type == BLE_HCI_UART_H4_CMD) { len = sizeof(struct ble_hci_cmd) + hci_ev[2]; STATS_INC(hci_sock_stats, ocmd); @@ -356,7 +357,7 @@ ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) (struct sockaddr *)&addr, sizeof(struct sockaddr_hci)); free(buf); - ble_hci_trans_buf_free(hci_ev); + ble_transport_free(hci_ev); if (i != len + 1) { if (i < 0) { dprintf(1, "sendto() failed : %d\n", errno); @@ -778,7 +779,7 @@ ble_hci_sock_init_task(void) ble_npl_callout_init(&ble_hci_sock_state.timer, &ble_hci_sock_state.evq, ble_hci_sock_rx_ev, NULL); -#if MYNEWT +#ifdef MYNEWT { os_stack_t *pstack; diff --git a/lib/bt/host/nimble/nimble/nimble/transport/src/monitor.c b/lib/bt/host/nimble/nimble/nimble/transport/src/monitor.c index 9a61a836..b6daeec8 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/src/monitor.c +++ b/lib/bt/host/nimble/nimble/nimble/transport/src/monitor.c @@ -520,6 +520,14 @@ ble_transport_to_ll_acl(struct os_mbuf *om) return ble_transport_to_ll_acl_impl(om); } +int +ble_transport_to_ll_iso(struct os_mbuf *om) +{ + ble_monitor_send_om(BLE_MONITOR_OPCODE_ISO_TX_PKT, om); + + return ble_transport_to_ll_iso_impl(om); +} + int ble_transport_to_hs_acl(struct os_mbuf *om) { @@ -539,4 +547,12 @@ ble_transport_to_hs_evt(void *buf) return ble_transport_to_hs_evt_impl(buf); } +int +ble_transport_to_hs_iso(struct os_mbuf *om) +{ + ble_monitor_send_om(BLE_MONITOR_OPCODE_ISO_RX_PKT, om); + + return ble_transport_to_hs_iso_impl(om); +} + #endif /* MYNEWT_VAL(BLE_MONITOR_RTT) || MYNEWT_VAL(BLE_MONITOR_UART) */ diff --git a/lib/bt/host/nimble/nimble/nimble/transport/src/monitor_priv.h b/lib/bt/host/nimble/nimble/nimble/transport/src/monitor_priv.h index 0fb96509..938da8f5 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/src/monitor_priv.h +++ b/lib/bt/host/nimble/nimble/nimble/transport/src/monitor_priv.h @@ -38,6 +38,8 @@ extern "C" { #define BLE_MONITOR_OPCODE_VENDOR_DIAG 11 #define BLE_MONITOR_OPCODE_SYSTEM_NOTE 12 #define BLE_MONITOR_OPCODE_USER_LOGGING 13 +#define BLE_MONITOR_OPCODE_ISO_TX_PKT 18 +#define BLE_MONITOR_OPCODE_ISO_RX_PKT 19 #define BLE_MONITOR_EXTHDR_COMMAND_DROPS 1 #define BLE_MONITOR_EXTHDR_EVENT_DROPS 2 diff --git a/lib/bt/host/nimble/nimble/nimble/transport/src/transport.c b/lib/bt/host/nimble/nimble/nimble/transport/src/transport.c index 85970ee2..a6b15086 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/src/transport.c +++ b/lib/bt/host/nimble/nimble/nimble/transport/src/transport.c @@ -25,6 +25,9 @@ #include #include #include +#if BLE_TRANSPORT_IPC +#include +#endif #include "esp_nimble_mem.h" int os_msys_buf_alloc(void); @@ -35,7 +38,8 @@ void os_msys_buf_free(void); #define OMP_FLAG_FROM_MASK (0x03) #if MYNEWT_VAL(BLE_HS_FLOW_CTRL) || \ - MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) + MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) || \ + (!MYNEWT_VAL(BLE_HOST) && BLE_TRANSPORT_IPC_ON_HS) #define POOL_CMD_COUNT (2) #else #define POOL_CMD_COUNT (1) @@ -49,18 +53,26 @@ void os_msys_buf_free(void); #if MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native) && \ MYNEWT_VAL_CHOICE(BLE_TRANSPORT_HS, native) #define POOL_ACL_COUNT (0) +#define POOL_ISO_COUNT (0) #elif !MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native) && \ !MYNEWT_VAL_CHOICE(BLE_TRANSPORT_HS, native) #define POOL_ACL_COUNT ((MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_HS_COUNT)) + \ (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT))) +#define POOL_ISO_COUNT ((MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_HS_COUNT)) + \ + (MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_LL_COUNT))) #elif MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native) #define POOL_ACL_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_HS_COUNT)) +#define POOL_ISO_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_HS_COUNT)) #else #define POOL_ACL_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT)) +#define POOL_ISO_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_LL_COUNT)) #endif #define POOL_ACL_SIZE (OS_ALIGN( MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE) + \ BLE_MBUF_MEMBLOCK_OVERHEAD + \ BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)) +#define POOL_ISO_SIZE (OS_ALIGN(MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE) + \ + BLE_MBUF_MEMBLOCK_OVERHEAD + \ + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)) #if !SOC_ESP_NIMBLE_CONTROLLER || !CONFIG_BT_CONTROLLER_ENABLED static os_membuf_t *pool_cmd_buf; @@ -72,9 +84,17 @@ static struct os_mempool pool_evt; static os_membuf_t *pool_evt_lo_buf; static struct os_mempool pool_evt_lo; +#if POOL_ACL_COUNT > 0 static os_membuf_t *pool_acl_buf; static struct os_mempool_ext pool_acl; static struct os_mbuf_pool mpool_acl; +#endif + +#if POOL_ISO_COUNT > 0 +static os_membuf_t *pool_iso_buf; +static struct os_mempool_ext pool_iso; +static struct os_mbuf_pool mpool_iso; +#endif static os_mempool_put_fn *transport_put_acl_from_ll_cb; @@ -84,17 +104,48 @@ ble_transport_alloc_cmd(void) return os_memblock_get(&pool_cmd); } +static void * +try_alloc_evt(struct os_mempool *mp) +{ +#if BLE_TRANSPORT_IPC_ON_LL + uint8_t type; +#endif + void *buf; + +#if BLE_TRANSPORT_IPC_ON_LL + if (mp == &pool_evt) { + type = HCI_IPC_TYPE_EVT; + } else { + type = HCI_IPC_TYPE_EVT_DISCARDABLE; + } + + if (!hci_ipc_get(type)) { + return NULL; + } +#endif + + buf = os_memblock_get(mp); + +#if BLE_TRANSPORT_IPC_ON_LL + if (!buf) { + hci_ipc_put(type); + } +#endif + + return buf; +} + void * ble_transport_alloc_evt(int discardable) { void *buf; if (discardable) { - buf = os_memblock_get(&pool_evt_lo); + buf = try_alloc_evt(&pool_evt_lo); } else { - buf = os_memblock_get(&pool_evt); + buf = try_alloc_evt(&pool_evt); if (!buf) { - buf = os_memblock_get(&pool_evt_lo); + buf = try_alloc_evt(&pool_evt_lo); } } @@ -104,6 +155,7 @@ ble_transport_alloc_evt(int discardable) struct os_mbuf * ble_transport_alloc_acl_from_hs(void) { +#if POOL_ACL_COUNT > 0 struct os_mbuf *om; struct os_mbuf_pkthdr *pkthdr; uint16_t usrhdr_len; @@ -121,11 +173,41 @@ ble_transport_alloc_acl_from_hs(void) } return om; +#else + return NULL; +#endif +} + +struct os_mbuf * +ble_transport_alloc_iso_from_hs(void) +{ +#if POOL_ISO_COUNT > 0 + struct os_mbuf *om; + struct os_mbuf_pkthdr *pkthdr; + uint16_t usrhdr_len; + +#if MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native) + usrhdr_len = sizeof(struct ble_mbuf_hdr); +#else + usrhdr_len = 0; +#endif + + om = os_mbuf_get_pkthdr(&mpool_iso, usrhdr_len); + if (om) { + pkthdr = OS_MBUF_PKTHDR(om); + pkthdr->omp_flags = OMP_FLAG_FROM_HS; + } + + return om; +#else + return NULL; +#endif } struct os_mbuf * ble_transport_alloc_acl_from_ll(void) { +#if POOL_ACL_COUNT > 0 struct os_mbuf *om; struct os_mbuf_pkthdr *pkthdr; @@ -136,10 +218,52 @@ ble_transport_alloc_acl_from_ll(void) } return om; +#else + return NULL; +#endif +} + +struct os_mbuf * +ble_transport_alloc_iso_from_ll(void) +{ +#if POOL_ISO_COUNT > 0 + struct os_mbuf *om; + struct os_mbuf_pkthdr *pkthdr; + + om = os_mbuf_get_pkthdr(&mpool_iso, 0); + if (om) { + pkthdr = OS_MBUF_PKTHDR(om); + pkthdr->omp_flags = OMP_FLAG_FROM_LL; + } + + return om; +#else + return NULL; +#endif } void ble_transport_free(void *buf) +{ + if (os_memblock_from(&pool_cmd, buf)) { + os_memblock_put(&pool_cmd, buf); + } else if (os_memblock_from(&pool_evt, buf)) { + os_memblock_put(&pool_evt, buf); +#if BLE_TRANSPORT_IPC + hci_ipc_put(HCI_IPC_TYPE_EVT); +#endif + } else if (os_memblock_from(&pool_evt_lo, buf)) { + os_memblock_put(&pool_evt_lo, buf); +#if BLE_TRANSPORT_IPC + hci_ipc_put(HCI_IPC_TYPE_EVT_DISCARDABLE); +#endif + } else { + assert(0); + } +} + +void +ble_transport_ipc_free(void *buf) { if (os_memblock_from(&pool_cmd, buf)) { os_memblock_put(&pool_cmd, buf); @@ -152,6 +276,7 @@ ble_transport_free(void *buf) } } +#if POOL_ACL_COUNT > 0 static os_error_t ble_transport_acl_put(struct os_mempool_ext *mpe, void *data, void *arg) { @@ -179,12 +304,13 @@ ble_transport_acl_put(struct os_mempool_ext *mpe, void *data, void *arg) from_ll = (pkthdr->omp_flags & OMP_FLAG_FROM_MASK) == OMP_FLAG_FROM_LL; if (from_ll && !err) { - ble_transport_int_flow_ctl_put(); + hci_ipc_put(HCI_IPC_TYPE_ACL); } #endif return err; } +#endif void ble_buf_free(void) { @@ -196,8 +322,14 @@ void ble_buf_free(void) pool_evt_lo_buf = NULL; nimble_platform_mem_free(pool_cmd_buf); pool_cmd_buf = NULL; +#if POOL_ACL_COUNT > 0 nimble_platform_mem_free(pool_acl_buf); pool_acl_buf = NULL; +#endif +#if POOL_ISO_COUNT > 0 + nimble_platform_mem_free(pool_iso_buf); + pool_iso_buf = NULL; +#endif } esp_err_t ble_buf_alloc(void) @@ -217,11 +349,25 @@ esp_err_t ble_buf_alloc(void) pool_cmd_buf = (os_membuf_t *) nimble_platform_mem_calloc(1, (sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(POOL_CMD_COUNT, POOL_CMD_SIZE))); +#if POOL_ACL_COUNT > 0 pool_acl_buf = (os_membuf_t *) nimble_platform_mem_calloc(1, (sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(POOL_ACL_COUNT, POOL_ACL_SIZE))); - - if (!pool_evt_buf || !pool_evt_lo_buf || !pool_cmd_buf || !pool_acl_buf) { + if(!pool_acl_buf) { + ble_buf_free(); + return ESP_ERR_NO_MEM; + } +#endif +#if POOL_ISO_COUNT > 0 + pool_iso_buf = (os_membuf_t *) nimble_platform_mem_calloc(1, + sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(POOL_ISO_COUNT, + POOL_ISO_SIZE)); + if(!pool_iso_buf) { + ble_buf_free(); + return ESP_ERR_NO_MEM; + } +#endif + if (!pool_evt_buf || !pool_evt_lo_buf || !pool_cmd_buf ) { ble_buf_free(); return ESP_ERR_NO_MEM; } @@ -247,6 +393,7 @@ ble_transport_init(void) pool_evt_lo_buf, "transport_pool_evt_lo"); SYSINIT_PANIC_ASSERT(rc == 0); +#if POOL_ACL_COUNT > 0 rc = os_mempool_ext_init(&pool_acl, POOL_ACL_COUNT, POOL_ACL_SIZE, pool_acl_buf, "transport_pool_acl"); SYSINIT_PANIC_ASSERT(rc == 0); @@ -256,6 +403,17 @@ ble_transport_init(void) SYSINIT_PANIC_ASSERT(rc == 0); pool_acl.mpe_put_cb = ble_transport_acl_put; +#endif + +#if POOL_ISO_COUNT > 0 + rc = os_mempool_ext_init(&pool_iso, POOL_ISO_COUNT, POOL_ISO_SIZE, + pool_iso_buf, "transport_pool_iso"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mbuf_pool_init(&mpool_iso, &pool_iso.mpe_mp, + POOL_ISO_SIZE, POOL_ISO_COUNT); + SYSINIT_PANIC_ASSERT(rc == 0); +#endif } void @@ -281,4 +439,22 @@ ble_transport_register_put_acl_from_ll_cb(os_mempool_put_fn (*cb)) return 0; } + +#if BLE_TRANSPORT_IPC +uint8_t +ble_transport_ipc_buf_evt_type_get(void *buf) +{ + if (os_memblock_from(&pool_cmd, buf)) { + return HCI_IPC_TYPE_EVT_IN_CMD; + } else if (os_memblock_from(&pool_evt, buf)) { + return HCI_IPC_TYPE_EVT; + } else if (os_memblock_from(&pool_evt_lo, buf)) { + return HCI_IPC_TYPE_EVT_DISCARDABLE; + } else { + assert(0); + } + return 0; +} +#endif #endif + diff --git a/lib/bt/host/nimble/nimble/nimble/transport/syscfg.yml b/lib/bt/host/nimble/nimble/nimble/transport/syscfg.yml index 03fe37b9..febe09d4 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/syscfg.yml +++ b/lib/bt/host/nimble/nimble/nimble/transport/syscfg.yml @@ -31,6 +31,7 @@ syscfg.defs: - nrf5340 - uart - usb + - cdc - custom BLE_TRANSPORT_LL: description: > @@ -57,7 +58,17 @@ syscfg.defs: value: 10 BLE_TRANSPORT_ACL_SIZE: description: Size of each buffer in ACL pool. - value: 255 + value: 251 + BLE_TRANSPORT_ISO_COUNT: + description: > + Number of ISO buffers available in transport. This determines + number of buffers used by host/controller for flow control. + Buffers pool is allocated for each non-native transport side + selected, unless overriden by BLE_TRANSPORT_ISO_FROM_[HS|LL]_COUNT. + value: 10 + BLE_TRANSPORT_ISO_SIZE: + description: Size of each buffer in ISO pool. + value: 300 BLE_TRANSPORT_EVT_COUNT: description: > Number of event buffers available in transport. @@ -88,10 +99,21 @@ syscfg.defs: of ACL buffers available for controller. value: MYNEWT_VAL(BLE_TRANSPORT_ACL_COUNT) + BLE_TRANSPORT_ISO_FROM_HS_COUNT: + description: > + Overrides BLE_TRANSPORT_ISO_COUNT on host side, i.e. number + of ISO buffers available for host. + value: MYNEWT_VAL(BLE_TRANSPORT_ISO_COUNT) + BLE_TRANSPORT_ISO_FROM_LL_COUNT: + description: > + Overrides BLE_TRANSPORT_ISO_COUNT on controller side, i.e. number + of ISO buffers available for controller. + value: MYNEWT_VAL(BLE_TRANSPORT_ISO_COUNT) + # import monitor and defunct settings from separate file to reduce clutter in main file $import: - "@apache-mynewt-nimble/nimble/transport/syscfg.monitor.yml" - "@apache-mynewt-nimble/nimble/transport/syscfg.defunct.yml" -syscfg.vals."BLE_EXT_ADV || BLE_LL_CFG_FEAT_LL_EXT_ADV": +syscfg.vals.'BLE_EXT_ADV || BLE_LL_CFG_FEAT_LL_EXT_ADV': BLE_TRANSPORT_EVT_SIZE: 257 diff --git a/lib/bt/host/nimble/nimble/nimble/transport/uart/src/hci_uart.c b/lib/bt/host/nimble/nimble/nimble/transport/uart/src/hci_uart.c index 42206f58..af1f45ae 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/uart/src/hci_uart.c +++ b/lib/bt/host/nimble/nimble/nimble/transport/uart/src/hci_uart.c @@ -61,6 +61,8 @@ hci_uart_frame_cb(uint8_t pkt_type, void *data) return ble_transport_to_ll_cmd(data); case HCI_H4_ACL: return ble_transport_to_ll_acl(data); + case HCI_H4_ISO: + return ble_transport_to_ll_iso(data); default: assert(0); break; @@ -227,6 +229,34 @@ ble_transport_to_hs_acl_impl(struct os_mbuf *om) return 0; } +int +ble_transport_to_hs_iso_impl(struct os_mbuf *om) +{ + struct hci_uart_tx *txe; + os_sr_t sr; + + txe = os_memblock_get(&pool_tx_q); + if (!txe) { + assert(0); + return -ENOMEM; + } + + txe->type = HCI_H4_ISO; + txe->sent_type = 0; + txe->len = OS_MBUF_PKTLEN(om); + txe->idx = 0; + txe->buf = NULL; + txe->om = om; + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&tx_q, txe, tx_q_next); + OS_EXIT_CRITICAL(sr); + + hal_uart_start_tx(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT)); + + return 0; +} + void ble_transport_hs_init(void) { diff --git a/lib/bt/host/nimble/nimble/nimble/transport/usb/syscfg.yml b/lib/bt/host/nimble/nimble/nimble/transport/usb/syscfg.yml index 2cdd5746..614f6437 100644 --- a/lib/bt/host/nimble/nimble/nimble/transport/usb/syscfg.yml +++ b/lib/bt/host/nimble/nimble/nimble/transport/usb/syscfg.yml @@ -17,3 +17,6 @@ # syscfg.defs: + +syscfg.vals: + USBD_BTH: 1 diff --git a/lib/bt/host/nimble/nimble/porting/examples/linux/README.md b/lib/bt/host/nimble/nimble/porting/examples/linux/README.md index bbf68bb5..562da266 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/linux/README.md +++ b/lib/bt/host/nimble/nimble/porting/examples/linux/README.md @@ -59,7 +59,7 @@ in sysconfig.h to use hci0. ```no-highlight cd porting/examples/linux - sudo ./_build/nimble_linux.out + sudo ./nimble-linux ``` 3. Build and run the unit tests @@ -68,6 +68,6 @@ The Operating System Abstraction Layer (OSAL) used to port Nimble to Linux has a suite of unit tests. ```no-highlight - cd tests/unit/porting/npl + cd porting/npl/linux/test make test ``` diff --git a/lib/bt/host/nimble/nimble/porting/examples/linux/include/logcfg/logcfg.h b/lib/bt/host/nimble/nimble/porting/examples/linux/include/logcfg/logcfg.h index fab4d812..89af3530 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/linux/include/logcfg/logcfg.h +++ b/lib/bt/host/nimble/nimble/porting/examples/linux/include/logcfg/logcfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_LOGCFG_ diff --git a/lib/bt/host/nimble/nimble/porting/examples/linux/include/syscfg/syscfg.h b/lib/bt/host/nimble/nimble/porting/examples/linux/include/syscfg/syscfg.h index a522cea0..d089d7e6 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/linux/include/syscfg/syscfg.h +++ b/lib/bt/host/nimble/nimble/porting/examples/linux/include/syscfg/syscfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_SYSCFG_ @@ -20,7 +20,7 @@ #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME -#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME ("trng") +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME "trng" #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG @@ -315,7 +315,7 @@ #endif #ifndef MYNEWT_VAL_CONSOLE_UART_DEV -#define MYNEWT_VAL_CONSOLE_UART_DEV ("uart0") +#define MYNEWT_VAL_CONSOLE_UART_DEV "uart0" #endif #ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL @@ -430,6 +430,10 @@ #endif /*** @apache-mynewt-nimble/nimble */ +#ifndef MYNEWT_VAL_BLE_CONN_SUBRATING +#define MYNEWT_VAL_BLE_CONN_SUBRATING (0) +#endif + #ifndef MYNEWT_VAL_BLE_EXT_ADV #define MYNEWT_VAL_BLE_EXT_ADV (0) #endif @@ -478,6 +482,10 @@ #define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) #endif +#ifndef MYNEWT_VAL_BLE_POWER_CONTROL +#define MYNEWT_VAL_BLE_POWER_CONTROL (0) +#endif + #ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER #define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) #endif @@ -502,10 +510,6 @@ #define MYNEWT_VAL_BLE_WHITELIST (1) #endif -#ifndef MYNEWT_VAL_BLE_POWER_CONTROL -#define MYNEWT_VAL_BLE_POWER_CONTROL (0) -#endif - /*** @apache-mynewt-nimble/nimble/host */ #ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU #define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) @@ -627,6 +631,10 @@ #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -727,6 +735,10 @@ #define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8) #endif +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT (1) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC #define MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC (0) #endif @@ -751,42 +763,6 @@ #define MYNEWT_VAL_BLE_MESH (0) #endif -#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT -#define MYNEWT_VAL_BLE_MONITOR_RTT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("btmonitor") -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART -#define MYNEWT_VAL_BLE_MONITOR_UART (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE -#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV -#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") -#endif - #ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT #define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) #endif @@ -807,6 +783,10 @@ #define MYNEWT_VAL_BLE_SM_LEGACY (1) #endif +#ifndef MYNEWT_VAL_BLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS #define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) #endif @@ -831,10 +811,6 @@ #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif -#ifndef MYNEWT_VAL_BLE_SM_SC_LVL -#define MYNEWT_VAL_BLE_SM_SC_LVL (0) -#endif - #ifndef MYNEWT_VAL_BLE_SM_SC_ONLY #define MYNEWT_VAL_BLE_SM_SC_ONLY (0) #endif @@ -914,7 +890,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT ("Apache Mynewt NimBLE") +#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT "Apache Mynewt NimBLE" #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM @@ -975,7 +951,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME ("nimble") +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME "nimble" #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH @@ -1046,6 +1022,42 @@ #undef MYNEWT_VAL_BLE_HCI_TRANSPORT +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME "btmonitor" +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV "uart0" +#endif + #ifndef MYNEWT_VAL_BLE_TRANSPORT #define MYNEWT_VAL_BLE_TRANSPORT (1) #endif @@ -1065,7 +1077,7 @@ #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE -#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (255) +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (251) #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT @@ -1076,11 +1088,13 @@ #define MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT (16) #endif -/* Overridden by @apache-mynewt-nimble/nimble/transport (defined by @apache-mynewt-nimble/nimble/transport) */ #ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE -#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (257) +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (70) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__cdc +#define MYNEWT_VAL_BLE_TRANSPORT_HS__cdc (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__custom #define MYNEWT_VAL_BLE_TRANSPORT_HS__custom (0) #endif @@ -1104,12 +1118,18 @@ #endif /* Overridden by @apache-mynewt-nimble/porting/targets/linux (defined by @apache-mynewt-nimble/nimble/transport) */ +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__custom #define MYNEWT_VAL_BLE_TRANSPORT_LL__custom (0) #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac #define MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac (0) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__emspi +#define MYNEWT_VAL_BLE_TRANSPORT_LL__emspi (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__native #define MYNEWT_VAL_BLE_TRANSPORT_LL__native (0) #endif @@ -1162,7 +1182,7 @@ /*** newt */ #ifndef MYNEWT_VAL_APP_NAME -#define MYNEWT_VAL_APP_NAME ("dummy_app") +#define MYNEWT_VAL_APP_NAME "dummy_app" #endif #ifndef MYNEWT_VAL_APP_dummy_app @@ -1170,7 +1190,7 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("sim") +#define MYNEWT_VAL_ARCH_NAME "sim" #endif #ifndef MYNEWT_VAL_ARCH_sim @@ -1178,7 +1198,7 @@ #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("native") +#define MYNEWT_VAL_BSP_NAME "native" #endif #ifndef MYNEWT_VAL_BSP_native @@ -1194,11 +1214,56 @@ #endif #ifndef MYNEWT_VAL_TARGET_NAME -#define MYNEWT_VAL_TARGET_NAME ("linux") +#define MYNEWT_VAL_TARGET_NAME "linux" #endif #ifndef MYNEWT_VAL_TARGET_linux #define MYNEWT_VAL_TARGET_linux (1) #endif +/*** Included packages */ +#define MYNEWT_PKG_apache_mynewt_core__compiler_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_bsp_native 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash_ef_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng_trng_sw 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart_uart_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_native 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_os 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_mn_socket 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_native_sockets 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_console_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_defs 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_flash_map 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_common 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_modlog 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_stats_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sys 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysdown 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysinit 1 +#define MYNEWT_PKG_apache_mynewt_core__util_mem 1 +#define MYNEWT_PKG_apache_mynewt_core__util_rwlock 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ans 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_bas 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_dis 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gap 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gatt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ias 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ipss 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_lls 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_tps 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_socket 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_npl_mynewt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_dummy_app 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_linux 1 + #endif diff --git a/lib/bt/host/nimble/nimble/porting/examples/linux/include/sysflash/sysflash.h b/lib/bt/host/nimble/nimble/porting/examples/linux/include/sysflash/sysflash.h index 28391ca6..8d358ac9 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/linux/include/sysflash/sysflash.h +++ b/lib/bt/host/nimble/nimble/porting/examples/linux/include/sysflash/sysflash.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_SYSFLASH_ @@ -15,10 +15,33 @@ extern const struct flash_area sysflash_map_dflt[6]; #define FLASH_AREA_BOOTLOADER 0 +#define FLASH_AREA_BOOTLOADER_DEVICE 0 +#define FLASH_AREA_BOOTLOADER_OFFSET 0x00000000 +#define FLASH_AREA_BOOTLOADER_SIZE 16384 + #define FLASH_AREA_IMAGE_0 1 +#define FLASH_AREA_IMAGE_0_DEVICE 0 +#define FLASH_AREA_IMAGE_0_OFFSET 0x00020000 +#define FLASH_AREA_IMAGE_0_SIZE 393216 + #define FLASH_AREA_IMAGE_1 2 +#define FLASH_AREA_IMAGE_1_DEVICE 0 +#define FLASH_AREA_IMAGE_1_OFFSET 0x00080000 +#define FLASH_AREA_IMAGE_1_SIZE 393216 + #define FLASH_AREA_IMAGE_SCRATCH 3 +#define FLASH_AREA_IMAGE_SCRATCH_DEVICE 0 +#define FLASH_AREA_IMAGE_SCRATCH_OFFSET 0x000e0000 +#define FLASH_AREA_IMAGE_SCRATCH_SIZE 131072 + #define FLASH_AREA_REBOOT_LOG 16 +#define FLASH_AREA_REBOOT_LOG_DEVICE 0 +#define FLASH_AREA_REBOOT_LOG_OFFSET 0x00004000 +#define FLASH_AREA_REBOOT_LOG_SIZE 16384 + #define FLASH_AREA_NFFS 17 +#define FLASH_AREA_NFFS_DEVICE 0 +#define FLASH_AREA_NFFS_OFFSET 0x00008000 +#define FLASH_AREA_NFFS_SIZE 32768 #endif diff --git a/lib/bt/host/nimble/nimble/porting/examples/linux/main.c b/lib/bt/host/nimble/nimble/porting/examples/linux/main.c index 7ffed49f..c39b927c 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/linux/main.c +++ b/lib/bt/host/nimble/nimble/porting/examples/linux/main.c @@ -39,6 +39,7 @@ void nimble_host_task(void *param); void ble_hci_sock_ack_handler(void *param); void ble_hci_sock_init(void); void ble_hci_sock_set_device(int dev); +void ble_store_ram_init(void); #define TASK_DEFAULT_PRIORITY 1 #define TASK_DEFAULT_STACK NULL diff --git a/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/ble.c b/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/ble.c index 7a64eac9..277481d2 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/ble.c +++ b/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/ble.c @@ -54,7 +54,7 @@ fault_get_cur(struct bt_mesh_model *model, *test_id = recent_test_id; *company_id = CID_VENDOR; - *fault_count = min(*fault_count, sizeof(reg_faults)); + *fault_count = MIN(*fault_count, sizeof(reg_faults)); memcpy(faults, reg_faults, *fault_count); return 0; @@ -78,7 +78,7 @@ fault_get_reg(struct bt_mesh_model *model, if (has_reg_fault) { uint8_t reg_faults[FAULT_ARR_SIZE] = { [0 ... FAULT_ARR_SIZE-1] = 0xff }; - *fault_count = min(*fault_count, sizeof(reg_faults)); + *fault_count = MIN(*fault_count, sizeof(reg_faults)); memcpy(faults, reg_faults, *fault_count); } else { *fault_count = 0; diff --git a/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/logcfg/logcfg.h b/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/logcfg/logcfg.h index c3b5cdf4..520c658c 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/logcfg/logcfg.h +++ b/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/logcfg/logcfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_LOGCFG_ diff --git a/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/syscfg/syscfg.h b/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/syscfg/syscfg.h index 9fb4f3f1..1df8abaf 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/syscfg/syscfg.h +++ b/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/syscfg/syscfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_SYSCFG_ @@ -20,7 +20,7 @@ #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME -#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME ("trng") +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME "trng" #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG @@ -316,7 +316,7 @@ #endif #ifndef MYNEWT_VAL_CONSOLE_UART_DEV -#define MYNEWT_VAL_CONSOLE_UART_DEV ("uart0") +#define MYNEWT_VAL_CONSOLE_UART_DEV "uart0" #endif #ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL @@ -431,6 +431,10 @@ #endif /*** @apache-mynewt-nimble/nimble */ +#ifndef MYNEWT_VAL_BLE_CONN_SUBRATING +#define MYNEWT_VAL_BLE_CONN_SUBRATING (0) +#endif + #ifndef MYNEWT_VAL_BLE_EXT_ADV #define MYNEWT_VAL_BLE_EXT_ADV (0) #endif @@ -479,6 +483,10 @@ #define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) #endif +#ifndef MYNEWT_VAL_BLE_POWER_CONTROL +#define MYNEWT_VAL_BLE_POWER_CONTROL (0) +#endif + #ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER #define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) #endif @@ -503,10 +511,6 @@ #define MYNEWT_VAL_BLE_WHITELIST (1) #endif -#ifndef MYNEWT_VAL_BLE_POWER_CONTROL -#define MYNEWT_VAL_BLE_POWER_CONTROL (0) -#endif - /*** @apache-mynewt-nimble/nimble/host */ #ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU #define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) @@ -628,6 +632,10 @@ #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -728,6 +736,10 @@ #define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8) #endif +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT (1) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC #define MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC (0) #endif @@ -753,42 +765,6 @@ #define MYNEWT_VAL_BLE_MESH (1) #endif -#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT -#define MYNEWT_VAL_BLE_MONITOR_RTT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("btmonitor") -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART -#define MYNEWT_VAL_BLE_MONITOR_UART (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE -#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV -#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") -#endif - #ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT #define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) #endif @@ -809,6 +785,10 @@ #define MYNEWT_VAL_BLE_SM_LEGACY (1) #endif +#ifndef MYNEWT_VAL_BLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS #define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) #endif @@ -834,10 +814,6 @@ #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif -#ifndef MYNEWT_VAL_BLE_SM_SC_LVL -#define MYNEWT_VAL_BLE_SM_SC_LVL (0) -#endif - #ifndef MYNEWT_VAL_BLE_SM_SC_ONLY #define MYNEWT_VAL_BLE_SM_SC_ONLY (0) #endif @@ -971,7 +947,7 @@ #endif #ifndef MYNEWT_VAL_BLE_MESH_DEVICE_NAME -#define MYNEWT_VAL_BLE_MESH_DEVICE_NAME ("nimble-mesh-node") +#define MYNEWT_VAL_BLE_MESH_DEVICE_NAME "nimble-mesh-node" #endif #ifndef MYNEWT_VAL_BLE_MESH_DEV_UUID @@ -1489,7 +1465,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT ("Apache Mynewt NimBLE") +#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT "Apache Mynewt NimBLE" #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM @@ -1550,7 +1526,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME ("nimble") +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME "nimble" #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH @@ -1621,6 +1597,42 @@ #undef MYNEWT_VAL_BLE_HCI_TRANSPORT +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME "btmonitor" +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV "uart0" +#endif + #ifndef MYNEWT_VAL_BLE_TRANSPORT #define MYNEWT_VAL_BLE_TRANSPORT (1) #endif @@ -1640,7 +1652,7 @@ #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE -#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (255) +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (251) #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT @@ -1651,11 +1663,13 @@ #define MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT (16) #endif -/* Overridden by @apache-mynewt-nimble/nimble/transport (defined by @apache-mynewt-nimble/nimble/transport) */ #ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE -#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (257) +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (70) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__cdc +#define MYNEWT_VAL_BLE_TRANSPORT_HS__cdc (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__custom #define MYNEWT_VAL_BLE_TRANSPORT_HS__custom (0) #endif @@ -1679,12 +1693,18 @@ #endif /* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/transport) */ +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__custom #define MYNEWT_VAL_BLE_TRANSPORT_LL__custom (0) #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac #define MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac (0) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__emspi +#define MYNEWT_VAL_BLE_TRANSPORT_LL__emspi (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__native #define MYNEWT_VAL_BLE_TRANSPORT_LL__native (0) #endif @@ -1737,7 +1757,7 @@ /*** newt */ #ifndef MYNEWT_VAL_APP_NAME -#define MYNEWT_VAL_APP_NAME ("dummy_app") +#define MYNEWT_VAL_APP_NAME "dummy_app" #endif #ifndef MYNEWT_VAL_APP_dummy_app @@ -1745,7 +1765,7 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("sim") +#define MYNEWT_VAL_ARCH_NAME "sim" #endif #ifndef MYNEWT_VAL_ARCH_sim @@ -1753,7 +1773,7 @@ #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("native") +#define MYNEWT_VAL_BSP_NAME "native" #endif #ifndef MYNEWT_VAL_BSP_native @@ -1769,11 +1789,57 @@ #endif #ifndef MYNEWT_VAL_TARGET_NAME -#define MYNEWT_VAL_TARGET_NAME ("linux_blemesh") +#define MYNEWT_VAL_TARGET_NAME "linux_blemesh" #endif #ifndef MYNEWT_VAL_TARGET_linux_blemesh #define MYNEWT_VAL_TARGET_linux_blemesh (1) #endif +/*** Included packages */ +#define MYNEWT_PKG_apache_mynewt_core__compiler_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_bsp_native 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash_ef_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng_trng_sw 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart_uart_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_native 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_os 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_mn_socket 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_native_sockets 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_console_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_defs 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_flash_map 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_common 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_modlog 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_stats_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sys 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysdown 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysinit 1 +#define MYNEWT_PKG_apache_mynewt_core__util_mem 1 +#define MYNEWT_PKG_apache_mynewt_core__util_rwlock 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_mesh 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ans 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_bas 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_dis 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gap 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gatt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ias 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ipss 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_lls 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_tps 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_socket 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_npl_mynewt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_dummy_app 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_linux_blemesh 1 + #endif diff --git a/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/sysflash/sysflash.h b/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/sysflash/sysflash.h index 28391ca6..8d358ac9 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/sysflash/sysflash.h +++ b/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/include/sysflash/sysflash.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_SYSFLASH_ @@ -15,10 +15,33 @@ extern const struct flash_area sysflash_map_dflt[6]; #define FLASH_AREA_BOOTLOADER 0 +#define FLASH_AREA_BOOTLOADER_DEVICE 0 +#define FLASH_AREA_BOOTLOADER_OFFSET 0x00000000 +#define FLASH_AREA_BOOTLOADER_SIZE 16384 + #define FLASH_AREA_IMAGE_0 1 +#define FLASH_AREA_IMAGE_0_DEVICE 0 +#define FLASH_AREA_IMAGE_0_OFFSET 0x00020000 +#define FLASH_AREA_IMAGE_0_SIZE 393216 + #define FLASH_AREA_IMAGE_1 2 +#define FLASH_AREA_IMAGE_1_DEVICE 0 +#define FLASH_AREA_IMAGE_1_OFFSET 0x00080000 +#define FLASH_AREA_IMAGE_1_SIZE 393216 + #define FLASH_AREA_IMAGE_SCRATCH 3 +#define FLASH_AREA_IMAGE_SCRATCH_DEVICE 0 +#define FLASH_AREA_IMAGE_SCRATCH_OFFSET 0x000e0000 +#define FLASH_AREA_IMAGE_SCRATCH_SIZE 131072 + #define FLASH_AREA_REBOOT_LOG 16 +#define FLASH_AREA_REBOOT_LOG_DEVICE 0 +#define FLASH_AREA_REBOOT_LOG_OFFSET 0x00004000 +#define FLASH_AREA_REBOOT_LOG_SIZE 16384 + #define FLASH_AREA_NFFS 17 +#define FLASH_AREA_NFFS_DEVICE 0 +#define FLASH_AREA_NFFS_OFFSET 0x00008000 +#define FLASH_AREA_NFFS_SIZE 32768 #endif diff --git a/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/main.c b/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/main.c index b90477db..064a12f9 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/main.c +++ b/lib/bt/host/nimble/nimble/porting/examples/linux_blemesh/main.c @@ -38,6 +38,8 @@ static struct ble_npl_task s_task_mesh_adv; void nimble_host_task(void *param); void ble_hci_sock_ack_handler(void *param); void ble_hci_sock_init(void); +void ble_hci_sock_set_device(int dev); +void ble_store_ram_init(void); #define TASK_DEFAULT_PRIORITY 1 #define TASK_DEFAULT_STACK NULL diff --git a/lib/bt/host/nimble/nimble/porting/examples/nuttx/Make.defs b/lib/bt/host/nimble/nimble/porting/examples/nuttx/Make.defs index f35d428e..94a2a3e1 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/nuttx/Make.defs +++ b/lib/bt/host/nimble/nimble/porting/examples/nuttx/Make.defs @@ -48,8 +48,7 @@ INC = \ INCLUDES := $(addprefix -I, $(INC)) -CFLAGS += \ - $(NIMBLE_CFLAGS) \ +CFLAGS += \ $(INCLUDES) \ $(TINYCRYPT_CFLAGS) \ -DNIMBLE_CFG_CONTROLLER=0 -DOS_CFG_ALIGN_4=4 -DOS_CFG_ALIGNMENT=4 \ diff --git a/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/logcfg/logcfg.h b/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/logcfg/logcfg.h index fab4d812..89af3530 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/logcfg/logcfg.h +++ b/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/logcfg/logcfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_LOGCFG_ diff --git a/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/syscfg/syscfg.h b/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/syscfg/syscfg.h index c2f2d89d..51f8c44b 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/syscfg/syscfg.h +++ b/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/syscfg/syscfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_SYSCFG_ @@ -20,7 +20,7 @@ #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME -#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME ("trng") +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME "trng" #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG @@ -315,7 +315,7 @@ #endif #ifndef MYNEWT_VAL_CONSOLE_UART_DEV -#define MYNEWT_VAL_CONSOLE_UART_DEV ("uart0") +#define MYNEWT_VAL_CONSOLE_UART_DEV "uart0" #endif #ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL @@ -430,6 +430,10 @@ #endif /*** @apache-mynewt-nimble/nimble */ +#ifndef MYNEWT_VAL_BLE_CONN_SUBRATING +#define MYNEWT_VAL_BLE_CONN_SUBRATING (0) +#endif + #ifndef MYNEWT_VAL_BLE_EXT_ADV #define MYNEWT_VAL_BLE_EXT_ADV (0) #endif @@ -478,6 +482,10 @@ #define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) #endif +#ifndef MYNEWT_VAL_BLE_POWER_CONTROL +#define MYNEWT_VAL_BLE_POWER_CONTROL (0) +#endif + #ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER #define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) #endif @@ -502,10 +510,6 @@ #define MYNEWT_VAL_BLE_WHITELIST (1) #endif -#ifndef MYNEWT_VAL_BLE_POWER_CONTROL -#define MYNEWT_VAL_BLE_POWER_CONTROL (0) -#endif - /*** @apache-mynewt-nimble/nimble/host */ #ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU #define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) @@ -627,6 +631,10 @@ #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -727,6 +735,10 @@ #define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8) #endif +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT (1) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC #define MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC (0) #endif @@ -751,42 +763,6 @@ #define MYNEWT_VAL_BLE_MESH (0) #endif -#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT -#define MYNEWT_VAL_BLE_MONITOR_RTT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("btmonitor") -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART -#define MYNEWT_VAL_BLE_MONITOR_UART (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE -#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV -#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") -#endif - #ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT #define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) #endif @@ -808,6 +784,10 @@ #define MYNEWT_VAL_BLE_SM_LEGACY (1) #endif +#ifndef MYNEWT_VAL_BLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS #define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) #endif @@ -833,10 +813,6 @@ #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif -#ifndef MYNEWT_VAL_BLE_SM_SC_LVL -#define MYNEWT_VAL_BLE_SM_SC_LVL (0) -#endif - #ifndef MYNEWT_VAL_BLE_SM_SC_ONLY #define MYNEWT_VAL_BLE_SM_SC_ONLY (0) #endif @@ -916,7 +892,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT ("Apache Mynewt NimBLE") +#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT "Apache Mynewt NimBLE" #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM @@ -977,7 +953,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME ("nimble") +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME "nimble" #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH @@ -1048,6 +1024,42 @@ #undef MYNEWT_VAL_BLE_HCI_TRANSPORT +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME "btmonitor" +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV "uart0" +#endif + #ifndef MYNEWT_VAL_BLE_TRANSPORT #define MYNEWT_VAL_BLE_TRANSPORT (1) #endif @@ -1067,7 +1079,7 @@ #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE -#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (255) +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (251) #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT @@ -1078,11 +1090,13 @@ #define MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT (16) #endif -/* Overridden by @apache-mynewt-nimble/nimble/transport (defined by @apache-mynewt-nimble/nimble/transport) */ #ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE -#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (257) +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (70) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__cdc +#define MYNEWT_VAL_BLE_TRANSPORT_HS__cdc (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__custom #define MYNEWT_VAL_BLE_TRANSPORT_HS__custom (0) #endif @@ -1106,12 +1120,18 @@ #endif /* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-nimble/nimble/transport) */ +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__custom #define MYNEWT_VAL_BLE_TRANSPORT_LL__custom (0) #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac #define MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac (0) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__emspi +#define MYNEWT_VAL_BLE_TRANSPORT_LL__emspi (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__native #define MYNEWT_VAL_BLE_TRANSPORT_LL__native (0) #endif @@ -1164,7 +1184,7 @@ /*** newt */ #ifndef MYNEWT_VAL_APP_NAME -#define MYNEWT_VAL_APP_NAME ("dummy_app") +#define MYNEWT_VAL_APP_NAME "dummy_app" #endif #ifndef MYNEWT_VAL_APP_dummy_app @@ -1172,7 +1192,7 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("sim") +#define MYNEWT_VAL_ARCH_NAME "sim" #endif #ifndef MYNEWT_VAL_ARCH_sim @@ -1180,7 +1200,7 @@ #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("native") +#define MYNEWT_VAL_BSP_NAME "native" #endif #ifndef MYNEWT_VAL_BSP_native @@ -1196,11 +1216,56 @@ #endif #ifndef MYNEWT_VAL_TARGET_NAME -#define MYNEWT_VAL_TARGET_NAME ("nuttx") +#define MYNEWT_VAL_TARGET_NAME "nuttx" #endif #ifndef MYNEWT_VAL_TARGET_nuttx #define MYNEWT_VAL_TARGET_nuttx (1) #endif +/*** Included packages */ +#define MYNEWT_PKG_apache_mynewt_core__compiler_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_bsp_native 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash_ef_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng_trng_sw 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart_uart_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_native 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_os 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_mn_socket 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_native_sockets 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_console_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_defs 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_flash_map 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_common 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_modlog 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_stats_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sys 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysdown 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysinit 1 +#define MYNEWT_PKG_apache_mynewt_core__util_mem 1 +#define MYNEWT_PKG_apache_mynewt_core__util_rwlock 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ans 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_bas 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_dis 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gap 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gatt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ias 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ipss 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_lls 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_tps 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_socket 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_npl_mynewt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_dummy_app 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_nuttx 1 + #endif diff --git a/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/sysflash/sysflash.h b/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/sysflash/sysflash.h index 28391ca6..8d358ac9 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/sysflash/sysflash.h +++ b/lib/bt/host/nimble/nimble/porting/examples/nuttx/include/sysflash/sysflash.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_SYSFLASH_ @@ -15,10 +15,33 @@ extern const struct flash_area sysflash_map_dflt[6]; #define FLASH_AREA_BOOTLOADER 0 +#define FLASH_AREA_BOOTLOADER_DEVICE 0 +#define FLASH_AREA_BOOTLOADER_OFFSET 0x00000000 +#define FLASH_AREA_BOOTLOADER_SIZE 16384 + #define FLASH_AREA_IMAGE_0 1 +#define FLASH_AREA_IMAGE_0_DEVICE 0 +#define FLASH_AREA_IMAGE_0_OFFSET 0x00020000 +#define FLASH_AREA_IMAGE_0_SIZE 393216 + #define FLASH_AREA_IMAGE_1 2 +#define FLASH_AREA_IMAGE_1_DEVICE 0 +#define FLASH_AREA_IMAGE_1_OFFSET 0x00080000 +#define FLASH_AREA_IMAGE_1_SIZE 393216 + #define FLASH_AREA_IMAGE_SCRATCH 3 +#define FLASH_AREA_IMAGE_SCRATCH_DEVICE 0 +#define FLASH_AREA_IMAGE_SCRATCH_OFFSET 0x000e0000 +#define FLASH_AREA_IMAGE_SCRATCH_SIZE 131072 + #define FLASH_AREA_REBOOT_LOG 16 +#define FLASH_AREA_REBOOT_LOG_DEVICE 0 +#define FLASH_AREA_REBOOT_LOG_OFFSET 0x00004000 +#define FLASH_AREA_REBOOT_LOG_SIZE 16384 + #define FLASH_AREA_NFFS 17 +#define FLASH_AREA_NFFS_DEVICE 0 +#define FLASH_AREA_NFFS_OFFSET 0x00008000 +#define FLASH_AREA_NFFS_SIZE 32768 #endif diff --git a/lib/bt/host/nimble/nimble/porting/examples/nuttx/main.c b/lib/bt/host/nimble/nimble/porting/examples/nuttx/main.c index c94dce73..d2a2344e 100644 --- a/lib/bt/host/nimble/nimble/porting/examples/nuttx/main.c +++ b/lib/bt/host/nimble/nimble/porting/examples/nuttx/main.c @@ -22,9 +22,12 @@ #include #include #include +#include +#include +#include +#include "netutils/netinit.h" -#include #include "nimble/nimble_npl.h" #include "nimble/nimble_port.h" @@ -71,6 +74,18 @@ int main(int argc, char *argv[]) ble_hci_sock_set_device(atoi(argv[1])); } +#ifndef CONFIG_NSH_ARCHINIT + /* Perform architecture-specific initialization */ + + boardctl(BOARDIOC_INIT, 0); +#endif + +#ifndef CONFIG_NSH_NETINIT + /* Bring up the network */ + + netinit_bringup(); +#endif + printf("port init\n"); ret = nimble_port_init(); @@ -101,8 +116,8 @@ int main(int argc, char *argv[]) printf("hci_sock task init\n"); ret = ble_npl_task_init(&s_task_hci, "hci_sock", ble_hci_sock_task, - NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, - TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); if (ret != 0) { @@ -112,8 +127,8 @@ int main(int argc, char *argv[]) /* Create task which handles default event queue for host stack. */ printf("ble_host task init\n"); ret = ble_npl_task_init(&s_task_host, "ble_host", ble_host_task, - NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, - TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); if (ret != 0) diff --git a/lib/bt/host/nimble/nimble/porting/nimble/include/logcfg/logcfg.h b/lib/bt/host/nimble/nimble/porting/nimble/include/logcfg/logcfg.h index 8ac736cf..f2f227c8 100644 --- a/lib/bt/host/nimble/nimble/porting/nimble/include/logcfg/logcfg.h +++ b/lib/bt/host/nimble/nimble/porting/nimble/include/logcfg/logcfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_LOGCFG_ diff --git a/lib/bt/host/nimble/nimble/porting/nimble/include/os/os.h b/lib/bt/host/nimble/nimble/porting/nimble/include/os/os.h index 64800956..ec495df9 100644 --- a/lib/bt/host/nimble/nimble/porting/nimble/include/os/os.h +++ b/lib/bt/host/nimble/nimble/porting/nimble/include/os/os.h @@ -30,6 +30,14 @@ extern "C" { #define static_assert _Static_assert #endif +#ifndef min +#define min(a, b) ((a)<(b)?(a):(b)) +#endif + +#ifndef max +#define max(a, b) ((a)>(b)?(a):(b)) +#endif + #include "syscfg/syscfg.h" #include "nimble/nimble_npl.h" diff --git a/lib/bt/host/nimble/nimble/porting/nimble/include/os/os_mbuf.h b/lib/bt/host/nimble/nimble/porting/nimble/include/os/os_mbuf.h index e6fd6b90..83e16c4c 100644 --- a/lib/bt/host/nimble/nimble/porting/nimble/include/os/os_mbuf.h +++ b/lib/bt/host/nimble/nimble/porting/nimble/include/os/os_mbuf.h @@ -139,12 +139,13 @@ struct os_mqueue { ((__om)->om_pkthdr_len >= sizeof (struct os_mbuf_pkthdr)) /** Get a packet header pointer given an mbuf pointer */ -#define OS_MBUF_PKTHDR(__om) ((struct os_mbuf_pkthdr *) \ - (void *)((uint8_t *)&(__om)->om_data + sizeof(struct os_mbuf))) +#define OS_MBUF_PKTHDR(__om) ((struct os_mbuf_pkthdr *)(uintptr_t) \ + (void *)((uint8_t *)&(__om)->om_data \ + + sizeof(struct os_mbuf))) /** Given a mbuf packet header pointer, return a pointer to the mbuf */ #define OS_MBUF_PKTHDR_TO_MBUF(__hdr) \ - (struct os_mbuf *)(void *)((uint8_t *)(__hdr) - sizeof(struct os_mbuf)) + (struct os_mbuf *)(uintptr_t)((uint8_t *)(__hdr) - sizeof(struct os_mbuf)) /** * Gets the length of an entire mbuf chain. The specified mbuf must have a diff --git a/lib/bt/host/nimble/nimble/porting/nimble/include/syscfg/syscfg.h b/lib/bt/host/nimble/nimble/porting/nimble/include/syscfg/syscfg.h index cdd2db3c..cc8a60b3 100644 --- a/lib/bt/host/nimble/nimble/porting/nimble/include/syscfg/syscfg.h +++ b/lib/bt/host/nimble/nimble/porting/nimble/include/syscfg/syscfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_SYSCFG_ @@ -24,7 +24,7 @@ #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME -#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME ("trng") +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME "trng" #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG @@ -319,7 +319,7 @@ #endif #ifndef MYNEWT_VAL_CONSOLE_UART_DEV -#define MYNEWT_VAL_CONSOLE_UART_DEV ("uart0") +#define MYNEWT_VAL_CONSOLE_UART_DEV "uart0" #endif #ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL @@ -433,6 +433,10 @@ #endif /*** @apache-mynewt-nimble/nimble */ +#ifndef MYNEWT_VAL_BLE_CONN_SUBRATING +#define MYNEWT_VAL_BLE_CONN_SUBRATING (0) +#endif + #ifndef MYNEWT_VAL_BLE_EXT_ADV #define MYNEWT_VAL_BLE_EXT_ADV (0) #endif @@ -481,6 +485,10 @@ #define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) #endif +#ifndef MYNEWT_VAL_BLE_POWER_CONTROL +#define MYNEWT_VAL_BLE_POWER_CONTROL (0) +#endif + #ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER #define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) #endif @@ -505,10 +513,6 @@ #define MYNEWT_VAL_BLE_WHITELIST (1) #endif -#ifndef MYNEWT_VAL_BLE_POWER_CONTROL -#define MYNEWT_VAL_BLE_POWER_CONTROL (0) -#endif - /*** @apache-mynewt-nimble/nimble/host */ #ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU #define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) @@ -630,6 +634,10 @@ #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -730,6 +738,10 @@ #define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8) #endif +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT (1) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC #define MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC (0) #endif @@ -754,42 +766,6 @@ #define MYNEWT_VAL_BLE_MESH (1) #endif -#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT -#define MYNEWT_VAL_BLE_MONITOR_RTT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("btmonitor") -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART -#define MYNEWT_VAL_BLE_MONITOR_UART (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE -#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV -#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") -#endif - #ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT #define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) #endif @@ -810,6 +786,10 @@ #define MYNEWT_VAL_BLE_SM_LEGACY (1) #endif +#ifndef MYNEWT_VAL_BLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS #define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) #endif @@ -834,10 +814,6 @@ #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif -#ifndef MYNEWT_VAL_BLE_SM_SC_LVL -#define MYNEWT_VAL_BLE_SM_SC_LVL (0) -#endif - #ifndef MYNEWT_VAL_BLE_SM_SC_ONLY #define MYNEWT_VAL_BLE_SM_SC_ONLY (0) #endif @@ -1229,7 +1205,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT ("Apache Mynewt NimBLE") +#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT "Apache Mynewt NimBLE" #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM @@ -1290,7 +1266,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME ("nimble") +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME "nimble" #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH @@ -1361,6 +1337,42 @@ #undef MYNEWT_VAL_BLE_HCI_TRANSPORT +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME "btmonitor" +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV "uart0" +#endif + #ifndef MYNEWT_VAL_BLE_TRANSPORT #define MYNEWT_VAL_BLE_TRANSPORT (1) #endif @@ -1380,7 +1392,7 @@ #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE -#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (255) +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (251) #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT @@ -1395,11 +1407,13 @@ #define MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT (16) #endif -/* Overridden by @apache-mynewt-nimble/nimble/transport (defined by @apache-mynewt-nimble/nimble/transport) */ #ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE -#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (257) +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (70) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__cdc +#define MYNEWT_VAL_BLE_TRANSPORT_HS__cdc (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__custom #define MYNEWT_VAL_BLE_TRANSPORT_HS__custom (0) #endif @@ -1423,12 +1437,18 @@ #endif /* Overridden by @apache-mynewt-nimble/porting/targets/porting_default (defined by @apache-mynewt-nimble/nimble/transport) */ +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__custom #define MYNEWT_VAL_BLE_TRANSPORT_LL__custom (0) #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac #define MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac (0) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__emspi +#define MYNEWT_VAL_BLE_TRANSPORT_LL__emspi (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__native #define MYNEWT_VAL_BLE_TRANSPORT_LL__native (0) #endif @@ -1479,7 +1499,7 @@ /*** newt */ #ifndef MYNEWT_VAL_APP_NAME -#define MYNEWT_VAL_APP_NAME ("dummy_app") +#define MYNEWT_VAL_APP_NAME "dummy_app" #endif #ifndef MYNEWT_VAL_APP_dummy_app @@ -1487,7 +1507,7 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("sim") +#define MYNEWT_VAL_ARCH_NAME "sim" #endif #ifndef MYNEWT_VAL_ARCH_sim @@ -1495,7 +1515,7 @@ #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("native") +#define MYNEWT_VAL_BSP_NAME "native" #endif #ifndef MYNEWT_VAL_BSP_native @@ -1511,11 +1531,57 @@ #endif #ifndef MYNEWT_VAL_TARGET_NAME -#define MYNEWT_VAL_TARGET_NAME ("porting_default") +#define MYNEWT_VAL_TARGET_NAME "porting_default" #endif #ifndef MYNEWT_VAL_TARGET_porting_default #define MYNEWT_VAL_TARGET_porting_default (1) #endif + +/*** Included packages */ +#define MYNEWT_PKG_apache_mynewt_core__compiler_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_bsp_native 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash_ef_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng_trng_sw 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart_uart_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_native 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_os 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_mn_socket 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_native_sockets 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_console_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_defs 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_flash_map 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_common 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_modlog 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_stats_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sys 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysdown 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysinit 1 +#define MYNEWT_PKG_apache_mynewt_core__util_mem 1 +#define MYNEWT_PKG_apache_mynewt_core__util_rwlock 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ans 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_bas 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_dis 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gap 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gatt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ias 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ipss 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_lls 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_tps 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_socket 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_npl_mynewt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_dummy_app 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_porting_default 1 + #endif #endif diff --git a/lib/bt/host/nimble/nimble/porting/nimble/include/sysflash/sysflash.h b/lib/bt/host/nimble/nimble/porting/nimble/include/sysflash/sysflash.h index 28391ca6..8d358ac9 100644 --- a/lib/bt/host/nimble/nimble/porting/nimble/include/sysflash/sysflash.h +++ b/lib/bt/host/nimble/nimble/porting/nimble/include/sysflash/sysflash.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_SYSFLASH_ @@ -15,10 +15,33 @@ extern const struct flash_area sysflash_map_dflt[6]; #define FLASH_AREA_BOOTLOADER 0 +#define FLASH_AREA_BOOTLOADER_DEVICE 0 +#define FLASH_AREA_BOOTLOADER_OFFSET 0x00000000 +#define FLASH_AREA_BOOTLOADER_SIZE 16384 + #define FLASH_AREA_IMAGE_0 1 +#define FLASH_AREA_IMAGE_0_DEVICE 0 +#define FLASH_AREA_IMAGE_0_OFFSET 0x00020000 +#define FLASH_AREA_IMAGE_0_SIZE 393216 + #define FLASH_AREA_IMAGE_1 2 +#define FLASH_AREA_IMAGE_1_DEVICE 0 +#define FLASH_AREA_IMAGE_1_OFFSET 0x00080000 +#define FLASH_AREA_IMAGE_1_SIZE 393216 + #define FLASH_AREA_IMAGE_SCRATCH 3 +#define FLASH_AREA_IMAGE_SCRATCH_DEVICE 0 +#define FLASH_AREA_IMAGE_SCRATCH_OFFSET 0x000e0000 +#define FLASH_AREA_IMAGE_SCRATCH_SIZE 131072 + #define FLASH_AREA_REBOOT_LOG 16 +#define FLASH_AREA_REBOOT_LOG_DEVICE 0 +#define FLASH_AREA_REBOOT_LOG_OFFSET 0x00004000 +#define FLASH_AREA_REBOOT_LOG_SIZE 16384 + #define FLASH_AREA_NFFS 17 +#define FLASH_AREA_NFFS_DEVICE 0 +#define FLASH_AREA_NFFS_OFFSET 0x00008000 +#define FLASH_AREA_NFFS_SIZE 32768 #endif diff --git a/lib/bt/host/nimble/nimble/porting/nimble/src/hal_timer.c b/lib/bt/host/nimble/nimble/porting/nimble/src/hal_timer.c index 7f6de970..0b6183b7 100644 --- a/lib/bt/host/nimble/nimble/porting/nimble/src/hal_timer.c +++ b/lib/bt/host/nimble/nimble/porting/nimble/src/hal_timer.c @@ -184,7 +184,7 @@ nrf_timer_set_ocmp(struct nrf52_hal_timer *bsptimer, uint32_t expiry) } else { rtctimer->INTENCLR = RTC_INTENCLR_TICK_Msk; - if (delta_t < (1UL << 24)) { + if (delta_t < (1L << 24)) { rtctimer->CC[NRF_RTC_TIMER_CC_INT] = expiry & 0x00ffffff; } else { /* CC too far ahead. Just make sure we set compare far ahead */ @@ -541,7 +541,7 @@ hal_timer_init(int timer_num, void *cfg) #ifndef RIOT_VERSION NVIC_SetPriority(irq_num, (1 << __NVIC_PRIO_BITS) - 1); #endif -#if MYNEWT +#ifdef MYNEWT NVIC_SetVector(irq_num, (uint32_t)irq_isr); #else ble_npl_hw_set_isr(irq_num, irq_isr); diff --git a/lib/bt/host/nimble/nimble/porting/nimble/src/nimble_port.c b/lib/bt/host/nimble/nimble/porting/nimble/src/nimble_port.c index 83b2c845..87059f23 100644 --- a/lib/bt/host/nimble/nimble/porting/nimble/src/nimble_port.c +++ b/lib/bt/host/nimble/nimble/porting/nimble/src/nimble_port.c @@ -44,6 +44,10 @@ #if !CONFIG_BT_CONTROLLER_ENABLED #include "nimble/transport.h" #endif +#if (BT_HCI_LOG_INCLUDED == TRUE) +#include "hci_log/bt_hci_log.h" +#endif // (BT_HCI_LOG_INCLUDED == TRUE) +#include "bt_common.h" #define NIMBLE_PORT_LOG_TAG "BLE_INIT" @@ -181,6 +185,11 @@ nimble_port_init(void) ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); if (ret != ESP_OK) { + // Deinit to free any memory the controller is using. + if(esp_bt_controller_deinit() != ESP_OK) { + ESP_LOGE(NIMBLE_PORT_LOG_TAG, "controller deinit failed\n"); + } + ESP_LOGE(NIMBLE_PORT_LOG_TAG, "controller enable failed\n"); return ret; } @@ -188,10 +197,26 @@ nimble_port_init(void) ret = esp_nimble_init(); if (ret != ESP_OK) { - ESP_LOGE(NIMBLE_PORT_LOG_TAG, "nimble host init failed\n"); + +#if CONFIG_BT_CONTROLLER_ENABLED + // Disable and deinit controller to free memory + if(esp_bt_controller_disable() != ESP_OK) { + ESP_LOGE(NIMBLE_PORT_LOG_TAG, "controller disable failed\n"); + } + + if(esp_bt_controller_deinit() != ESP_OK) { + ESP_LOGE(NIMBLE_PORT_LOG_TAG, "controller deinit failed\n"); + } +#endif + + ESP_LOGE(NIMBLE_PORT_LOG_TAG, "nimble host init failed\n"); return ret; } +#if (BT_HCI_LOG_INCLUDED == TRUE) + bt_hci_log_init(); +#endif // (BT_HCI_LOG_INCLUDED == TRUE) + return ESP_OK; } @@ -226,6 +251,10 @@ nimble_port_deinit(void) } #endif +#if (BT_HCI_LOG_INCLUDED == TRUE) + bt_hci_log_deinit(); +#endif // (BT_HCI_LOG_INCLUDED == TRUE) + return ESP_OK; } diff --git a/lib/bt/host/nimble/nimble/porting/npl/dummy/src/npl_os_dummy.c b/lib/bt/host/nimble/nimble/porting/npl/dummy/src/npl_os_dummy.c index a522531f..059e1a68 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/dummy/src/npl_os_dummy.c +++ b/lib/bt/host/nimble/nimble/porting/npl/dummy/src/npl_os_dummy.c @@ -41,6 +41,7 @@ ble_npl_eventq_init(struct ble_npl_eventq *evq) struct ble_npl_event * ble_npl_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo) { + return NULL; } void diff --git a/lib/bt/host/nimble/nimble/porting/npl/freertos/src/npl_os_freertos.c b/lib/bt/host/nimble/nimble/porting/npl/freertos/src/npl_os_freertos.c index 1e9a88f6..d72f0f6e 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/freertos/src/npl_os_freertos.c +++ b/lib/bt/host/nimble/nimble/porting/npl/freertos/src/npl_os_freertos.c @@ -808,10 +808,9 @@ npl_freertos_callout_deinit(struct ble_npl_callout *co) if(esp_timer_delete(callout->handle)) ESP_LOGW(TAG, "Timer not deleted"); - #else - xTimerDelete(callout->handle, portMAX_DELAY); +#endif #if OS_MEM_ALLOC os_memblock_put(&ble_freertos_co_pool,callout); @@ -819,7 +818,6 @@ npl_freertos_callout_deinit(struct ble_npl_callout *co) free((void *)callout); #endif -#endif co->co = NULL; memset(co, 0, sizeof(struct ble_npl_callout)); } diff --git a/lib/bt/host/nimble/nimble/porting/npl/linux/include/nimble/nimble_npl_os.h b/lib/bt/host/nimble/nimble/porting/npl/linux/include/nimble/nimble_npl_os.h index 585d3785..d171fc04 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/linux/include/nimble/nimble_npl_os.h +++ b/lib/bt/host/nimble/nimble/porting/npl/linux/include/nimble/nimble_npl_os.h @@ -35,15 +35,6 @@ extern "C" { #define BLE_NPL_TIME_FOREVER INT32_MAX -#define SYSINIT_PANIC_MSG(msg) __assert_fail(msg, __FILE__, __LINE__, __func__) - -#define SYSINIT_PANIC_ASSERT_MSG(rc, msg) do \ -{ \ - if (!(rc)) { \ - SYSINIT_PANIC_MSG(msg); \ - } \ -} while (0) - #ifdef __cplusplus } #endif diff --git a/lib/bt/host/nimble/nimble/porting/npl/linux/include/nimble/os_types.h b/lib/bt/host/nimble/nimble/porting/npl/linux/include/nimble/os_types.h index a5d8bf54..aa24745f 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/linux/include/nimble/os_types.h +++ b/lib/bt/host/nimble/nimble/porting/npl/linux/include/nimble/os_types.h @@ -21,7 +21,6 @@ #define _NPL_OS_TYPES_H #include -#include #include #include #include diff --git a/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_atomic.c b/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_atomic.c index 3aaec08a..b01e234b 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_atomic.c +++ b/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_atomic.c @@ -18,14 +18,21 @@ */ #include +#define __USE_GNU #include #include "nimble/nimble_npl.h" -static pthread_mutex_t s_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +static pthread_mutex_t s_mutex = PTHREAD_MUTEX_INITIALIZER; +static uint8_t s_mutex_inited = 0; uint32_t ble_npl_hw_enter_critical(void) { + if( !s_mutex_inited ) { + pthread_mutexattr_settype(&s_mutex, PTHREAD_MUTEX_RECURSIVE); + s_mutex_inited = 1; + } + pthread_mutex_lock(&s_mutex); return 0; } diff --git a/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_mutex.c b/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_mutex.c index c7d6190e..86cad965 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_mutex.c +++ b/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_mutex.c @@ -31,7 +31,7 @@ ble_npl_mutex_init(struct ble_npl_mutex *mu) } pthread_mutexattr_init(&mu->attr); - pthread_mutexattr_settype(&mu->attr, PTHREAD_MUTEX_RECURSIVE_NP); + pthread_mutexattr_settype(&mu->attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&mu->lock, &mu->attr); return BLE_NPL_OK; diff --git a/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_task.c b/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_task.c index fe6c2df1..b03deb06 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_task.c +++ b/lib/bt/host/nimble/nimble/porting/npl/linux/src/os_task.c @@ -17,6 +17,8 @@ * under the License. */ +#include + #include "os/os.h" #include "nimble/nimble_npl.h" @@ -106,7 +108,7 @@ bool ble_npl_os_started(void) void ble_npl_task_yield(void) { - pthread_yield(); + sched_yield(); } #ifdef __cplusplus diff --git a/lib/bt/host/nimble/nimble/porting/npl/linux/src/wqueue.h b/lib/bt/host/nimble/nimble/porting/npl/linux/src/wqueue.h index d9a7b6cc..61540562 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/linux/src/wqueue.h +++ b/lib/bt/host/nimble/nimble/porting/npl/linux/src/wqueue.h @@ -27,7 +27,7 @@ template class wqueue { - list m_queue; + std::list m_queue; pthread_mutex_t m_mutex; pthread_mutexattr_t m_mutex_attr; pthread_cond_t m_condv; diff --git a/lib/bt/host/nimble/nimble/porting/npl/linux/test/Makefile b/lib/bt/host/nimble/nimble/porting/npl/linux/test/Makefile index c0be3d5f..cab378d3 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/linux/test/Makefile +++ b/lib/bt/host/nimble/nimble/porting/npl/linux/test/Makefile @@ -43,11 +43,12 @@ CFLAGS = \ $(INCLUDES) $(DEFINES) \ -g \ -D_GNU_SOURCE \ + -m32 \ $(NULL) LIBS = -lrt -lpthread -lstdc++ -LDFLAGS = +LDFLAGS = -m32 ### ===== Sources ===== @@ -99,7 +100,7 @@ show_objs: ### ===== Clean ===== clean: @echo "Cleaning artifacts." - rm *~ .depend $(OBJS) *.o *.exe + rm -f .depend $(OBJS) *.o *.exe ### ===== Dependencies ===== ### Rebuild if headers change diff --git a/lib/bt/host/nimble/nimble/porting/npl/nuttx/include/nimble/nimble_npl_os.h b/lib/bt/host/nimble/nimble/porting/npl/nuttx/include/nimble/nimble_npl_os.h index 0f765f5a..8a41d411 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/nuttx/include/nimble/nimble_npl_os.h +++ b/lib/bt/host/nimble/nimble/porting/npl/nuttx/include/nimble/nimble_npl_os.h @@ -35,15 +35,6 @@ extern "C" { #define BLE_NPL_TIME_FOREVER INT32_MAX -#define SYSINIT_PANIC_MSG(msg) { fprintf(stderr, "%s\n", msg); abort(); } - -#define SYSINIT_PANIC_ASSERT_MSG(rc, msg) do \ -{ \ - if (!(rc)) { \ - SYSINIT_PANIC_MSG(msg); \ - } \ -} while (0) - #ifdef __cplusplus } #endif diff --git a/lib/bt/host/nimble/nimble/porting/npl/nuttx/src/os_callout.c b/lib/bt/host/nimble/nimble/porting/npl/nuttx/src/os_callout.c index e4580da9..3b4ee5fb 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/nuttx/src/os_callout.c +++ b/lib/bt/host/nimble/nimble/porting/npl/nuttx/src/os_callout.c @@ -44,21 +44,23 @@ callout_handler(pthread_addr_t arg) { struct ble_npl_callout *c; - pthread_mutex_lock(&callout_mutex); - while (!pending_callout) { - pthread_cond_wait(&callout_cond, &callout_mutex); - } - - c = pending_callout; - pending_callout = NULL; - pthread_mutex_unlock(&callout_mutex); - - /* Invoke callback */ - - if (c->c_evq) { - ble_npl_eventq_put(c->c_evq, &c->c_ev); - } else { - c->c_ev.ev_cb(&c->c_ev); + while (true) { + pthread_mutex_lock(&callout_mutex); + while (!pending_callout) { + pthread_cond_wait(&callout_cond, &callout_mutex); + } + + c = pending_callout; + pending_callout = NULL; + pthread_mutex_unlock(&callout_mutex); + + /* Invoke callback */ + + if (c->c_evq) { + ble_npl_eventq_put(c->c_evq, &c->c_ev); + } else { + c->c_ev.ev_cb(&c->c_ev); + } } return NULL; @@ -89,6 +91,7 @@ ble_npl_callout_init(struct ble_npl_callout *c, pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, CONFIG_NIMBLE_CALLOUT_THREAD_STACKSIZE); pthread_create(&callout_thread, &attr, callout_handler, NULL); + pthread_setname_np(callout_thread, "ble_npl_callout"); thread_started = true; } diff --git a/lib/bt/host/nimble/nimble/porting/npl/nuttx/src/os_task.c b/lib/bt/host/nimble/nimble/porting/npl/nuttx/src/os_task.c index 40f8c8c7..075928a7 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/nuttx/src/os_task.c +++ b/lib/bt/host/nimble/nimble/porting/npl/nuttx/src/os_task.c @@ -77,6 +77,10 @@ ble_npl_task_init(struct ble_npl_task *t, const char *name, ble_npl_task_func_t { err = OS_ENOMEM; } + else + { + pthread_setname_np(t->handle, t->name); + } return err; } diff --git a/lib/bt/host/nimble/nimble/porting/npl/riot/include/logcfg/logcfg.h b/lib/bt/host/nimble/nimble/porting/npl/riot/include/logcfg/logcfg.h index fab4d812..89af3530 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/riot/include/logcfg/logcfg.h +++ b/lib/bt/host/nimble/nimble/porting/npl/riot/include/logcfg/logcfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_LOGCFG_ diff --git a/lib/bt/host/nimble/nimble/porting/npl/riot/include/syscfg/syscfg.h b/lib/bt/host/nimble/nimble/porting/npl/riot/include/syscfg/syscfg.h index a814bc56..c90322ea 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/riot/include/syscfg/syscfg.h +++ b/lib/bt/host/nimble/nimble/porting/npl/riot/include/syscfg/syscfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_SYSCFG_ @@ -19,6 +19,19 @@ #define MYNEWT_VAL_HARDFLOAT (0) #endif +/*** @apache-mynewt-core/crypto/tinycrypt */ +#ifndef MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE +#define MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE (200) +#endif + +#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME "trng" +#endif + +#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) +#endif + /*** @apache-mynewt-core/hw/bsp/nordic_pca10056 */ #ifndef MYNEWT_VAL_BSP_NRF52840 #define MYNEWT_VAL_BSP_NRF52840 (1) @@ -145,7 +158,7 @@ #endif #ifndef MYNEWT_VAL_MCU_ICACHE_ENABLED -#define MYNEWT_VAL_MCU_ICACHE_ENABLED (0) +#define MYNEWT_VAL_MCU_ICACHE_ENABLED (1) #endif /* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ @@ -670,13 +683,17 @@ #define MYNEWT_VAL_BASELIBC_PRESENT (1) #endif +#ifndef MYNEWT_VAL_BASELIBC_THREAD_SAFE_HEAP_ALLOCATION +#define MYNEWT_VAL_BASELIBC_THREAD_SAFE_HEAP_ALLOCATION (0) +#endif + /*** @apache-mynewt-core/sys/console/stub */ #ifndef MYNEWT_VAL_CONSOLE_UART_BAUD #define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) #endif #ifndef MYNEWT_VAL_CONSOLE_UART_DEV -#define MYNEWT_VAL_CONSOLE_UART_DEV ("uart0") +#define MYNEWT_VAL_CONSOLE_UART_DEV "uart0" #endif #ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL @@ -788,6 +805,10 @@ #endif /*** @apache-mynewt-nimble/nimble */ +#ifndef MYNEWT_VAL_BLE_CONN_SUBRATING +#define MYNEWT_VAL_BLE_CONN_SUBRATING (0) +#endif + #ifndef MYNEWT_VAL_BLE_EXT_ADV #define MYNEWT_VAL_BLE_EXT_ADV (0) #endif @@ -838,6 +859,10 @@ #define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) #endif +#ifndef MYNEWT_VAL_BLE_POWER_CONTROL +#define MYNEWT_VAL_BLE_POWER_CONTROL (0) +#endif + #ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER #define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) #endif @@ -879,6 +904,56 @@ #define MYNEWT_VAL_BLE_DEVICE (1) #endif +#ifndef MYNEWT_VAL_BLE_FEM_ANTENNA +#define MYNEWT_VAL_BLE_FEM_ANTENNA (0) +#endif + +/* Value copied from BLE_LL_LNA */ +#ifndef MYNEWT_VAL_BLE_FEM_LNA +#define MYNEWT_VAL_BLE_FEM_LNA (0) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_LNA_GAIN +#define MYNEWT_VAL_BLE_FEM_LNA_GAIN (0) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_LNA_GAIN_TUNABLE +#define MYNEWT_VAL_BLE_FEM_LNA_GAIN_TUNABLE (0) +#endif + +/* Value copied from BLE_LL_LNA_GPIO */ +#ifndef MYNEWT_VAL_BLE_FEM_LNA_GPIO +#define MYNEWT_VAL_BLE_FEM_LNA_GPIO (-1) +#endif + +/* Value copied from BLE_LL_LNA_TURN_ON_US */ +#ifndef MYNEWT_VAL_BLE_FEM_LNA_TURN_ON_US +#define MYNEWT_VAL_BLE_FEM_LNA_TURN_ON_US (1) +#endif + +/* Value copied from BLE_LL_PA */ +#ifndef MYNEWT_VAL_BLE_FEM_PA +#define MYNEWT_VAL_BLE_FEM_PA (0) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_PA_GAIN +#define MYNEWT_VAL_BLE_FEM_PA_GAIN (0) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_PA_GAIN_TUNABLE +#define MYNEWT_VAL_BLE_FEM_PA_GAIN_TUNABLE (0) +#endif + +/* Value copied from BLE_LL_PA_GPIO */ +#ifndef MYNEWT_VAL_BLE_FEM_PA_GPIO +#define MYNEWT_VAL_BLE_FEM_PA_GPIO (-1) +#endif + +/* Value copied from BLE_LL_PA_TURN_ON_US */ +#ifndef MYNEWT_VAL_BLE_FEM_PA_TURN_ON_US +#define MYNEWT_VAL_BLE_FEM_PA_TURN_ON_US (1) +#endif + /* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/controller) */ #ifndef MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE #define MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE (0) @@ -923,6 +998,10 @@ #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_PING (MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION) #endif +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE (0) +#endif + /* Value copied from BLE_EXT_ADV */ #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV (0) @@ -975,6 +1054,14 @@ #define MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG (0) #endif +#ifndef MYNEWT_VAL_BLE_LL_CONN_EVENT_END_MARGIN +#define MYNEWT_VAL_BLE_LL_CONN_EVENT_END_MARGIN (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_AUTO_DLE +#define MYNEWT_VAL_BLE_LL_CONN_INIT_AUTO_DLE (1) +#endif + /* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/controller) */ #ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES #define MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) @@ -1049,6 +1136,10 @@ #define MYNEWT_VAL_BLE_LL_DTM_EXTENSIONS (0) #endif +#ifndef MYNEWT_VAL_BLE_LL_EXT +#define MYNEWT_VAL_BLE_LL_EXT (0) +#endif + #ifndef MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT #define MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT (0) #endif @@ -1083,6 +1174,15 @@ #define MYNEWT_VAL_BLE_LL_LNA_GPIO (-1) #endif +#ifndef MYNEWT_VAL_BLE_LL_LNA_TURN_ON_US +#define MYNEWT_VAL_BLE_LL_LNA_TURN_ON_US (1) +#endif + +/* Value copied from BLE_LL_MFRG_ID */ +#ifndef MYNEWT_VAL_BLE_LL_MANUFACTURER_ID +#define MYNEWT_VAL_BLE_LL_MANUFACTURER_ID (0x0B65) +#endif + #ifndef MYNEWT_VAL_BLE_LL_MASTER_SCA #define MYNEWT_VAL_BLE_LL_MASTER_SCA (4) #endif @@ -1092,7 +1192,7 @@ #endif #ifndef MYNEWT_VAL_BLE_LL_MFRG_ID -#define MYNEWT_VAL_BLE_LL_MFRG_ID (0xFFFF) +#define MYNEWT_VAL_BLE_LL_MFRG_ID (0x0B65) #endif #ifndef MYNEWT_VAL_BLE_LL_NUM_COMP_PKT_ITVL_MS @@ -1119,6 +1219,10 @@ #define MYNEWT_VAL_BLE_LL_PA_GPIO (-1) #endif +#ifndef MYNEWT_VAL_BLE_LL_PA_TURN_ON_US +#define MYNEWT_VAL_BLE_LL_PA_TURN_ON_US (1) +#endif + #ifndef MYNEWT_VAL_BLE_LL_PRIO #define MYNEWT_VAL_BLE_LL_PRIO (0) #endif @@ -1186,6 +1290,10 @@ #define MYNEWT_VAL_BLE_LL_SCHED_SCAN_SYNC_PDU_LEN (32) #endif +#ifndef MYNEWT_VAL_BLE_LL_STACK_SIZE +#define MYNEWT_VAL_BLE_LL_STACK_SIZE (120) +#endif + #ifndef MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING #define MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING (0) #endif @@ -1212,6 +1320,10 @@ #define MYNEWT_VAL_BLE_LL_TX_PWR_DBM (0) #endif +#ifndef MYNEWT_VAL_BLE_LL_TX_PWR_MAX_DBM +#define MYNEWT_VAL_BLE_LL_TX_PWR_MAX_DBM (20) +#endif + #ifndef MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD #define MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD (0) #endif @@ -1240,7 +1352,7 @@ #define MYNEWT_VAL_BLE_XTAL_SETTLE_TIME (0) #endif -/*** @apache-mynewt-nimble/nimble/drivers/nrf52 */ +/*** @apache-mynewt-nimble/nimble/drivers/nrf5x */ #ifndef MYNEWT_VAL_BLE_PHY_DBG_TIME_ADDRESS_END_PIN #define MYNEWT_VAL_BLE_PHY_DBG_TIME_ADDRESS_END_PIN (-1) #endif @@ -1253,12 +1365,8 @@ #define MYNEWT_VAL_BLE_PHY_DBG_TIME_WFR_PIN (-1) #endif -#ifndef MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_164 -#define MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_164 (0) -#endif - -#ifndef MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_191 -#define MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_191 (1) +#ifndef MYNEWT_VAL_BLE_PHY_NRF52_HEADERMASK_WORKAROUND +#define MYNEWT_VAL_BLE_PHY_NRF52_HEADERMASK_WORKAROUND (0) #endif #ifndef MYNEWT_VAL_BLE_PHY_SYSVIEW @@ -1269,6 +1377,10 @@ #define MYNEWT_VAL_BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR (0) #endif +#ifndef MYNEWT_VAL_BLE_PHY_VARIABLE_TIFS +#define MYNEWT_VAL_BLE_PHY_VARIABLE_TIFS (0) +#endif + /*** @apache-mynewt-nimble/nimble/host */ #ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU #define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) @@ -1390,6 +1502,10 @@ #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -1486,6 +1602,10 @@ #define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8) #endif +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT (1) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC #define MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC (0) #endif @@ -1510,42 +1630,6 @@ #define MYNEWT_VAL_BLE_MESH (0) #endif -#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT -#define MYNEWT_VAL_BLE_MONITOR_RTT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("btmonitor") -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART -#define MYNEWT_VAL_BLE_MONITOR_UART (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE -#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV -#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") -#endif - #ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT #define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) #endif @@ -1567,6 +1651,10 @@ #define MYNEWT_VAL_BLE_SM_LEGACY (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS #define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) #endif @@ -1592,10 +1680,6 @@ #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif -#ifndef MYNEWT_VAL_BLE_SM_SC_LVL -#define MYNEWT_VAL_BLE_SM_SC_LVL (0) -#endif - #ifndef MYNEWT_VAL_BLE_SM_SC_ONLY #define MYNEWT_VAL_BLE_SM_SC_ONLY (0) #endif @@ -1630,7 +1714,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME ("nimble") +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME "nimble" #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH @@ -1681,6 +1765,42 @@ #undef MYNEWT_VAL_BLE_HCI_TRANSPORT +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME "btmonitor" +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV "uart0" +#endif + #ifndef MYNEWT_VAL_BLE_TRANSPORT #define MYNEWT_VAL_BLE_TRANSPORT (1) #endif @@ -1701,7 +1821,7 @@ #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE -#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (255) +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (251) #endif /* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/transport) */ @@ -1713,11 +1833,13 @@ #define MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT (16) #endif -/* Overridden by @apache-mynewt-nimble/nimble/transport (defined by @apache-mynewt-nimble/nimble/transport) */ #ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE -#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (257) +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (70) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__cdc +#define MYNEWT_VAL_BLE_TRANSPORT_HS__cdc (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__custom #define MYNEWT_VAL_BLE_TRANSPORT_HS__custom (0) #endif @@ -1740,12 +1862,18 @@ #define MYNEWT_VAL_BLE_TRANSPORT_HS (1) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__custom #define MYNEWT_VAL_BLE_TRANSPORT_LL__custom (0) #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac #define MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac (0) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__emspi +#define MYNEWT_VAL_BLE_TRANSPORT_LL__emspi (0) +#endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__native #define MYNEWT_VAL_BLE_TRANSPORT_LL__native (1) #endif @@ -1761,7 +1889,7 @@ /*** newt */ #ifndef MYNEWT_VAL_APP_NAME -#define MYNEWT_VAL_APP_NAME ("dummy_app") +#define MYNEWT_VAL_APP_NAME "dummy_app" #endif #ifndef MYNEWT_VAL_APP_dummy_app @@ -1769,7 +1897,7 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("cortex_m4") +#define MYNEWT_VAL_ARCH_NAME "cortex_m4" #endif #ifndef MYNEWT_VAL_ARCH_cortex_m4 @@ -1777,7 +1905,7 @@ #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("nordic_pca10056") +#define MYNEWT_VAL_BSP_NAME "nordic_pca10056" #endif #ifndef MYNEWT_VAL_BSP_nordic_pca10056 @@ -1793,11 +1921,46 @@ #endif #ifndef MYNEWT_VAL_TARGET_NAME -#define MYNEWT_VAL_TARGET_NAME ("riot") +#define MYNEWT_VAL_TARGET_NAME "riot" #endif #ifndef MYNEWT_VAL_TARGET_riot #define MYNEWT_VAL_TARGET_riot (1) #endif +/*** Included packages */ +#define MYNEWT_PKG_apache_mynewt_core__compiler_arm_none_eabi_m4 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_bsp_nordic_pca10056 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_cmsis_core 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart_uart_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_nordic 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_nordic_nrf52xxx 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_os 1 +#define MYNEWT_PKG_apache_mynewt_core__libc_baselibc 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_console_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_defs 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_flash_map 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_common 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_modlog 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_stats_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sys 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysdown 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysinit 1 +#define MYNEWT_PKG_apache_mynewt_core__util_mem 1 +#define MYNEWT_PKG_apache_mynewt_core__util_rwlock 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_controller 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_drivers_nrf5x 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gap 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gatt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_npl_mynewt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_dummy_app 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_riot 1 + #endif diff --git a/lib/bt/host/nimble/nimble/porting/npl/riot/include/sysflash/sysflash.h b/lib/bt/host/nimble/nimble/porting/npl/riot/include/sysflash/sysflash.h index 28391ca6..05324aaa 100644 --- a/lib/bt/host/nimble/nimble/porting/npl/riot/include/sysflash/sysflash.h +++ b/lib/bt/host/nimble/nimble/porting/npl/riot/include/sysflash/sysflash.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.10.0-dev + * This file was generated by Apache newt version: 1.11.0-dev */ #ifndef H_MYNEWT_SYSFLASH_ @@ -15,10 +15,33 @@ extern const struct flash_area sysflash_map_dflt[6]; #define FLASH_AREA_BOOTLOADER 0 +#define FLASH_AREA_BOOTLOADER_DEVICE 0 +#define FLASH_AREA_BOOTLOADER_OFFSET 0x00000000 +#define FLASH_AREA_BOOTLOADER_SIZE 32768 + #define FLASH_AREA_IMAGE_0 1 +#define FLASH_AREA_IMAGE_0_DEVICE 0 +#define FLASH_AREA_IMAGE_0_OFFSET 0x0000c000 +#define FLASH_AREA_IMAGE_0_SIZE 483328 + #define FLASH_AREA_IMAGE_1 2 +#define FLASH_AREA_IMAGE_1_DEVICE 0 +#define FLASH_AREA_IMAGE_1_OFFSET 0x00082000 +#define FLASH_AREA_IMAGE_1_SIZE 483328 + #define FLASH_AREA_IMAGE_SCRATCH 3 +#define FLASH_AREA_IMAGE_SCRATCH_DEVICE 0 +#define FLASH_AREA_IMAGE_SCRATCH_OFFSET 0x000f8000 +#define FLASH_AREA_IMAGE_SCRATCH_SIZE 16384 + #define FLASH_AREA_REBOOT_LOG 16 +#define FLASH_AREA_REBOOT_LOG_DEVICE 0 +#define FLASH_AREA_REBOOT_LOG_OFFSET 0x00008000 +#define FLASH_AREA_REBOOT_LOG_SIZE 16384 + #define FLASH_AREA_NFFS 17 +#define FLASH_AREA_NFFS_DEVICE 0 +#define FLASH_AREA_NFFS_OFFSET 0x000fc000 +#define FLASH_AREA_NFFS_SIZE 16384 #endif diff --git a/lib/bt/host/nimble/nimble/repository.yml b/lib/bt/host/nimble/nimble/repository.yml index 4c87b3ee..797edaa7 100644 --- a/lib/bt/host/nimble/nimble/repository.yml +++ b/lib/bt/host/nimble/nimble/repository.yml @@ -22,8 +22,8 @@ repo.versions: "0.0.0": "master" "0-dev": "0.0.0" - "0-latest": "1.4.0" - "1-latest": "1.4.0" + "0-latest": "1.5.0" + "1-latest": "1.5.0" "1.0.0": "nimble_1_0_0_tag" "1.1.0": "nimble_1_1_0_tag" @@ -31,6 +31,7 @@ repo.versions: "1.3.0": "nimble_1_3_0_tag" "1.4.0": "nimble_1_4_0_tag" "1.5.0": "nimble_1_5_0_tag" + "1.6.0": "nimble_1_6_0_tag" "1.0-latest": "1.0.0" "1.1-latest": "1.1.0" @@ -38,6 +39,7 @@ repo.versions: "1.3-latest": "1.3.0" "1.4-latest": "1.4.0" "1.5-latest": "1.5.0" + "1.6-latest": "1.6.0" repo.newt_compatibility: 0.0.0: @@ -54,3 +56,5 @@ repo.newt_compatibility: 1.9.0: good 1.5.0: 1.10.0: good + 1.6.0: + 1.11.0: good diff --git a/lib/bt/host/nimble/nimble/targets/dialog_cmac/syscfg.yml b/lib/bt/host/nimble/nimble/targets/dialog_cmac/syscfg.yml index 71a109a2..f73d4e01 100644 --- a/lib/bt/host/nimble/nimble/targets/dialog_cmac/syscfg.yml +++ b/lib/bt/host/nimble/nimble/targets/dialog_cmac/syscfg.yml @@ -21,10 +21,18 @@ syscfg.vals: MCU_DEEP_SLEEP: 1 MCU_SLP_TIMER: 1 MCU_SLP_TIMER_32K_ONLY: 1 + MCU_DEBUG_HCI_EVENT_ON_FAULT: 1 + MCU_DEBUG_HCI_EVENT_ON_ASSERT: 1 + MSYS_1_BLOCK_SIZE: 308 BLE_TRANSPORT_HS: dialog_cmac + BLE_TRANSPORT_ACL_COUNT: 16 + BLE_TRANSPORT_ACL_SIZE: 255 + BLE_TRANSPORT_EVT_COUNT: 4 + BLE_TRANSPORT_EVT_DISCARDABLE_COUNT: 16 # LL recommended settings (decreasing timing values is not recommended) + BLE_LL_STACK_SIZE: 200 BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL: 1 BLE_LL_CONN_INIT_MIN_WIN_OFFSET: 2 BLE_LL_RFMGMT_ENABLE_TIME: 20 @@ -33,3 +41,22 @@ syscfg.vals: # NOTE: set public address in target settings # BLE_LL_PUBLIC_DEV_ADDR: 0xffffffffffff + + # LL features + BLE_VERSION: 53 + BLE_EXT_ADV: 1 + BLE_EXT_ADV_MAX_SIZE: 1650 + BLE_PERIODIC_ADV: 1 + BLE_PERIODIC_ADV_SYNC_TRANSFER: 1 + BLE_MULTI_ADV_INSTANCES: 4 + BLE_MAX_PERIODIC_SYNCS: 4 + BLE_MAX_CONNECTIONS: 4 + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_CFG_FEAT_LE_2M_PHY: 1 + BLE_LL_CFG_FEAT_LE_CODED_PHY: 0 + BLE_LL_CFG_FEAT_LL_PRIVACY: 1 + BLE_LL_CFG_FEAT_LL_SCA_UPDATE: 1 + BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE: 1 + BLE_LL_CONN_INIT_SLOTS: 1 + BLE_LL_SCAN_AUX_SEGMENT_CNT: 16 + BLE_LL_NUM_SCAN_DUP_ADVS: 64 diff --git a/lib/bt/host/nimble/nimble/tools/README.md b/lib/bt/host/nimble/nimble/tools/README.md new file mode 100644 index 00000000..e69de29b diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/README.md b/lib/bt/host/nimble/nimble/tools/hci_throughput/README.md new file mode 100644 index 00000000..1e153928 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/README.md @@ -0,0 +1,110 @@ +# HCI Throughput + +Tool for measuring BLE throughput. + +## Packages versions +Python 3.8.10 \ +Matplotlib 3.5.1 + +Install all required packages with: +``` +sudo pip install -r requirements.txt +``` + +## Usage +### Prepare devices +This tool may be used with the existing controller or with any board with ```blehci``` app. + + - If you want to use the builtin PC controller, provide HCI index of the controller. Turn the Bluetooth ON on your device, run ```hciconfig``` in the terminal and get the HCI index. In the case below HCI index is equal to 0: + +``` +user@user:~$ hciconfig +hci0: Type: Primary Bus: USB + BD Address: 64:BC:58:E2:9C:52 ACL MTU: 1021:4 SCO MTU: 96:6 + UP RUNNING + RX bytes:20003 acl:0 sco:0 events:3176 errors:0 + TX bytes:771246 acl:0 sco:0 commands:3174 errors:0 +``` + + - If you want to use the nimble controller, create the image and load the provided target (can be found under ```/targets``` for NRF52840 and NRF52832). + - NRF52840 may use USB or UART as HCI transport. The target is configured for USB by default. + - NRF52832 uses UART as HCI transport. This requires some additional configuration. Get the tty path and run in the terminal: + ``` + sudo btattach -B /dev/ttyACM0 -S 1000000 + ``` + Then proceed with ```hciconfig``` as shown above. + +### Run tests + + +This tool opens a raw socket which requires running all scripts as ```sudo```. Copy the ```config.yaml.sample``` file, change the name to ```config.yaml``` and fill the parameters. +Optionally pass the path to the custom transport directory if used. Run ```main.py``` as shown below: +``` +sudo python main.py -i -m rx tx -t -cf config.yaml +``` +Switch `````` and `````` to corresponding hci indexes present in your computer. ```-m```, ```-t``` and ```-cf``` may be omitted if the defaults are correct. \ +The output provides the plots of measured throughput in ```kb``` or ```kB``` as predefined in ```config.yaml```. In addition to the throughput plots, when the ```flag_plot_packets``` is turned on, the number of packets transmitted/received in time is visualized. + +**_When encountering issues with running tests, try to investigate the files in the log folder._** + +#### Set ```config.yaml``` file +To run **once** the throughput measurement with given parameters, set the ```flag_testing``` to false. +``` +flag_testing: false +``` + +To run the throughput measurements **more than once** with the same parameters and to generate the plot of average throughputs, set ```config.yaml``` as shown below: +``` +show_tp_plots: false +flag_testing: true +test: + change_param_group: null + change_param_variable: null + start_value: 0 + stop_value: 5 + step: 1 +``` +This configuration provides 5 measurements. The ```show_tp_plots``` flag is optionally set as ```false``` for speed, changing it to ```true``` will trigger rx and tx throughput plots at the end of every iteration. + +To run the throughput measurement with some parameters changing within tests, fill config as below: +``` +flag_testing: true +test: + change_param_group: + - conn + - conn + change_param_variable: + - connection_interval_min + - connection_interval_max + start_value: 0x000A + stop_value: 0x0320 + step: 20 +``` +This will run each test incrementing ```connection_interval_min``` and ```connection_interval_max``` by 20. the final plot will show the influence of the parameters change on the average throughput. + +## Tools +The ```main.py``` script usees all tools mentioned below and it is advised to use it above all. Nevertheless, the sub-tools may be used separately as shown below. + +### HCI device sub-tool +```hci_device.py``` is a tool that manages one hci device. User can provide parameters and run it as receiver or transmitter as shown below: +``` +sudo python hci_device.py -m rx -oa 00:00:00:00:00:00 -oat 0 -di 0 -pa 00:00:00:00:00:00 -pat 0 -pdi 0 -cf config.yaml +``` +Run ```python hci_device.py --help``` for parameters description. \ +If properly configured ```init.yaml``` is present (it is created automatically while running ```main.py```), the script can be run like this: + +``` +sudo python hci_device.py -m tx -if init.yaml +``` + +### Check addr sub-tool +When given hci indexes, ```check_addr.py``` returns devices' address types and addresses. Optionally pass the path to the custom transport directory if used. +``` +sudo python check_addr.py -i ... -t +``` + +### Throughput sub-tool +The timestamps of the received packets are stored in csv files (```tp_receiver.csv``` and ```tp_transmitter.csv``` by default). If the program stopped in the middle of the measurements, you can still plot the values and get the average througput. Provide the filename, sample time and run the tool as shown below: +``` +python throughput.py -f tp_receiver -s 0.1 +``` diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/check_addr.py b/lib/bt/host/nimble/nimble/tools/hci_throughput/check_addr.py new file mode 100644 index 00000000..ce2a9446 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/check_addr.py @@ -0,0 +1,124 @@ +# +# 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. +# + +import argparse +import asyncio +import hci_commands +import sys +import logging +import hci +import traceback +import util +import transport_factory + + +def parse_arguments(): + parser = argparse.ArgumentParser( + description='Check HCI device address type and address', + epilog='How to run script: \ + sudo python check_addr.py -i 0 1 2 \ + -t path/to/custom_transport_dir') + parser.add_argument('-i', '--indexes', type=str, nargs='*', + help='specify hci adapters indexes', default=0) + parser.add_argument('-t', '--transport_directory', type=str, nargs='*', + help='specify hci transport directory path. \ + Use for transport other than the default linux socket.', + default=["default"]) + try: + args = parser.parse_args() + if (isinstance(args.transport_directory, list)): + args.transport_directory = args.transport_directory.pop() + else: + args.transport_directory = args.transport_directory + + except Exception as e: + print(traceback.format_exc()) + return args + + +async def main(dev: hci_commands.HCI_Commands): + result = tuple() + task = asyncio.create_task(dev.rx_buffer_q_wait()) + await dev.cmd_reset() + await dev.cmd_read_bd_addr() + + if hci.bdaddr != '00:00:00:00:00:00': + logging.info("Type public: %s, address: %s", + hci.PUBLIC_ADDRESS_TYPE, hci.bdaddr) + result = (0, hci.bdaddr) + print("Public address: ", result) + else: + await dev.cmd_vs_read_static_addr() + if hci.static_addr != '00:00:00:00:00:00': + logging.info("Type static random: %s, address: %s", + hci.STATIC_RANDOM_ADDRESS_TYPE, hci.static_addr) + result = (1, hci.static_addr) + print("Static random address: ", result) + else: + addr = hci.gen_static_rand_addr() + logging.info("Type static random: %s, generated address: %s", + hci.STATIC_RANDOM_ADDRESS_TYPE, addr) + result = (1, addr) + print("Generated static random address: ", result) + task.cancel() + return result + + +def check_addr( + device_indexes: list, + addresses: list, + transport_directory: str) -> list: + util.configure_logging(f"log/check_addr.log", clear_log_file=True) + + logging.info(f"Devices indexes: {device_indexes}") + for index in device_indexes: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + loop.set_debug(True) + + transport = transport_factory.TransportFactory(device_index=str( + index), asyncio_loop=loop, transport_directory=transport_directory) + + bt_dev = hci_commands.HCI_Commands(send=transport.send, + rx_buffer_q=transport.rx_buffer_q, + asyncio_loop=loop) + + transport.start() + + addresses.append(loop.run_until_complete(main(bt_dev))) + + transport.stop() + loop.close() + + logging.info(f"Finished: {addresses}") + return addresses + + +if __name__ == '__main__': + try: + args = parse_arguments() + print(args) + addresses = [] + addresses = check_addr(args.indexes, addresses, + args.transport_directory) + print(addresses) + except Exception as e: + print(traceback.format_exc()) + finally: + sys.exit() diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/config.yaml.sample b/lib/bt/host/nimble/nimble/tools/hci_throughput/config.yaml.sample new file mode 100644 index 00000000..6d5dcbcf --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/config.yaml.sample @@ -0,0 +1,56 @@ +# +# 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. +# + +num_of_bytes_to_send: 247 +num_of_packets_to_send: 2000 +show_tp_plots: true +flag_testing: false +test: + change_param_group: + - conn + - conn + change_param_variable: + - connection_interval_min + - connection_interval_max + start_value: 16 + stop_value: 160 + step: 8 +tp: + data_type: kb + sample_time: 0.1 + flag_plot_packets: true +phy: 2M +adv: + advertising_interval_min: 2048 + advertising_interval_max: 2048 + advertising_type: 0 + peer_address: 00:00:00:00:00:00 + advertising_channel_map: 7 + advertising_filter_policy: 0 +enable_encryption: false +conn: + le_scan_interval: 2400 + le_scan_window: 2400 + initiator_filter_policy: 0 + connection_interval_min: 0x0080 + connection_interval_max: 0x0080 + max_latency: 0 + supervision_timeout: 3200 + min_ce_length: 0 + max_ce_length: 0 \ No newline at end of file diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/hci.py b/lib/bt/host/nimble/nimble/tools/hci_throughput/hci.py new file mode 100644 index 00000000..e5eb1179 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/hci.py @@ -0,0 +1,742 @@ +# +# 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. +# + +from dataclasses import dataclass +import struct +from binascii import unhexlify +import random +import ctypes + +############ +# DEFINES +############ +AF_BLUETOOTH = 31 +HCI_CHANNEL_USER = 1 +HCI_COMMAND_PACKET = 0x01 +HCI_ACL_DATA_PACKET = 0x02 +HCI_EVENT_PACKET = 0x04 + +L2CAP_HDR_BYTES = 4 + +HCI_EV_CODE_DISCONN_CMP = 0x05 +HCI_EV_CODE_ENCRYPTION_CHANGE = 0x08 +HCI_EV_CODE_CMD_CMP = 0x0e +HCI_EV_CODE_CMD_STATUS = 0x0f +HCI_EV_CODE_LE_META_EVENT = 0x3e +HCI_SUBEV_CODE_LE_ENHANCED_CONN_CMP = 0x0a +HCI_SUBEV_CODE_LE_DATA_LEN_CHANGE = 0x07 +HCI_SUBEV_CODE_LE_PHY_UPDATE_CMP = 0x0c +HCI_SUBEV_CODE_LE_CHAN_SEL_ALG = 0x14 +HCI_SUBEV_CODE_LE_LONG_TERM_KEY_REQUEST = 0x05 +HCI_EV_NUM_COMP_PKTS = 0x13 + +CONN_FAILED_TO_BE_ESTABLISHED = 0x3e +CONN_TIMEOUT = 0x08 + +OGF_HOST_CTL = 0x03 +OCF_SET_EVENT_MASK = 0x0001 +OCF_RESET = 0X0003 + +OGF_INFO_PARAM = 0x04 +OCF_READ_LOCAL_COMMANDS = 0x0002 +OCF_READ_BD_ADDR = 0x0009 + +OGF_LE_CTL = 0x08 +OCF_LE_SET_EVENT_MASK = 0x0001 +OCF_LE_READ_BUFFER_SIZE_V1 = 0x0002 +OCF_LE_READ_LOCAL_SUPPORTED_FEATURES = 0x0003 +OCF_LE_READ_BUFFER_SIZE_V2 = 0x0060 +OCF_LE_SET_RANDOM_ADDRESS = 0x0005 +OCF_LE_SET_ADVERTISING_PARAMETERS = 0x0006 +OCF_LE_SET_ADVERTISE_ENABLE = 0x000a +OCF_LE_SET_SCAN_PARAMETERS = 0x000b +OCF_LE_SET_SCAN_ENABLE = 0x000c +OCF_LE_CREATE_CONN = 0x000d +OCF_LE_ENABLE_ENCRYPTION = 0x0019 +OCF_LE_LONG_TERM_KEY_REQUEST_REPLY = 0x001A +OCF_LE_SET_DATA_LEN = 0x0022 +OCF_LE_READ_SUGGESTED_DFLT_DATA_LEN = 0x0023 +OCF_LE_READ_MAX_DATA_LEN = 0x002f +OCF_LE_READ_PHY = 0x0030 +OCF_LE_SET_DFLT_PHY = 0x0031 +OCF_LE_SET_PHY = 0x0032 + +OGF_VENDOR_SPECIFIC = 0x003f +BLE_HCI_OCF_VS_RD_STATIC_ADDR = 0x0001 + +PUBLIC_ADDRESS_TYPE = 0 +STATIC_RANDOM_ADDRESS_TYPE = 1 + +WAIT_FOR_EVENT_TIMEOUT = 5 +WAIT_FOR_EVENT_CONN_TIMEOUT = 25 + +LE_FEATURE_2M_PHY = ctypes.c_uint64(0x0100).value +LE_FEATURE_CODED_PHY = ctypes.c_uint64(0x0800).value + +############ +# GLOBAL VAR +############ +num_of_bytes_to_send = None # based on supported_max_tx_octets +num_of_packets_to_send = None + +events_list = [] +bdaddr = '00:00:00:00:00:00' +static_addr = '00:00:00:00:00:00' +le_read_buffer_size = None +conn_handle = 0 +requested_tx_octets = 1 +requested_tx_time = 1 +suggested_dflt_data_len = None +max_data_len = None +phy = None +ev_num_comp_pkts = None +num_of_completed_packets_cnt = 0 +num_of_completed_packets_time = 0 +read_local_commands = None +le_read_local_supported_features = None +ltk = None + +############ +# FUNCTIONS +############ + + +def get_opcode(ogf: int, ocf: int): + return ((ocf & 0x03ff) | (ogf << 10)) + + +def get_ogf_ocf(opcode: int): + ogf = opcode >> 10 + ocf = opcode & 0x03ff + return ogf, ocf + + +def cmd_addr_to_ba(addr_str: str): + return unhexlify("".join(addr_str.split(':')))[::-1] + + +def ba_addr_to_str(addr_ba: bytearray): + addr_str = addr_ba.hex().upper() + return ':'.join(addr_str[i:i + 2] + for i in range(len(addr_str), -2, -2))[1:] + + +def gen_static_rand_addr(): + while True: + x = [random.randint(0, 1) for _ in range(0, 48)] + + if 0 in x[:-2] and 1 in x[:-2]: + x[0] = 1 + x[1] = 1 + break + addr_int = int("".join([str(x[i]) for i in range(0, len(x))]), 2) + addr_hex = "{0:0{1}x}".format(addr_int, 12) + addr = ":".join(addr_hex[i:i + 2] for i in range(0, len(addr_hex), 2)) + return addr.upper() + +############ +# GLOBAL VAR CLASSES +############ + + +@dataclass +class Suggested_Dflt_Data_Length(): + status: int + suggested_max_tx_octets: int + suggested_max_tx_time: int + + def __init__(self): + self.set() + + def set( + self, + status=0, + suggested_max_tx_octets=0, + suggested_max_tx_time=0): + self.status = status + self.suggested_max_tx_octets = suggested_max_tx_octets + self.suggested_max_tx_time = suggested_max_tx_time + + +@dataclass +class Max_Data_Length(): + status: int + supported_max_tx_octets: int + supported_max_tx_time: int + supported_max_rx_octets: int + supported_max_rx_time: int + + def __init__(self): + self.set() + + def set(self, status=0, supported_max_tx_octets=0, supported_max_tx_time=0, + supported_max_rx_octets=0, supported_max_rx_time=0): + self.status = status + self.supported_max_tx_octets = supported_max_tx_octets + self.supported_max_tx_time = supported_max_tx_time + self.supported_max_rx_octets = supported_max_rx_octets + self.supported_max_rx_time = supported_max_rx_time + + +@dataclass +class LE_Read_Buffer_Size: + status: int + le_acl_data_packet_length: int + total_num_le_acl_data_packets: int + iso_data_packet_len: int + total_num_iso_data_packets: int + + def __init__(self): + self.set() + + def set(self, status=0, le_acl_data_packet_length=0, + total_num_le_acl_data_packets=0, iso_data_packet_len=0, + total_num_iso_data_packets=0): + self.status = status + self.le_acl_data_packet_length = le_acl_data_packet_length + self.total_num_le_acl_data_packets = total_num_le_acl_data_packets + self.iso_data_packet_len = iso_data_packet_len + self.total_num_iso_data_packets = total_num_iso_data_packets + + +@dataclass +class LE_Read_PHY: + status: int + connection_handle: int + tx_phy: int + rx_phy: int + + def __init__(self): + self.set() + + def set(self, status=0, connection_handle=0, tx_phy=0, rx_phy=0): + self.status = status + self.connection_handle = connection_handle + self.tx_phy = tx_phy + self.rx_phy = rx_phy + + +@dataclass +class Read_Local_Commands: + status: int + supported_commands: bytes + + def __init__(self): + self.set() + + def set(self, rcv_bytes=bytes(65)): + self.status = int(rcv_bytes[0]) + self.supported_commands = rcv_bytes[1:] + + +@dataclass +class LE_Read_Local_Supported_Features: + status: int + le_features: bytes + + def __init__(self): + self.set() + + def set(self, rcv_bytes=bytes(9)): + self.status = int(rcv_bytes[0]) + self.le_features = ctypes.c_uint64.from_buffer_copy( + rcv_bytes[1:]).value + +############ +# EVENTS +############ + + +@dataclass +class HCI_Ev_Disconn_Complete: + status: int + connection_handle: int + reason: int + + def __init__(self): + self.set() + + def set(self, status=0, connection_handle=0, reason=0): + self.status = status + self.connection_handle = connection_handle + self.reason = reason + + +@dataclass +class HCI_Ev_Cmd_Complete: + num_hci_command_packets: int + opcode: int + return_parameters: int + + def __init__(self): + self.set() + + def set(self, num_hci_cmd_packets=0, opcode=0, return_parameters=b''): + self.num_hci_command_packets = num_hci_cmd_packets + self.opcode = opcode + self.return_parameters = return_parameters + + +@dataclass +class HCI_Ev_Cmd_Status: + status: int + num_hci_command_packets: int + opcode: int + + def __init__(self): + self.set() + + def set(self, status=0, num_hci_cmd_packets=0, opcode=0): + self.status = status + self.num_hci_command_packets = num_hci_cmd_packets + self.opcode = opcode + + +@dataclass +class HCI_Ev_LE_Encryption_Change(): + status: int + connection_handle: int + encryption_enabled: int + + def __init__(self): + self.set() + + def set(self, status=0, connection_handle=0, encryption_enabled=0): + self.status = status + self.connection_handle = connection_handle + self.encryption_enabled = encryption_enabled + + +@dataclass +class HCI_Ev_LE_Meta: + subevent_code: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0): + self.subevent_code = subevent_code + + +@dataclass +class HCI_Ev_LE_Enhanced_Connection_Complete(HCI_Ev_LE_Meta): + status: int + connection_handle: int + role: int + peer_address_type: int + peer_address: str + local_resolvable_private_address: int + peer_resolvable_private_address: int + connection_interval: int + peripheral_latency: int + supervision_timeout: int + central_clock_accuracy: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0, status=0, connection_handle=0, role=0, + peer_address_type=0, peer_address='00:00:00:00:00:00', + local_resolvable_private_address='00:00:00:00:00:00', + peer_resolvable_private_address='00:00:00:00:00:00', + connection_interval=0, peripheral_latency=0, supervision_timeout=0, + central_clock_accuracy=0): + super().set(subevent_code) + self.status = status + self.connection_handle = connection_handle + self.role = role + self.peer_address_type = peer_address_type + self.peer_address = peer_address + self.local_resolvable_private_address = local_resolvable_private_address + self.peer_resolvable_private_address = peer_resolvable_private_address + self.connection_interval = connection_interval + self.peripheral_latency = peripheral_latency + self.supervision_timeout = supervision_timeout + self.central_clock_accuracy = central_clock_accuracy + + +@dataclass +class HCI_Ev_LE_Data_Length_Change(HCI_Ev_LE_Meta): + conn_handle: int + max_tx_octets: int + max_tx_time: int + max_rx_octets: int + max_rx_time: int + triggered: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0, conn_handle=0, max_tx_octets=0, + max_tx_time=0, max_rx_octets=0, max_rx_time=0, triggered=0): + super().set(subevent_code) + self.conn_handle = conn_handle + self.max_tx_octets = max_tx_octets + self.max_tx_time = max_tx_time + self.max_rx_octets = max_rx_octets + self.max_rx_time = max_rx_time + self.triggered = triggered + + +@dataclass +class HCI_Ev_LE_Long_Term_Key_Request(HCI_Ev_LE_Meta): + conn_handle: int + random_number: int + encrypted_diversifier: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0, conn_handle=0, random_number=0, + encrypted_diversifier=0): + super().set(subevent_code) + self.conn_handle = conn_handle + self.random_number = random_number + self.encrypted_diversifier = encrypted_diversifier + + +@dataclass +class HCI_Ev_LE_PHY_Update_Complete(HCI_Ev_LE_Meta): + status: int + connection_handle: int + tx_phy: int + rx_phy: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0, status=0, connection_handle=0, + tx_phy=0, rx_phy=0): + super().set(subevent_code) + self.status = status + self.connection_handle = connection_handle + self.tx_phy = tx_phy + self.rx_phy = rx_phy + + +@dataclass +class HCI_Number_Of_Completed_Packets: + num_handles: int + connection_handle: int + num_completed_packets: int + + def __init__(self): + self.set() + + def set(self, num_handles=0, connection_handle=0, num_completed_packets=0): + self.num_handles = num_handles + self.connection_handle = connection_handle + self.num_completed_packets = num_completed_packets + + +class HCI_Ev_LE_Chan_Sel_Alg(HCI_Ev_LE_Meta): + connection_handle: int + algorithm: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0, connection_handle=0, algorithm=0): + super().set(subevent_code) + self.connection_handle = connection_handle + self.algorithm = algorithm + +############ +# PARAMETERS +############ + + +@dataclass +class HCI_Advertising: + advertising_interval_min: int + advertising_interval_max: int + advertising_type: int + own_address_type: int + peer_address_type: int + peer_address: str + advertising_channel_map: int + advertising_filter_policy: int + ba_full_message: bytearray + + def __init__(self): + self.set() + + def set(self, advertising_interval_min=0, advertising_interval_max=0, + advertising_type=0, own_address_type=0, peer_address_type=0, + peer_address='00:00:00:00:00:00', advertising_channel_map=0, + advertising_filter_policy=0): + self.advertising_interval_min = advertising_interval_min + self.advertising_interval_max = advertising_interval_max + self.advertising_type = advertising_type + self.own_address_type = own_address_type + self.peer_address_type = peer_address_type + self.peer_address = peer_address + self.advertising_channel_map = advertising_channel_map + self.advertising_filter_policy = advertising_filter_policy + self.ba_full_message = bytearray( + struct.pack( + ' int: + current_ev_name = type( + self.hci_recv_ev_packet.current_event).__name__ + if current_ev_name == type(hci.HCI_Ev_Cmd_Complete()).__name__: + return struct.unpack_from( + " + hci.max_data_len.supported_max_tx_octets - hci.L2CAP_HDR_BYTES): + logging.critical( + f"Number of data bytes to send + 4 bytes of L2CAP header: {hci.num_of_bytes_to_send + 4} " + f"exceeds allowed value of: {hci.max_data_len.supported_max_tx_octets}. Closing.") + raise SystemExit( + f"Number of data bytes to send + 4 bytes of L2CAP header: {hci.num_of_bytes_to_send + 4} " + f"exceeds allowed value of: {hci.max_data_len.supported_max_tx_octets}. Closing.") + + return status() + elif ocf == hci.OCF_LE_READ_PHY: + hci.phy = hci.LE_Read_PHY() + hci.phy.set(*struct.unpack('> 12 + bc_flag = (handle_pb_bc_flags & 0xC000) >> 14 + + hci_recv_acl_data_packet = hci.HCI_Recv_ACL_Data_Packet() + + if pb_flag == 0b10: + l2cap_data = hci.HCI_Recv_L2CAP_Data() + data = buffer[5:] + l2cap_data.set(*struct.unpack(" self.tp.sample_time \ + # or packet_number == 0 \ + # or packet_number == self.tp.total_packets_number-1: + # self.tp.record_throughput(packet_number, timestamp) + # self.last_timestamp = timestamp + + if packet_number >= self.tp.total_packets_number - 1: + self.async_ev_recv_data_finish.set() + + def handle_acl_data(self, buffer: bytes, timestamp: int): + hci_recv_acl_data_packet = self.parse_acl_data(buffer) + logging.debug("%s", hci_recv_acl_data_packet) + recv_data_type = type(hci_recv_acl_data_packet.data).__name__ + if recv_data_type == 'HCI_Recv_L2CAP_Data': + self.match_recv_l2cap_data(buffer, timestamp) + + async def recv_handler(self): + while not self.rx_buffer_q.empty(): + q_buffer_item, q_timestamp = self.rx_buffer_q.get() + packet_type = struct.unpack(' 0 and packets_to_send > 0: + data, last_value = tp.gen_data( + hci.num_of_bytes_to_send, last_value) + l2cap_data.set(channel_id=0x0044, data=data) + acl_data.set(connection_handle=hci.conn_handle, pb_flag=0b00, + bc_flag=0b00, data=l2cap_data.ba_full_message) + await bt_dev.acl_data_send(acl_data) + async with bt_dev.async_lock_packets_cnt: + packets_to_send -= 1 + packet_credits -= 1 + else: + logging.info(f"Waiting for num_of_cmp_packets event") + await bt_dev.async_ev_num_cmp_pckts.wait() + bt_dev.async_ev_num_cmp_pckts.clear() + + if hci.num_of_completed_packets_cnt > 0: + async with bt_dev.async_lock_packets_cnt: + sent_packets += hci.num_of_completed_packets_cnt + tx_sent_timestamps.append((hci.num_of_completed_packets_time, + sent_packets)) + logging.info(f"Sent : {sent_packets}") + + packet_credits += hci.num_of_completed_packets_cnt + hci.num_of_completed_packets_cnt = 0 + + for timestamp in tx_sent_timestamps: + bt_dev.tp.append_to_csv_file(*timestamp) + + await finish(bt_dev, cfg) + + +def parse_cfg_files(args) -> dict: + if args.init_file is None: + ini = { + "own_address": args.own_addr, + "own_address_type": args.own_addr_type, + "dev_index": args.dev_idx, + "peer_address": args.peer_addr, + "peer_address_type": args.peer_addr_type, + "peer_dev_index": args.peer_dev_idx + } + else: + with open(args.init_file, "r") as file: + init_file = yaml.safe_load(file) + ini = init_file[args.mode] + global test_dir, transport_directory, ltk + test_dir = init_file["test_dir"] + transport_directory = init_file["transport_directory"] + hci.ltk = int(init_file["ltk"], 16) + + with open(args.config_file) as f: + cfg = yaml.safe_load(f) + + global show_tp_plots + + hci.num_of_bytes_to_send = cfg["num_of_bytes_to_send"] + hci.num_of_packets_to_send = cfg["num_of_packets_to_send"] + show_tp_plots = cfg["show_tp_plots"] + + return ini, cfg + + +def signal_handler(signum, frame): + logging.critical(f"Received signal: {signal.Signals(signum).name}") + raise ParentCalledException( + f"Received signal: {signal.Signals(signum).name}") + + +def main(): + args = parse_arguments() + ini, cfg = parse_cfg_files(args) + log_path = f"log/log_{args.mode}.log" + transport = None + + try: + util.configure_logging(log_path, clear_log_file=True) + + loop = asyncio.get_event_loop() + loop.set_debug(True) + + transport = transport_factory.TransportFactory( + device_index=ini['dev_index'], + device_mode=args.mode, asyncio_loop=loop, + transport_directory=transport_directory) + + signal.signal(signal.SIGTERM, signal_handler) + + bt_dev = hci_commands.HCI_Commands(send=transport.send, + rx_buffer_q=transport.rx_buffer_q, + asyncio_loop=loop, + device_mode=args.mode) + + transport.start() + + if args.mode == 'rx': + loop.run_until_complete(async_main_rx(bt_dev, ini, cfg)) + elif args.mode == 'tx': + loop.run_until_complete(async_main_tx(bt_dev, ini, cfg)) + + except Exception as e: + logging.error(traceback.format_exc()) + except (KeyboardInterrupt or ParentCalledException): + logging.critical("Hard exit triggered.") + logging.error(traceback.format_exc()) + finally: + if transport is not None: + transport.stop() + sys.exit() + + +if __name__ == '__main__': + main() diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/hci_socket.py b/lib/bt/host/nimble/nimble/tools/hci_throughput/hci_socket.py new file mode 100644 index 00000000..da908b8f --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/hci_socket.py @@ -0,0 +1,173 @@ +# +# 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. +# + +import hci +import socket +import ctypes +import struct +import asyncio +import logging +import subprocess +import sys +import time +import multiprocessing + + +SOCKET_RECV_BUFFER_SIZE = 425984 +SOCKET_RECV_TIMEOUT = 3 + + +def btmgmt_dev_reset(index): + logging.info(f"Selecting index {index}") + proc = subprocess.Popen(['btmgmt', '-i', str(index), 'power', 'off'], + shell=False, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + proc.communicate() + + +class BindingError(Exception): + pass + + +class HCI_User_Channel_Socket_Error(BaseException): + pass + + +class HCI_User_Channel_Socket(): + def __init__(self, device_index=0, device_mode=None, + asyncio_loop=None): + logging.debug( + "Device index: %s, Device address: %s", + device_index, + device_mode) + self.loop = asyncio_loop + self.libc = ctypes.cdll.LoadLibrary('libc.so.6') + self.rx_buffer_q = multiprocessing.Manager().Queue() + self.counter = 0 + self.device_index = device_index + self.device_mode = device_mode + self.hci_socket = self.socket_create() + self.socket_bind(self.device_index) + self.socket_clear() + self.listener_proc = None + self.listener_ev = multiprocessing.Manager().Event() + + def socket_create(self): + logging.debug("%s", self.socket_create.__name__) + new_socket = socket.socket(socket.AF_BLUETOOTH, + socket.SOCK_RAW | socket.SOCK_NONBLOCK, + socket.BTPROTO_HCI) + if new_socket is None: + raise HCI_User_Channel_Socket_Error("Socket error. \ + Opening socket failed") + new_socket.setblocking(False) + socket_size = new_socket.getsockopt( + socket.SOL_SOCKET, socket.SO_RCVBUF) + logging.info(f"Default socket recv buffer size: {socket_size}") + new_socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 500000) + socket_size = new_socket.getsockopt( + socket.SOL_SOCKET, socket.SO_RCVBUF) + logging.info(f"Set socket recv buffer size: {socket_size}") + return new_socket + + def socket_bind(self, index): + logging.debug("%s index: %s", self.socket_bind.__name__, index) + # addr: struct sockaddr_hci from /usr/include/bluetooth/hci.h + addr = struct.pack( + 'HHH', + hci.AF_BLUETOOTH, + index, + hci.HCI_CHANNEL_USER) + retry_binding = 2 + for i in range(retry_binding): + try: + bind = self.libc.bind(self.hci_socket.fileno(), + ctypes.cast(addr, + ctypes.POINTER(ctypes.c_ubyte)), + len(addr)) + if bind != 0: + raise BindingError + except BindingError: + logging.warning("Binding error. Trying to reset bluetooth.") + btmgmt_dev_reset(self.device_index) + if i < retry_binding - 1: + continue + else: + self.hci_socket.close() + logging.error("Binding error. Check HCI index present.") + sys.exit() + logging.info("Binding done!") + break + + def socket_clear(self): + logging.debug("%s", self.socket_clear.__name__) + try: + logging.info("Clearing the buffer...") + time.sleep(1) + cnt = 0 + while True: + buff = self.hci_socket.recv(SOCKET_RECV_BUFFER_SIZE) + cnt += len(buff) + logging.debug(f"Read from buffer {cnt} bytes") + except BlockingIOError: + logging.info("Buffer empty and ready!") + return + + async def send(self, ba_message): + await self.loop.sock_sendall(self.hci_socket, ba_message) + + def socket_listener(self): + recv_at_once = 0 + while True: + try: + if self.listener_ev.is_set(): + logging.info("listener_ev set") + break + buffer = self.hci_socket.recv(SOCKET_RECV_BUFFER_SIZE) + logging.info( + f"Socket recv: {self.counter} th packet with len: {len(buffer)}") + self.rx_buffer_q.put((buffer, time.perf_counter())) + recv_at_once += 1 + self.counter += 1 + + except BlockingIOError: + if recv_at_once > 1: + logging.info(f"Socket recv in one loop: {recv_at_once}") + recv_at_once = 0 + pass + except BrokenPipeError: + logging.info("BrokenPipeError: Closing...") + print("BrokenPipeError. Press Ctrl-C to exit...") + + def close(self): + logging.debug("%s ", self.close.__name__) + return self.hci_socket.close() + + def start(self): + self.listener_proc = multiprocessing.Process( + target=self.socket_listener, daemon=True) + self.listener_proc.start() + logging.info(f"start listener_proc pid: {self.listener_proc.pid}") + + def stop(self): + logging.info(f"stop listener_proc pid: {self.listener_proc.pid}") + self.listener_ev.set() + self.listener_proc.join() + self.close() diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/init.yaml.sample b/lib/bt/host/nimble/nimble/tools/hci_throughput/init.yaml.sample new file mode 100644 index 00000000..f097d9cf --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/init.yaml.sample @@ -0,0 +1,36 @@ +# +# 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. +# + +rx: + dev_index: '1' + own_address_type: 1 + own_address: C0:0D:A5:1A:98:EF + peer_dev_index: '2' + peer_address_type: 1 + peer_address: FE:69:8F:77:2F:49 +tx: + dev_index: '2' + own_address_type: 1 + own_address: FE:69:8F:77:2F:49 + peer_dev_index: '1' + peer_address_type: 1 + peer_address: C0:0D:A5:1A:98:EF +test_dir: /path/to/blehci_throughput/tests/Mon_May_23_12:29:10_2022 +transport_directory: default or /path/to/custom_transport.py +ltk: '0xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' \ No newline at end of file diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/log/.gitignore b/lib/bt/host/nimble/nimble/tools/hci_throughput/log/.gitignore new file mode 100644 index 00000000..c96a04f0 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/log/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/main.py b/lib/bt/host/nimble/nimble/tools/hci_throughput/main.py new file mode 100644 index 00000000..1f9d6e15 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/main.py @@ -0,0 +1,264 @@ +# +# 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. +# + +import multiprocessing +import check_addr +import argparse +import yaml +import sys +import subprocess +import traceback +import matplotlib.pyplot as plt +import csv +import util +import os +import math +import random + +PROCESS_TIMEOUT = 500 # seconds, adjust if necessary + + +def parse_arguments(): + parser = argparse.ArgumentParser( + description='App for measuring BLE throughput over ACL.', + epilog='How to run python script for hci0 -> rx and hci1 -> tx: \ + sudo python main.py -i 0 1 -m rx tx \ + -t path/to/custom_transport_directory -cf config.yaml') + parser.add_argument('-i', '--indexes', type=str, nargs='*', + help='specify adapters indexes', default=[0, 1]) + parser.add_argument('-m', '--modes', type=str, nargs="*", + help='devices modes - receiver, transmitter', + choices=['rx', 'tx'], default=['rx', 'tx']) + parser.add_argument('-t', '--transport_directory', type=str, nargs='*', + help='specify hci transport directory path. \ + Use for transport other than the default linux socket.', + default=["default"]) + parser.add_argument('-cf', '--config_file', type=str, nargs="*", + help='configuration file for devices', + default=["config.yaml"]) + try: + args = parser.parse_args() + except Exception as e: + print(traceback.format_exc()) + + print(f"Indexes: {args.indexes}") + print(f"Modes: {args.modes}") + print(f"Transport directory: {args.transport_directory}") + + return args + + +def get_dev_addr_and_type(hci_indexes: list, transport_directory: str): + if (len(hci_indexes) != 2): + raise Exception("HCI index error.") + manager = multiprocessing.Manager() + addr_list = manager.list() + check_addrs_proc = multiprocessing.Process(target=check_addr.check_addr, + name="Check addresses", + args=(hci_indexes, addr_list, + transport_directory)) + check_addrs_proc.start() + print("check_addrs_proc pid: ", check_addrs_proc.pid) + check_addrs_proc.join() + dev_addr_type_list = [] + for i in range(0, len(addr_list)): + dev_addr_type_list.append((hci_indexes[i],) + addr_list[i]) + return dev_addr_type_list + + +def change_config_var(filename: str, group: str, variable: str, + new_value: int): + with open(filename, "r") as file: + cfg = yaml.safe_load(file) + + if group: + cfg[group][variable] = new_value + else: + cfg[variable] = new_value + + with open(filename, "w") as file: + yaml.safe_dump(cfg, file, indent=1, sort_keys=False, + default_style=None, default_flow_style=False) + +def generate_long_term_key(): + rand_val = random.getrandbits(128) + return rand_val.to_bytes(16, byteorder='little') + + +def get_init_dict(filename: str, args_list: list, modes: list, dir: str, + transport_directory: str): + ini = { + modes[0]: { + "dev_index": args_list[0][0], + "own_address_type": args_list[0][1], + "own_address": args_list[0][2], + "peer_dev_index": args_list[1][0], + "peer_address_type": args_list[1][1], + "peer_address": args_list[1][2] + }, + modes[1]: { + "dev_index": args_list[1][0], + "own_address_type": args_list[1][1], + "own_address": args_list[1][2], + "peer_dev_index": args_list[0][0], + "peer_address_type": args_list[0][1], + "peer_address": args_list[0][2] + }, + "test_dir": dir, + "transport_directory": transport_directory, + "ltk": hex(random.getrandbits(128)) + } + + with open(filename, 'w') as file: + yaml.safe_dump(ini, file, indent=1, sort_keys=False) + + return ini + + +def run_once(modes: list, cfg_file: str, init_file: str): + list_proc = [] + for mode in modes: + proc = subprocess.Popen(["python", "hci_device.py", "-m", + mode, "-if", init_file, "-cf", cfg_file]) + print("start subprocess pid: ", proc.pid) + list_proc.append(proc) + try: + for proc in list_proc: + proc.wait(PROCESS_TIMEOUT) + except subprocess.TimeoutExpired: + for proc in list_proc: + print("TimeoutExpired subprocess pid: ", proc.pid) + proc.terminate() + for proc in list_proc: + proc.wait() + return -1 + + for proc in list_proc: + print("stop subprocess pid: ", proc.pid) + proc.terminate() + proc.wait() + return 0 + + +def testing_variable_influence(cfg: dict, modes: list, cfg_file: str, + init_file: str, init_dict: dict, + save_to_file: bool): + tp_test_counter = 1 + changed_params_list = [] + averages = [] + cfg_group = cfg["test"]["change_param_group"] + cfg_variable = cfg["test"]["change_param_variable"] + cfg_start_val = cfg["test"]["start_value"] + cfg_stop_val = cfg["test"]["stop_value"] + cfg_step = cfg["test"]["step"] + data_type = cfg["tp"]["data_type"] + total_iterations = math.ceil((cfg_stop_val - cfg_start_val) / cfg_step) + average_tp_csv_path = init_dict["test_dir"] + "/average_rx_tp.csv" + + with open(average_tp_csv_path, "w") as file: + file.write(f"Average throughput [{data_type}ps]\n") + + for i in range(cfg_start_val, cfg_stop_val, cfg_step): + changed_params_list.append(i) + + if cfg_group and cfg_variable: + print(f"Current param value: {i}") + num_of_params_to_change = len(cfg_variable) + + for j in range(0, num_of_params_to_change): + change_config_var(filename=cfg_file, group=cfg_group[j], + variable=cfg_variable[j], new_value=i) + + print(f"Running test: {tp_test_counter}/{total_iterations}...") + rc = run_once(modes, cfg_file, init_file) + if rc != 0: + print(f"Test {i} failed. Closing...") + return + + tp_test_counter += 1 + + with open(average_tp_csv_path, "r") as file: + csv_reader = csv.reader(file) + next(csv_reader) + for row in csv_reader: + averages.append(float(*row)) + + fig, ax = plt.subplots() + ax.plot(changed_params_list[:len(averages)], averages, '-k') + ax.set_ylabel(f"Average throughput [{data_type}/s]") + ax.set_xlabel("Changed parameter/next iteration") + ax.set_title("Average througput") + + if save_to_file: + name = init_dict["test_dir"] + "/average_tps" + plt.savefig(fname=name, format='png') + + plt.show(block=True) + + +def main(): + args = parse_arguments() + + init_file = "init.yaml" + cfg_file = args.config_file[0] + if (isinstance(args.transport_directory, list)): + args.transport_directory = args.transport_directory.pop() + else: + args.transport_directory = args.transport_directory + + with open(cfg_file, "r") as file: + cfg = yaml.safe_load(file) + + addr_list = get_dev_addr_and_type(args.indexes, args.transport_directory) + if len(addr_list) != len(args.indexes): + raise Exception("No device address received. Check HCI indexes.") + print(f"Received: {addr_list}") + + test_dir_path = util.create_test_directory() + init_dict = get_init_dict(filename=init_file, args_list=addr_list, + modes=args.modes, dir=test_dir_path, + transport_directory=args.transport_directory) + + util.copy_config_files_to_test_directory([init_file, cfg_file], + init_dict["test_dir"]) + + try: + if cfg["flag_testing"]: + testing_variable_influence(cfg, args.modes, *args.config_file, + init_file, init_dict, True) + else: + print(f"Running test...") + rc = run_once(args.modes, cfg_file, init_file) + if rc != 0: + print("Test failed.") + + print("Finished. Closing...") + + except KeyboardInterrupt: + pass + except Exception as e: + print(traceback.format_exc()) + finally: + # Set default ownership for dirs and files + util.set_default_chmod_recurs(os.getcwd() + "/tests") + sys.exit() + + +if __name__ == "__main__": + main() diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/requirements.txt b/lib/bt/host/nimble/nimble/tools/hci_throughput/requirements.txt new file mode 100644 index 00000000..8b2a114e --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/requirements.txt @@ -0,0 +1,3 @@ +matplotlib==3.1.2 +PyYAML==6.0 +libusb1 \ No newline at end of file diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_blehci/pkg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_blehci/pkg.yml new file mode 100644 index 00000000..9cd3540e --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_blehci/pkg.yml @@ -0,0 +1,24 @@ +# +# 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. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10040_blehci +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_blehci/syscfg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_blehci/syscfg.yml new file mode 100644 index 00000000..1c2bbee2 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_blehci/syscfg.yml @@ -0,0 +1,27 @@ +# +# 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. +# + +syscfg.vals: + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_CFG_FEAT_LE_2M_PHY: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 + MSYS_1_BLOCK_COUNT: 80 + MSYS_1_BLOCK_SIZE: 308 + BLE_TRANSPORT_ACL_COUNT: 80 + diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_blehci/target.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_blehci/target.yml new file mode 100644 index 00000000..f9d6d0fb --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_blehci/target.yml @@ -0,0 +1,22 @@ +# +# 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. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10040" +target.build_profile: optimized diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_boot/pkg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_boot/pkg.yml new file mode 100644 index 00000000..b4f0ee6c --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_boot/pkg.yml @@ -0,0 +1,23 @@ +# 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. + +pkg.name: targets/nordic_pca10040_boot +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: + diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_boot/target.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_boot/target.yml new file mode 100644 index 00000000..ad6f05a3 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10040_boot/target.yml @@ -0,0 +1,20 @@ +# 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. + +target.app: "@mcuboot/boot/mynewt" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10040" +target.build_profile: optimized diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_blehci/pkg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_blehci/pkg.yml new file mode 100644 index 00000000..a60adc72 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_blehci/pkg.yml @@ -0,0 +1,27 @@ +# +# 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. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10056_blehci +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: + +pkg.deps: + - "@apache-mynewt-core/hw/usb/tinyusb/std_descriptors" diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_blehci/syscfg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_blehci/syscfg.yml new file mode 100644 index 00000000..1c65d055 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_blehci/syscfg.yml @@ -0,0 +1,31 @@ +# +# 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. +# + +syscfg.vals: + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_CFG_FEAT_LE_2M_PHY: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 + BLE_TRANSPORT_HS: usb + USBD_VID: 0xDCAB + USBD_PID: 0x1234 + USBD_BTH: 1 + USBD_PRODUCT_STRING: '"throughput"' + MSYS_1_BLOCK_COUNT: 80 + MSYS_1_BLOCK_SIZE: 308 + BLE_TRANSPORT_ACL_COUNT: 80 diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_blehci/target.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_blehci/target.yml new file mode 100644 index 00000000..e6317f2d --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_blehci/target.yml @@ -0,0 +1,22 @@ +# +# 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. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10056" +target.build_profile: optimized diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_boot/pkg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_boot/pkg.yml new file mode 100644 index 00000000..5546afa8 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_boot/pkg.yml @@ -0,0 +1,23 @@ +# 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. + +pkg.name: targets/nordic_pca10056_boot +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: + diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_boot/target.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_boot/target.yml new file mode 100644 index 00000000..ff3aec12 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10056_boot/target.yml @@ -0,0 +1,20 @@ +# 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. + +target.app: "@mcuboot/boot/mynewt" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10056" +target.build_profile: optimized diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10059_blehci/pkg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10059_blehci/pkg.yml new file mode 100644 index 00000000..6b9edc3b --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10059_blehci/pkg.yml @@ -0,0 +1,27 @@ +# +# 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. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10059_blehci +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: + +pkg.deps: + - "@apache-mynewt-core/hw/usb/tinyusb/std_descriptors" diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10059_blehci/syscfg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10059_blehci/syscfg.yml new file mode 100644 index 00000000..6fc26b9d --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10059_blehci/syscfg.yml @@ -0,0 +1,31 @@ +# +# 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. +# + +syscfg.vals: + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_CFG_FEAT_LE_2M_PHY: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 + BLE_TRANSPORT_HS: usb + USBD_VID: 0xDCAB + USBD_PID: 0x1234 + USBD_BTH: 1 + USBD_PRODUCT_STRING: '"throughput_dongle"' + MSYS_1_BLOCK_COUNT: 80 + MSYS_1_BLOCK_SIZE: 308 + BLE_TRANSPORT_ACL_COUNT: 80 diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10059_blehci/target.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10059_blehci/target.yml new file mode 100644 index 00000000..b582fddd --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10059_blehci/target.yml @@ -0,0 +1,22 @@ +# +# 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. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10059" +target.build_profile: optimized diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_blehci/pkg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_blehci/pkg.yml new file mode 100644 index 00000000..eab5e987 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_blehci/pkg.yml @@ -0,0 +1,24 @@ +# +# 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. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10095_app_blehci +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_blehci/syscfg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_blehci/syscfg.yml new file mode 100644 index 00000000..c7ff62bb --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_blehci/syscfg.yml @@ -0,0 +1,42 @@ +# +# 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. +# + +syscfg.vals: + BSP_NRF5340_NET_ENABLE: 1 + NRF5340_EMBED_NET_CORE: 1 + NET_CORE_IMAGE_TARGET_NAME: '@apache-mynewt-nimble/tools/hci_throughput/targets/nordic_pca10095_net_blehci' + + BLE_TRANSPORT_HS: usb + USBD_VID: 0xDCAB + USBD_PID: 0x1234 + USBD_PRODUCT_STRING: '"throughput"' + USBD_BTH: 1 + USBD_BTH_EVENT_EP: 0x81 + USBD_BTH_DATA_IN_EP: 0x82 + USBD_BTH_DATA_OUT_EP: 0x02 + USBD_WINDOWS_COMP_ID: 1 + + BLE_TRANSPORT_ACL_COUNT: 80 + MSYS_1_BLOCK_COUNT: 80 + MSYS_1_BLOCK_SIZE: 308 + IPC_NRF5340_BUF_SZ: 3072 + + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_CFG_FEAT_LE_2M_PHY: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_blehci/target.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_blehci/target.yml new file mode 100644 index 00000000..9d5dbb72 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_blehci/target.yml @@ -0,0 +1,22 @@ +# +# 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. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095" +target.build_profile: optimized diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_boot/pkg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_boot/pkg.yml new file mode 100644 index 00000000..505dcbd5 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_boot/pkg.yml @@ -0,0 +1,24 @@ +# +# 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. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10095_app_boot +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_boot/syscfg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_boot/syscfg.yml new file mode 100644 index 00000000..30097ef0 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_boot/syscfg.yml @@ -0,0 +1,18 @@ +# +# 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. +# diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_boot/target.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_boot/target.yml new file mode 100644 index 00000000..0ccd2a98 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_app_boot/target.yml @@ -0,0 +1,22 @@ +# +# 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. +# + +target.app: "@mcuboot/boot/mynewt" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095" +target.build_profile: optimized diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_blehci/pkg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_blehci/pkg.yml new file mode 100644 index 00000000..3983cea9 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_blehci/pkg.yml @@ -0,0 +1,24 @@ +# +# 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. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10095_net_blehci +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_blehci/syscfg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_blehci/syscfg.yml new file mode 100644 index 00000000..7f0b5b60 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_blehci/syscfg.yml @@ -0,0 +1,33 @@ +# +# 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. +# + +syscfg.vals: + BLE_VERSION: 53 + BLE_TRANSPORT_HS: nrf5340 + BLE_LL_SCA: 50 + OS_CRASH_FILE_LINE: 1 + + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_CFG_FEAT_LE_2M_PHY: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 + + BLE_TRANSPORT_ACL_COUNT: 80 + MSYS_1_BLOCK_COUNT: 80 + MSYS_1_BLOCK_SIZE: 308 + IPC_NRF5340_BUF_SZ: 3072 diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_blehci/target.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_blehci/target.yml new file mode 100644 index 00000000..0bf51ba8 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_blehci/target.yml @@ -0,0 +1,22 @@ +# +# 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. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095_net" +target.build_profile: optimized diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_boot/pkg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_boot/pkg.yml new file mode 100644 index 00000000..61c48efc --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_boot/pkg.yml @@ -0,0 +1,24 @@ +# +# 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. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10095_net_boot +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_boot/syscfg.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_boot/syscfg.yml new file mode 100644 index 00000000..10b03c60 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_boot/syscfg.yml @@ -0,0 +1,22 @@ +# +# 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. +# + +syscfg.vals: + BOOTUTIL_OVERWRITE_ONLY: 1 + WATCHDOG_INTERVAL: 0 diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_boot/target.yml b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_boot/target.yml new file mode 100644 index 00000000..a293a4ca --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/targets/nordic_pca10095_net_boot/target.yml @@ -0,0 +1,22 @@ +# +# 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. +# + +target.app: "@mcuboot/boot/mynewt" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095_net" +target.build_profile: optimized diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/tests/.gitignore b/lib/bt/host/nimble/nimble/tools/hci_throughput/tests/.gitignore new file mode 100755 index 00000000..c96a04f0 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/tests/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/throughput.py b/lib/bt/host/nimble/nimble/tools/hci_throughput/throughput.py new file mode 100644 index 00000000..e2b78b72 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/throughput.py @@ -0,0 +1,216 @@ +# +# 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. +# + +import time +import matplotlib.pyplot as plt +import csv +import struct +import argparse +import traceback + +data_types = ['kb', 'kB'] + + +def parse_arguments(): + parser = argparse.ArgumentParser( + description='Plot throughput from the csv file.', + epilog='How to run script: \ + python throughput.py -f tests/Wed_Apr_13_08:36:29_2022/tp_receiver.csv -s 0.1') + + parser.add_argument('-f', '--file', type=str, nargs='*', + help='csv file path', default=["tp_receiver"]) + parser.add_argument('-s', '--samp_t', type=float, nargs='*', + help='specify throughput sample time', default=1.0) + try: + args = parser.parse_args() + except Exception as e: + print(traceback.format_exc()) + return args + + +def gen_data(num_of_bytes_in_packet: int, + last_number_from_previous_data_packet: int): + counter = last_number_from_previous_data_packet + 1 + rem = num_of_bytes_in_packet % 4 + valid_data_len = int((num_of_bytes_in_packet - rem) / 4) + total_data_len = valid_data_len + rem + data = [0] * total_data_len + for i in range(rem, total_data_len): + data[i] = counter + counter += 1 + last_value = data[len(data) - 1] + if rem: + fmt = "<" + str(rem) + "B" + str(valid_data_len) + "I" + else: + fmt = "<" + str(valid_data_len) + "I" + data_ba = struct.pack(fmt, *data) + return data_ba, last_value + + +class Throughput(): + def __init__( + self, + name="tp_chart", + mode="rx", + total_packets_number=0, + bytes_number_in_packet=0, + throughput_data_type='kb', + flag_plot_packets=True, + sample_time=1, + test_directory=None): + self.name = name + self.mode = mode + self.total_packets_number = total_packets_number + self.bytes_number_in_packet = bytes_number_in_packet + self.predef_packet_key = int( + (bytes_number_in_packet - (bytes_number_in_packet % 4)) / 4) + self.total_bits_number = bytes_number_in_packet * 8 + assert throughput_data_type in data_types + self.throughput_data_type = throughput_data_type + self.flag_plot_packets = flag_plot_packets + self.sample_time = sample_time + self.test_directory = test_directory + + if self.test_directory is not None: + self.csv_file_name = self.test_directory + "/" + \ + time.strftime("%Y_%m_%d_%H_%M_%S_") + self.name + ".csv" + else: + self.csv_file_name = time.strftime( + "%Y_%m_%d_%H_%M_%S_") + self.name + ".csv" + self.clean_csv_file() + + def calc_throughput(self, current_num, last_num, current_time, last_time): + if self.throughput_data_type == 'kb': + return float( + (((current_num - last_num) * self.total_bits_number) / + (current_time - last_time)) / 1000) + elif self.throughput_data_type == 'kB': + return float( + (((current_num - last_num) * self.bytes_number_in_packet) / + (current_time - last_time)) / 1000) + + def clean_csv_file(self): + file = open(self.csv_file_name, 'w') + file.write("Time,Packet\n") + + def append_to_csv_file( + self, + timestamp: float = 0.0, + packet_number: int = 0): + with open(self.csv_file_name, "a") as file: + csv_writer = csv.writer(file) + csv_writer.writerow([timestamp, packet_number]) + + def get_average(self, packet_numbers, timestamps): + if self.throughput_data_type == 'kb': + average_tp = ((packet_numbers * self.total_bits_number) + / (timestamps[-1] - timestamps[0])) / 1000 + elif self.throughput_data_type == 'kB': + average_tp = ((packet_numbers * self.bytes_number_in_packet) + / (timestamps[-1] - timestamps[0])) / 1000 + return average_tp + + def save_average(self, tp_csv_filename=None): + if self.mode == "rx": + timestamps = [] + packet_numbers = [] + + if tp_csv_filename is None: + tp_csv_filename = self.csv_file_name + else: + tp_csv_filename += ".csv" + + with open(tp_csv_filename, "r") as file: + csv_reader = csv.reader(file) + next(csv_reader) + for row in csv_reader: + timestamps.append(float(row[0])) + packet_numbers.append(float(row[1])) + + average_tp = self.get_average(packet_numbers[-1], timestamps) + print( + f"Average rx throughput: {round(average_tp, 3)} {self.throughput_data_type}ps") + + with open(self.test_directory + "/average_rx_tp.csv", "a") as file: + csv_writer = csv.writer(file) + csv_writer.writerow([average_tp]) + + def plot_tp_from_file(self, filename: str = None, sample_time: float = 1, + save_to_file: bool = True): + timestamps = [] + packet_numbers = [] + + if filename is None: + filename = self.csv_file_name + print("Results:", filename) + + with open(filename, "r") as file: + csv_reader = csv.reader(file) + next(csv_reader) + for row in csv_reader: + timestamps.append(float(row[0])) + packet_numbers.append(float(row[1])) + + last_time = 0 + last_number = packet_numbers[0] + throughput = [] + offset = timestamps[0] + + for i in range(0, len(timestamps)): + timestamps[i] -= offset + if timestamps[i] - last_time > sample_time: + throughput.append((timestamps[i], + self.calc_throughput(packet_numbers[i], + last_number, + timestamps[i], + last_time))) + last_time = timestamps[i] + last_number = packet_numbers[i] + + average_tp = self.get_average(packet_numbers[-1], timestamps) + + fig, ax = plt.subplots() + if self.flag_plot_packets: + ax2 = ax.twinx() + + ax.plot(*zip(*throughput), 'k-') + if self.flag_plot_packets: + ax2.plot(timestamps, packet_numbers, 'b-') + + ax.set_title(self.name) + ax.set_ylabel(f"Throughput [{self.throughput_data_type}/s]") + ax.set_xlabel("Time [s]") + ax.text(0.9, 1.02, f"Average: {round(average_tp, 3)}" + f"{self.throughput_data_type}ps", transform=ax.transAxes, + color='k') + if self.flag_plot_packets: + ax2 = ax2.set_ylabel(f"Packets [Max:{len(packet_numbers)}]", + color='b') + + if save_to_file: + path = filename.replace(".csv", ".png") + plt.savefig(path) + + plt.show(block=True) + + +if __name__ == "__main__": + args = parse_arguments() + tp = Throughput(bytes_number_in_packet=247) + tp.plot_tp_from_file(*args.file, args.samp_t[0], save_to_file=False) diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/transport_factory.py b/lib/bt/host/nimble/nimble/tools/hci_throughput/transport_factory.py new file mode 100644 index 00000000..9b5f07aa --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/transport_factory.py @@ -0,0 +1,55 @@ +# +# 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. +# + +import hci_socket +import logging +import traceback +import sys + + +class TransportFactory: + def __init__(self, device_index: str = None, device_mode=None, + asyncio_loop=None, transport_directory=None) -> None: + if (device_index.isnumeric()): + self.transport = hci_socket.HCI_User_Channel_Socket( + int(device_index), device_mode, asyncio_loop) + else: + try: + if (transport_directory != "default"): + sys.path.append(transport_directory) + print(sys.path) + import custom_transport + self.transport = custom_transport.Transport(device_index, + device_mode, + asyncio_loop) + else: + raise Exception( + "Device index and transport does not match.") + except Exception as e: + logging.error(traceback.format_exc()) + sys.exit() + + self.rx_buffer_q = self.transport.rx_buffer_q + self.send = self.transport.send + + def start(self): + self.transport.start() + + def stop(self): + self.transport.stop() diff --git a/lib/bt/host/nimble/nimble/tools/hci_throughput/util.py b/lib/bt/host/nimble/nimble/tools/hci_throughput/util.py new file mode 100644 index 00000000..96bfd908 --- /dev/null +++ b/lib/bt/host/nimble/nimble/tools/hci_throughput/util.py @@ -0,0 +1,72 @@ +# +# 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. +# + +import logging +import shutil +import time +import os +from pathlib import Path + + +def create_test_directory(): + test_dir_name = "tests/" + time.strftime("%Y_%m_%d_%H_%M_%S") + path = os.path.join(os.getcwd(), test_dir_name) + os.mkdir(path, mode=0o777) + print("Test directory: ", path) + return path + + +def configure_logging(log_filename, clear_log_file=True): + format_template = ("%(asctime)s %(threadName)s %(name)s %(levelname)s " + "%(filename)-25s %(lineno)-5s " + "%(funcName)-25s : %(message)s") + logging.basicConfig(format=format_template, + filename=log_filename, + filemode='a', + level=logging.DEBUG) + if clear_log_file: + with open(log_filename, "w") as f: + f.write("asctime\t\t\t\t\tthreadName name levelname filename\ + \tlineno\tfuncName\t\t\t\tmessage\n") + + logging.getLogger("asyncio").setLevel(logging.WARNING) + logging.getLogger("matplotlib").setLevel(logging.WARNING) + + +def copy_config_files_to_test_directory(files: list, test_directory: str): + for file in files: + shutil.copy(file, test_directory + "/" + Path(file).name) + + +def copy_log_files_to_test_directory(dir: str): + log_files = ["log/log_rx.log", "log/log_tx.log", "log/check_addr.log"] + for file in log_files: + shutil.copy(file, dir + "/" + time.strftime("%Y_%m_%d_%H_%M_%S_") + + file.replace("log/", "")) + + +# Running tests as sudo implies root permissions on created directories/files. +# This function sets the default permission mode to dirs/files in given path +# recursively. +def set_default_chmod_recurs(path): + for root, dirs, files in os.walk(path): + for d in dirs: + os.chmod(os.path.join(root, d), 0o0777) + for f in files: + os.chmod(os.path.join(root, f), 0o0777) diff --git a/lib/bt/host/nimble/nimble/uncrustify.cfg b/lib/bt/host/nimble/nimble/uncrustify.cfg index 481a62ab..1735f339 100644 --- a/lib/bt/host/nimble/nimble/uncrustify.cfg +++ b/lib/bt/host/nimble/nimble/uncrustify.cfg @@ -225,7 +225,7 @@ indent_paren_nl = false # false/true # 0: Indent to body level # 1: Align under the open paren # 2: Indent to the brace level -indent_paren_close = 0 # number +indent_paren_close = 2 # number # Controls the indent of a comma when inside a paren.If TRUE, aligns under the open paren indent_comma_paren = false # false/true @@ -678,7 +678,7 @@ sp_try_brace = ignore # ignore/add/remove/force sp_getset_brace = ignore # ignore/add/remove/force # Add or remove space between a variable and '{' for C++ uniform initialization. Default=Add -sp_word_brace = add # ignore/add/remove/force +sp_word_brace_init_lst = add # ignore/add/remove/force # Add or remove space between a variable and '{' for a namespace. Default=Add sp_word_brace_ns = add # ignore/add/remove/force diff --git a/lib/bt/host/nimble/port/include/esp_nimble_cfg.h b/lib/bt/host/nimble/port/include/esp_nimble_cfg.h index d837d17e..d2fa3338 100644 --- a/lib/bt/host/nimble/port/include/esp_nimble_cfg.h +++ b/lib/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -133,10 +133,31 @@ #define MYNEWT_VAL_BLE_GATT_CACHING (0) #else #define MYNEWT_VAL_BLE_GATT_CACHING (CONFIG_BT_NIMBLE_GATT_CACHING) + +#ifdef CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CONNS #define MYNEWT_VAL_BLE_GATT_CACHING_MAX_CONNS (CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CONNS) +#else +#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_CONNS (0) +#endif + +#ifdef CONFIG_BT_NIMBLE_GATT_CACHING_MAX_SVCS #define MYNEWT_VAL_BLE_GATT_CACHING_MAX_SVCS (CONFIG_BT_NIMBLE_GATT_CACHING_MAX_SVCS) +#else +#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_SVCS (0) +#endif + +#ifdef CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CHRS #define MYNEWT_VAL_BLE_GATT_CACHING_MAX_CHRS (CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CHRS) +#else +#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_CHRS (0) +#endif + +#ifdef CONFIG_BT_NIMBLE_GATT_CACHING_MAX_DSCS #define MYNEWT_VAL_BLE_GATT_CACHING_MAX_DSCS (CONFIG_BT_NIMBLE_GATT_CACHING_MAX_DSCS) +#else +#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_DSCS (0) +#endif + #endif #ifndef CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES @@ -486,8 +507,16 @@ /*** @apache-mynewt-nimble/nimble/host */ +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT CONFIG_BT_NIMBLE_L2CAP_COC_SDU_BUFF_COUNT +#endif + #ifndef MYNEWT_VAL_BLE_DYNAMIC_SERVICE +#ifdef CONFIG_BT_NIMBLE_DYNAMIC_SERVICE #define MYNEWT_VAL_BLE_DYNAMIC_SERVICE CONFIG_BT_NIMBLE_DYNAMIC_SERVICE +#else +#define MYNEWT_VAL_BLE_DYNAMIC_SERVICE (0) +#endif #endif #ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU @@ -610,6 +639,10 @@ #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -843,15 +876,18 @@ #endif -#ifndef MYNEWT_VAL_BLE_SM_SC_LVL -#define MYNEWT_VAL_BLE_SM_SC_LVL CONFIG_BT_NIMBLE_SM_SC_LVL +#ifndef MYNEWT_VAL_BLE_SM_LVL +#ifdef CONFIG_BT_NIMBLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL CONFIG_BT_NIMBLE_SM_LVL +#else +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif #endif #ifndef MYNEWT_VAL_BLE_SM_SC_ONLY #define MYNEWT_VAL_BLE_SM_SC_ONLY (0) #endif - #ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif @@ -1792,7 +1828,7 @@ #endif #endif -#if CONFIG_BT_CONTROLLER_DISABLED +#if CONFIG_BT_CONTROLLER_DISABLED && CONFIG_BT_NIMBLE_TRANSPORT_UART #ifndef MYNEWT_VAL_BLE_TRANSPORT_UART_PORT #define MYNEWT_VAL_BLE_TRANSPORT_UART_PORT CONFIG_BT_NIMBLE_TRANSPORT_UART_PORT #endif @@ -1814,7 +1850,7 @@ #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_UART_BAUDRATE -#define MYNEWT_VAL_BLE_TRANSPORT_UART_BAUDRATE (921600) +#define MYNEWT_VAL_BLE_TRANSPORT_UART_BAUDRATE CONFIG_BT_NIMBLE_HCI_UART_BAUDRATE #endif #ifndef MYNEWT_VAL_BLE_TRANSPORT_UART_DATA_BITS diff --git a/lib/bt/include/esp32/include/esp_bt.h b/lib/bt/include/esp32/include/esp_bt.h index 6b7ef157..b31ce276 100644 --- a/lib/bt/include/esp32/include/esp_bt.h +++ b/lib/bt/include/esp32/include/esp_bt.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -50,7 +50,7 @@ extern "C" { #endif //CONFIG_BT_ENABLED -#define ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL 0x20221207 +#define ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL 0x20240315 /** * @brief Bluetooth mode for controller enable/disable @@ -167,6 +167,12 @@ the adv packet will be discarded until the memory is restored. */ #define BTDM_CONTROLLER_SCO_DATA_PATH_HCI 0 // SCO data is routed to HCI #define BTDM_CONTROLLER_SCO_DATA_PATH_PCM 1 // SCO data path is PCM +#ifdef CONFIG_BTDM_CTRL_SCAN_BACKOFF_UPPERLIMITMAX +#define BTDM_CTRL_SCAN_BACKOFF_UPPERLIMITMAX CONFIG_BTDM_CTRL_SCAN_BACKOFF_UPPERLIMITMAX +#else +#define BTDM_CTRL_SCAN_BACKOFF_UPPERLIMITMAX 0 +#endif + #define BT_CONTROLLER_INIT_CONFIG_DEFAULT() { \ .controller_task_stack_size = ESP_TASK_BT_CONTROLLER_STACK, \ .controller_task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \ @@ -190,6 +196,7 @@ the adv packet will be discarded until the memory is restored. */ .pcm_polar = CONFIG_BTDM_CTRL_PCM_POLAR_EFF, \ .hli = BTDM_CTRL_HLI, \ .dup_list_refresh_period = SCAN_DUPL_CACHE_REFRESH_PERIOD, \ + .ble_scan_backoff = BTDM_CTRL_SCAN_BACKOFF_UPPERLIMITMAX, \ .magic = ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL, \ } @@ -233,6 +240,7 @@ typedef struct { uint8_t pcm_polar; /*!< PCM polar trig (falling clk edge & rising clk edge) */ bool hli; /*!< Using high level interrupt or not */ uint16_t dup_list_refresh_period; /*!< Duplicate scan list refresh period */ + bool ble_scan_backoff; /*!< BLE scan backoff */ uint32_t magic; /*!< Magic number */ } esp_bt_controller_config_t; diff --git a/lib/bt/include/esp32c3/include/esp_bt.h b/lib/bt/include/esp32c3/include/esp_bt.h index 64760fc6..8beb1d17 100644 --- a/lib/bt/include/esp32c3/include/esp_bt.h +++ b/lib/bt/include/esp32c3/include/esp_bt.h @@ -19,7 +19,7 @@ extern "C" { #endif #define ESP_BT_CTRL_CONFIG_MAGIC_VAL 0x5A5AA5A5 -#define ESP_BT_CTRL_CONFIG_VERSION 0x02401120 +#define ESP_BT_CTRL_CONFIG_VERSION 0x02404010 #define ESP_BT_HCI_TL_MAGIC_VALUE 0xfadebead #define ESP_BT_HCI_TL_VERSION 0x00010000 @@ -194,6 +194,18 @@ typedef void (* esp_bt_hci_tl_callback_t) (void *arg, uint8_t status); #define BT_BLE_ADV_DATA_LENGTH_ZERO_AUX (0) #endif +#if defined(CONFIG_BT_CTRL_CHAN_ASS_EN) +#define BT_CTRL_CHAN_ASS_EN (CONFIG_BT_CTRL_CHAN_ASS_EN) +#else +#define BT_CTRL_CHAN_ASS_EN (0) +#endif + +#if defined(CONFIG_BT_CTRL_LE_PING_EN) +#define BT_CTRL_LE_PING_EN (CONFIG_BT_CTRL_LE_PING_EN) +#else +#define BT_CTRL_LE_PING_EN (0) +#endif + #define AGC_RECORRECT_EN ((BT_CTRL_AGC_RECORRECT_EN << 0) | (BT_CTRL_CODED_AGC_RECORRECT <<1) | (BT_CTRL_AGC_RECORRECT_NEW << 2)) #define CFG_MASK_BIT_SCAN_DUPLICATE_OPTION (1<<0) @@ -241,6 +253,8 @@ typedef void (* esp_bt_hci_tl_callback_t) (void *arg, uint8_t status); .ble_50_feat_supp = BT_CTRL_50_FEATURE_SUPPORT, \ .ble_cca_mode = BT_BLE_CCA_MODE, \ .ble_data_lenth_zero_aux = BT_BLE_ADV_DATA_LENGTH_ZERO_AUX, \ + .ble_chan_ass_en = BT_CTRL_CHAN_ASS_EN, \ + .ble_ping_en = BT_CTRL_LE_PING_EN, \ } #else @@ -289,7 +303,7 @@ typedef struct { uint8_t sleep_clock; /*!< controller sleep clock */ uint8_t ble_st_acl_tx_buf_nb; /*!< controller static ACL TX BUFFER number */ uint8_t ble_hw_cca_check; /*!< controller hardware triggered CCA check */ - uint16_t ble_adv_dup_filt_max; /*!< maxinum number of duplicate scan filter */ + uint16_t ble_adv_dup_filt_max; /*!< maximum number of duplicate scan filter */ bool coex_param_en; /*!< deprecated */ uint8_t ce_len_type; /*!< connection event length computation method */ bool coex_use_hooks; /*!< deprecated */ @@ -312,7 +326,9 @@ typedef struct { uint16_t dup_list_refresh_period; /*!< duplicate scan list refresh time */ bool ble_50_feat_supp; /*!< BLE 5.0 feature support */ uint8_t ble_cca_mode; /*!< BLE CCA mode */ - uint8_t ble_data_lenth_zero_aux; /*!< Config ext adv aux option*/ + uint8_t ble_data_lenth_zero_aux; /*!< Config ext adv aux option */ + uint8_t ble_chan_ass_en; /*!< BLE channel assessment enable */ + uint8_t ble_ping_en; /*!< BLE ping procedure enable */ } esp_bt_controller_config_t; /** @@ -600,6 +616,15 @@ void esp_wifi_bt_power_domain_on(void); */ void esp_wifi_bt_power_domain_off(void); +/** + * @brief Get the Bluetooth module sleep clock source. + * + * Note that this function shall not be invoked before esp_bt_controller_init() + * + * @return clock source used in Bluetooth low power mode + */ +esp_bt_sleep_clock_t esp_bt_get_lpclk_src(void); + #ifdef __cplusplus } #endif diff --git a/lib/bt/include/esp32c5/include/esp_bt.h b/lib/bt/include/esp32c5/include/esp_bt.h new file mode 100644 index 00000000..1a7cd646 --- /dev/null +++ b/lib/bt/include/esp32c5/include/esp_bt.h @@ -0,0 +1,433 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ESP_BT_H__ +#define __ESP_BT_H__ + +#include +#include +#include "esp_err.h" +#include "sdkconfig.h" +#include "esp_task.h" + +#include "nimble/nimble_npl.h" +#include "../../../../controller/esp32c5/esp_bt_cfg.h" +#include "hal/efuse_hal.h" + +#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART +#include "driver/uart.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @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 */ + ESP_BT_MODE_CLASSIC_BT = 0x02, /*!< Run Classic BT mode */ + ESP_BT_MODE_BTDM = 0x03, /*!< Run dual mode */ +} esp_bt_mode_t; + +/** + * @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 */ + ESP_BT_CONTROLLER_STATUS_ENABLED, /*!< Controller is in enabled state */ + ESP_BT_CONTROLLER_STATUS_NUM, /*!< Controller is in disabled state */ +} esp_bt_controller_status_t; + +/** + * @brief BLE tx power type + * ESP_BLE_PWR_TYPE_CONN_HDL0-8: for each connection, and only be set after connection completed. + * when disconnect, the correspond TX power is not effected. + * ESP_BLE_PWR_TYPE_ADV : for advertising/scan response. + * ESP_BLE_PWR_TYPE_SCAN : for scan. + * ESP_BLE_PWR_TYPE_DEFAULT : if each connection's TX power is not set, it will use this default value. + * if neither in scan mode nor in adv mode, it will use this default value. + * If none of power type is set, system will use ESP_PWR_LVL_P3 as default for ADV/SCAN/CONN0-9. + */ +typedef enum { + ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, /*!< For connection handle 0 */ + ESP_BLE_PWR_TYPE_CONN_HDL1 = 1, /*!< For connection handle 1 */ + ESP_BLE_PWR_TYPE_CONN_HDL2 = 2, /*!< For connection handle 2 */ + ESP_BLE_PWR_TYPE_CONN_HDL3 = 3, /*!< For connection handle 3 */ + ESP_BLE_PWR_TYPE_CONN_HDL4 = 4, /*!< For connection handle 4 */ + ESP_BLE_PWR_TYPE_CONN_HDL5 = 5, /*!< For connection handle 5 */ + ESP_BLE_PWR_TYPE_CONN_HDL6 = 6, /*!< For connection handle 6 */ + ESP_BLE_PWR_TYPE_CONN_HDL7 = 7, /*!< For connection handle 7 */ + ESP_BLE_PWR_TYPE_CONN_HDL8 = 8, /*!< For connection handle 8 */ + ESP_BLE_PWR_TYPE_ADV = 9, /*!< For advertising */ + ESP_BLE_PWR_TYPE_SCAN = 10, /*!< For scan */ + ESP_BLE_PWR_TYPE_DEFAULT = 11, /*!< For default, if not set other, it will use default value */ + ESP_BLE_PWR_TYPE_NUM = 12, /*!< TYPE numbers */ +} esp_ble_power_type_t; + +/** + * @brief Bluetooth TX power level(index), it's just a index corresponding to power(dbm). + */ +typedef enum { + 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_P18 = 14, /*!< Corresponding to +18dbm */ + ESP_PWR_LVL_P20 = 15, /*!< 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, + ESP_BLE_ENHANCED_PWR_TYPE_SCAN, + ESP_BLE_ENHANCED_PWR_TYPE_INIT, + ESP_BLE_ENHANCED_PWR_TYPE_CONN, + ESP_BLE_ENHANCED_PWR_TYPE_MAX, +} esp_ble_enhanced_power_type_t; + +/** + * @brief Select buffers +*/ +typedef enum { + ESP_BLE_LOG_BUF_HCI = 0x02, + ESP_BLE_LOG_BUF_CONTROLLER = 0x05, +} esp_ble_log_buf_t; + +/** + * @brief Address type and address value. + */ +typedef struct { + 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 Set BLE TX power + * Connection Tx power should only be set after connection created. + * @param power_type : The type of which tx power, could set Advertising/Connection/Default and etc + * @param power_level: Power level(index) corresponding to absolute value(dbm) + * @return ESP_OK - success, other - failed + */ +esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_t power_level); + +/** + * @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 ENHANCED API for Setting BLE TX power + * Connection Tx power should only be set after connection created. + * @param power_type : The enhanced type of which tx power, could set Advertising/Connection/Default and etc. + * @param handle : The handle of Advertising or Connection and the value 0 for other enhanced power types. + * @param power_level: Power level(index) corresponding to absolute value(dbm) + * @return ESP_OK - success, other - failed + */ +esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle, esp_power_level_t power_level); + +/** + * @brief ENHANCED API of Getting BLE TX power + * Connection Tx power should only be get after connection created. + * @param power_type : The enhanced type of which tx power, could set Advertising/Connection/Default and etc + * @param handle : The handle of Advertising or Connection and the value 0 for other enhanced power types. + * @return >= 0 - Power level, < 0 - Invalid + */ +esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle); + +#define CONFIG_VERSION 0x20231124 +#define CONFIG_MAGIC 0x5A5AA5A5 + +/** + * @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; /*!< Configuration version */ + uint16_t ble_ll_resolv_list_size; /*!< Size of the BLE resolving list */ + uint16_t ble_hci_evt_hi_buf_count; /*!< Number of high priority HCI event buffers */ + uint16_t ble_hci_evt_lo_buf_count; /*!< Number of low priority HCI event buffers */ + uint8_t ble_ll_sync_list_cnt; /*!< Number of entries in the BLE sync list */ + uint8_t ble_ll_sync_cnt; /*!< Number of BLE sync instances */ + uint16_t ble_ll_rsp_dup_list_count; /*!< Size of the BLE response duplicate list */ + uint16_t ble_ll_adv_dup_list_count; /*!< Size of the BLE advertising duplicate list */ + uint8_t ble_ll_tx_pwr_dbm; /*!< BLE transmit power in dBm */ + uint64_t rtc_freq; /*!< RTC (Real-Time Clock) frequency */ + uint16_t ble_ll_sca; /*!< BLE sleep clock accuracy in ppm */ + uint8_t ble_ll_scan_phy_number; /*!< Number of BLE scanning physical layers */ + uint16_t ble_ll_conn_def_auth_pyld_tmo; /*!< BLE connection default authentication payload timeout */ + uint8_t ble_ll_jitter_usecs; /*!< BLE link layer jitter in microseconds */ + uint16_t ble_ll_sched_max_adv_pdu_usecs; /*!< BLE scheduler maximum advertising PDU duration in microseconds */ + uint16_t ble_ll_sched_direct_adv_max_usecs; /*!< BLE scheduler maximum direct advertising duration in microseconds */ + uint16_t ble_ll_sched_adv_max_usecs; /*!< BLE scheduler maximum advertising duration in microseconds */ + uint16_t ble_scan_rsp_data_max_len; /*!< Maximum length of BLE scan response data */ + uint8_t ble_ll_cfg_num_hci_cmd_pkts; /*!< Number of BLE LL configuration HCI command packets */ + uint32_t ble_ll_ctrl_proc_timeout_ms; /*!< BLE link layer controller process timeout in milliseconds */ + uint16_t nimble_max_connections; /*!< Maximum number of concurrent BLE connections */ + uint8_t ble_whitelist_size; /*!< Size of the BLE whitelist */ + uint16_t ble_acl_buf_size; /*!< Size of the BLE ACL data buffer */ + uint16_t ble_acl_buf_count; /*!< Number of BLE ACL data buffers */ + uint16_t ble_hci_evt_buf_size; /*!< Size of the BLE HCI event buffer */ + uint16_t ble_multi_adv_instances; /*!< Number of BLE multi-advertising instances */ + uint16_t ble_ext_adv_max_size; /*!< Maximum size of BLE extended advertising data */ + uint16_t controller_task_stack_size; /*!< Controller task stack size */ + uint8_t controller_task_prio; /*!< Controller task priority */ + uint8_t controller_run_cpu; /*!< CPU core on which the controller runs */ + uint8_t enable_qa_test; /*!< Enable quality assurance (QA) testing */ + uint8_t enable_bqb_test; /*!< Enable Bluetooth Qualification Test (BQB) testing */ + uint8_t enable_uart_hci; /*!< Enable UART HCI (Host Controller Interface) */ + uint8_t ble_hci_uart_port; /*!< UART port number for Bluetooth HCI */ + uint32_t ble_hci_uart_baud; /*!< Baud rate for Bluetooth HCI UART */ + uint8_t ble_hci_uart_data_bits; /*!< Number of data bits for Bluetooth HCI UART */ + uint8_t ble_hci_uart_stop_bits; /*!< Number of stop bits for Bluetooth HCI UART */ + uint8_t ble_hci_uart_flow_ctrl; /*!< Flow control settings for Bluetooth HCI UART */ + uint8_t ble_hci_uart_uart_parity; /*!< Parity settings for Bluetooth HCI UART */ + uint8_t enable_tx_cca; /*!< Enable Transmit Clear Channel Assessment (TX CCA) */ + uint8_t cca_rssi_thresh; /*!< RSSI threshold for Transmit Clear Channel Assessment (CCA) */ + uint8_t sleep_en; /*!< Enable sleep mode */ + uint8_t coex_phy_coded_tx_rx_time_limit; /*!< PHY coded transmission and reception time limit for coexistence */ + uint8_t dis_scan_backoff; /*!< Disable scan backoff */ + uint8_t ble_scan_classify_filter_enable; /*!< Enable BLE scan classify filter */ + uint8_t cca_drop_mode; /*!< CCA drop mode */ + int8_t cca_low_tx_pwr; /*!< CCA low transmit power */ + uint8_t main_xtal_freq; /*!< Main crystal frequency */ + uint8_t cpu_freq_mhz; /*!< CPU frequency in megahertz (MHz) */ + uint8_t ignore_wl_for_direct_adv; /*!< Ignore the whitelist for direct advertising */ + uint8_t enable_pcl; /*!< Enable power control */ + uint8_t csa2_select; /*!< Select CSA#2*/ + uint32_t config_magic; /*!< Magic number for configuration validation */ +} esp_bt_controller_config_t; + +#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, \ + .sleep_en = NIMBLE_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, \ + .cpu_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, \ + .ignore_wl_for_direct_adv = 0, \ + .enable_pcl = DEFAULT_BT_LE_POWER_CONTROL_ENABLED, \ + .csa2_select = DEFAULT_BT_LE_50_FEATURE_SUPPORT, \ + .config_magic = CONFIG_MAGIC, \ +} + +/** + * @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. + * @return ESP_OK - success, other - failed + */ +esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg); + +/** + * @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 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. + * @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 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*/ +} esp_vhci_host_callback_t; + +/** @brief esp_vhci_host_check_send_available + * used for check actively if the host can send packet to controller or not. + * @return true for ready to send, false means cannot send packet + */ +bool esp_vhci_host_check_send_available(void); + +/** @brief esp_vhci_host_send_packet + * host send packet to controller + * + * Should not call this function from within a critical section + * or when the scheduler is suspended. + * + * @param data the packet point + * @param len the packet length + */ +void esp_vhci_host_send_packet(uint8_t *data, uint16_t len); + +/** @brief esp_vhci_host_register_callback + * register the vhci reference callback + * struct defined by vhci_host_callback structure. + * @param callback esp_vhci_host_callback type variable + * @return ESP_OK - success, ESP_FAIL - failed + */ +esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback); + +/** @brief esp_bt_controller_mem_release + * release the controller memory as per the mode + * + * This function releases the BSS, data and other sections of the controller to heap. The total size is about 70k bytes. + * + * esp_bt_controller_mem_release(mode) should be called only before esp_bt_controller_init() + * or after esp_bt_controller_deinit(). + * + * Note that once BT controller memory is released, the process cannot be reversed. It means you cannot use the bluetooth + * mode which you have released by this function. + * + * If your firmware will later upgrade the Bluetooth controller mode (BLE -> BT Classic or disabled -> enabled) + * then do not call this function. + * + * If the app calls esp_bt_controller_enable(ESP_BT_MODE_BLE) to use BLE only then it is safe to call + * esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT) at initialization time to free unused BT Classic memory. + * + * If the mode is ESP_BT_MODE_BTDM, then it may be useful to call API esp_bt_mem_release(ESP_BT_MODE_BTDM) instead, + * which internally calls esp_bt_controller_mem_release(ESP_BT_MODE_BTDM) and additionally releases the BSS and data + * consumed by the BT/BLE host stack to heap. For more details about usage please refer to the documentation of + * esp_bt_mem_release() function + * + * @param mode : the mode want to release memory + * @return ESP_OK - success, other - failed + */ +esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); + +/** @brief esp_bt_mem_release + * release controller memory and BSS and data section of the BT/BLE host stack as per the mode + * + * This function first releases controller memory by internally calling esp_bt_controller_mem_release(). + * Additionally, if the mode is set to ESP_BT_MODE_BTDM, it also releases the BSS and data consumed by the BT/BLE host stack to heap + * + * Note that once BT memory is released, the process cannot be reversed. It means you cannot use the bluetooth + * mode which you have released by this function. + * + * If your firmware will later upgrade the Bluetooth controller mode (BLE -> BT Classic or disabled -> enabled) + * then do not call this function. + * + * If you never intend to use bluetooth in a current boot-up cycle, you can call esp_bt_mem_release(ESP_BT_MODE_BTDM) + * before esp_bt_controller_init or after esp_bt_controller_deinit. + * + * For example, if a user only uses bluetooth for setting the WiFi configuration, and does not use bluetooth in the rest of the product operation". + * In such cases, after receiving the WiFi configuration, you can disable/deinit bluetooth and release its memory. + * Below is the sequence of APIs to be called for such scenarios: + * + * esp_bluedroid_disable(); + * esp_bluedroid_deinit(); + * esp_bt_controller_disable(); + * esp_bt_controller_deinit(); + * esp_bt_mem_release(ESP_BT_MODE_BTDM); + * + * @param mode : the mode whose memory is to be released + * @return ESP_OK - success, other - failed + */ +esp_err_t esp_bt_mem_release(esp_bt_mode_t mode); + +/** + * @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 + +#endif /* __ESP_BT_H__ */ diff --git a/lib/bt/linker_common.lf b/lib/bt/linker_common.lf new file mode 100644 index 00000000..501acd95 --- /dev/null +++ b/lib/bt/linker_common.lf @@ -0,0 +1,42 @@ +[sections:bt_bss] +entries: + .bss+ + +[sections:bt_common] +entries: + COMMON + +[scheme:bt_default] +entries: + bt_bss -> dram0_bss + bt_common -> dram0_bss + data -> dram0_data + +[scheme:bt_extram_bss] +entries: + bt_bss -> extern_ram + bt_common -> extern_ram + data -> dram0_data + +# For the following fragments, order matters for +# 'ALIGN(4) ALIGN(4, post) SURROUND(sym)', which generates: +# +# . = ALIGN(4) +# _sym_start +# ... +# . = ALIGN(4) +# _sym_end + +[mapping:bt] +archive: libbt.a +entries: + if ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY = y: + * (bt_extram_bss); + bt_bss -> extern_ram ALIGN(4) ALIGN(4, post) SURROUND(bt_bss), + bt_common -> extern_ram ALIGN(4) ALIGN(4, post) SURROUND(bt_common), + data -> dram0_data ALIGN(4) ALIGN(4, post) SURROUND(bt_data) + else: + * (bt_default); + bt_bss -> dram0_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_bss), + bt_common -> dram0_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_common), + data -> dram0_data ALIGN(4) ALIGN(4, post) SURROUND(bt_data) diff --git a/lib/bt/linker_esp32c2.lf b/lib/bt/linker_esp32c2.lf new file mode 100644 index 00000000..7178420a --- /dev/null +++ b/lib/bt/linker_esp32c2.lf @@ -0,0 +1,50 @@ +[sections:bt_iram_text] +entries: + .iram1+ + +[sections:bt_bss] +entries: + .bss+ + .sbss+ + +[sections:bt_data] +entries: + .data+ + .sdata+ + .dram1+ + +[sections:bt_common] +entries: + COMMON + +[scheme:bt_default] +entries: + bt_iram_text -> iram0_bt_text + bt_bss -> dram0_bt_bss + bt_common -> dram0_bt_bss + bt_data -> dram0_bt_data + +# For the following fragments, order matters for +# 'ALIGN(4) ALIGN(4, post) SURROUND(sym)', which generates: +# +# . = ALIGN(4) +# _sym_start +# ... +# . = ALIGN(4) +# _sym_end + +[mapping:bt] +archive: libbt.a +entries: + * (bt_default); + bt_bss -> dram0_bt_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_bss), + bt_common -> dram0_bt_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_common), + bt_data -> dram0_bt_data ALIGN(4) ALIGN(4, post) SURROUND(bt_data) + +[mapping:ble_app] +archive: libble_app.a +entries: + * (bt_default); + bt_bss -> dram0_bt_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_bss), + bt_common -> dram0_bt_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_common), + bt_data -> dram0_bt_data ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_data) diff --git a/lib/bt/linker_esp_ble_controller.lf b/lib/bt/linker_esp_ble_controller.lf new file mode 100644 index 00000000..fe859811 --- /dev/null +++ b/lib/bt/linker_esp_ble_controller.lf @@ -0,0 +1,7 @@ +[mapping:ble_app] +archive: libble_app.a +entries: + * (bt_default); + bt_bss -> dram0_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_bss), + bt_common -> dram0_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_common), + data -> dram0_data ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_data) diff --git a/lib/bt/linker_rw_bt_controller.lf b/lib/bt/linker_rw_bt_controller.lf new file mode 100644 index 00000000..083d6e90 --- /dev/null +++ b/lib/bt/linker_rw_bt_controller.lf @@ -0,0 +1,7 @@ +[mapping:btdm] +archive: libbtdm_app.a +entries: + * (bt_default); + bt_bss -> dram0_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_bss), + bt_common -> dram0_bss ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_common), + data -> dram0_data ALIGN(4) ALIGN(4, post) SURROUND(bt_controller_data) diff --git a/lib/bt/porting/include/ble_hci_trans.h b/lib/bt/porting/include/ble_hci_trans.h new file mode 100644 index 00000000..05267b6b --- /dev/null +++ b/lib/bt/porting/include/ble_hci_trans.h @@ -0,0 +1,315 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_HCI_TRANSPORT_ +#define H_HCI_TRANSPORT_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "os/os_mempool.h" + +#define BLE_HCI_TRANS_CMD_SZ 260 +/*** Type of buffers for holding commands and events. */ +/** + * Controller-to-host event buffers. Events have one of two priorities: + * o Low-priority (BLE_HCI_TRANS_BUF_EVT_LO) + * o High-priority (BLE_HCI_TRANS_BUF_EVT_HI) + * + * 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. + * + * High-priority event buffers are for everything except advertising reports. + * If there are no free high-priority event buffers, a request to allocate one + * will try to allocate a low-priority buffer instead. + * + * If you want all events to be given equal treatment, then you should allocate + * low-priority events only. + * + * Event priorities solve the problem of critical events getting dropped due to + * a flood of advertising reports. This solution is likely temporary: when + * HCI flow control is added, event priorities may become obsolete. + * + * Not all transports distinguish between low and high priority events. If the + * transport does not have separate settings for low and high buffer counts, + * then it treats all events with equal priority. + */ +#define BLE_HCI_TRANS_BUF_EVT_LO 1 +#define BLE_HCI_TRANS_BUF_EVT_HI 2 + +/* Host-to-controller command. */ +#define BLE_HCI_TRANS_BUF_CMD 3 + +/** Callback function types; executed when HCI packets are received. */ +typedef int ble_hci_trans_rx_cmd_fn(uint8_t *cmd, void *arg); +typedef int ble_hci_trans_rx_acl_fn(struct os_mbuf *om, void *arg); + +#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED +#define ble_transport_alloc_cmd() ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD) +#define ble_transport_alloc_event(X) ble_hci_trans_buf_alloc(X ? BLE_HCI_TRANS_BUF_EVT_LO : BLE_HCI_TRANS_BUF_EVT_HI) +#define ble_transport_free ble_hci_trans_buf_free + +struct ble_hci_trans_funcs_t { + int(*_ble_hci_trans_hs_acl_tx)(struct os_mbuf *om); + int(*_ble_hci_trans_hs_cmd_tx)(uint8_t *cmd); + int(*_ble_hci_trans_ll_acl_tx)(struct os_mbuf *om); + int(*_ble_hci_trans_ll_evt_tx)(uint8_t *hci_ev); + int(*_ble_hci_trans_reset)(void); + int(*_ble_hci_trans_set_acl_free_cb)(os_mempool_put_fn *cb, void *arg); +}; + +extern struct ble_hci_trans_funcs_t *ble_hci_trans_funcs_ptr; + +/** + * Sends an HCI event from the controller to the host. + * + * @param cmd The HCI event to send. This buffer must be + * allocated via ble_hci_trans_buf_alloc(). + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +extern int r_ble_hci_trans_ll_evt_tx(uint8_t *hci_ev); +#define ble_hci_trans_ll_evt_tx ble_hci_trans_funcs_ptr->_ble_hci_trans_ll_evt_tx + +/** + * Sends ACL data from controller to host. + * + * @param om The ACL data packet to send. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +extern int r_ble_hci_trans_ll_acl_tx(struct os_mbuf *om); +#define ble_hci_trans_ll_acl_tx ble_hci_trans_funcs_ptr->_ble_hci_trans_ll_acl_tx + +/** + * 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. + */ +extern int r_ble_hci_trans_hs_cmd_tx(uint8_t *cmd); +#define ble_hci_trans_hs_cmd_tx ble_hci_trans_funcs_ptr->_ble_hci_trans_hs_cmd_tx + +/** + * 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. + */ +extern int r_ble_hci_trans_hs_acl_tx(struct os_mbuf *om); +#define ble_hci_trans_hs_acl_tx ble_hci_trans_funcs_ptr->_ble_hci_trans_hs_acl_tx + +/** + * 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. + */ +extern uint8_t *r_ble_hci_trans_buf_alloc(int type); +#define ble_hci_trans_buf_alloc r_ble_hci_trans_buf_alloc + +/** + * Frees the specified flat buffer. The buffer must have been allocated via + * ble_hci_trans_buf_alloc(). + * + * @param buf The buffer to free. + */ +extern void r_ble_hci_trans_buf_free(uint8_t *buf); +#define ble_hci_trans_buf_free r_ble_hci_trans_buf_free + +/** + * Configures a callback to get executed whenever an ACL data packet is freed. + * The function is called immediately before the free occurs. + * + * @param cb The callback to configure. + * @param arg An optional argument to pass to the callback. + * + * @return 0 on success; + * BLE_ERR_UNSUPPORTED if the transport does not + * support this operation. + */ +extern int r_ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg); +#define ble_hci_trans_set_acl_free_cb ble_hci_trans_funcs_ptr->_ble_hci_trans_set_acl_free_cb + +/** + * Configures the HCI transport to operate with a controller. The transport + * will execute specified callbacks upon receiving HCI packets from the host. + * + * @param cmd_cb The callback to execute upon receiving an HCI + * command. + * @param cmd_arg Optional argument to pass to the command + * callback. + * @param acl_cb The callback to execute upon receiving ACL + * data. + * @param acl_arg Optional argument to pass to the ACL + * callback. + */ +extern void r_ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, + void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg); +#define ble_hci_trans_cfg_ll r_ble_hci_trans_cfg_ll + +/** + * 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. + */ +extern void r_ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *evt_cb, + void *evt_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg); +#define ble_hci_trans_cfg_hs r_ble_hci_trans_cfg_hs + +/** + * Resets the HCI module to a clean state. Frees all buffers and reinitializes + * the underlying transport. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +extern int r_ble_hci_trans_reset(void); +#define ble_hci_trans_reset ble_hci_trans_funcs_ptr->_ble_hci_trans_reset + +void esp_ble_hci_trans_init(uint8_t); + +#else +/** + * Sends an HCI event from the controller to the host. + * + * @param cmd The HCI event 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 ble_hci_trans_ll_evt_tx(uint8_t *hci_ev); + +/** + * Sends ACL data from controller to host. + * + * @param om The ACL data packet to send. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int ble_hci_trans_ll_acl_tx(struct os_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 ble_hci_trans_hs_cmd_tx(uint8_t *cmd); + +/** + * 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 ble_hci_trans_hs_acl_tx(struct os_mbuf *om); + +/** + * 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. + */ +int esp_ble_hci_trans_hs_cmd_tx(uint8_t *cmd); + +/** + * 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 esp_ble_hci_trans_hs_acl_tx(struct os_mbuf *om); + +/** + * 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 *esp_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 esp_ble_hci_trans_buf_free(uint8_t *buf); + +/** + * 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 esp_ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *evt_cb, + void *evt_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg); + +/** + * Resets the HCI module to a clean state. Frees all buffers and reinitializes + * the underlying transport. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int esp_ble_hci_trans_reset(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_HCI_TRANSPORT_ */ diff --git a/lib/bt/porting/include/bt_osi_mem.h b/lib/bt/porting/include/bt_osi_mem.h new file mode 100644 index 00000000..9ab06d0a --- /dev/null +++ b/lib/bt/porting/include/bt_osi_mem.h @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" +#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); diff --git a/lib/bt/porting/include/os/endian.h b/lib/bt/porting/include/os/endian.h new file mode 100644 index 00000000..2e06a8b5 --- /dev/null +++ b/lib/bt/porting/include/os/endian.h @@ -0,0 +1,296 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD + */ +/* + * 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 H_ENDIAN_ +#define H_ENDIAN_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Internal helpers */ +#ifndef os_bswap_64 +#define os_bswap_64(x) ((uint64_t) \ + ((((x) & 0xff00000000000000ull) >> 56) | \ + (((x) & 0x00ff000000000000ull) >> 40) | \ + (((x) & 0x0000ff0000000000ull) >> 24) | \ + (((x) & 0x000000ff00000000ull) >> 8) | \ + (((x) & 0x00000000ff000000ull) << 8) | \ + (((x) & 0x0000000000ff0000ull) << 24) | \ + (((x) & 0x000000000000ff00ull) << 40) | \ + (((x) & 0x00000000000000ffull) << 56))) +#endif + +#ifndef os_bswap_32 +#define os_bswap_32(x) ((uint32_t) \ + ((((x) & 0xff000000) >> 24) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x000000ff) << 24))) +#endif + +#ifndef os_bswap_16 +#define os_bswap_16(x) ((uint16_t) \ + ((((x) & 0xff00) >> 8) | \ + (((x) & 0x00ff) << 8))) +#endif + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + +#ifndef ntohll +#define ntohll(x) ((uint64_t)(x)) +#endif + +#ifndef htonll +#define htonll(x) ((uint64_t)(x)) +#endif + +#ifndef ntohl +#define ntohl(x) ((uint32_t)(x)) +#endif + +#ifndef htonl +#define htonl(x) ((uint32_t)(x)) +#endif + +#ifndef ntohs +#define ntohs(x) ((uint16_t)(x)) +#endif + +#ifndef htons +#define htons(x) ((uint16_t)(x)) +#endif + +#ifndef htobe16 +#define htobe16(x) ((uint16_t)(x)) +#endif + +#ifndef htole16 +#define htole16(x) os_bswap_16 (x) +#endif + +#ifndef be16toh +#define be16toh(x) ((uint16_t)(x)) +#endif + +#ifndef le16toh +#define le16toh(x) os_bswap_16 (x) +#endif + +#ifndef htobe32 +#define htobe32(x) ((uint32_t)(x)) +#endif + +#ifndef htole32 +#define htole32(x) os_bswap_32 (x) +#endif + +#ifndef be32toh +#define be32toh(x) ((uint32_t)(x)) +#endif + +#ifndef le32toh +#define le32toh(x) os_bswap_32 (x) +#endif + +#ifndef htobe64 +#define htobe64(x) ((uint64_t)(x)) +#endif + +#ifndef htole64 +#define htole64(x) os_bswap_64 (x) +#endif + +#ifndef be64toh +#define be64toh(x) ((uint64_t)(x)) +#endif + +#ifndef le64toh +#define le64toh(x) os_bswap_64 (x) +#endif + +#else + +#ifndef ntohll +#define ntohll(x) os_bswap_64(x) +#endif + +#ifndef htonll +#define htonll ntohll +#endif + +/* These are not used in NimBLE and ESP-IDF uses them from LwIP */ +#if 0 +#ifndef ntohl +#define ntohl(x) os_bswap_32(x) +#endif + +#ifndef htonl +#define htonl ntohl +#endif + +#ifndef htons +#define htons(x) os_bswap_16(x) +#endif + +#ifndef ntohs +#define ntohs htons +#endif +#endif + +#ifndef htobe16 +#define htobe16(x) os_bswap_16(x) +#endif + +#ifndef htole16 +#define htole16(x) ((uint16_t)(x)) +#endif + +#ifndef be16toh +#define be16toh(x) os_bswap_16(x) +#endif + +#ifndef le16toh +#define le16toh(x) ((uint16_t)(x)) +#endif + +#ifndef htobe32 +#define htobe32(x) os_bswap_32(x) +#endif + +#ifndef htole32 +#define htole32(x) ((uint32_t)(x)) +#endif + +#ifndef be32toh +#define be32toh(x) os_bswap_32(x) +#endif + +#ifndef le32toh +#define le32toh(x) ((uint32_t)(x)) +#endif + +#ifndef htobe64 +#define htobe64(x) os_bswap_64(x) +#endif + +#ifndef htole64 +#define htole64(x) ((uint64_t)(x)) +#endif + +#ifndef be64toh +#define be64toh(x) os_bswap_64(x) +#endif + +#ifndef le64toh +#define le64toh(x) ((uint64_t)(x)) +#endif + +#endif + +#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED +void r_put_le16(void *buf, uint16_t x); +#define put_le16 r_put_le16 + +void r_put_le24(void *buf, uint32_t x); +#define put_le24 r_put_le24 + +void r_put_le32(void *buf, uint32_t x); +#define put_le32 r_put_le32 + +void r_put_le64(void *buf, uint64_t x); +#define put_le64 r_put_le64 + +uint16_t r_get_le16(const void *buf); +#define get_le16 r_get_le16 + +uint32_t r_get_le24(const void *buf); +#define get_le24 r_get_le24 + +uint32_t r_get_le32(const void *buf); +#define get_le32 r_get_le32 + +uint64_t r_get_le64(const void *buf); +#define get_le64 r_get_le64 + +void r_put_be16(void *buf, uint16_t x); +#define put_be16 r_put_be16 + +void r_put_be24(void *buf, uint32_t x); +#define put_be24 r_put_be24 + +void r_put_be32(void *buf, uint32_t x); +#define put_be32 r_put_be32 + +void r_put_be64(void *buf, uint64_t x); +#define put_be64 r_put_be64 + +uint16_t r_get_be16(const void *buf); +#define get_be16 r_get_be16 + +uint32_t r_get_be24(const void *buf); +#define get_be24 r_get_be24 + +uint32_t r_get_be32(const void *buf); +#define get_be32 r_get_be32 + +uint64_t r_get_be64(const void *buf); +#define get_be64 r_get_be64 + +void r_swap_in_place(void *buf, int len); +#define swap_in_place r_swap_in_place + +void r_swap_buf(uint8_t *dst, const uint8_t *src, int len); +#define swap_buf r_swap_buf + + +#else +void put_le16(void *buf, uint16_t x); +void put_le24(void *buf, uint32_t x); +void put_le32(void *buf, uint32_t x); +void put_le64(void *buf, uint64_t x); +uint16_t get_le16(const void *buf); +uint32_t get_le24(const void *buf); +uint32_t get_le32(const void *buf); +uint64_t get_le64(const void *buf); +void put_be16(void *buf, uint16_t x); +void put_be24(void *buf, uint32_t x); +void put_be32(void *buf, uint32_t x); +void put_be64(void *buf, uint64_t x); +uint16_t get_be16(const void *buf); +uint32_t get_be24(const void *buf); +uint32_t get_be32(const void *buf); +uint64_t get_be64(const void *buf); +void swap_in_place(void *buf, int len); +void swap_buf(uint8_t *dst, const uint8_t *src, int len); +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/bt/porting/include/os/os.h b/lib/bt/porting/include/os/os.h new file mode 100644 index 00000000..56fdf52d --- /dev/null +++ b/lib/bt/porting/include/os/os.h @@ -0,0 +1,66 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD + */ +/* + * 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 _OS_H +#define _OS_H + +#include +#include "esp_assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined __cplusplus && !defined static_assert +#define static_assert _Static_assert +#endif + +#include "nimble/nimble_npl.h" + +#define OS_ALIGN(__n, __a) ( \ + (((__n) & ((__a) - 1)) == 0) ? \ + (__n) : \ + ((__n) + ((__a) - ((__n) & ((__a) - 1)))) \ + ) +#define OS_ALIGNMENT (BLE_NPL_OS_ALIGNMENT) + +typedef uint32_t os_sr_t; +#define OS_ENTER_CRITICAL(_sr) (_sr = ble_npl_hw_enter_critical()) +#define OS_EXIT_CRITICAL(_sr) (ble_npl_hw_exit_critical(_sr)) +#define OS_ASSERT_CRITICAL() assert(ble_npl_hw_is_in_critical()) + +/* Mynewt components (not abstracted in NPL) */ +#include "os/endian.h" +#include "os/queue.h" +#include "os/os_error.h" +#include "os/os_mbuf.h" +#include "os/os_mempool.h" + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_H */ diff --git a/lib/bt/porting/include/os/os_error.h b/lib/bt/porting/include/os/os_error.h new file mode 100644 index 00000000..2e736e39 --- /dev/null +++ b/lib/bt/porting/include/os/os_error.h @@ -0,0 +1,69 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD + */ +/* + * 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 H_OS_ERROR_ +#define H_OS_ERROR_ + +#include "os/os.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* OS error enumerations */ +enum os_error { + OS_OK = 0, + OS_ENOMEM = 1, + OS_EINVAL = 2, + OS_INVALID_PARM = 3, + OS_MEM_NOT_ALIGNED = 4, + OS_BAD_MUTEX = 5, + OS_TIMEOUT = 6, + OS_ERR_IN_ISR = 7, /* Function cannot be called from ISR */ + OS_ERR_PRIV = 8, /* Privileged access error */ + OS_NOT_STARTED = 9, /* OS must be started to call this function, but isn't */ + OS_ENOENT = 10, /* No such thing */ + OS_EBUSY = 11, /* Resource busy */ + OS_ERROR = 12, /* Generic Error */ +}; + +typedef enum os_error os_error_t; + +/** + * @brief Converts an OS error code (`OS_[...]`) to an equivalent system error + * code (`SYS_E[...]`). + * + * @param os_error The OS error code to convert. + * + * @return The equivalent system error code. + */ +int os_error_to_sys(os_error_t os_error); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/bt/porting/include/os/os_mbuf.h b/lib/bt/porting/include/os/os_mbuf.h new file mode 100644 index 00000000..c6ea6b6e --- /dev/null +++ b/lib/bt/porting/include/os/os_mbuf.h @@ -0,0 +1,1145 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD + */ +/* + * 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 OSMbuf Chained Memory Buffers + * @{ + */ + + +#ifndef _OS_MBUF_H +#define _OS_MBUF_H + +#include "os/os.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: + * os_mbuf_count * (omp_databuf_len + sizeof(struct os_mbuf)) + */ +struct os_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 os_mempool *omp_pool; + + STAILQ_ENTRY(os_mbuf_pool) omp_next; +}; + + +/** + * A packet header structure that proceeds the mbuf packet headers. + */ +struct os_mbuf_pkthdr { + /** + * Overall length of the packet. + */ + uint16_t omp_len; + /** + * Flags + */ + uint16_t omp_flags; + + STAILQ_ENTRY(os_mbuf_pkthdr) omp_next; +}; + +/** + * Chained memory buffer. + */ +struct os_mbuf { + /** + * Current pointer to data in the structure + */ + uint8_t *om_data; + /** + * Flags associated with this buffer, see OS_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 os_mbuf_pool *om_omp; + + SLIST_ENTRY(os_mbuf) om_next; + + /** + * Pointer to the beginning of the data, after this buffer + */ + uint8_t om_databuf[0]; +}; + +/** + * Structure representing a queue of mbufs. + */ +struct os_mqueue { + STAILQ_HEAD(, os_mbuf_pkthdr) mq_head; + /** Event to post when new buffers are available on the queue. */ + struct ble_npl_event mq_ev; +}; + +/* + * Given a flag number, provide the mask for it + * + * @param __n The number of the flag in the mask + */ +#define OS_MBUF_F_MASK(__n) (1 << (__n)) + +/* + * Checks whether a given mbuf is a packet header mbuf + * + * @param __om The mbuf to check + */ +#define OS_MBUF_IS_PKTHDR(__om) \ + ((__om)->om_pkthdr_len >= sizeof (struct os_mbuf_pkthdr)) + +/** Get a packet header pointer given an mbuf pointer */ +#define OS_MBUF_PKTHDR(__om) ((struct os_mbuf_pkthdr *) \ + (void *)((uint8_t *)&(__om)->om_data + sizeof(struct os_mbuf))) + +/** Given a mbuf packet header pointer, return a pointer to the mbuf */ +#define OS_MBUF_PKTHDR_TO_MBUF(__hdr) \ + (struct os_mbuf *)(void *)((uint8_t *)(__hdr) - sizeof(struct os_mbuf)) + +/** + * Gets the length of an entire mbuf chain. The specified mbuf must have a + * packet header. + */ +#define OS_MBUF_PKTLEN(__om) (OS_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 OS_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 OS_MBUF_USRHDR(om) \ + (void *)((uint8_t *)om + sizeof (struct os_mbuf) + \ + sizeof (struct os_mbuf_pkthdr)) + +/** + * Retrieves the length of the user header in an mbuf. + * + * @param om Pointer to the mbuf to query. + */ +#define OS_MBUF_USRHDR_LEN(om) \ + ((om)->om_pkthdr_len - sizeof (struct os_mbuf_pkthdr)) + + +/** @cond INTERNAL_HIDDEN */ + +/* + * Called by OS_MBUF_LEADINGSPACE() macro + */ +static inline uint16_t +_os_mbuf_leadingspace(struct os_mbuf *om) +{ + uint16_t startoff; + uint16_t leadingspace; + + startoff = 0; + if (OS_MBUF_IS_PKTHDR(om)) { + startoff = om->om_pkthdr_len; + } + + leadingspace = (uint16_t) (OS_MBUF_DATA(om, uint8_t *) - + ((uint8_t *) &om->om_databuf[0] + startoff)); + + return (leadingspace); +} + +/** @endcond */ + +/** + * 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 OS_MBUF_LEADINGSPACE(__om) _os_mbuf_leadingspace(__om) + + +/** @cond INTERNAL_HIDDEN */ + +/* Called by OS_MBUF_TRAILINGSPACE() macro. */ +static inline uint16_t +_os_mbuf_trailingspace(struct os_mbuf *om) +{ + struct os_mbuf_pool *omp; + + omp = om->om_omp; + + return (&om->om_databuf[0] + omp->omp_databuf_len) - + (om->om_data + om->om_len); +} + +/** @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 OS_MBUF_TRAILINGSPACE(__om) _os_mbuf_trailingspace(__om) + + +#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED +/** + * Initializes an mqueue. An mqueue is a queue of mbufs that ties to a + * particular task's event queue. Mqueues form a helper API around a common + * paradigm: wait on an event queue until at least one packet is available, + * then process a queue of packets. + * + * When mbufs are available on the queue, an event OS_EVENT_T_MQUEUE_DATA + * will be posted to the task's mbuf queue. + * + * @param mq The mqueue to initialize + * @param ev_cb The callback to associate with the mqeueue + * event. Typically, this callback pulls each + * packet off the mqueue and processes them. + * @param arg The argument to associate with the mqueue event. + * + * @return 0 on success, non-zero on failure. + */ +int r_os_mqueue_init(struct os_mqueue *mq, ble_npl_event_fn *ev_cb, void *arg); +#define os_mqueue_init r_os_mqueue_init + + +/** + * Remove and return a single mbuf from the mbuf queue. Does not block. + * + * @param mq The mbuf queue to pull an element off of. + * + * @return The next mbuf in the queue, or NULL if queue has no mbufs. + */ +struct os_mbuf *r_os_mqueue_get(struct os_mqueue *); +#define os_mqueue_get r_os_mqueue_get +/** + * Adds a packet (i.e. packet header mbuf) to an mqueue. The event associated + * with the mqueue gets posted to the specified eventq. + * + * @param mq The mbuf queue to append the mbuf to. + * @param evq The event queue to post an event to. + * @param m The mbuf to append to the mbuf queue. + * + * @return 0 on success, non-zero on failure. + */ +int r_os_mqueue_put(struct os_mqueue *, struct ble_npl_eventq *, struct os_mbuf *); +#define os_mqueue_put r_os_mqueue_put + + +/** + * 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 + */ +int r_os_msys_register(struct os_mbuf_pool *); +#define os_msys_register r_os_msys_register + + +/** + * 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. + */ +struct os_mbuf *r_os_msys_get(uint16_t dsize, uint16_t leadingspace); +#define os_msys_get r_os_msys_get +/** + * De-registers all mbuf pools from msys. + */ +void r_os_msys_reset(void); +#define os_msys_reset 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. + */ +struct os_mbuf *r_os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len); +#define os_msys_get_pkthdr r_os_msys_get_pkthdr +/** + * Count the number of blocks in all the mbuf pools that are allocated. + * + * @return total number of blocks allocated in Msys + */ +int r_os_msys_count(void); +#define os_msys_count r_os_msys_count + + +/** + * Return the number of free blocks in Msys + * + * @return Number of free blocks available in Msys + */ +int r_os_msys_num_free(void); +#define os_msys_num_free 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. + */ +int r_os_mbuf_pool_init(struct os_mbuf_pool *, struct os_mempool *mp, + uint16_t, uint16_t); +#define os_mbuf_pool_init r_os_mbuf_pool_init +/** + * 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. + */ +struct os_mbuf *r_os_mbuf_get(struct os_mbuf_pool *omp, uint16_t); +#define os_mbuf_get r_os_mbuf_get +/** + * 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. + */ +struct os_mbuf *r_os_mbuf_get_pkthdr(struct os_mbuf_pool *omp, + uint8_t pkthdr_len); +#define os_mbuf_get_pkthdr r_os_mbuf_get_pkthdr +/** + * 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 + */ +struct os_mbuf *r_os_mbuf_dup(struct os_mbuf *m); +#define os_mbuf_dup r_os_mbuf_dup +/** + * 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. + */ +struct os_mbuf *r_os_mbuf_off(const struct os_mbuf *om, int off, + uint16_t *out_off); +#define os_mbuf_off r_os_mbuf_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. + */ +int r_os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst); +#define os_mbuf_copydata r_os_mbuf_copydata + + +/** + * @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. + */ +uint16_t r_os_mbuf_len(const struct os_mbuf *om); +#define os_mbuf_len r_os_mbuf_len + + +/** + * 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 + */ +int r_os_mbuf_append(struct os_mbuf *m, const void *, uint16_t); +#define os_mbuf_append r_os_mbuf_append + + +/** + * 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. + */ +int r_os_mbuf_appendfrom(struct os_mbuf *dst, const struct os_mbuf *src, + uint16_t src_off, uint16_t len); +#define os_mbuf_appendfrom r_os_mbuf_appendfrom +/** + * Release a mbuf back to the pool + * + * @param omp The Mbuf pool to release back to + * @param om The Mbuf to release back to the pool + * + * @return 0 on success, -1 on failure + */ +int r_os_mbuf_free(struct os_mbuf *mb); +#define os_mbuf_free r_os_mbuf_free + + +/** + * Free a chain of mbufs + * + * @param omp The mbuf pool to free the chain of mbufs into + * @param om The starting mbuf of the chain to free back into the pool + * + * @return 0 on success, -1 on failure + */ +int r_os_mbuf_free_chain(struct os_mbuf *om); +#define os_mbuf_free_chain r_os_mbuf_free_chain + + +/** + * 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. + */ +void r_os_mbuf_adj(struct os_mbuf *mp, int req_len); +#define os_mbuf_adj r_os_mbuf_adj + + + +/** + * 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. + */ +int r_os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int len); +#define os_mbuf_cmpf r_os_mbuf_cmpf + + +/** + * 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. + */ +int r_os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1, + const struct os_mbuf *om2, uint16_t offset2, + uint16_t len); +#define os_mbuf_cmpm r_os_mbuf_cmpm +/** + * 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. + */ +struct os_mbuf *r_os_mbuf_prepend(struct os_mbuf *om, int len); +#define os_mbuf_prepend r_os_mbuf_prepend +/** + * 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). + */ +struct os_mbuf *r_os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len); +#define os_mbuf_prepend_pullup r_os_mbuf_prepend_pullup +/** + * 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 omp The mbuf pool to allocate from. + * @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. + */ +int r_os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int len); +#define os_mbuf_copyinto r_os_mbuf_copyinto + + +/** + * 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. + */ +void r_os_mbuf_concat(struct os_mbuf *first, struct os_mbuf *second); +#define os_mbuf_concat r_os_mbuf_concat + + + +/** + * 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 omp + * @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. + */ +void *r_os_mbuf_extend(struct os_mbuf *om, uint16_t len); +#define os_mbuf_extend r_os_mbuf_extend +/** + * 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 omp The mbuf pool to take the mbufs out of + * @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. + */ +struct os_mbuf *r_os_mbuf_pullup(struct os_mbuf *om, uint16_t len); +#define os_mbuf_pullup r_os_mbuf_pullup + +/** + * 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. + */ +struct os_mbuf *r_os_mbuf_trim_front(struct os_mbuf *om); +#define os_mbuf_trim_front r_os_mbuf_trim_front +/** + * 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. + */ +int r_os_mbuf_widen(struct os_mbuf *om, uint16_t off, uint16_t len); +#define os_mbuf_widen r_os_mbuf_widen + + + +/** + * 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 + */ +struct os_mbuf *r_os_mbuf_pack_chains(struct os_mbuf *m1, struct os_mbuf *m2); +#define os_mbuf_pack_chains r_os_mbuf_pack_chains + +#else +/** + * Initializes an mqueue. An mqueue is a queue of mbufs that ties to a + * particular task's event queue. Mqueues form a helper API around a common + * paradigm: wait on an event queue until at least one packet is available, + * then process a queue of packets. + * + * When mbufs are available on the queue, an event OS_EVENT_T_MQUEUE_DATA + * will be posted to the task's mbuf queue. + * + * @param mq The mqueue to initialize + * @param ev_cb The callback to associate with the mqeueue + * event. Typically, this callback pulls each + * packet off the mqueue and processes them. + * @param arg The argument to associate with the mqueue event. + * + * @return 0 on success, non-zero on failure. + */ +int os_mqueue_init(struct os_mqueue *mq, ble_npl_event_fn *ev_cb, void *arg); + +/** + * Remove and return a single mbuf from the mbuf queue. Does not block. + * + * @param mq The mbuf queue to pull an element off of. + * + * @return The next mbuf in the queue, or NULL if queue has no mbufs. + */ +struct os_mbuf *os_mqueue_get(struct os_mqueue *); + +/** + * Adds a packet (i.e. packet header mbuf) to an mqueue. The event associated + * with the mqueue gets posted to the specified eventq. + * + * @param mq The mbuf queue to append the mbuf to. + * @param evq The event queue to post an event to. + * @param m The mbuf to append to the mbuf queue. + * + * @return 0 on success, non-zero on failure. + */ +int os_mqueue_put(struct os_mqueue *, struct ble_npl_eventq *, struct os_mbuf *); + +/** + * 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 + */ +int os_msys_register(struct os_mbuf_pool *); + +/** + * 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. + */ +struct os_mbuf *os_msys_get(uint16_t dsize, uint16_t leadingspace); + +/** + * De-registers all mbuf pools from msys. + */ +void os_msys_reset(void); + +/** + * 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. + */ +struct os_mbuf *os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len); + +/** + * Count the number of blocks in all the mbuf pools that are allocated. + * + * @return total number of blocks allocated in Msys + */ +int os_msys_count(void); + +/** + * Return the number of free blocks in Msys + * + * @return Number of free blocks available in Msys + */ +int os_msys_num_free(void); + +/** + * 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. + */ +int os_mbuf_pool_init(struct os_mbuf_pool *, struct os_mempool *mp, + uint16_t, uint16_t); + +/** + * 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. + */ +struct os_mbuf *os_mbuf_get(struct os_mbuf_pool *omp, uint16_t); + +/** + * 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. + */ +struct os_mbuf *os_mbuf_get_pkthdr(struct os_mbuf_pool *omp, + uint8_t 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 + */ +struct os_mbuf *os_mbuf_dup(struct os_mbuf *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. + */ +struct os_mbuf *os_mbuf_off(const struct os_mbuf *om, int off, + uint16_t *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. + */ +int os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *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. + */ +uint16_t os_mbuf_len(const struct os_mbuf *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 + */ +int os_mbuf_append(struct os_mbuf *m, const void *, uint16_t); + +/** + * 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. + */ +int os_mbuf_appendfrom(struct os_mbuf *dst, const struct os_mbuf *src, + uint16_t src_off, uint16_t len); + +/** + * Release a mbuf back to the pool + * + * @param omp The Mbuf pool to release back to + * @param om The Mbuf to release back to the pool + * + * @return 0 on success, -1 on failure + */ +int os_mbuf_free(struct os_mbuf *mb); + +/** + * Free a chain of mbufs + * + * @param omp The mbuf pool to free the chain of mbufs into + * @param om The starting mbuf of the chain to free back into the pool + * + * @return 0 on success, -1 on failure + */ +int os_mbuf_free_chain(struct os_mbuf *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. + */ +void os_mbuf_adj(struct os_mbuf *mp, int 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. + */ +int os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int 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. + */ +int os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1, + const struct os_mbuf *om2, uint16_t offset2, + uint16_t 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. + */ +struct os_mbuf *os_mbuf_prepend(struct os_mbuf *om, int 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). + */ +struct os_mbuf *os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t 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 omp The mbuf pool to allocate from. + * @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. + */ +int os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int 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. + */ +void os_mbuf_concat(struct os_mbuf *first, struct os_mbuf *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 omp + * @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. + */ +void *os_mbuf_extend(struct os_mbuf *om, uint16_t 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 omp The mbuf pool to take the mbufs out of + * @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. + */ +struct os_mbuf *os_mbuf_pullup(struct os_mbuf *om, uint16_t 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. + */ +struct os_mbuf *os_mbuf_trim_front(struct os_mbuf *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. + */ +int os_mbuf_widen(struct os_mbuf *om, uint16_t off, uint16_t 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 + */ +struct os_mbuf *os_mbuf_pack_chains(struct os_mbuf *m1, struct os_mbuf *m2); + +#endif +#ifdef __cplusplus +} +#endif + +#endif /* _OS_MBUF_H */ + + +/** + * @} OSMbuf + * @} OSKernel + */ diff --git a/lib/bt/porting/include/os/os_mempool.h b/lib/bt/porting/include/os/os_mempool.h new file mode 100644 index 00000000..3ef8e6d5 --- /dev/null +++ b/lib/bt/porting/include/os/os_mempool.h @@ -0,0 +1,407 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD + */ +/* + * 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 +#include "os/os.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; +}; + +/** + * Indicates an extended mempool. Address can be safely cast to + * (struct os_mempool_ext *). + */ +#define OS_MEMPOOL_F_EXT 0x01 + +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 *); + +#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 r_os_mempool_unregister + + +/** + * 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 + */ diff --git a/lib/bt/porting/include/os/queue.h b/lib/bt/porting/include/os/queue.h new file mode 100644 index 00000000..868f9abf --- /dev/null +++ b/lib/bt/porting/include/os/queue.h @@ -0,0 +1,212 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD + */ +/* + * 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 + +#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_ */ diff --git a/lib/bt/porting/include/os/util.h b/lib/bt/porting/include/os/util.h new file mode 100644 index 00000000..2438373e --- /dev/null +++ b/lib/bt/porting/include/os/util.h @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD + */ +/* + * 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 H_OS_UTIL_ +#define H_OS_UTIL_ + +/* Helpers to pass integers as pointers and vice-versa */ +#define POINTER_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) +#define UINT_TO_POINTER(u) ((void *) ((uintptr_t) (u))) +#define POINTER_TO_INT(p) ((int) ((intptr_t) (p))) +#define INT_TO_POINTER(u) ((void *) ((intptr_t) (u))) + +/* Helper to retrieve pointer to "parent" object in structure */ +#define CONTAINER_OF(ptr, type, field) \ + ((type *)(((char *)(ptr)) - offsetof(type, field))) + +/* Helper to calculate number of elements in array */ +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(array) \ + (sizeof(array) / sizeof((array)[0])) +#endif +#endif diff --git a/lib/bt/porting/mem/os_msys_init.c b/lib/bt/porting/mem/os_msys_init.c new file mode 100644 index 00000000..1a121e6d --- /dev/null +++ b/lib/bt/porting/mem/os_msys_init.c @@ -0,0 +1,240 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD + */ + +#include + +#include "os/os.h" +#include "mem_api.h" +#include "bt_osi_mem.h" +#include "esp_err.h" + +#if CONFIG_BT_NIMBLE_ENABLED +#include "syscfg/syscfg.h" +#endif + +#define SYSINIT_PANIC_ASSERT(rc) assert(rc); + +static STAILQ_HEAD(, os_mbuf_pool) g_msys_pool_list = + STAILQ_HEAD_INITIALIZER(g_msys_pool_list); + +#if CONFIG_BT_NIMBLE_ENABLED +#define OS_MSYS_1_BLOCK_COUNT MYNEWT_VAL(MSYS_1_BLOCK_COUNT) +#define OS_MSYS_1_BLOCK_SIZE MYNEWT_VAL(MSYS_1_BLOCK_SIZE) +#define OS_MSYS_2_BLOCK_COUNT MYNEWT_VAL(MSYS_2_BLOCK_COUNT) +#define OS_MSYS_2_BLOCK_SIZE MYNEWT_VAL(MSYS_2_BLOCK_SIZE) + +#define OS_MSYS_1_SANITY_MIN_COUNT MYNEWT_VAL(MSYS_1_SANITY_MIN_COUNT) +#define OS_MSYS_2_SANITY_MIN_COUNT MYNEWT_VAL(MSYS_2_SANITY_MIN_COUNT) +#if CONFIG_BT_NIMBLE_MSYS_BUF_FROM_HEAP +#define OS_MSYS_BLOCK_FROM_HEAP (1) +#else +#define OS_MSYS_BLOCK_FROM_HEAP (0) +#endif // CONFIG_BT_NIMBLE_MSYS_BUF_FROM_HEAP +#else +#define OS_MSYS_1_BLOCK_COUNT CONFIG_BT_LE_MSYS_1_BLOCK_COUNT +#define OS_MSYS_1_BLOCK_SIZE CONFIG_BT_LE_MSYS_1_BLOCK_SIZE +#define OS_MSYS_2_BLOCK_COUNT CONFIG_BT_LE_MSYS_2_BLOCK_COUNT +#define OS_MSYS_2_BLOCK_SIZE CONFIG_BT_LE_MSYS_2_BLOCK_SIZE + +#define OS_MSYS_1_SANITY_MIN_COUNT 0 +#define OS_MSYS_2_SANITY_MIN_COUNT 0 + +#if CONFIG_BT_LE_MSYS_BUF_FROM_HEAP +#define OS_MSYS_BLOCK_FROM_HEAP (1) +#else +#define OS_MSYS_BLOCK_FROM_HEAP (0) +#endif // CONFIG_BT_LE_MSYS_BUF_FROM_HEAP +#endif + + + +#if OS_MSYS_1_BLOCK_COUNT > 0 +#define SYSINIT_MSYS_1_MEMBLOCK_SIZE \ + OS_ALIGN(OS_MSYS_1_BLOCK_SIZE, 4) +#define SYSINIT_MSYS_1_MEMPOOL_SIZE \ + OS_MEMPOOL_SIZE(OS_MSYS_1_BLOCK_COUNT, \ + SYSINIT_MSYS_1_MEMBLOCK_SIZE) + +#if !CONFIG_BT_LE_MSYS_INIT_IN_CONTROLLER +static os_membuf_t *os_msys_init_1_data; +static struct os_mbuf_pool os_msys_init_1_mbuf_pool; +static struct os_mempool os_msys_init_1_mempool; +#endif // !CONFIG_BT_LE_MSYS_INIT_IN_CONTROLLER +#endif + +#if OS_MSYS_2_BLOCK_COUNT > 0 +#define SYSINIT_MSYS_2_MEMBLOCK_SIZE \ + OS_ALIGN(OS_MSYS_2_BLOCK_SIZE, 4) +#define SYSINIT_MSYS_2_MEMPOOL_SIZE \ + OS_MEMPOOL_SIZE(OS_MSYS_2_BLOCK_COUNT, \ + SYSINIT_MSYS_2_MEMBLOCK_SIZE) + +#if !CONFIG_BT_LE_MSYS_INIT_IN_CONTROLLER +static os_membuf_t *os_msys_init_2_data; +static struct os_mbuf_pool os_msys_init_2_mbuf_pool; +static struct os_mempool os_msys_init_2_mempool; +#endif // !CONFIG_BT_LE_MSYS_INIT_IN_CONTROLLER +#endif + +#if CONFIG_BT_LE_MSYS_INIT_IN_CONTROLLER +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); + +int os_msys_init(void) +{ + return r_esp_ble_msys_init(SYSINIT_MSYS_1_MEMBLOCK_SIZE, + SYSINIT_MSYS_2_MEMBLOCK_SIZE, + OS_MSYS_1_BLOCK_COUNT, + OS_MSYS_2_BLOCK_COUNT, + OS_MSYS_BLOCK_FROM_HEAP); +} + +void os_msys_deinit(void) +{ + r_esp_ble_msys_deinit(); +} + +#else // CONFIG_BT_LE_MSYS_INIT_IN_CONTROLLER + +#if OS_MSYS_SANITY_ENABLED + +/** + * Retrieves the minimum safe buffer count for an msys pool. That is, the + * lowest a pool's buffer count can be without causing the sanity check to + * fail. + * + * @param idx The index of the msys pool to query. + * + * @return The msys pool's minimum safe buffer count. + */ +static int +IRAM_ATTR os_msys_sanity_min_count(int idx) +{ + switch (idx) { + case 0: + return OS_MSYS_1_SANITY_MIN_COUNT; + + case 1: + return OS_MSYS_2_SANITY_MIN_COUNT; + + default: + BLE_LL_ASSERT(0); + return ESP_OK; + } +} + +static int +IRAM_ATTR os_msys_sanity(struct os_sanity_check *sc, void *arg) +{ + const struct os_mbuf_pool *omp; + int min_count; + int idx; + + idx = 0; + STAILQ_FOREACH(omp, &g_msys_pool_list, omp_next) { + min_count = os_msys_sanity_min_count(idx); + if (omp->omp_pool->mp_num_free < min_count) { + return OS_ENOMEM; + } + + idx++; + } + + return ESP_OK; +} +#endif + +static void +os_msys_init_once(void *data, struct os_mempool *mempool, + struct os_mbuf_pool *mbuf_pool, + int block_count, int block_size, const char *name) +{ + int rc; + + rc = mem_init_mbuf_pool(data, mempool, mbuf_pool, block_count, block_size, + name); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_msys_register(mbuf_pool); + SYSINIT_PANIC_ASSERT(rc == 0); +} + +int +os_msys_buf_alloc(void) +{ +#if OS_MSYS_1_BLOCK_COUNT > 0 + os_msys_init_1_data = (os_membuf_t *)bt_osi_mem_calloc(1, (sizeof(os_membuf_t) * SYSINIT_MSYS_1_MEMPOOL_SIZE)); + if (!os_msys_init_1_data) { + return ESP_ERR_NO_MEM; + } +#endif + +#if OS_MSYS_2_BLOCK_COUNT > 0 + os_msys_init_2_data = (os_membuf_t *)bt_osi_mem_calloc(1, (sizeof(os_membuf_t) * SYSINIT_MSYS_2_MEMPOOL_SIZE)); + if (!os_msys_init_2_data) { +#if OS_MSYS_1_BLOCK_COUNT > 0 + bt_osi_mem_free(os_msys_init_1_data); + os_msys_init_1_data = NULL; +#endif + return ESP_ERR_NO_MEM; + } +#endif + + return ESP_OK; +} + +void +os_msys_buf_free(void) +{ +#if OS_MSYS_1_BLOCK_COUNT > 0 + bt_osi_mem_free(os_msys_init_1_data); + os_msys_init_1_data = NULL; +#endif + +#if OS_MSYS_2_BLOCK_COUNT > 0 + bt_osi_mem_free(os_msys_init_2_data); + os_msys_init_2_data = NULL; +#endif + +} + +void os_msys_init(void) +{ +#if OS_MSYS_SANITY_ENABLED + int rc; +#endif + + os_msys_reset(); + +#if OS_MSYS_1_BLOCK_COUNT > 0 + os_msys_init_once(os_msys_init_1_data, + &os_msys_init_1_mempool, + &os_msys_init_1_mbuf_pool, + OS_MSYS_1_BLOCK_COUNT, + SYSINIT_MSYS_1_MEMBLOCK_SIZE, + "msys_1"); +#endif + +#if OS_MSYS_2_BLOCK_COUNT > 0 + os_msys_init_once(os_msys_init_2_data, + &os_msys_init_2_mempool, + &os_msys_init_2_mbuf_pool, + OS_MSYS_2_BLOCK_COUNT, + SYSINIT_MSYS_2_MEMBLOCK_SIZE, + "msys_2"); +#endif + +#if OS_MSYS_SANITY_ENABLED + os_msys_sc.sc_func = os_msys_sanity; + os_msys_sc.sc_checkin_itvl = + OS_TICKS_PER_SEC * MYNEWT_VAL(MSYS_SANITY_TIMEOUT) / 1000; + rc = os_sanity_check_register(&os_msys_sc); + SYSINIT_PANIC_ASSERT(rc == 0); +#endif +} +#endif // CONFIG_BT_LE_MSYS_INIT_IN_CONTROLLER diff --git a/lib/bt/porting/npl/freertos/include/nimble/nimble_npl.h b/lib/bt/porting/npl/freertos/include/nimble/nimble_npl.h new file mode 100644 index 00000000..c9482044 --- /dev/null +++ b/lib/bt/porting/npl/freertos/include/nimble/nimble_npl.h @@ -0,0 +1,167 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NIMBLE_NPL_H_ +#define _NIMBLE_NPL_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ble_npl_event; +typedef void ble_npl_event_fn(struct ble_npl_event *ev); + +enum ble_npl_error { + BLE_NPL_OK = 0, + BLE_NPL_ENOMEM = 1, + BLE_NPL_EINVAL = 2, + BLE_NPL_INVALID_PARAM = 3, + BLE_NPL_MEM_NOT_ALIGNED = 4, + BLE_NPL_BAD_MUTEX = 5, + BLE_NPL_TIMEOUT = 6, + BLE_NPL_ERR_IN_ISR = 7, + BLE_NPL_ERR_PRIV = 8, + BLE_NPL_OS_NOT_STARTED = 9, + BLE_NPL_ENOENT = 10, + BLE_NPL_EBUSY = 11, + BLE_NPL_ERROR = 12, +}; + +typedef enum ble_npl_error ble_npl_error_t; + +/* Include OS-specific definitions */ +#include "nimble/nimble_npl_os.h" + +/* + * Generic + */ + +bool ble_npl_os_started(void); + +void *ble_npl_get_current_task_id(void); + +/* + * Event queue + */ + +void ble_npl_eventq_init(struct ble_npl_eventq *evq); + +void ble_npl_eventq_deinit(struct ble_npl_eventq *evq); + +struct ble_npl_event *ble_npl_eventq_get(struct ble_npl_eventq *evq, + ble_npl_time_t tmo); + +void ble_npl_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_event *ev); + +void ble_npl_eventq_remove(struct ble_npl_eventq *evq, + struct ble_npl_event *ev); + +void ble_npl_event_init(struct ble_npl_event *ev, ble_npl_event_fn *fn, + void *arg); + +bool ble_npl_event_is_queued(struct ble_npl_event *ev); + +void *ble_npl_event_get_arg(struct ble_npl_event *ev); + +void ble_npl_event_set_arg(struct ble_npl_event *ev, void *arg); + +bool ble_npl_eventq_is_empty(struct ble_npl_eventq *evq); + +void ble_npl_event_run(struct ble_npl_event *ev); + +/* + * Mutexes + */ + +ble_npl_error_t ble_npl_mutex_init(struct ble_npl_mutex *mu); + +ble_npl_error_t ble_npl_mutex_pend(struct ble_npl_mutex *mu, + ble_npl_time_t timeout); + +ble_npl_error_t ble_npl_mutex_release(struct ble_npl_mutex *mu); + +ble_npl_error_t ble_npl_mutex_deinit(struct ble_npl_mutex *mu); + +/* + * Semaphores + */ + +ble_npl_error_t ble_npl_sem_init(struct ble_npl_sem *sem, uint16_t tokens); + +ble_npl_error_t ble_npl_sem_pend(struct ble_npl_sem *sem, + ble_npl_time_t timeout); + +ble_npl_error_t ble_npl_sem_release(struct ble_npl_sem *sem); + +ble_npl_error_t ble_npl_sem_deinit(struct ble_npl_sem *sem); + +uint16_t ble_npl_sem_get_count(struct ble_npl_sem *sem); + +/* + * Callouts + */ + +int ble_npl_callout_init(struct ble_npl_callout *co, struct ble_npl_eventq *evq, + ble_npl_event_fn *ev_cb, void *ev_arg); + +ble_npl_error_t ble_npl_callout_reset(struct ble_npl_callout *co, + ble_npl_time_t ticks); + +void ble_npl_callout_stop(struct ble_npl_callout *co); + +bool ble_npl_callout_is_active(struct ble_npl_callout *co); + +ble_npl_time_t ble_npl_callout_get_ticks(struct ble_npl_callout *co); + +ble_npl_time_t ble_npl_callout_remaining_ticks(struct ble_npl_callout *co, + ble_npl_time_t time); + +void ble_npl_callout_set_arg(struct ble_npl_callout *co, + void *arg); +/* + * Time functions + */ + +ble_npl_time_t ble_npl_time_get(void); + +ble_npl_error_t ble_npl_time_ms_to_ticks(uint32_t ms, ble_npl_time_t *out_ticks); + +ble_npl_error_t ble_npl_time_ticks_to_ms(ble_npl_time_t ticks, uint32_t *out_ms); + +ble_npl_time_t ble_npl_time_ms_to_ticks32(uint32_t ms); + +uint32_t ble_npl_time_ticks_to_ms32(ble_npl_time_t ticks); + +void ble_npl_time_delay(ble_npl_time_t ticks); + +/* + * Hardware-specific + * + * These symbols should be most likely defined by application since they are + * specific to hardware, not to OS. + */ + +#if NIMBLE_CFG_CONTROLLER + +void ble_npl_hw_set_isr(int irqn, uint32_t addr); + +#endif + +uint32_t ble_npl_hw_enter_critical(void); + +void ble_npl_hw_exit_critical(uint32_t ctx); + +bool ble_npl_hw_is_in_critical(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _NIMBLE_NPL_H_ */ diff --git a/lib/bt/porting/npl/freertos/src/npl_os_freertos.c b/lib/bt/porting/npl/freertos/src/npl_os_freertos.c index 4e68c0e6..29e2567d 100644 --- a/lib/bt/porting/npl/freertos/src/npl_os_freertos.c +++ b/lib/bt/porting/npl/freertos/src/npl_os_freertos.c @@ -1,9 +1,7 @@ /* - * SPDX-FileCopyrightText: 2019-2023 The Apache Software Foundation (ASF) + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 - * - * SPDX-FileContributor: 2019-2023 Espressif Systems (Shanghai) CO LTD */ #include @@ -18,7 +16,6 @@ #include "freertos/timers.h" #include "freertos/portable.h" #include "nimble/npl_freertos.h" -#include "nimble/nimble_port.h" #include "os/os_mempool.h" #include "esp_log.h" @@ -481,32 +478,32 @@ IRAM_ATTR npl_freertos_mutex_release(struct ble_npl_mutex *mu) ble_npl_error_t npl_freertos_sem_init(struct ble_npl_sem *sem, uint16_t tokens) { - struct ble_npl_sem_freertos *semaphor = NULL; + struct ble_npl_sem_freertos *semaphore = NULL; #if OS_MEM_ALLOC if (!os_memblock_from(&ble_freertos_sem_pool,sem->sem)) { sem->sem = os_memblock_get(&ble_freertos_sem_pool); - semaphor = (struct ble_npl_sem_freertos *)sem->sem; + semaphore = (struct ble_npl_sem_freertos *)sem->sem; - if (!semaphor) { + if (!semaphore) { return BLE_NPL_INVALID_PARAM; } - memset(semaphor, 0, sizeof(*semaphor)); - semaphor->handle = xSemaphoreCreateCounting(128, tokens); - BLE_LL_ASSERT(semaphor->handle); + memset(semaphore, 0, sizeof(*semaphore)); + semaphore->handle = xSemaphoreCreateCounting(128, tokens); + BLE_LL_ASSERT(semaphore->handle); } #else if(!sem->sem) { sem->sem = malloc(sizeof(struct ble_npl_sem_freertos)); - semaphor = (struct ble_npl_sem_freertos *)sem->sem; + semaphore = (struct ble_npl_sem_freertos *)sem->sem; - if (!semaphor) { + if (!semaphore) { return BLE_NPL_INVALID_PARAM; } - memset(semaphor, 0, sizeof(*semaphor)); - semaphor->handle = xSemaphoreCreateCounting(128, tokens); - BLE_LL_ASSERT(semaphor->handle); + memset(semaphore, 0, sizeof(*semaphore)); + semaphore->handle = xSemaphoreCreateCounting(128, tokens); + BLE_LL_ASSERT(semaphore->handle); } #endif @@ -516,19 +513,19 @@ npl_freertos_sem_init(struct ble_npl_sem *sem, uint16_t tokens) ble_npl_error_t npl_freertos_sem_deinit(struct ble_npl_sem *sem) { - struct ble_npl_sem_freertos *semaphor = (struct ble_npl_sem_freertos *)sem->sem; + struct ble_npl_sem_freertos *semaphore = (struct ble_npl_sem_freertos *)sem->sem; - if (!semaphor) { + if (!semaphore) { return BLE_NPL_INVALID_PARAM; } - BLE_LL_ASSERT(semaphor->handle); - vSemaphoreDelete(semaphor->handle); + BLE_LL_ASSERT(semaphore->handle); + vSemaphoreDelete(semaphore->handle); #if OS_MEM_ALLOC - os_memblock_put(&ble_freertos_sem_pool,semaphor); + os_memblock_put(&ble_freertos_sem_pool,semaphore); #else - free((void *)semaphor); + free((void *)semaphore); #endif sem->sem = NULL; @@ -540,22 +537,22 @@ IRAM_ATTR npl_freertos_sem_pend(struct ble_npl_sem *sem, ble_npl_time_t timeout) { BaseType_t woken; BaseType_t ret; - struct ble_npl_sem_freertos *semaphor = (struct ble_npl_sem_freertos *)sem->sem; + struct ble_npl_sem_freertos *semaphore = (struct ble_npl_sem_freertos *)sem->sem; - if (!semaphor) { + if (!semaphore) { return BLE_NPL_INVALID_PARAM; } - BLE_LL_ASSERT(semaphor->handle); + BLE_LL_ASSERT(semaphore->handle); if (in_isr()) { BLE_LL_ASSERT(timeout == 0); - ret = xSemaphoreTakeFromISR(semaphor->handle, &woken); + ret = xSemaphoreTakeFromISR(semaphore->handle, &woken); if( woken == pdTRUE ) { portYIELD_FROM_ISR(); } } else { - ret = xSemaphoreTake(semaphor->handle, timeout); + ret = xSemaphoreTake(semaphore->handle, timeout); } return ret == pdPASS ? BLE_NPL_OK : BLE_NPL_TIMEOUT; @@ -566,21 +563,21 @@ IRAM_ATTR npl_freertos_sem_release(struct ble_npl_sem *sem) { BaseType_t ret; BaseType_t woken; - struct ble_npl_sem_freertos *semaphor = (struct ble_npl_sem_freertos *)sem->sem; + struct ble_npl_sem_freertos *semaphore = (struct ble_npl_sem_freertos *)sem->sem; - if (!semaphor) { + if (!semaphore) { return BLE_NPL_INVALID_PARAM; } - BLE_LL_ASSERT(semaphor->handle); + BLE_LL_ASSERT(semaphore->handle); if (in_isr()) { - ret = xSemaphoreGiveFromISR(semaphor->handle, &woken); + ret = xSemaphoreGiveFromISR(semaphore->handle, &woken); if( woken == pdTRUE ) { portYIELD_FROM_ISR(); } } else { - ret = xSemaphoreGive(semaphor->handle); + ret = xSemaphoreGive(semaphore->handle); } BLE_LL_ASSERT(ret == pdPASS); @@ -773,8 +770,8 @@ npl_freertos_callout_deinit(struct ble_npl_callout *co) uint16_t IRAM_ATTR npl_freertos_sem_get_count(struct ble_npl_sem *sem) { - struct ble_npl_sem_freertos *semaphor = (struct ble_npl_sem_freertos *)sem->sem; - return uxSemaphoreGetCount(semaphor->handle); + struct ble_npl_sem_freertos *semaphore = (struct ble_npl_sem_freertos *)sem->sem; + return uxSemaphoreGetCount(semaphore->handle); } @@ -842,15 +839,35 @@ ble_npl_time_t IRAM_ATTR npl_freertos_callout_get_ticks(struct ble_npl_callout *co) { #if BLE_NPL_USE_ESP_TIMER - /* Currently, esp_timer does not support an API which gets the expiry time for - * current timer. - * Returning 0 from here should not cause any effect. + + uint32_t exp = 0; + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + uint64_t expiry = 0; + esp_err_t err; + + struct ble_npl_callout_freertos *callout = (struct ble_npl_callout_freertos *)co->co; + + //Fetch expiry time in microseconds + err = esp_timer_get_expiry_time((esp_timer_handle_t)(callout->handle), &expiry); + if (err != ESP_OK) { + //Error. Could not fetch the expiry time + return 0; + } + + //Convert microseconds to ticks + npl_freertos_time_ms_to_ticks((uint32_t)(expiry / 1000), &exp); +#else + //esp_timer_get_expiry_time() is only available from IDF 5.0 onwards + /* Returning 0 from here should not cause any effect. * Drawback of this approach is that existing code to reset timer would be called * more often (since the if condition to invoke reset timer would always succeed if * timer is active). */ + exp = 0; +#endif //ESP_IDF_VERSION - return 0; + return exp; #else struct ble_npl_callout_freertos *callout = (struct ble_npl_callout_freertos *)co->co; return xTimerGetExpiryTime(callout->handle); diff --git a/lib/bt/sdkconfig.rename b/lib/bt/sdkconfig.rename index 55beeffc..0d38d15e 100644 --- a/lib/bt/sdkconfig.rename +++ b/lib/bt/sdkconfig.rename @@ -251,6 +251,7 @@ CONFIG_NIMBLE_SM_LEGACY CONFIG_BT_NIMBLE_SM_ CONFIG_NIMBLE_SM_SC CONFIG_BT_NIMBLE_SM_SC CONFIG_NIMBLE_DEBUG CONFIG_BT_NIMBLE_DEBUG CONFIG_NIMBLE_SM_SC_DEBUG_KEYS CONFIG_BT_NIMBLE_SM_SC_DEBUG_KEYS +CONFIG_BT_NIMBLE_SM_SC_LVL CONFIG_BT_NIMBLE_SM_LVL CONFIG_NIMBLE_SVC_GAP_DEVICE_NAME CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME CONFIG_NIMBLE_GAP_DEVICE_NAME_MAX_LEN CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN CONFIG_NIMBLE_ATT_PREFERRED_MTU CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU diff --git a/lib/bt/test_apps/.build-test-rules.yml b/lib/bt/test_apps/.build-test-rules.yml index f96777d2..9b434736 100644 --- a/lib/bt/test_apps/.build-test-rules.yml +++ b/lib/bt/test_apps/.build-test-rules.yml @@ -1,8 +1,17 @@ # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps -components/bt/test_apps: +components/bt/test_apps/basic_unit_test: disable: - if: IDF_TARGET not in ["esp32", "esp32c3"] reason: Sufficient to run the tests on one chip of each architecture depends_components: - bt + +components/bt/test_apps/memory_release: + disable: + - if: IDF_TARGET not in ["esp32", "esp32c2"] + - if: CONFIG_NAME == "iram" and IDF_TARGET != "esp32c2" + - if: CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1 + reason: Sufficient to run the tests on one chip of each architecture + depends_components: + - bt diff --git a/lib/bt/test_apps/basic_unit_test/CMakeLists.txt b/lib/bt/test_apps/basic_unit_test/CMakeLists.txt new file mode 100644 index 00000000..ab61d4b6 --- /dev/null +++ b/lib/bt/test_apps/basic_unit_test/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(COMPONENTS main) +list(PREPEND SDKCONFIG_DEFAULTS + "$ENV{IDF_PATH}/tools/test_apps/configs/sdkconfig.debug_helpers" + "sdkconfig.defaults") + +project(bt_test) diff --git a/lib/bt/test_apps/basic_unit_test/README.md b/lib/bt/test_apps/basic_unit_test/README.md new file mode 100644 index 00000000..fc828476 --- /dev/null +++ b/lib/bt/test_apps/basic_unit_test/README.md @@ -0,0 +1,21 @@ +| Supported Targets | ESP32 | ESP32-C3 | +| ----------------- | ----- | -------- | + +# `bt` component unit tests + +When adding new test cases, check if the `depends_components` list in `.build-test-rules.yml` needs to be updated to include additional components. The test app will only be built and tested when these components are modified. + +To build and run this test app, using esp32c3 target for example: + +```bash +idf.py set-target esp32c3 +idf.py build flash monitor +``` + +To run tests using pytest: + +```bash +idf.py set-target esp32c3 +idf.py build +pytest --target=esp32c3 +``` diff --git a/lib/bt/test_apps/basic_unit_test/main/CMakeLists.txt b/lib/bt/test_apps/basic_unit_test/main/CMakeLists.txt new file mode 100644 index 00000000..6aecb24e --- /dev/null +++ b/lib/bt/test_apps/basic_unit_test/main/CMakeLists.txt @@ -0,0 +1,6 @@ +idf_component_register(SRCS "test_bt_main.c" + "test_bt_common.c" + "test_smp.c" + INCLUDE_DIRS "." + PRIV_REQUIRES unity bt + WHOLE_ARCHIVE) diff --git a/lib/bt/test_apps/basic_unit_test/main/test_bt_common.c b/lib/bt/test_apps/basic_unit_test/main/test_bt_common.c new file mode 100644 index 00000000..402633d0 --- /dev/null +++ b/lib/bt/test_apps/basic_unit_test/main/test_bt_common.c @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +/* + Tests for the BT common things implementation +*/ + +#include + +#include "unity.h" +#include "sdkconfig.h" + +// btdm_controller_compile_version_check defined only for ESP32 +#ifdef CONFIG_IDF_TARGET_ESP32 +extern bool btdm_controller_compile_version_check(void); + +TEST_CASE("bt_controller_git_commit_check", "[bt_common]") +{ + TEST_ASSERT(btdm_controller_compile_version_check() == true); +} +#endif diff --git a/lib/bt/test_apps/basic_unit_test/main/test_bt_main.c b/lib/bt/test_apps/basic_unit_test/main/test_bt_main.c new file mode 100644 index 00000000..53a93c95 --- /dev/null +++ b/lib/bt/test_apps/basic_unit_test/main/test_bt_main.c @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" + +#define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT 0 +static int leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; +void set_leak_threshold(int threshold) +{ + leak_threshold = threshold; +} + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= leak_threshold, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); + + leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; +} + +void app_main(void) +{ + printf("Running bt component tests\n"); + unity_run_menu(); +} diff --git a/lib/bt/test_apps/basic_unit_test/main/test_smp.c b/lib/bt/test_apps/basic_unit_test/main/test_smp.c new file mode 100644 index 00000000..ea89ec26 --- /dev/null +++ b/lib/bt/test_apps/basic_unit_test/main/test_smp.c @@ -0,0 +1,126 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +/* + * Tests for the BLE SMP implementation + */ + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" +#include "esp_random.h" + +#include "esp_bt_main.h" +#include "esp_bt_device.h" +#include "esp_gap_ble_api.h" + +#define KEY_LENGTH_DWORDS_P256 8 + +typedef unsigned long DWORD; +typedef uint32_t UINT32; + +typedef struct { + DWORD x[KEY_LENGTH_DWORDS_P256]; + DWORD y[KEY_LENGTH_DWORDS_P256]; + DWORD z[KEY_LENGTH_DWORDS_P256]; +} Point; + +typedef struct { + // curve's coefficients + DWORD a[KEY_LENGTH_DWORDS_P256]; + DWORD b[KEY_LENGTH_DWORDS_P256]; + + //whether a is -3 + int a_minus3; + + // prime modulus + DWORD p[KEY_LENGTH_DWORDS_P256]; + + // Omega, p = 2^m -omega + DWORD omega[KEY_LENGTH_DWORDS_P256]; + + // base point, a point on E of order r + Point G; + +} elliptic_curve_t; + +extern void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength); +extern bool ECC_CheckPointIsInElliCur_P256(Point *p); +extern void p_256_init_curve(UINT32 keyLength); +extern elliptic_curve_t curve_p256; + +static void bt_rand(void *buf, size_t len) +{ + if (!len) { + return; + } + // Reset the buf value to the fixed value. + memset(buf, 0x55, len); + + for (int i = 0; i < (int)(len / sizeof(uint32_t)); i++) { + uint32_t rand = esp_random(); + memcpy(buf + i * sizeof(uint32_t), &rand, sizeof(uint32_t)); + } + + return; +} + +TEST_CASE("ble_smp_public_key_check", "[ble_smp]") +{ + /* We wait init finish 200ms here */ + vTaskDelay(200 / portTICK_PERIOD_MS); + Point public_key; + DWORD private_key[KEY_LENGTH_DWORDS_P256] = {[0 ... (KEY_LENGTH_DWORDS_P256 - 1)] = 0x12345678}; + p_256_init_curve(KEY_LENGTH_DWORDS_P256); + ECC_PointMult_Bin_NAF(&public_key, &(curve_p256.G), private_key, KEY_LENGTH_DWORDS_P256); + /* Check Is the public key generated by the system on the given elliptic curve */ + TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&public_key)); + /* We simulate the attacker and set the y coordinate of the public key to 0. */ + for (int i = 0; i < KEY_LENGTH_DWORDS_P256; i++) { + public_key.y[i] = 0x0; + } + /* At this point the public key should not be on the given elliptic curve. */ + TEST_ASSERT(!ECC_CheckPointIsInElliCur_P256(&public_key)); + /* Test whether the G point on the protocol is on a given elliptic curve */ + TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&(curve_p256.G))); + /* test 100 times when the private key is generated by the random number. */ + for (int j = 0; j < 100; j++) { + bt_rand(private_key, sizeof(DWORD)*KEY_LENGTH_DWORDS_P256); + ECC_PointMult_Bin_NAF(&public_key, &(curve_p256.G), private_key, KEY_LENGTH_DWORDS_P256); + /* Check Is the public key generated by the system on the given elliptic curve */ + TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&public_key)); + } +} + +TEST_CASE("ble_smp_set_clear_static_passkey", "[ble_smp]") +{ + /* We wait init finish 200ms here */ + vTaskDelay(200 / portTICK_PERIOD_MS); + esp_ble_auth_req_t auth_req = ESP_LE_AUTH_BOND; + uint32_t passkey = 123456; + /* test len = 0 when type != ESP_BLE_SM_CLEAR_STATIC_PASSKEY */ + TEST_ASSERT(esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, 0) == ESP_ERR_INVALID_ARG); + /* test function */ + TEST_ASSERT(esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(esp_ble_auth_req_t)) != ESP_ERR_INVALID_ARG); + /* test type >= ESP_BLE_SM_MAX_PARAM */ + TEST_ASSERT(esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_PARAM, &passkey, sizeof(uint32_t)) == ESP_ERR_INVALID_ARG); + /* test len < sizeof(uint32_t) when type is ESP_BLE_SM_SET_STATIC_PASSKEY */ + TEST_ASSERT(esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint8_t)) != ESP_ERR_INVALID_ARG); + /* test value is NULL when type != ESP_BLE_SM_CLEAR_STATIC_PASSKEY */ + TEST_ASSERT(esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, NULL, sizeof(uint8_t)) == ESP_ERR_INVALID_ARG); + /* test value is NULL and len is 0 when type != ESP_BLE_SM_CLEAR_STATIC_PASSKEY */ + TEST_ASSERT(esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, NULL, 0) == ESP_ERR_INVALID_ARG); + /* test function */ + TEST_ASSERT(esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t)) != ESP_ERR_INVALID_ARG); + /* test function */ + TEST_ASSERT(esp_ble_gap_set_security_param(ESP_BLE_SM_CLEAR_STATIC_PASSKEY, &passkey, sizeof(uint32_t)) != ESP_ERR_INVALID_ARG); + /* test function */ + TEST_ASSERT(esp_ble_gap_set_security_param(ESP_BLE_SM_CLEAR_STATIC_PASSKEY, NULL, sizeof(uint32_t)) != ESP_ERR_INVALID_ARG); + /* test function */ + TEST_ASSERT(esp_ble_gap_set_security_param(ESP_BLE_SM_CLEAR_STATIC_PASSKEY, NULL, 0) != ESP_ERR_INVALID_ARG); +} diff --git a/lib/bt/test_apps/basic_unit_test/pytest_basic_unit_test.py b/lib/bt/test_apps/basic_unit_test/pytest_basic_unit_test.py new file mode 100644 index 00000000..de3d235b --- /dev/null +++ b/lib/bt/test_apps/basic_unit_test/pytest_basic_unit_test.py @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.generic +@pytest.mark.esp32 +@pytest.mark.esp32c3 +def test_bt(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/lib/bt/test_apps/basic_unit_test/sdkconfig.defaults b/lib/bt/test_apps/basic_unit_test/sdkconfig.defaults new file mode 100644 index 00000000..dc2d7ca0 --- /dev/null +++ b/lib/bt/test_apps/basic_unit_test/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_BT_ENABLED=y +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n diff --git a/lib/bt/test_apps/memory_release/CMakeLists.txt b/lib/bt/test_apps/memory_release/CMakeLists.txt new file mode 100644 index 00000000..f3d75bb4 --- /dev/null +++ b/lib/bt/test_apps/memory_release/CMakeLists.txt @@ -0,0 +1,5 @@ +# This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test_bt_memory_release) diff --git a/lib/bt/test_apps/memory_release/README.md b/lib/bt/test_apps/memory_release/README.md new file mode 100644 index 00000000..2975ce8f --- /dev/null +++ b/lib/bt/test_apps/memory_release/README.md @@ -0,0 +1,4 @@ +| Supported Targets | ESP32 | ESP32-C2 | +| ----------------- | ----- | -------- | + +This test app is used to test esp_bt_memory_release function diff --git a/lib/bt/test_apps/memory_release/main/CMakeLists.txt b/lib/bt/test_apps/memory_release/main/CMakeLists.txt new file mode 100644 index 00000000..660eb587 --- /dev/null +++ b/lib/bt/test_apps/memory_release/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "test_app_main.c" + INCLUDE_DIRS "." + PRIV_REQUIRES bt nvs_flash) diff --git a/lib/bt/test_apps/memory_release/main/test_app_main.c b/lib/bt/test_apps/memory_release/main/test_app_main.c new file mode 100644 index 00000000..562d1d97 --- /dev/null +++ b/lib/bt/test_apps/memory_release/main/test_app_main.c @@ -0,0 +1,131 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "multi_heap.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_bt.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "host/ble_hs.h" +#include "host/util/util.h" +#include "services/gap/ble_svc_gap.h" + +#define FAIL() do { printf("FAILURE\n"); return; } while(0) + +extern uint8_t _bt_bss_start; +extern uint8_t _bt_bss_end; +extern uint8_t _bt_controller_bss_start; +extern uint8_t _bt_controller_bss_end; + +extern void ble_store_config_init(void); + +static const char *tag = "MEM_RELEASE_APP"; + +static void nimble_host_on_reset(int reason) +{ + ESP_LOGI(tag, "Resetting state; reason=%d", reason); +} + +static void nimble_host_on_sync(void) +{ + ESP_LOGI(tag, "NimBLE host synchronized"); +} + +static void nimble_host_task_fn(void *param) +{ + ESP_LOGI(tag, "BLE Host Task Started"); + /* This function will return only when nimble_port_stop() is executed */ + nimble_port_run(); + + nimble_port_freertos_deinit(); +} + +static void bt_stack_init(void) +{ + esp_err_t ret = nimble_port_init(); + ESP_ERROR_CHECK(ret); + + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = nimble_host_on_reset; + ble_hs_cfg.sync_cb = nimble_host_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + + /* Set the default device name. */ + int rc = ble_svc_gap_device_name_set(tag); + assert(rc == 0); + + /* XXX Need to have template for store */ + ble_store_config_init(); + + nimble_port_freertos_init(nimble_host_task_fn); +} + +static void bt_stack_deinit(void) +{ + int rc = nimble_port_stop(); + assert(rc == 0); + + nimble_port_deinit(); + ESP_LOGI(tag, "BLE Host Task Stopped"); +} + +void app_main(void) +{ + esp_err_t ret = ESP_OK; + + /* Initialize NVS — it is used to store PHY calibration data */ + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + /* initialize and then deinitialize bluetooth stack */ + bt_stack_init(); + + vTaskDelay(pdMS_TO_TICKS(200)); + + bt_stack_deinit(); + + /* Get the size of heap located in external RAM */ + const uint32_t free_before = heap_caps_get_free_size(MALLOC_CAP_DEFAULT); + ESP_LOGI(tag, "Free size in external RAM heap: %"PRIu32, free_before); + + /* Make sure at least one of the Bluetooth BSS section that can be used as a heap */ + const uint32_t heap_size = sizeof(multi_heap_info_t); + const uint32_t bt_bss_size = &_bt_bss_end - &_bt_bss_start; + const uint32_t bt_ctrl_bss_size = &_bt_controller_bss_end - &_bt_controller_bss_start; + + ESP_LOGI(tag, "bt_bss_size %"PRIu32", bt_ctrl_bss_size %"PRIu32, bt_bss_size, bt_ctrl_bss_size); + if (bt_bss_size < heap_size && bt_ctrl_bss_size < heap_size) + { + ESP_LOGW(tag, "Bluetooth BSS sections are too small!"); + FAIL(); + } + + /* Release the BSS sections to use them as heap */ + ret = esp_bt_mem_release(ESP_BT_MODE_BTDM); + ESP_ERROR_CHECK(ret); + + /* Check that we have more available memory in the external RAM heap */ + const uint32_t free_after = heap_caps_get_free_size(MALLOC_CAP_DEFAULT); + ESP_LOGI(tag, "Free size in external RAM after releasing: %"PRIu32, free_after); + if (free_after <= free_before) { + FAIL(); + } + ESP_LOGI(tag, "Free heap size increased by %"PRIu32" bytes", free_after - free_before); + + ESP_LOGI(tag, "SUCCESS"); +} diff --git a/lib/bt/test_apps/memory_release/pytest_memory_release.py b/lib/bt/test_apps/memory_release/pytest_memory_release.py new file mode 100644 index 00000000..dbefc908 --- /dev/null +++ b/lib/bt/test_apps/memory_release/pytest_memory_release.py @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.parametrize('config', [ + pytest.param('default', marks=[pytest.mark.esp32, pytest.mark.esp32c2, pytest.mark.generic]), + pytest.param('iram', marks=[pytest.mark.esp32c2, pytest.mark.generic]), + pytest.param('psram', marks=[pytest.mark.esp32, pytest.mark.psram]), +], indirect=True) +def test_bt_memory_release(dut: Dut) -> None: + dut.expect_exact('BLE Host Task Started', timeout=6) + dut.expect_exact('BLE Host Task Stopped', timeout=8) + dut.expect_exact('SUCCESS', timeout=10) diff --git a/lib/bt/test_apps/memory_release/sdkconfig.ci.iram b/lib/bt/test_apps/memory_release/sdkconfig.ci.iram new file mode 100644 index 00000000..36e7ceb9 --- /dev/null +++ b/lib/bt/test_apps/memory_release/sdkconfig.ci.iram @@ -0,0 +1,2 @@ +CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT=n +CONFIG_BT_RELEASE_IRAM=y diff --git a/lib/bt/test_apps/memory_release/sdkconfig.ci.psram b/lib/bt/test_apps/memory_release/sdkconfig.ci.psram new file mode 100644 index 00000000..4090a49e --- /dev/null +++ b/lib/bt/test_apps/memory_release/sdkconfig.ci.psram @@ -0,0 +1,2 @@ +CONFIG_SPIRAM=y +CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y diff --git a/lib/bt/test_apps/memory_release/sdkconfig.defaults b/lib/bt/test_apps/memory_release/sdkconfig.defaults new file mode 100644 index 00000000..a22d8109 --- /dev/null +++ b/lib/bt/test_apps/memory_release/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y diff --git a/lib/console/CMakeLists.txt b/lib/console/CMakeLists.txt index 5904ac5a..093380e1 100644 --- a/lib/console/CMakeLists.txt +++ b/lib/console/CMakeLists.txt @@ -28,4 +28,4 @@ idf_component_register(SRCS "commands.c" ${argtable_srcs} INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} REQUIRES vfs - PRIV_REQUIRES driver) + PRIV_REQUIRES driver esp_vfs_console) diff --git a/lib/esp-idf b/lib/esp-idf index a322e6bd..e0991fac 160000 --- a/lib/esp-idf +++ b/lib/esp-idf @@ -1 +1 @@ -Subproject commit a322e6bdad4b6675d4597fb2722eea2851ba88cb +Subproject commit e0991facf5ecb362af6aac1fae972139eb38d2e4 diff --git a/lib/fatfs/CMakeLists.txt b/lib/fatfs/CMakeLists.txt index b6a288e0..f641ca86 100644 --- a/lib/fatfs/CMakeLists.txt +++ b/lib/fatfs/CMakeLists.txt @@ -22,9 +22,9 @@ else() list(APPEND include_dirs "vfs") - list(APPEND requires "sdmmc") + list(APPEND requires "sdmmc" "esp_driver_sdmmc" "esp_driver_sdspi") - list(APPEND priv_requires "vfs") + list(APPEND priv_requires "vfs" "esp_driver_gpio") endif() idf_component_register(SRCS ${srcs} diff --git a/lib/fatfs/src/ffconf.h b/lib/fatfs/src/ffconf.h index 77bd5981..a5a4ae17 100644 --- a/lib/fatfs/src/ffconf.h +++ b/lib/fatfs/src/ffconf.h @@ -58,7 +58,7 @@ /* This option switches f_forward() function. (0:Disable or 1:Enable) */ -#define FF_USE_STRFUNC 0 +#define FF_USE_STRFUNC 1 #define FF_PRINT_LLI 0 #define FF_PRINT_FLOAT 0 #define FF_STRF_ENCODE 3 diff --git a/lib/lvgl/lv_conf.h b/lib/lvgl/lv_conf.h index 026e2ee2..3adaeb8f 100644 --- a/lib/lvgl/lv_conf.h +++ b/lib/lvgl/lv_conf.h @@ -47,7 +47,7 @@ #if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN /*Size of the memory available for `lv_malloc()` in bytes (>= 2kB)*/ - #define LV_MEM_SIZE (1024U * 1024U) /*[bytes]*/ + #define LV_MEM_SIZE (2048U * 1024U) /*[bytes]*/ /*Size of the memory expand for `lv_malloc()` in bytes*/ #define LV_MEM_POOL_EXPAND_SIZE 0 diff --git a/lib/lvgl/src/draw/sw/lv_draw_sw.c b/lib/lvgl/src/draw/sw/lv_draw_sw.c index 4ced5d1d..c0ec052b 100644 --- a/lib/lvgl/src/draw/sw/lv_draw_sw.c +++ b/lib/lvgl/src/draw/sw/lv_draw_sw.c @@ -143,7 +143,7 @@ void lv_draw_sw_init(void) draw_sw_unit->base_unit.delete_cb = LV_USE_OS ? lv_draw_sw_delete : NULL; #if LV_USE_OS - lv_thread_init(&draw_sw_unit->thread, LV_THREAD_PRIO_HIGH, render_thread_cb, 8 * 1024, draw_sw_unit); + lv_thread_init(&draw_sw_unit->thread, LV_THREAD_PRIO_HIGH, render_thread_cb, 4 * 1024, draw_sw_unit); #endif } diff --git a/lua/browser.lua b/lua/browser.lua index ce0f7978..406c2e49 100644 --- a/lua/browser.lua +++ b/lua/browser.lua @@ -10,7 +10,7 @@ local theme = require("theme") local screen = require("screen") return screen:new{ - createUi = function(self) + create_ui = function(self) self.root = lvgl.Object(nil, { flex = { flex_direction = "column", @@ -58,7 +58,7 @@ return screen:new{ flex = { flex_direction = "row", flex_wrap = "wrap", - justify_content = "center", + justify_content = "space-between", align_items = "center", align_content = "center" }, @@ -84,6 +84,7 @@ return screen:new{ local play = widgets.IconBtn(buttons, "//lua/img/play_small.png", "Play") play:onClicked(function() queue.clear() + queue.random:set(false) queue.add(original_iterator) playback.playing:set(true) backstack.push(playing:new()) diff --git a/lua/file_browser.lua b/lua/file_browser.lua index 91b84c84..0ccd2c13 100644 --- a/lua/file_browser.lua +++ b/lua/file_browser.lua @@ -10,64 +10,75 @@ local theme = require("theme") local screen = require("screen") local filesystem = require("filesystem") -return screen:new{ - createUi = function(self) - self.root = lvgl.Object(nil, { - flex = { - flex_direction = "column", - flex_wrap = "wrap", - justify_content = "flex-start", - align_items = "flex-start", - align_content = "flex-start" - }, - w = lvgl.HOR_RES(), - h = lvgl.VER_RES() - }) - self.root:center() +return screen:new { + create_ui = function(self) + self.root = lvgl.Object(nil, { + flex = { + flex_direction = "column", + flex_wrap = "wrap", + justify_content = "flex-start", + align_items = "flex-start", + align_content = "flex-start" + }, + w = lvgl.HOR_RES(), + h = lvgl.VER_RES() + }) + self.root:center() - self.status_bar = widgets.StatusBar(self, { - back_cb = backstack.pop, - title = self.title - }) + self.status_bar = widgets.StatusBar(self, { + back_cb = backstack.pop, + title = self.title + }) - local header = self.root:Object{ - flex = { - flex_direction = "column", - flex_wrap = "wrap", - justify_content = "flex-start", - align_items = "flex-start", - align_content = "flex-start" - }, - w = lvgl.HOR_RES(), - h = lvgl.SIZE_CONTENT, - pad_left = 4, - pad_right = 4, - pad_bottom = 2, - bg_opa = lvgl.OPA(100), - scrollbar_mode = lvgl.SCROLLBAR_MODE.OFF - } - theme.set_style(header, "header") + local header = self.root:Object { + flex = { + flex_direction = "column", + flex_wrap = "wrap", + justify_content = "flex-start", + align_items = "flex-start", + align_content = "flex-start" + }, + w = lvgl.HOR_RES(), + h = lvgl.SIZE_CONTENT, + pad_left = 4, + pad_right = 4, + pad_bottom = 2, + bg_opa = lvgl.OPA(100), + scrollbar_mode = lvgl.SCROLLBAR_MODE.OFF + } + theme.set_style(header, "header") - if self.breadcrumb then - header:Label{ - text = self.breadcrumb, - text_font = font.fusion_10 - } - end - - widgets.InfiniteList(self.root, self.iterator, { - callback = function(item) - return function() - local is_dir = item:is_directory() - if is_dir then - backstack.push(require("file_browser"):new{ - title = self.title, - iterator = filesystem.iterator(tostring(item)), - breadcrumb = tostring(item) - }) - end - end - end - }) + if self.breadcrumb then + header:Label { + text = self.breadcrumb, + text_font = font.fusion_10 + } end + + widgets.InfiniteList(self.root, self.iterator, { + callback = function(item) + return function() + local is_dir = item:is_directory() + if is_dir then + backstack.push(require("file_browser"):new { + title = self.title, + iterator = filesystem.iterator(item:filepath()), + breadcrumb = item:filepath() + }) + elseif + item:filepath():match("%.playlist$") or + item:filepath():match("%.m3u8?$") then + queue.open_playlist(item:filepath()) + playback.playing:set(true) + backstack.push(playing:new()) + elseif playback.is_playable(item:filepath()) then + queue.clear() + queue.add(item:filepath()) + playback.playing:set(true) + backstack.push(playing:new()) + end + end + end + }) + end } diff --git a/lua/fonts/fusion10 b/lua/fonts/fusion10 index 9fa4b78d..41e3916e 100644 Binary files a/lua/fonts/fusion10 and b/lua/fonts/fusion10 differ diff --git a/lua/fonts/fusion12 b/lua/fonts/fusion12 index 0fda8b03..3745c17d 100644 Binary files a/lua/fonts/fusion12 and b/lua/fonts/fusion12 differ diff --git a/lua/images.lua b/lua/images.lua index 1634bc44..5bb33d4d 100644 --- a/lua/images.lua +++ b/lua/images.lua @@ -1,6 +1,7 @@ local lvgl = require("lvgl") local img = { + back = lvgl.ImgData("//lua/img/back.png"), play = lvgl.ImgData("//lua/img/play.png"), play_small = lvgl.ImgData("//lua/img/playcirc.png"), pause = lvgl.ImgData("//lua/img/pause.png"), @@ -8,7 +9,9 @@ local img = { next = lvgl.ImgData("//lua/img/next.png"), prev = lvgl.ImgData("//lua/img/prev.png"), shuffle = lvgl.ImgData("//lua/img/shuffle.png"), + shuffle_off = lvgl.ImgData("//lua/img/shuffle_off.png"), repeat_src = lvgl.ImgData("//lua/img/repeat.png"), -- repeat is a reserved word + repeat_off = lvgl.ImgData("//lua/img/repeat_off.png"), queue = lvgl.ImgData("//lua/img/queue.png"), files = lvgl.ImgData("//lua/img/files.png"), settings = lvgl.ImgData("//lua/img/settings.png"), diff --git a/lua/img/back.png b/lua/img/back.png new file mode 100644 index 00000000..0f34453b Binary files /dev/null and b/lua/img/back.png differ diff --git a/lua/img/bat/0.png b/lua/img/bat/0.png index 15639ef5..d4c69fd4 100644 Binary files a/lua/img/bat/0.png and b/lua/img/bat/0.png differ diff --git a/lua/img/bat/0chg.png b/lua/img/bat/0chg.png deleted file mode 100644 index 7267ade1..00000000 Binary files a/lua/img/bat/0chg.png and /dev/null differ diff --git a/lua/img/bat/100.png b/lua/img/bat/100.png index f762ec2f..443ac6cc 100644 Binary files a/lua/img/bat/100.png and b/lua/img/bat/100.png differ diff --git a/lua/img/bat/20.png b/lua/img/bat/20.png index b1fcca1b..11fb049e 100644 Binary files a/lua/img/bat/20.png and b/lua/img/bat/20.png differ diff --git a/lua/img/bat/40.png b/lua/img/bat/40.png index fbba9c3b..3dcfe2e6 100644 Binary files a/lua/img/bat/40.png and b/lua/img/bat/40.png differ diff --git a/lua/img/bat/60.png b/lua/img/bat/60.png index 97a8b605..9e677571 100644 Binary files a/lua/img/bat/60.png and b/lua/img/bat/60.png differ diff --git a/lua/img/bat/80.png b/lua/img/bat/80.png index ab90987b..4c393f03 100644 Binary files a/lua/img/bat/80.png and b/lua/img/bat/80.png differ diff --git a/lua/img/bat/chg.png b/lua/img/bat/chg.png index d604bb76..629586e3 100644 Binary files a/lua/img/bat/chg.png and b/lua/img/bat/chg.png differ diff --git a/lua/img/bt.png b/lua/img/bt.png index 73f3179f..ae45dfbf 100644 Binary files a/lua/img/bt.png and b/lua/img/bt.png differ diff --git a/lua/img/bt_conn.png b/lua/img/bt_conn.png index 91f9964d..890e4160 100644 Binary files a/lua/img/bt_conn.png and b/lua/img/bt_conn.png differ diff --git a/lua/img/ce.png b/lua/img/ce.png new file mode 100644 index 00000000..dae12bc6 Binary files /dev/null and b/lua/img/ce.png differ diff --git a/lua/img/next.png b/lua/img/next.png index 1f6f044b..d245148e 100644 Binary files a/lua/img/next.png and b/lua/img/next.png differ diff --git a/lua/img/pause.png b/lua/img/pause.png index e7011821..32c5a2b4 100644 Binary files a/lua/img/pause.png and b/lua/img/pause.png differ diff --git a/lua/img/pausecirc.png b/lua/img/pausecirc.png index d7e944fa..4c6f4fd8 100644 Binary files a/lua/img/pausecirc.png and b/lua/img/pausecirc.png differ diff --git a/lua/img/play.png b/lua/img/play.png index a3b8a5af..833cb087 100644 Binary files a/lua/img/play.png and b/lua/img/play.png differ diff --git a/lua/img/playcirc.png b/lua/img/playcirc.png index f2e48da7..dc394f3e 100644 Binary files a/lua/img/playcirc.png and b/lua/img/playcirc.png differ diff --git a/lua/img/prev.png b/lua/img/prev.png index b445c75a..ee4273e7 100644 Binary files a/lua/img/prev.png and b/lua/img/prev.png differ diff --git a/lua/img/repeat.png b/lua/img/repeat.png index 40a7564e..c9941601 100644 Binary files a/lua/img/repeat.png and b/lua/img/repeat.png differ diff --git a/lua/img/repeat_off.png b/lua/img/repeat_off.png new file mode 100644 index 00000000..b8db6c4d Binary files /dev/null and b/lua/img/repeat_off.png differ diff --git a/lua/img/settings.png b/lua/img/settings.png index 4fc29e51..e6fbecb3 100644 Binary files a/lua/img/settings.png and b/lua/img/settings.png differ diff --git a/lua/img/shuffle_off.png b/lua/img/shuffle_off.png new file mode 100644 index 00000000..eb99ccf5 Binary files /dev/null and b/lua/img/shuffle_off.png differ diff --git a/lua/img/weee.png b/lua/img/weee.png new file mode 100644 index 00000000..ca0a5ddd Binary files /dev/null and b/lua/img/weee.png differ diff --git a/lua/licenses.lua b/lua/licenses.lua index b8c71f36..404719e3 100644 --- a/lua/licenses.lua +++ b/lua/licenses.lua @@ -8,8 +8,8 @@ local function show_license(text) backstack.push(widgets.MenuScreen:new { show_back = true, title = "Licenses", - createUi = function(self) - widgets.MenuScreen.createUi(self) + create_ui = function(self) + widgets.MenuScreen.create_ui(self) self.root:Label { w = lvgl.PCT(100), h = lvgl.SIZE_CONTENT, @@ -64,7 +64,7 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I end return function(self) - local container = self.root:Object { + local container = self.content:Object { flex = { flex_direction = "column", flex_wrap = "nowrap", diff --git a/lua/main.lua b/lua/main.lua index 4cd754b6..f79b0e87 100644 --- a/lua/main.lua +++ b/lua/main.lua @@ -14,9 +14,15 @@ local backstack = require("backstack") local main_menu = require("main_menu") local function init_ui() - -- Load the theme within init_ui because the theme needs fonts to be ready. - local theme_dark = require("theme_dark") - theme.set(theme_dark) + -- Theme is set within init_ui because the theme needs fonts to be ready. + -- Set the theme to the saved theme if available + local saved_theme = theme.theme_filename() + local res = theme.load_theme(saved_theme) + if not res then + -- Set a default theme (in case the saved theme does not load) + local default_theme = require("theme_light") + theme.set(default_theme) + end local lock_time = time.ticks() @@ -59,7 +65,7 @@ local function init_ui() elseif time.ticks() - lock_time > 8000 then local queue = require("queue") if queue.size:get() > 0 then - require("playing"):pushIfNotShown() + require("playing"):push_if_not_shown() end end end), diff --git a/lua/main_menu.lua b/lua/main_menu.lua index f3b7a042..a6b46a8a 100644 --- a/lua/main_menu.lua +++ b/lua/main_menu.lua @@ -13,8 +13,8 @@ local img = require("images") local playback = require("playback") return widgets.MenuScreen:new { - createUi = function(self) - widgets.MenuScreen.createUi(self) + create_ui = function(self) + widgets.MenuScreen.create_ui(self) -- At the top, a card showing details about the current track. Hidden if -- there is no track currently playing. @@ -33,9 +33,9 @@ return widgets.MenuScreen:new { margin_all = 2, pad_bottom = 2, pad_column = 4, - border_color = "#FFFFFF", border_width = 1, }) + theme.set_style(now_playing, "now_playing"); local play_pause = now_playing:Image { src = img.play_small } local title = now_playing:Label { @@ -140,6 +140,7 @@ return widgets.MenuScreen:new { w = lvgl.PCT(100), h = lvgl.SIZE_CONTENT, pad_top = 4, + pad_bottom = 2, }) -- local queue_btn = bottom_bar:Button {} @@ -154,13 +155,13 @@ return widgets.MenuScreen:new { }) end) files_btn:Image { src = img.files } - theme.set_style(files_btn, "icon_enabled") + theme.set_style(files_btn, "menu_icon") local settings_btn = bottom_bar:Button {} settings_btn:onClicked(function() backstack.push(require("settings"):new()) end) settings_btn:Image { src = img.settings } - theme.set_style(settings_btn, "icon_enabled") + theme.set_style(settings_btn, "menu_icon") end, } diff --git a/lua/playing.lua b/lua/playing.lua index 90e20f49..b3b4ec4d 100644 --- a/lua/playing.lua +++ b/lua/playing.lua @@ -20,7 +20,7 @@ local icon_enabled_class = "icon_enabled" local icon_disabled_class = "icon_disabled" return screen:new { - createUi = function(self) + create_ui = function(self) self.root = lvgl.Object(nil, { flex = { flex_direction = "column", @@ -74,7 +74,7 @@ return screen:new { align_items = "center", align_content = "center", }, - w = lvgl.PCT(100), + w = lvgl.PCT(95), h = lvgl.SIZE_CONTENT, } @@ -114,11 +114,12 @@ return screen:new { playlist:Object({ w = 3, h = 1 }) -- spacer local scrubber = self.root:Slider { - w = lvgl.PCT(100), + w = lvgl.PCT(90), h = 5, range = { min = 0, max = 100 }, value = 0, } + theme.set_style(scrubber, "scrubber"); local scrubber_desc = widgets.Description(scrubber, "Scrubber") scrubber:onevent(lvgl.EVENT.RELEASED, function() @@ -138,6 +139,8 @@ return screen:new { end end) + self.root:Object({ w = 1, h = 1 }) -- spacer + local controls = self.root:Object { flex = { flex_direction = "row", @@ -158,7 +161,7 @@ return screen:new { queue.repeat_track:set(not queue.repeat_track:get()) end) local repeat_img = repeat_btn:Image { src = img.repeat_src } - theme.set_style(repeat_img, icon_enabled_class) + theme.set_style(repeat_btn, icon_enabled_class) local repeat_desc = widgets.Description(repeat_btn) @@ -171,7 +174,7 @@ return screen:new { end end) local prev_img = prev_btn:Image { src = img.prev } - theme.set_style(prev_img, icon_enabled_class) + theme.set_style(prev_btn, icon_enabled_class) local prev_desc = widgets.Description(prev_btn, "Previous track") local play_pause_btn = controls:Button {} @@ -180,13 +183,13 @@ return screen:new { end) play_pause_btn:focus() local play_pause_img = play_pause_btn:Image { src = img.pause } - theme.set_style(play_pause_img, icon_enabled_class) + theme.set_style(play_pause_btn, icon_enabled_class) local play_pause_desc = widgets.Description(play_pause_btn, "Play") local next_btn = controls:Button {} next_btn:onClicked(queue.next) local next_img = next_btn:Image { src = img.next } - theme.set_style(next_img, icon_disabled_class) + theme.set_style(next_btn, icon_disabled_class) local next_desc = widgets.Description(next_btn, "Next track") local shuffle_btn = controls:Button {} @@ -194,7 +197,7 @@ return screen:new { queue.random:set(not queue.random:get()) end) local shuffle_img = shuffle_btn:Image { src = img.shuffle } - theme.set_style(shuffle_img, icon_enabled_class) + theme.set_style(shuffle_btn, icon_enabled_class) local shuffle_desc = widgets.Description(shuffle_btn) controls:Object({ flex_grow = 1, h = 1 }) -- spacer @@ -223,7 +226,18 @@ return screen:new { end end), playback.track:bind(function(track) - if not track then return end + if not track then + if queue.loading:get() then + title:set { text = "Loading..." } + else + title:set { text = "" } + end + artist:set { text = "" } + cur_time:set { text = format_time(0) } + end_time:set { text = format_time(0) } + scrubber:set { value = 0 } + return + end if track.duration then end_time:set { text = format_time(track.duration) } else @@ -238,22 +252,26 @@ return screen:new { local can_next = pos < queue.size:get() or queue.random:get() theme.set_style( - next_img, can_next and icon_enabled_class or icon_disabled_class + next_btn, can_next and icon_enabled_class or icon_disabled_class ) end), queue.random:bind(function(shuffling) - theme.set_style(shuffle_img, shuffling and icon_enabled_class or icon_disabled_class) + theme.set_style(shuffle_btn, shuffling and icon_enabled_class or icon_disabled_class) if shuffling then + shuffle_img:set_src(img.shuffle) shuffle_desc:set { text = "Disable shuffle" } else + shuffle_img:set_src(img.shuffle_off) shuffle_desc:set { text = "Enable shuffle" } end end), queue.repeat_track:bind(function(en) - theme.set_style(repeat_img, en and icon_enabled_class or icon_disabled_class) + theme.set_style(repeat_btn, en and icon_enabled_class or icon_disabled_class) if en then + repeat_img:set_src(img.repeat_src) repeat_desc:set { text = "Disable track repeat" } else + repeat_img:set_src(img.repeat_off) repeat_desc:set { text = "Enable track repeat" } end end), @@ -263,9 +281,9 @@ return screen:new { end), } end, - onShown = function() is_now_playing_shown = true end, - onHidden = function() is_now_playing_shown = false end, - pushIfNotShown = function(self) + on_show = function() is_now_playing_shown = true end, + on_hide = function() is_now_playing_shown = false end, + push_if_not_shown = function(self) if not is_now_playing_shown then backstack.push(self:new()) end diff --git a/lua/settings.lua b/lua/settings.lua index cb7f65e0..9b77274d 100644 --- a/lua/settings.lua +++ b/lua/settings.lua @@ -7,13 +7,16 @@ local display = require("display") local controls = require("controls") local bluetooth = require("bluetooth") local theme = require("theme") +local filesystem = require("filesystem") local database = require("database") local usb = require("usb") +local font = require("font") +local main_menu = require("main_menu") local SettingsScreen = widgets.MenuScreen:new { show_back = true, - createUi = function(self) - widgets.MenuScreen.createUi(self) + create_ui = function(self) + widgets.MenuScreen.create_ui(self) self.content = self.root:Object { flex = { flex_direction = "column", @@ -30,10 +33,38 @@ local SettingsScreen = widgets.MenuScreen:new { end } +local BluetoothPairing = SettingsScreen:new { + title = "Nearby Devices", + create_ui = function(self) + SettingsScreen.create_ui(self) + + local devices = self.content:List { + w = lvgl.PCT(100), + h = lvgl.SIZE_CONTENT, + } + + self.bindings = self.bindings + { + bluetooth.discovered_devices:bind(function(devs) + devices:clean() + for _, dev in pairs(devs) do + devices:add_btn(nil, dev.name):onClicked(function() + bluetooth.paired_device:set(dev) + backstack.pop() + end) + end + end) + } + end, + on_show = function() bluetooth.discovering:set(true) end, + on_hide = function() bluetooth.discovering:set(false) end, +} + local BluetoothSettings = SettingsScreen:new { title = "Bluetooth", - createUi = function(self) - SettingsScreen.createUi(self) + create_ui = function(self) + SettingsScreen.create_ui(self) + + -- Enable/Disable switch local enable_container = self.content:Object { flex = { flex_direction = "row", @@ -52,11 +83,42 @@ local BluetoothSettings = SettingsScreen:new { bluetooth.enabled:set(enabled) end) - theme.set_style(self.content:Label { - text = "Paired Device", - pad_bottom = 1, - }, "settings_title") + self.bindings = self.bindings + { + bluetooth.enabled:bind(function(en) + if en then + enable_sw:add_state(lvgl.STATE.CHECKED) + else + enable_sw:clear_state(lvgl.STATE.CHECKED) + end + end), + } + + -- Connection status + -- This is presented as a label on the field showing the currently paired + -- device. + + local paired_label = + self.content:Label { + text = "", + pad_bottom = 1, + } + theme.set_style(paired_label, "settings_title") + + self.bindings = self.bindings + { + bluetooth.connecting:bind(function(conn) + if conn then + paired_label:set { text = "Connecting to:" } + else + if bluetooth.connected:get() then + paired_label:set { text = "Connected to:" } + else + paired_label:set { text = "Paired with:" } + end + end + end), + } + -- The name of the currently paired device. local paired_container = self.content:Object { flex = { flex_direction = "row", @@ -78,24 +140,7 @@ local BluetoothSettings = SettingsScreen:new { bluetooth.paired_device:set() end) - theme.set_style(self.content:Label { - text = "Nearby Devices", - pad_bottom = 1, - }, "settings_title") - - local devices = self.content:List { - w = lvgl.PCT(100), - h = lvgl.SIZE_CONTENT, - } - self.bindings = self.bindings + { - bluetooth.enabled:bind(function(en) - if en then - enable_sw:add_state(lvgl.STATE.CHECKED) - else - enable_sw:clear_state(lvgl.STATE.CHECKED) - end - end), bluetooth.paired_device:bind(function(device) if device then paired_device:set { text = device.name } @@ -105,13 +150,52 @@ local BluetoothSettings = SettingsScreen:new { clear_paired:add_flag(lvgl.FLAG.HIDDEN) end end), - bluetooth.devices:bind(function(devs) + } + + theme.set_style(self.content:Label { + text = "Known Devices", + pad_bottom = 1, + }, "settings_title") + + local devices = self.content:List { + w = lvgl.PCT(100), + h = lvgl.SIZE_CONTENT, + } + + -- 'Pair new device' button that goes to the discovery screen. + + local button_container = self.content:Object { + w = lvgl.PCT(100), + h = lvgl.SIZE_CONTENT, + flex = { + flex_direction = "row", + justify_content = "center", + align_items = "space-evenly", + align_content = "center", + }, + pad_top = 4, + pad_column = 4, + } + button_container:add_style(styles.list_item) + + local pair_new = button_container:Button {} + pair_new:Label { text = "Pair new device" } + pair_new:onClicked(function() + backstack.push(BluetoothPairing:new()) + end) + + + self.bindings = self.bindings + { + bluetooth.known_devices:bind(function(devs) + local group = lvgl.group.get_default() + group.remove_obj(pair_new) devices:clean() for _, dev in pairs(devs) do devices:add_btn(nil, dev.name):onClicked(function() bluetooth.paired_device:set(dev) end) end + group:add_obj(pair_new) end) } end @@ -119,8 +203,8 @@ local BluetoothSettings = SettingsScreen:new { local HeadphonesSettings = SettingsScreen:new { title = "Headphones", - createUi = function(self) - SettingsScreen.createUi(self) + create_ui = function(self) + SettingsScreen.create_ui(self) theme.set_style(self.content:Label { text = "Maxiumum volume limit", @@ -143,7 +227,6 @@ local HeadphonesSettings = SettingsScreen:new { local balance = self.content:Slider { w = lvgl.PCT(100), - h = 5, range = { min = -100, max = 100 }, value = 0, } @@ -183,8 +266,8 @@ local HeadphonesSettings = SettingsScreen:new { local DisplaySettings = SettingsScreen:new { title = "Display", - createUi = function(self) - SettingsScreen.createUi(self) + create_ui = function(self) + SettingsScreen.create_ui(self) local brightness_title = self.content:Object { flex = { @@ -203,7 +286,6 @@ local DisplaySettings = SettingsScreen:new { local brightness = self.content:Slider { w = lvgl.PCT(100), - h = 5, range = { min = 0, max = 100 }, value = display.brightness:get(), } @@ -219,10 +301,69 @@ local DisplaySettings = SettingsScreen:new { end } +local ThemeSettings = SettingsScreen:new { + title = "Theme", + create_ui = function(self) + SettingsScreen.create_ui(self) + + theme.set_style(self.content:Label { + text = "Theme", + }, "settings_title") + + local themeOptions = {} + themeOptions["Dark"] = "/lua/theme_dark.lua" + themeOptions["Light"] = "/lua/theme_light.lua" + themeOptions["High Contrast"] = "/lua/theme_hicon.lua" + + -- Parse theme directory for more themes + local theme_dir_iter = filesystem.iterator("/.themes/") + for dir in theme_dir_iter do + local theme_name = tostring(dir):match("(.+).lua$") + themeOptions[theme_name] = "/sdcard/.themes/" .. theme_name .. ".lua" + end + + local saved_theme = theme.theme_filename(); + local saved_theme_name = saved_theme:match(".+/(.*).lua$") + + local options = "" + local idx = 0 + local selected_idx = -1 + for i, v in pairs(themeOptions) do + if (saved_theme == v) then + selected_idx = idx + end + if idx > 0 then + options = options .. "\n" + end + options = options .. i + idx = idx + 1 + end + + if (selected_idx == -1) then + options = options .. "\n" .. saved_theme_name + selected_idx = idx + end + + local theme_chooser = self.content:Dropdown { + options = options, + } + theme_chooser:set({selected = selected_idx}) + + theme_chooser:onevent(lvgl.EVENT.VALUE_CHANGED, function() + local option = theme_chooser:get('selected_str') + local selectedTheme = themeOptions[option] + if (selectedTheme) then + theme.load_theme(tostring(selectedTheme)) + backstack.reset(main_menu:new()) + end + end) + end +} + local InputSettings = SettingsScreen:new { title = "Input Method", - createUi = function(self) - SettingsScreen.createUi(self) + create_ui = function(self) + SettingsScreen.create_ui(self) theme.set_style(self.content:Label { text = "Control scheme", @@ -262,14 +403,13 @@ local InputSettings = SettingsScreen:new { controls.scheme:set(scheme) end) - theme.set_style(self.menu.content:Label { + theme.set_style(self.content:Label { text = "Scroll Sensitivity", }, "settings_title") local slider_scale = 4; -- Power steering local sensitivity = self.content:Slider { w = lvgl.PCT(90), - h = 5, range = { min = 0, max = 255 / slider_scale }, value = controls.scroll_sensitivity:get() / slider_scale, } @@ -281,8 +421,8 @@ local InputSettings = SettingsScreen:new { local MassStorageSettings = SettingsScreen:new { title = "USB Storage", - createUi = function(self) - SettingsScreen.createUi(self) + create_ui = function(self) + SettingsScreen.create_ui(self) local version = require("version").samd() if tonumber(version) < 3 then @@ -339,15 +479,15 @@ local MassStorageSettings = SettingsScreen:new { end) } end, - canPop = function() + can_pop = function() return not usb.msc_enabled:get() end } local DatabaseSettings = SettingsScreen:new { title = "Database", - createUi = function(self) - SettingsScreen.createUi(self) + create_ui = function(self) + SettingsScreen.create_ui(self) local db = require("database") widgets.Row(self.content, "Schema version", db.version()) @@ -357,11 +497,12 @@ local DatabaseSettings = SettingsScreen:new { flex = { flex_direction = "row", justify_content = "flex-start", - align_items = "flex-start", + align_items = "center", align_content = "flex-start", }, w = lvgl.PCT(100), h = lvgl.SIZE_CONTENT, + pad_bottom = 4, } auto_update_container:add_style(styles.list_item) auto_update_container:Label { text = "Auto update", flex_grow = 1 } @@ -403,10 +544,63 @@ local DatabaseSettings = SettingsScreen:new { end } +local PowerSettings = SettingsScreen:new { + title = "Power", + create_ui = function(self) + SettingsScreen.create_ui(self) + local power = require("power") + + local charge_pct = widgets.Row(self.content, "Charge").right + local charge_volts = widgets.Row(self.content, "Voltage").right + local charge_state = widgets.Row(self.content, "Status").right + + self.bindings = self.bindings + { + power.battery_pct:bind(function(pct) + charge_pct:set { text = string.format("%d%%", pct) } + end), + power.battery_millivolts:bind(function(mv) + charge_volts:set { text = string.format("%.2fV", mv / 1000) } + end), + power.charge_state:bind(function(state) + charge_state:set { text = state } + end), + } + + local fast_charge_container = self.content:Object { + flex = { + flex_direction = "row", + justify_content = "flex-start", + align_items = "center", + align_content = "flex-start", + }, + w = lvgl.PCT(100), + h = lvgl.SIZE_CONTENT, + pad_bottom = 4, + } + fast_charge_container:add_style(styles.list_item) + fast_charge_container:Label { text = "Fast Charging", flex_grow = 1 } + local fast_charge_sw = fast_charge_container:Switch {} + + fast_charge_sw:onevent(lvgl.EVENT.VALUE_CHANGED, function() + power.fast_charge:set(fast_charge_sw:enabled()) + end) + + self.bindings = self.bindings + { + power.fast_charge:bind(function(en) + if en then + fast_charge_sw:add_state(lvgl.STATE.CHECKED) + else + fast_charge_sw:clear_state(lvgl.STATE.CHECKED) + end + end), + } + end +} + local SamdConfirmation = SettingsScreen:new { title = "Are you sure?", - createUi = function(self) - SettingsScreen.createUi(self) + create_ui = function(self) + SettingsScreen.create_ui(self) self.content:Label { w = lvgl.PCT(100), text = "After selecting 'flash', copy the new UF2 file onto the USB drive that appears. The screen will be blank until the update is finished.", @@ -437,8 +631,8 @@ local SamdConfirmation = SettingsScreen:new { local FirmwareSettings = SettingsScreen:new { title = "Firmware", - createUi = function(self) - SettingsScreen.createUi(self) + create_ui = function(self) + SettingsScreen.create_ui(self) local version = require("version") widgets.Row(self.content, "ESP32", version.esp()) widgets.Row(self.content, "SAMD21", version.samd()) @@ -468,17 +662,118 @@ local FirmwareSettings = SettingsScreen:new { local LicensesScreen = SettingsScreen:new { title = "Licenses", - createUi = function(self) - SettingsScreen.createUi(self) - self.root = require("licenses")(self) + create_ui = function(self) + SettingsScreen.create_ui(self) + require("licenses")(self) + end +} + +local FccStatementScreen = SettingsScreen:new { + title = "FCC Statement", + create_ui = function(self) + SettingsScreen.create_ui(self) + + local text_part = function(text) + self.content:Label { + w = lvgl.PCT(100), + h = lvgl.SIZE_CONTENT, + text = text, + text_font = font.fusion_10, + long_mode = lvgl.LABEL.LONG_WRAP, + } + end + + text_part( + "This device complies with part 15 of the FCC Rules. Operation is subject to the following two conditions:") + text_part("(1) This device may not cause harmful interference, and") + text_part( + "(2) this device must accept any interference received, including interference that may cause undesired operation.") + + local scroller = self.content:Object { w = 1, h = 1 } + scroller:onevent(lvgl.EVENT.FOCUSED, function() + scroller:scroll_to_view(1); + end) + lvgl.group.get_default():add_obj(scroller) + end +} + +local RegulatoryScreen = SettingsScreen:new { + title = "Regulatory", + create_ui = function(self) + SettingsScreen.create_ui(self) + local version = require("version") + + local small_row = function(left, right) + local container = self.content:Object { + flex = { + flex_direction = "row", + justify_content = "flex-start", + align_items = "flex-start", + align_content = "flex-start" + }, + w = lvgl.PCT(100), + h = lvgl.SIZE_CONTENT + } + container:add_style(styles.list_item) + container:Label { + text = left, + flex_grow = 1, + text_font = font.fusion_10, + } + container:Label { + text = right, + text_font = font.fusion_10, + } + end + small_row("Manufacturer", "cool tech zone") + small_row("Product model", "CTZ-1") + small_row("FCC ID", "2BG33-CTZ1") + + local button_container = self.content:Object { + w = lvgl.PCT(100), + h = lvgl.SIZE_CONTENT, + flex = { + flex_direction = "row", + justify_content = "center", + align_items = "space-evenly", + align_content = "center", + }, + pad_top = 4, + pad_column = 4, + } + button_container:add_style(styles.list_item) + + local button = button_container:Button {} + button:Label { text = "FCC Statement" } + button:onClicked(function() + backstack.push(FccStatementScreen:new()) + end) + + local logo_container = self.content:Object { + w = lvgl.PCT(100), + h = lvgl.SIZE_CONTENT, + flex = { + flex_direction = "row", + justify_content = "center", + align_items = "center", + align_content = "center", + }, + pad_top = 4, + pad_column = 4, + } + theme.set_style(logo_container, "regulatory_icons") + button_container:add_style(styles.list_item) + + logo_container:Image { src = "//lua/img/ce.png" } + logo_container:Image { src = "//lua/img/weee.png" } end } return widgets.MenuScreen:new { show_back = true, title = "Settings", - createUi = function(self) - widgets.MenuScreen.createUi(self) + create_ui = function(self) + widgets.MenuScreen.create_ui(self) local list = self.root:List { w = lvgl.PCT(100), h = lvgl.PCT(100), @@ -507,6 +802,7 @@ return widgets.MenuScreen:new { section("Interface") submenu("Display", DisplaySettings) + submenu("Theme", ThemeSettings) submenu("Input Method", InputSettings) section("USB") @@ -514,7 +810,11 @@ return widgets.MenuScreen:new { section("System") submenu("Database", DatabaseSettings) + submenu("Power", PowerSettings) + + section("About") submenu("Firmware", FirmwareSettings) submenu("Licenses", LicensesScreen) + submenu("Regulatory", RegulatoryScreen) end } diff --git a/lua/theme_dark.lua b/lua/theme_dark.lua index 6508f642..41fddf81 100644 --- a/lua/theme_dark.lua +++ b/lua/theme_dark.lua @@ -79,8 +79,6 @@ local theme_dark = { radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff pad_all = 2, bg_color = background_muted, - shadow_width = 5, - shadow_opa = lvgl.OPA(100) }}, {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { bg_color = background_muted, @@ -88,6 +86,37 @@ local theme_dark = { {lvgl.PART.KNOB | lvgl.STATE.FOCUSED, lvgl.Style { bg_color = highlight_color, }}, + {lvgl.PART.KNOB | lvgl.STATE.EDITED, lvgl.Style { + pad_all = 2, + }}, + {lvgl.PART.INDICATOR | lvgl.STATE.CHECKED, lvgl.Style { + bg_color = highlight_color, + }}, + }, + scrubber = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = background_muted, + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + }}, + {lvgl.PART.INDICATOR, lvgl.Style { + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + bg_color = highlight_color, + }}, + {lvgl.PART.KNOB, lvgl.Style { + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + bg_color = background_muted, + }}, + {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { + bg_color = background_muted, + }}, + {lvgl.PART.KNOB | lvgl.STATE.FOCUSED, lvgl.Style { + bg_color = highlight_color, + pad_all = 1, + }}, + {lvgl.PART.KNOB | lvgl.STATE.EDITED, lvgl.Style { + pad_all = 2, + }}, {lvgl.PART.INDICATOR | lvgl.STATE.CHECKED, lvgl.Style { bg_color = highlight_color, }}, @@ -95,24 +124,27 @@ local theme_dark = { switch = { {lvgl.PART.MAIN, lvgl.Style { bg_opa = lvgl.OPA(100), - width = 28, - height = 8, + width = 18, + height = 10, radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff bg_color = background_muted, - border_color = highlight_color, + border_color = text_color, + border_width = 1, }}, {lvgl.PART.INDICATOR, lvgl.Style { radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff - bg_color = background_muted, + bg_color = background_color, }}, {lvgl.PART.INDICATOR | lvgl.STATE.CHECKED, lvgl.Style { + bg_opa = lvgl.OPA(100), bg_color = highlight_color, }}, {lvgl.PART.KNOB, lvgl.Style { radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff - pad_all = 2, bg_opa = lvgl.OPA(100), bg_color = background_muted, + border_color = text_color, + border_width = 1, }}, {lvgl.PART.KNOB | lvgl.STATE.FOCUSED, lvgl.Style { bg_color = highlight_color, @@ -170,7 +202,44 @@ local theme_dark = { image_recolor = icon_enabled_color, }}, }, - + now_playing = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + border_width = 1, + border_color = highlight_color, + border_side = 15, -- LV_BORDER_SIDE_FULL + }}, + }, + menu_icon = { + {lvgl.PART.MAIN, lvgl.Style { + pad_all = 4, + radius = 4 + }}, + }, + battery = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 0, + }}, + }, + battery_0 = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 180, + image_recolor = "#aa3333", + }}, + }, + battery_charging = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 180, + image_recolor = "#33aa33", + }}, + }, + battery_charge_icon = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 180, + image_recolor = "#fdd833", + }}, + }, } return theme_dark diff --git a/lua/theme_hicon.lua b/lua/theme_hicon.lua new file mode 100644 index 00000000..30947c18 --- /dev/null +++ b/lua/theme_hicon.lua @@ -0,0 +1,273 @@ +local lvgl = require("lvgl") +local font = require("font") + +-- local background_color = "#000000" +-- local text_color = "#33b5e5" + +local text_color = "#000000" +local background_color = "#FFFFFF" + +local theme_hicon = { + base = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(0), + text_font = font.fusion_12, + }}, + {lvgl.PART.SCROLLBAR, lvgl.Style { + bg_color = text_color, + }}, + }, + root = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = background_color, -- Root background color + text_color = text_color + }}, + }, + header = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = background_color, + }}, + }, + pop_up = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = background_color, + border_color = text_color, + border_width = 1, + }}, + }, + button = { + {lvgl.PART.MAIN, lvgl.Style { + pad_left = 2, + pad_right = 2, + pad_top = 1, + pad_bottom = 1, + bg_color = background_color, + image_recolor_opa = 255, + image_recolor = text_color, + radius = 5, + border_color = text_color, + border_width = 1, + }}, + {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = text_color, + image_recolor_opa = 255, + image_recolor = background_color, + text_color = background_color, + }}, + }, + listbutton = { + {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = text_color, + text_color = background_color, + }}, + }, + bar = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = background_color, + border_color = text_color, + border_width = 1, + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + }}, + {lvgl.PART.INDICATOR, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = text_color, + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + }}, + }, + slider = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = background_color, + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + border_color = text_color, + border_width = 1, + height = 8, + }}, + {lvgl.PART.INDICATOR, lvgl.Style { + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + bg_color = text_color, + }}, + {lvgl.PART.KNOB, lvgl.Style { + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + bg_color = background_color, + border_color = text_color, + border_width = 1, + }}, + {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { + bg_color = background_color, + }}, + {lvgl.PART.KNOB | lvgl.STATE.FOCUSED, lvgl.Style { + bg_color = text_color, + }}, + {lvgl.PART.KNOB | lvgl.STATE.EDITED, lvgl.Style { + pad_all = 2, + }}, + {lvgl.PART.INDICATOR | lvgl.STATE.CHECKED, lvgl.Style { + bg_color = text_color, + }}, + }, + scrubber = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = background_color, + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + border_color = text_color, + border_width = 1, + }}, + {lvgl.PART.INDICATOR, lvgl.Style { + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + bg_color = text_color, + }}, + {lvgl.PART.KNOB, lvgl.Style { + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + bg_color = background_color, + border_color = text_color, + border_width = 1, + }}, + {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { + bg_color = background_color, + }}, + {lvgl.PART.KNOB | lvgl.STATE.FOCUSED, lvgl.Style { + bg_color = text_color, + pad_all = 1, + }}, + {lvgl.PART.KNOB | lvgl.STATE.EDITED, lvgl.Style { + pad_all = 4, + }}, + {lvgl.PART.INDICATOR | lvgl.STATE.CHECKED, lvgl.Style { + bg_color = text_color, + }}, + }, + switch = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + width = 18, + height = 10, + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + bg_color = background_color, + border_color = text_color, + border_width = 1, + }}, + {lvgl.PART.INDICATOR, lvgl.Style { + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + bg_color = background_color, + }}, + {lvgl.PART.INDICATOR | lvgl.STATE.CHECKED, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = text_color, + }}, + {lvgl.PART.KNOB, lvgl.Style { + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + bg_opa = lvgl.OPA(100), + bg_color = background_color, + border_color = text_color, + border_width = 1, + }}, + {lvgl.PART.KNOB | lvgl.STATE.FOCUSED, lvgl.Style { + bg_color = text_color, + }}, + }, + dropdown = { + {lvgl.PART.MAIN, lvgl.Style{ + radius = 2, + pad_all = 2, + border_width = 1, + border_color = text_color, + border_side = 15, -- LV_BORDER_SIDE_FULL + bg_color = background_color, + bg_opa = lvgl.OPA(100), + }}, + {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { + border_color = text_color, + bg_color = text_color, + text_color = background_color, + }}, + }, + dropdownlist = { + {lvgl.PART.MAIN, lvgl.Style{ + radius = 2, + pad_all = 2, + border_width = 1, + border_color = text_color, + bg_opa = lvgl.OPA(100), + bg_color = background_color + }}, + {lvgl.PART.SELECTED | lvgl.STATE.CHECKED, lvgl.Style { + bg_color = text_color, + text_color = background_color, + }}, + }, + database_indicator = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 255, + image_recolor = text_color, + }}, + }, + settings_title = { + {lvgl.PART.MAIN, lvgl.Style { + pad_top = 2, + pad_bottom = 4, + text_font = font.fusion_10, + text_color = text_color, + }}, + }, + icon_disabled = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 255, + image_recolor = text_color, + }}, + }, + icon_enabled = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 255, + image_recolor = text_color, + }}, + }, + now_playing = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + border_width = 1, + border_color = text_color, + border_side = 15, -- LV_BORDER_SIDE_FULL + }}, + }, + menu_icon = { + {lvgl.PART.MAIN, lvgl.Style { + pad_all = 4, + radius = 4 + }}, + }, + battery = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 255, + image_recolor = text_color, + }}, + }, + battery_0 = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 255, + image_recolor = text_color, + }}, + }, + battery_charging = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 255, + image_recolor = text_color, + }}, + }, + battery_charge_icon = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 200, + image_recolor = text_color, + }}, + }, +} + +return theme_hicon diff --git a/lua/theme_light.lua b/lua/theme_light.lua index 05b7d291..275d06ca 100644 --- a/lua/theme_light.lua +++ b/lua/theme_light.lua @@ -2,11 +2,12 @@ local lvgl = require("lvgl") local font = require("font") local background_color = "#ffffff" -local background_muted = "#fafafa" -local text_color = "#000000" -local highlight_color = "#ce93d8" -local icon_enabled_color = "#2c2c2c" +local background_muted = "#f2f2f2" +local text_color = "#2c2c2c" +local highlight_color = "#ff82bc" +local icon_enabled_color = "#ff82bc" local icon_disabled_color = "#999999" +local border_color = "#888888" local theme_light = { base = { @@ -36,25 +37,35 @@ local theme_light = { }, button = { {lvgl.PART.MAIN, lvgl.Style { - pad_left = 2, - pad_right = 2, - pad_top = 1, - pad_bottom = 1, + pad_left = 1, + pad_right = 1, + margin_all = 1, bg_color = background_color, image_recolor_opa = 180, image_recolor = highlight_color, - radius = 5, + radius = 4, + border_color = border_color, + border_width = 1, + border_side = 9, -- Bottom right + outline_color = border_color, + outline_width = 1, }}, {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { bg_opa = lvgl.OPA(100), + text_color = "#ffffff", bg_color = highlight_color, image_recolor_opa = 0, }}, + {lvgl.PART.MAIN | lvgl.STATE.PRESSED, lvgl.Style { + margin_left = 2, + border_width = 0, + }}, }, listbutton = { {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { bg_opa = lvgl.OPA(100), bg_color = highlight_color, + text_color = "#ffffff" }}, }, bar = { @@ -68,23 +79,61 @@ local theme_light = { bg_opa = lvgl.OPA(100), bg_color = background_muted, radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + border_color = border_color, + border_width = 1, + height = 8, }}, {lvgl.PART.INDICATOR, lvgl.Style { radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff bg_color = highlight_color, + border_color = border_color, + border_width = 1, }}, {lvgl.PART.KNOB, lvgl.Style { radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + bg_color = background_muted, + border_color = border_color, + border_width = 1, + border_side = 9, + outline_color = border_color, + outline_width = 1, + }}, + {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { + bg_color = background_muted, + }}, + {lvgl.PART.KNOB | lvgl.STATE.FOCUSED, lvgl.Style { + bg_color = highlight_color, + }}, + {lvgl.PART.KNOB | lvgl.STATE.EDITED, lvgl.Style { pad_all = 2, + }}, + {lvgl.PART.INDICATOR | lvgl.STATE.CHECKED, lvgl.Style { + bg_color = highlight_color, + }}, + }, + scrubber = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + bg_color = background_muted, + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + }}, + {lvgl.PART.INDICATOR, lvgl.Style { + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + bg_color = highlight_color, + }}, + {lvgl.PART.KNOB, lvgl.Style { + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff bg_color = background_muted, - shadow_width = 5, - shadow_opa = lvgl.OPA(100) }}, {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { bg_color = background_muted, }}, {lvgl.PART.KNOB | lvgl.STATE.FOCUSED, lvgl.Style { bg_color = highlight_color, + pad_all = 1, + }}, + {lvgl.PART.KNOB | lvgl.STATE.EDITED, lvgl.Style { + pad_all = 2, }}, {lvgl.PART.INDICATOR | lvgl.STATE.CHECKED, lvgl.Style { bg_color = highlight_color, @@ -93,24 +142,30 @@ local theme_light = { switch = { {lvgl.PART.MAIN, lvgl.Style { bg_opa = lvgl.OPA(100), - width = 28, - height = 8, + width = 18, + height = 10, radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff bg_color = background_muted, - border_color = highlight_color, + border_color = border_color, + border_width = 1, }}, {lvgl.PART.INDICATOR, lvgl.Style { radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff - bg_color = background_muted, + bg_color = background_color, }}, {lvgl.PART.INDICATOR | lvgl.STATE.CHECKED, lvgl.Style { + bg_opa = lvgl.OPA(100), bg_color = highlight_color, }}, {lvgl.PART.KNOB, lvgl.Style { radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff - pad_all = 2, bg_opa = lvgl.OPA(100), bg_color = background_muted, + border_color = border_color, + border_width = 1, + border_side = 9, + outline_color = border_color, + outline_width = 1, }}, {lvgl.PART.KNOB | lvgl.STATE.FOCUSED, lvgl.Style { bg_color = highlight_color, @@ -120,10 +175,12 @@ local theme_light = { {lvgl.PART.MAIN, lvgl.Style{ radius = 2, pad_all = 2, - border_width = 1, - border_color = background_muted, - border_side = 15, -- LV_BORDER_SIDE_FULL bg_color = background_color, + border_color = border_color, + border_width = 1, + border_side = 9, + outline_color = border_color, + outline_width = 1, }}, {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { border_color = highlight_color, @@ -134,7 +191,7 @@ local theme_light = { radius = 2, pad_all = 2, border_width = 1, - border_color = highlight_color, + border_color = border_color, bg_opa = lvgl.OPA(100), bg_color = background_color }}, @@ -148,6 +205,17 @@ local theme_light = { image_recolor = highlight_color, }}, }, + back_button = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 180, + image_recolor = icon_enabled_color, + pad_all = 0, + }}, + {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { + image_recolor_opa = 0, + image_recolor = "#ffffff", + }}, + }, settings_title = { {lvgl.PART.MAIN, lvgl.Style { pad_top = 2, @@ -161,14 +229,63 @@ local theme_light = { image_recolor_opa = 180, image_recolor = icon_disabled_color, }}, + {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { + image_recolor_opa = 0, + image_recolor = "#ffffff", + }}, }, icon_enabled = { {lvgl.PART.MAIN, lvgl.Style { image_recolor_opa = 180, image_recolor = icon_enabled_color, }}, + {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { + image_recolor_opa = 0, + image_recolor = "#ffffff", + }}, + }, + now_playing = { + {lvgl.PART.MAIN, lvgl.Style { + bg_opa = lvgl.OPA(100), + radius = 32767, -- LV_RADIUS_CIRCLE = 0x7fff + }}, + }, + menu_icon = { + {lvgl.PART.MAIN, lvgl.Style { + pad_all = 4, + radius = 4 + }}, + }, + battery = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 180, + image_recolor = highlight_color, + }}, + }, + battery_0 = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 180, + image_recolor = "#aa3333", + }}, + }, + battery_charging = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 180, + image_recolor = "#33aa33", + }}, + }, + battery_charge_icon = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 180, + image_recolor = "#fdd833", + }}, + }, + regulatory_icons = { + {lvgl.PART.MAIN, lvgl.Style { + image_recolor_opa = 255, + image_recolor = text_color, + }}, }, - } return theme_light diff --git a/lua/widgets.lua b/lua/widgets.lua index c3573c0b..980f0bb2 100644 --- a/lua/widgets.lua +++ b/lua/widgets.lua @@ -8,6 +8,7 @@ local styles = require("styles") local database = require("database") local theme = require("theme") local screen = require("screen") +local images = require("images") local img = { db = lvgl.ImgData("//lua/img/db.png"), @@ -18,7 +19,6 @@ local img = { bat_40 = lvgl.ImgData("//lua/img/bat/40.png"), bat_20 = lvgl.ImgData("//lua/img/bat/20.png"), bat_0 = lvgl.ImgData("//lua/img/bat/0.png"), - bat_0chg = lvgl.ImgData("//lua/img/bat/0chg.png"), bt_conn = lvgl.ImgData("//lua/img/bt_conn.png"), bt = lvgl.ImgData("//lua/img/bt.png") } @@ -37,7 +37,7 @@ end widgets.MenuScreen = screen:new { show_back = false, title = "", - createUi = function(self) + create_ui = function(self) self.root = lvgl.Object(nil, { flex = { flex_direction = "column", @@ -58,7 +58,7 @@ widgets.MenuScreen = screen:new { end } -function widgets.Row(parent, left, right) +function widgets.Row(parent, left_text, right_text) local container = parent:Object { flex = { flex_direction = "row", @@ -70,20 +70,23 @@ function widgets.Row(parent, left, right) h = lvgl.SIZE_CONTENT } container:add_style(styles.list_item) - container:Label { - text = left, - flex_grow = 1 + local left = container:Label { + text = left_text, + flex_grow = 1, + } + local right = container:Label { + text = right_text or "", } - container:Label { - text = right + return { + left = left, + right = right, } end -local bindings_meta = { - __add = function(a, b) - return table.move(a, 1, #a, #b + 1, b) - end -} +local bindings_meta = {} +bindings_meta["__add"] = function(a, b) + return setmetatable(table.move(a, 1, #a, #b + 1, b), bindings_meta) +end function widgets.StatusBar(parent, opts) local root = parent.root:Object { @@ -98,6 +101,7 @@ function widgets.StatusBar(parent, opts) pad_top = 1, pad_bottom = 1, pad_left = 4, + pad_right = 4, pad_column = 1, scrollbar_mode = lvgl.SCROLLBAR_MODE.OFF, } @@ -109,11 +113,22 @@ function widgets.StatusBar(parent, opts) if opts.back_cb then local back = root:Button { w = lvgl.SIZE_CONTENT, - h = 12, + h = lvgl.SIZE_CONTENT, } - local label = back:Label({ text = "<", align = lvgl.ALIGN.CENTER }) - widgets.Description(label, "Back") + back:Image{src=images.back} + theme.set_style(back, "back_button") + widgets.Description(back, "Back") back:onClicked(opts.back_cb) + back:onevent(lvgl.EVENT.FOCUSED, function() + local first_view = parent.content + if not first_view then return end + while first_view:get_child_cnt() > 0 do + first_view = first_view:get_child(0) + end + if first_view then + first_view:scroll_to_view_recursive(1) + end + end) end local title = root:Label { @@ -123,6 +138,7 @@ function widgets.StatusBar(parent, opts) text = "", align = lvgl.ALIGN.CENTER, flex_grow = 1, + pad_left = 2, } if opts.title then title:set { text = opts.title } @@ -141,24 +157,29 @@ function widgets.StatusBar(parent, opts) local function update_battery_icon() if is_charging == nil or percent == nil then return end local src + theme.set_style(battery_icon, "battery") if percent >= 95 then + theme.set_style(battery_icon, "battery_100") src = img.bat_100 elseif percent >= 75 then + theme.set_style(battery_icon, "battery_80") src = img.bat_80 elseif percent >= 55 then + theme.set_style(battery_icon, "battery_60") src = img.bat_60 elseif percent >= 35 then + theme.set_style(battery_icon, "battery_40") src = img.bat_40 elseif percent >= 15 then + theme.set_style(battery_icon, "battery_20") src = img.bat_20 else - if is_charging then - src = img.bat_0chg - else - src = img.bat_0 - end + theme.set_style(battery_icon, "battery_0") + src = img.bat_0 end if is_charging then + theme.set_style(battery_icon, "battery_charging") + theme.set_style(charge_icon, "battery_charge_icon") charge_icon:clear_flag(lvgl.FLAG.HIDDEN) else charge_icon:add_flag(lvgl.FLAG.HIDDEN) @@ -190,6 +211,7 @@ function widgets.StatusBar(parent, opts) end end), bluetooth.connected:bind(function(connected) + theme.set_style(bt_icon, "bluetooth_icon") if connected then bt_icon:set_src(img.bt_conn) else @@ -210,10 +232,6 @@ function widgets.IconBtn(parent, icon, text) }, w = lvgl.SIZE_CONTENT, h = lvgl.SIZE_CONTENT, - pad_top = 1, - pad_bottom = 1, - pad_left = 1, - pad_column = 1 } btn:Image { src = icon diff --git a/luals-stubs/backstack.lua b/luals-stubs/backstack.lua index b39fcbf2..84a57e5c 100644 --- a/luals-stubs/backstack.lua +++ b/luals-stubs/backstack.lua @@ -17,4 +17,8 @@ function backstack.push(screen) end --- there are no other screens in the stack. function backstack.pop() end +--- Sets a new root screen, replacing any existing screens +--- @param screen screen The new root screen +function backstack.reset(screen) end + return backstack diff --git a/luals-stubs/bluetooth.lua b/luals-stubs/bluetooth.lua index a2dd476d..d362974a 100644 --- a/luals-stubs/bluetooth.lua +++ b/luals-stubs/bluetooth.lua @@ -5,8 +5,17 @@ --- @class bluetooth --- @field enabled Property Whether or not the Bluetooth stack is currently enabled. This property is writeable, and can be used to enable or disable Bluetooth. --- @field connected Property Whether or not there is an active connection to another Bluetooth device. ---- @field paired_device Property The device that is currently paired. The bluetooth stack will automatically connected to this device if possible. ---- @field devices Property Devices nearby that have been discovered. +--- @field connecting Property Whether or not we are currently connecting to the paired device. +--- @field discovering Property Whether or not we are actively scanning for new devices. +--- @field paired_device Property The device that is currently paired. The bluetooth stack will automatically connect to this device if possible. +--- @field discovered_devices Property Devices nearby that have been discovered. +--- @field known_devices Property Devices that have previously been paired. local bluetooth = {} +--- Enables Bluetooth, this is the same as bluetooth.enabled:set(true) +function bluetooth.enable() end + +--- Disables Bluetooth, this is the same as bluetooth.enabled:set(false) +function bluetooth.disable() end + return bluetooth diff --git a/luals-stubs/playback.lua b/luals-stubs/playback.lua index 85392e93..f905f384 100644 --- a/luals-stubs/playback.lua +++ b/luals-stubs/playback.lua @@ -8,4 +8,9 @@ --- @field position Property The current playback position within the current track, in seconds. local playback = {} +--- Returns whether or not this file can be played (i.e. is this an audio track) +--- @param filepath string +--- @return boolean +function playback.is_playable(filepath) end + return playback diff --git a/luals-stubs/power.lua b/luals-stubs/power.lua index ac7f15bb..d28cd196 100644 --- a/luals-stubs/power.lua +++ b/luals-stubs/power.lua @@ -6,6 +6,8 @@ --- @field battery_pct Property The battery's current charge, as a percentage of the maximum charge. --- @field battery_millivolts Property The battery's current voltage, in millivolts. --- @field plugged_in Property Whether or not the device is currently receiving external power. +--- @field fast_charge Property Whether or not fast charging is enabled. Fast charging can fully recharge the battery up to two times faster than regular charging, but will have a small negative impact on the lifetime of the battery. +--- @field charge_state Property a string property describing the current charging state. May be one of "no_battery", "critical", "discharging", "charge_regular", "charge_fast", "full_charge", "fault", or "unknown". local power = {} return power diff --git a/luals-stubs/queue.lua b/luals-stubs/queue.lua index 353b4823..97583587 100644 --- a/luals-stubs/queue.lua +++ b/luals-stubs/queue.lua @@ -13,12 +13,17 @@ --- @field random Property Determines whether, when progressing to the next track in the queue, the next track will be chosen randomly. The random selection algorithm used is a Miller Shuffle, which guarantees that no repeat selections will be made until every item in the queue has been played. Writeable. local queue = {} ---- Adds the given track or database iterator to the end of the queue. Database +--- Adds the given track, database iterator, or file to the end of the queue. Database --- iterators passed to this method will be unnested and expanded into the track --- ids they contain. ---- @param val TrackId|Iterator +--- @param val TrackId|Iterator|string function queue.add(val) end +--- Opens a playlist file from a filepath +--- This will replace the existing queue +--- @param filepath string +function queue.open_playlist(filepath) end + --- Removes all tracks from the queue. function queue.clear() end diff --git a/luals-stubs/screen.lua b/luals-stubs/screen.lua index fc1b37f8..14ea75dd 100644 --- a/luals-stubs/screen.lua +++ b/luals-stubs/screen.lua @@ -12,19 +12,19 @@ local screen = {} function screen:new(params) end --- Called just before this screen is first displayed to the user. -function screen:createUi() end +function screen:create_ui() end --- Called whenever this screen is displayed to the user. -function screen:onShown() end +function screen:on_show() end --- Called whenever this screen is being hidden by the user; either because a --- new screen is being pushed on top of this way, or because this screen has --- been popped off of the stack. -function screen:onHidden() end +function screen:on_hide() end --- Called when this screen is about to be popped off of the stack. If this --- returns false, it will not be popped. May be a function, or any boolean --- convertable value. -function screen:canPop() end +function screen:can_pop() end return screen diff --git a/luals-stubs/theme.lua b/luals-stubs/theme.lua new file mode 100644 index 00000000..4a945cb3 --- /dev/null +++ b/luals-stubs/theme.lua @@ -0,0 +1,28 @@ +--- @meta + +--- @class theme +local theme = {} + +--- Loads a theme from a filename, this can be either builtin (ie, located in +--- "/lua/") or on the sdcard (in, '/sdcard/.themes/') +--- If successful, the filename will be saved to non-volatile storage. +--- Returns whether the theme was successfully loaded +--- @param filename string +--- @return boolean +function theme.load_theme(filename) end + +--- Sets a theme directly from a table. Does not persist between restarts. +--- @param theme +function theme.set(theme) end + +--- Set the style name (similar in concept to a css selector) for an object +--- This will set any styles associated with that style name on the object +--- @param obj Object The object to set a particular style on +--- @param style string The name of the style to apply to this object +function theme.set_style(obj, style) end + +--- Returns the filename of the saved theme +--- @return string +function theme.theme_filename() end + +return theme diff --git a/sdkconfig.common b/sdkconfig.common index 5306422a..c41586c6 100644 --- a/sdkconfig.common +++ b/sdkconfig.common @@ -9,21 +9,23 @@ CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y CONFIG_COMPILER_STACK_CHECK_MODE_NORM=y CONFIG_BT_ENABLED=y +CONFIG_BT_BTC_TASK_STACK_SIZE=4096 CONFIG_BT_BLUEDROID_PINNED_TO_CORE_1=y CONFIG_BT_CLASSIC_ENABLED=y CONFIG_BT_A2DP_ENABLE=y # CONFIG_BT_BLE_ENABLED is not set CONFIG_BT_STACK_NO_LOG=y -CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y +CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y -CONFIG_SPI_MASTER_IN_IRAM=y -# CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set # CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC is not set # CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST is not set # CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID is not set # CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT is not set # CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM is not set +# CONFIG_ESP_COEX_SW_COEXIST_ENABLE is not set CONFIG_GPIO_CTRL_FUNC_IN_IRAM=y +CONFIG_SPI_MASTER_IN_IRAM=y +# CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set # CONFIG_ETH_USE_ESP32_EMAC is not set # CONFIG_ETH_USE_SPI_ETHERNET is not set # CONFIG_ESP_EVENT_POST_FROM_ISR is not set @@ -41,9 +43,9 @@ CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY=y # CONFIG_SPIRAM_BANKSWITCH_ENABLE is not set CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y CONFIG_SPIRAM_OCCUPY_HSPI_HOST=y -CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH=y CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y -CONFIG_ESP_MAIN_TASK_STACK_SIZE=12000 +CONFIG_ESP_SYSTEM_ESP32_SRAM1_REGION_AS_IRAM=y +CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096 CONFIG_ESP_INT_WDT_TIMEOUT_MS=5000 CONFIG_ESP_TASK_WDT_PANIC=y CONFIG_ESP_TASK_WDT_TIMEOUT_S=10 @@ -71,21 +73,17 @@ CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=512 # CONFIG_MQTT_PROTOCOL_311 is not set # CONFIG_MQTT_TRANSPORT_SSL is not set # CONFIG_MQTT_TRANSPORT_WEBSOCKET is not set +# CONFIG_OPENTHREAD_RX_ON_WHEN_IDLE is not set # CONFIG_SPIFFS_CACHE is not set CONFIG_SPIFFS_OBJ_NAME_LEN=64 CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION=y # CONFIG_LV_CONF_SKIP is not set -CONFIG_LV_COLOR_16_SWAP=y CONFIG_LV_COLOR_MIX_ROUND_OFS=0 -CONFIG_LV_MEM_CUSTOM=y -CONFIG_LV_TICK_CUSTOM=y -CONFIG_LV_TICK_CUSTOM_INCLUDE="ui_tick.hpp" CONFIG_LV_ATTRIBUTE_MEM_ALIGN_SIZE=16 # CONFIG_LV_FONT_MONTSERRAT_14 is not set CONFIG_LV_FONT_DEFAULT_UNSCII_8=y CONFIG_LV_FONT_FMT_TXT_LARGE=y CONFIG_LV_USE_FONT_COMPRESSED=y -CONFIG_LV_TXT_BREAK_CHARS=" ,.;:-_)]}" # CONFIG_LV_USE_THEME_DEFAULT is not set CONFIG_LV_USE_QRCODE=y # CONFIG_LV_BUILD_EXAMPLES is not set diff --git a/src/codecs/README.md b/src/codecs/README.md deleted file mode 100644 index d8eaf405..00000000 --- a/src/codecs/README.md +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -# Software Codecs - -This component contains a collection of software decoders for various diff --git a/src/codecs/vorbis.cpp b/src/codecs/vorbis.cpp index 0b2af691..ea33a2af 100644 --- a/src/codecs/vorbis.cpp +++ b/src/codecs/vorbis.cpp @@ -137,10 +137,15 @@ auto TremorVorbisDecoder::DecodeTo(std::span output) ((output.size() - 1) * sizeof(sample::Sample)), &unused); if (bytes_written == OV_HOLE) { ESP_LOGE(kTag, "got OV_HOLE"); - return cpp::fail(Error::kMalformedData); + return OutputInfo{ + .samples_written = 0, + .is_stream_finished = false, + }; } else if (bytes_written == OV_EBADLINK) { ESP_LOGE(kTag, "got OV_EBADLINK"); return cpp::fail(Error::kMalformedData); + } else if (bytes_written == OV_EINVAL) { + return cpp::fail(Error::kMalformedData); } return OutputInfo{ diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt index 33d25894..fea5780f 100644 --- a/src/drivers/CMakeLists.txt +++ b/src/drivers/CMakeLists.txt @@ -8,5 +8,5 @@ idf_component_register( "samd.cpp" "wm8523.cpp" "nvs.cpp" "haptics.cpp" "spiffs.cpp" "pcm_buffer.cpp" INCLUDE_DIRS "include" REQUIRES "esp_adc" "fatfs" "result" "lvgl" "nvs_flash" "spiffs" "bt" - "tasks" "tinyfsm" "util" "libcppbor") + "tasks" "tinyfsm" "util" "libcppbor" "driver") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/drivers/bluetooth.cpp b/src/drivers/bluetooth.cpp index acb38ce4..3da5dd0c 100644 --- a/src/drivers/bluetooth.cpp +++ b/src/drivers/bluetooth.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -116,93 +117,111 @@ IRAM_ATTR auto a2dp_data_cb(uint8_t* buf, int32_t buf_size) -> int32_t { return buf_size; } -Bluetooth::Bluetooth(NvsStorage& storage, tasks::WorkerPool& bg_worker) { +Bluetooth::Bluetooth(NvsStorage& storage, + tasks::WorkerPool& bg_worker, + EventHandler cb) + : nvs_(storage) { sBgWorker = &bg_worker; - bluetooth::BluetoothState::Init(storage); + bluetooth::BluetoothState::Init(storage, cb); } -auto Bluetooth::Enable() -> bool { - auto lock = bluetooth::BluetoothState::lock(); - tinyfsm::FsmList::dispatch( - bluetooth::events::Enable{}); +auto Bluetooth::enable(bool en) -> void { + if (en) { + auto lock = bluetooth::BluetoothState::lock(); + tinyfsm::FsmList::dispatch( + bluetooth::events::Enable{}); + } else { + // FIXME: the BT tasks unfortunately call back into us while holding an + // internal lock, which then deadlocks with our fsm lock. + // auto lock = bluetooth::BluetoothState::lock(); + tinyfsm::FsmList::dispatch( + bluetooth::events::Disable{}); + } +} +auto Bluetooth::enabled() -> bool { + auto lock = bluetooth::BluetoothState::lock(); return !bluetooth::BluetoothState::is_in_state(); } -auto Bluetooth::Disable() -> void { - // FIXME: the BT tasks unfortunately call back into us while holding an - // internal lock, which then deadlocks with our fsm lock. - // auto lock = bluetooth::BluetoothState::lock(); +auto Bluetooth::sources(OutputBuffers* src) -> void { + auto lock = bluetooth::BluetoothState::lock(); + if (src == sStreams) { + return; + } + sStreams = src; tinyfsm::FsmList::dispatch( - bluetooth::events::Disable{}); + bluetooth::events::SourcesChanged{}); } -auto Bluetooth::IsEnabled() -> bool { - auto lock = bluetooth::BluetoothState::lock(); - return !bluetooth::BluetoothState::is_in_state(); +auto Bluetooth::softVolume(float f) -> void { + sVolumeFactor = f; } -auto Bluetooth::IsConnected() -> bool { +auto Bluetooth::connectionState() -> ConnectionState { auto lock = bluetooth::BluetoothState::lock(); - return bluetooth::BluetoothState::is_in_state(); + if (bluetooth::BluetoothState::is_in_state()) { + return ConnectionState::kConnected; + } else if (bluetooth::BluetoothState::is_in_state()) { + return ConnectionState::kConnecting; + } + return ConnectionState::kDisconnected; } -auto Bluetooth::ConnectedDevice() -> std::optional { +auto Bluetooth::pairedDevice() -> std::optional { auto lock = bluetooth::BluetoothState::lock(); - if (!bluetooth::BluetoothState::is_in_state()) { - return {}; - } - return bluetooth::BluetoothState::preferred_device(); + return bluetooth::BluetoothState::pairedDevice(); } -auto Bluetooth::KnownDevices() -> std::vector { +auto Bluetooth::pairedDevice(std::optional dev) -> void { auto lock = bluetooth::BluetoothState::lock(); - std::vector out = bluetooth::BluetoothState::devices(); - std::sort(out.begin(), out.end(), [](const auto& a, const auto& b) -> bool { - return a.signal_strength < b.signal_strength; - }); - return out; + bluetooth::BluetoothState::pairedDevice(dev); } -auto Bluetooth::SetPreferredDevice(std::optional dev) - -> void { - auto lock = bluetooth::BluetoothState::lock(); - auto cur = bluetooth::BluetoothState::preferred_device(); - if (dev && cur && dev->mac == cur->mac) { - return; - } - ESP_LOGI(kTag, "preferred is '%s' (%u%u%u%u%u%u)", dev->name.c_str(), - dev->mac[0], dev->mac[1], dev->mac[2], dev->mac[3], dev->mac[4], - dev->mac[5]); - bluetooth::BluetoothState::preferred_device(dev); - tinyfsm::FsmList::dispatch( - bluetooth::events::PreferredDeviceChanged{}); +auto Bluetooth::knownDevices() -> std::vector { + return nvs_.BluetoothNames(); } -auto Bluetooth::PreferredDevice() -> std::optional { - auto lock = bluetooth::BluetoothState::lock(); - return bluetooth::BluetoothState::preferred_device(); +auto Bluetooth::forgetKnownDevice(const bluetooth::mac_addr_t& mac) -> void { + nvs_.BluetoothName(mac, {}); } -auto Bluetooth::SetSources(OutputBuffers* src) -> void { +auto Bluetooth::discoveryEnabled(bool en) -> void { auto lock = bluetooth::BluetoothState::lock(); - OutputBuffers* cur = bluetooth::BluetoothState::sources(); - if (src == cur) { - return; - } - bluetooth::BluetoothState::sources(src); - tinyfsm::FsmList::dispatch( - bluetooth::events::SourcesChanged{}); + bluetooth::BluetoothState::discovery(en); } -auto Bluetooth::SetVolumeFactor(float f) -> void { - sVolumeFactor = f; +auto Bluetooth::discoveryEnabled() -> bool { + auto lock = bluetooth::BluetoothState::lock(); + return bluetooth::BluetoothState::discovery(); } -auto Bluetooth::SetEventHandler(std::function cb) - -> void { - auto lock = bluetooth::BluetoothState::lock(); - bluetooth::BluetoothState::event_handler(cb); +auto Bluetooth::discoveredDevices() -> std::vector { + std::vector discovered; + { + auto lock = bluetooth::BluetoothState::lock(); + discovered = bluetooth::BluetoothState::discoveredDevices(); + } + + // Show devices with stronger signals first, since they're more likely to be + // physically close (and therefore more likely to be what the user wants). + std::sort(discovered.begin(), discovered.end(), + [](const auto& a, const auto& b) -> bool { + return a.signal_strength < b.signal_strength; + }); + + // Convert to the right format. + std::vector out; + out.reserve(discovered.size()); + std::transform(discovered.begin(), discovered.end(), std::back_inserter(out), + [&](const bluetooth::Device& dev) { + return bluetooth::MacAndName{ + .mac = dev.address, + .name = {dev.name.data(), dev.name.size()}, + }; + }); + + return out; } static auto DeviceName() -> std::pmr::string { @@ -255,6 +274,10 @@ auto Scanner::StopScanningNow() -> void { } } +auto Scanner::enabled() -> bool { + return enabled_; +} + auto Scanner::HandleGapEvent(const events::internal::Gap& ev) -> void { switch (ev.type) { case ESP_BT_GAP_DISC_RES_EVT: @@ -347,16 +370,18 @@ NvsStorage* BluetoothState::sStorage_; Scanner* BluetoothState::sScanner_; std::mutex BluetoothState::sFsmMutex{}; -std::map BluetoothState::sDevices_{}; -std::optional BluetoothState::sPreferredDevice_{}; -std::optional BluetoothState::sConnectingDevice_{}; +std::map BluetoothState::sDiscoveredDevices_{}; +std::optional BluetoothState::sPairedWith_{}; +std::optional BluetoothState::sConnectingTo_{}; int BluetoothState::sConnectAttemptsRemaining_{0}; std::function BluetoothState::sEventHandler_; -auto BluetoothState::Init(NvsStorage& storage) -> void { +auto BluetoothState::Init(NvsStorage& storage, Bluetooth::EventHandler cb) + -> void { sStorage_ = &storage; - sPreferredDevice_ = storage.PreferredBluetoothDevice(); + sEventHandler_ = cb; + sPairedWith_ = storage.PreferredBluetoothDevice(); tinyfsm::FsmList::start(); } @@ -364,68 +389,85 @@ auto BluetoothState::lock() -> std::lock_guard { return std::lock_guard{sFsmMutex}; } -auto BluetoothState::devices() -> std::vector { - std::vector out; - for (const auto& device : sDevices_) { - out.push_back(device.second); - } - return out; +auto BluetoothState::pairedDevice() -> std::optional { + return sPairedWith_; } -auto BluetoothState::preferred_device() -> std::optional { - return sPreferredDevice_; -} +auto BluetoothState::pairedDevice(std::optional dev) -> void { + auto cur = sPairedWith_; + if (dev && cur && dev->mac == cur->mac) { + return; + } + if (dev) { + ESP_LOGI(kTag, "pairing with '%s' (%u%u%u%u%u%u)", dev->name.c_str(), + dev->mac[0], dev->mac[1], dev->mac[2], dev->mac[3], dev->mac[4], + dev->mac[5]); + } + sPairedWith_ = dev; + std::invoke(sEventHandler_, SimpleEvent::kDeviceDiscovered); -auto BluetoothState::preferred_device(std::optional addr) -> void { - sPreferredDevice_ = addr; + tinyfsm::FsmList::dispatch( + bluetooth::events::PairedDeviceChanged{}); } -auto BluetoothState::sources() -> OutputBuffers* { - return sStreams; +auto BluetoothState::discovery() -> bool { + return sScanner_->enabled(); } -auto BluetoothState::sources(OutputBuffers* src) -> void { - sStreams = src; +auto BluetoothState::discovery(bool en) -> void { + if (en) { + if (!sScanner_->enabled()) { + sDiscoveredDevices_.clear(); + } + sScanner_->ScanContinuously(); + } else { + sScanner_->StopScanning(); + } } -auto BluetoothState::event_handler(std::function cb) -> void { - sEventHandler_ = cb; +auto BluetoothState::discoveredDevices() -> std::vector { + std::vector out; + for (const auto& device : sDiscoveredDevices_) { + out.push_back(device.second); + } + return out; } auto BluetoothState::react(const events::DeviceDiscovered& ev) -> void { - bool is_preferred = false; - bool already_known = sDevices_.contains(ev.device.address); - sDevices_[ev.device.address] = ev.device; + bool is_paired = false; + bool already_known = sDiscoveredDevices_.contains(ev.device.address); + sDiscoveredDevices_[ev.device.address] = ev.device; - if (sPreferredDevice_ && ev.device.address == sPreferredDevice_->mac) { - is_preferred = true; + if (sPairedWith_ && ev.device.address == sPairedWith_->mac) { + is_paired = true; } - if (sEventHandler_ && !already_known) { - std::invoke(sEventHandler_, SimpleEvent::kKnownDevicesChanged); + if (!already_known) { + std::invoke(sEventHandler_, SimpleEvent::kDeviceDiscovered); } - if (is_preferred && sPreferredDevice_) { - connect(*sPreferredDevice_); + if (is_paired && sPairedWith_) { + connect(*sPairedWith_); } } auto BluetoothState::connect(const MacAndName& dev) -> bool { - if (sConnectingDevice_ && sConnectingDevice_->mac == dev.mac) { + if (sConnectingTo_ && sConnectingTo_->mac == dev.mac) { sConnectAttemptsRemaining_--; } else { sConnectAttemptsRemaining_ = 3; } if (sConnectAttemptsRemaining_ == 0) { + sConnectingTo_ = {}; return false; } - sConnectingDevice_ = dev; + sConnectingTo_ = dev; ESP_LOGI(kTag, "connecting to '%s' (%u%u%u%u%u%u)", dev.name.c_str(), dev.mac[0], dev.mac[1], dev.mac[2], dev.mac[3], dev.mac[4], dev.mac[5]); - if (esp_a2d_source_connect(sConnectingDevice_->mac.data()) != ESP_OK) { + if (esp_a2d_source_connect(sConnectingTo_->mac.data()) != ESP_OK) { ESP_LOGI(kTag, "Connecting failed..."); if (sConnectAttemptsRemaining_ > 1) { ESP_LOGI(kTag, "Will retry."); @@ -489,7 +531,7 @@ void Disabled::react(const events::Enable&) { // Set a reasonable name for the device. std::pmr::string name = DeviceName(); - esp_bt_dev_set_device_name(name.c_str()); + esp_bt_gap_set_device_name(name.c_str()); // Initialise GAP. This controls advertising our device, and scanning for // other devices. @@ -553,36 +595,31 @@ void Disabled::react(const events::Enable&) { esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE); ESP_LOGI(kTag, "bt enabled"); - if (sPreferredDevice_) { - ESP_LOGI(kTag, "connecting to preferred device '%s'", - sPreferredDevice_->name.c_str()); - connect(*sPreferredDevice_); + if (sPairedWith_) { + ESP_LOGI(kTag, "connecting to paired device '%s'", + sPairedWith_->name.c_str()); + connect(*sPairedWith_); } else { - ESP_LOGI(kTag, "scanning for devices"); transit(); } } void Idle::entry() { ESP_LOGI(kTag, "bt is idle"); - sScanner_->ScanContinuously(); + std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged); } void Idle::exit() { - sScanner_->StopScanning(); + std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged); } void Idle::react(const events::Disable& ev) { transit(); } -void Idle::react(const events::PreferredDeviceChanged& ev) { - bool is_discovered = false; - if (sPreferredDevice_ && sDevices_.contains(sPreferredDevice_->mac)) { - is_discovered = true; - } - if (is_discovered) { - connect(*sPreferredDevice_); +void Idle::react(const events::PairedDeviceChanged& ev) { + if (sPairedWith_) { + connect(*sPairedWith_); } } @@ -604,36 +641,32 @@ void Connecting::entry() { sTimeoutTimer = xTimerCreate("bt_timeout", pdMS_TO_TICKS(15000), false, NULL, timeoutCallback); xTimerStart(sTimeoutTimer, portMAX_DELAY); - - sScanner_->StopScanning(); - if (sEventHandler_) { - std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged); - } } void Connecting::exit() { xTimerDelete(sTimeoutTimer, portMAX_DELAY); - - if (sEventHandler_) { - std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged); - } } void Connecting::react(const events::ConnectTimedOut& ev) { ESP_LOGI(kTag, "timed out awaiting connection"); - esp_a2d_source_disconnect(sConnectingDevice_->mac.data()); - if (!connect(*sConnectingDevice_)) { + esp_a2d_source_disconnect(sConnectingTo_->mac.data()); + if (!connect(*sConnectingTo_)) { transit(); } } void Connecting::react(const events::Disable& ev) { - // TODO: disconnect gracefully + esp_a2d_source_disconnect(sConnectingTo_->mac.data()); transit(); } -void Connecting::react(const events::PreferredDeviceChanged& ev) { - // TODO. Cancel out and start again. +void Connecting::react(const events::PairedDeviceChanged& ev) { + esp_a2d_source_disconnect(sConnectingTo_->mac.data()); + if (sPairedWith_) { + connect(*sPairedWith_); + } else { + transit(); + } } void Connecting::react(events::internal::Gap ev) { @@ -704,29 +737,41 @@ void Connected::entry() { ESP_LOGI(kTag, "entering connected state"); transaction_num_ = 0; - connected_to_ = sConnectingDevice_->mac; - sPreferredDevice_ = sConnectingDevice_; - sConnectingDevice_ = {}; + connected_to_ = sConnectingTo_->mac; + sPairedWith_ = sConnectingTo_; + + sStorage_->BluetoothName(sConnectingTo_->mac, sConnectingTo_->name); + std::invoke(sEventHandler_, SimpleEvent::kKnownDevicesChanged); + + sConnectingTo_ = {}; auto stored_pref = sStorage_->PreferredBluetoothDevice(); - if (!stored_pref || (sPreferredDevice_->name != stored_pref->name || - sPreferredDevice_->mac != stored_pref->mac)) { - sStorage_->PreferredBluetoothDevice(sPreferredDevice_); + if (!stored_pref || (sPairedWith_->name != stored_pref->name || + sPairedWith_->mac != stored_pref->mac)) { + sStorage_->PreferredBluetoothDevice(sPairedWith_); } + + std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged); + + // TODO: if we already have a source, immediately start playing } void Connected::exit() { ESP_LOGI(kTag, "exiting connected state"); esp_a2d_source_disconnect(connected_to_.data()); + + std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged); } void Connected::react(const events::Disable& ev) { transit(); } -void Connected::react(const events::PreferredDeviceChanged& ev) { - sConnectingDevice_ = sPreferredDevice_; - transit(); +void Connected::react(const events::PairedDeviceChanged& ev) { + transit(); + if (sPairedWith_) { + connect(*sPairedWith_); + } } void Connected::react(const events::SourcesChanged& ev) { diff --git a/src/drivers/display.cpp b/src/drivers/display.cpp index efc9df93..7321f20b 100644 --- a/src/drivers/display.cpp +++ b/src/drivers/display.cpp @@ -242,6 +242,7 @@ void Display::SendInitialisationSequence(const uint8_t* data) { spi_device_release_bus(handle_); } +IRAM_ATTR void Display::SendCommandWithData(uint8_t command, const uint8_t* data, size_t length) { @@ -249,17 +250,20 @@ void Display::SendCommandWithData(uint8_t command, SendData(data, length); } +IRAM_ATTR void Display::SendCmd(const uint8_t* data, size_t length) { SendTransaction(COMMAND, data, length); } +IRAM_ATTR void Display::SendData(const uint8_t* data, size_t length) { SendTransaction(DATA, data, length); } +IRAM_ATTR void Display::SendTransaction(TransactionType type, - const uint8_t* data, - size_t length) { + const uint8_t* data, + size_t length) { // TODO(jacqueline): What's sending this? if (length == 0) { return; @@ -290,6 +294,7 @@ void Display::SendTransaction(TransactionType type, ESP_ERROR_CHECK(spi_device_transmit(handle_, &sTransaction)); } +IRAM_ATTR void Display::OnLvglFlush(const lv_area_t* area, uint8_t* color_map) { // Swap the pixel byte order first, since we don't want to do this whilst // holding the SPI bus lock. diff --git a/src/drivers/i2s_dac.cpp b/src/drivers/i2s_dac.cpp index 4e2e171a..46bf8e80 100644 --- a/src/drivers/i2s_dac.cpp +++ b/src/drivers/i2s_dac.cpp @@ -46,12 +46,12 @@ extern "C" IRAM_ATTR auto callback(i2s_chan_handle_t handle, if (event == nullptr || user_ctx == nullptr) { return false; } - if (event->data == nullptr || event->size == 0) { + if (event->dma_buf == nullptr || event->size == 0) { return false; } assert(event->size % 4 == 0); - uint8_t* buf = *reinterpret_cast(event->data); + uint8_t* buf = reinterpret_cast(event->dma_buf); auto* src = reinterpret_cast(user_ctx); BaseType_t ret1 = src->first.receive( diff --git a/src/drivers/include/drivers/bluetooth.hpp b/src/drivers/include/drivers/bluetooth.hpp index eaecfb2b..99c71e52 100644 --- a/src/drivers/include/drivers/bluetooth.hpp +++ b/src/drivers/include/drivers/bluetooth.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -25,28 +26,68 @@ namespace drivers { /* - * A handle used to interact with the bluetooth state machine. + * A handle used to interact with the bluetooth state machine. This is the main + * API that the rest of the system should use to interact with Bluetooth. */ class Bluetooth { public: - Bluetooth(NvsStorage& storage, tasks::WorkerPool&); + /* + * Callback invoked when an event is generated by the Bluetooth stack. This + * callback is invoked synchronously from a Bluetooth task context, so + * implementations should immediately hop to a different task to process the + * event. + */ + using EventHandler = std::function; + + Bluetooth(NvsStorage&, tasks::WorkerPool&, EventHandler); + + /* Enables or disables the entire Bluetooth stack. */ + auto enable(bool en) -> void; + auto enabled() -> bool; + + auto sources(OutputBuffers*) -> void; + auto softVolume(float) -> void; + + enum class ConnectionState { + kConnected, + kConnecting, + kDisconnected, + }; + + auto connectionState() -> ConnectionState; + + /* + * The 'paired' device is a device that will be preferred for connections. + * When Bluetooth is first enabled, we immediately try to connect to the + * paired device. If the paired device is seen during a scan, then we will + * also automatically connect to it. + */ + auto pairedDevice() -> std::optional; + + /* + * Sets the preferred device. If a device is provided, a connection will be + * attempted immediately, even if the device has not been detected in a + * previous scan. + */ + auto pairedDevice(std::optional dev) -> void; + + /* A list of devices that have previously been the paired device. */ + auto knownDevices() -> std::vector; + auto forgetKnownDevice(const bluetooth::mac_addr_t&) -> void; + + /* Enables or disables scanning for nearby Bluetooth devices. */ + auto discoveryEnabled(bool) -> void; + auto discoveryEnabled() -> bool; + + /* + * A list of nearby devices that have been discovered since discovery was + * last enabled. This list may include the paired device, as well as devices + * that are also present in the known devices list. + */ + auto discoveredDevices() -> std::vector; - auto Enable() -> bool; - auto Disable() -> void; - auto IsEnabled() -> bool; - - auto IsConnected() -> bool; - auto ConnectedDevice() -> std::optional; - - auto KnownDevices() -> std::vector; - - auto SetPreferredDevice(std::optional dev) -> void; - auto PreferredDevice() -> std::optional; - - auto SetSources(OutputBuffers*) -> void; - auto SetVolumeFactor(float) -> void; - - auto SetEventHandler(std::function cb) -> void; + private: + NvsStorage& nvs_; }; namespace bluetooth { @@ -56,7 +97,7 @@ struct Enable : public tinyfsm::Event {}; struct Disable : public tinyfsm::Event {}; struct ConnectTimedOut : public tinyfsm::Event {}; -struct PreferredDeviceChanged : public tinyfsm::Event {}; +struct PairedDeviceChanged : public tinyfsm::Event {}; struct SourcesChanged : public tinyfsm::Event {}; struct DeviceDiscovered : public tinyfsm::Event { const Device& device; @@ -94,6 +135,8 @@ class Scanner { auto StopScanning() -> void; auto StopScanningNow() -> void; + auto enabled() -> bool; + auto HandleGapEvent(const events::internal::Gap&) -> void; private: @@ -103,25 +146,22 @@ class Scanner { auto HandleDeviceDiscovery(const esp_bt_gap_cb_param_t& param) -> void; }; +/* + * The main state machine for managing the state of the Bluetooth stack, and + * the current (if any) Bluetooth connection. + */ class BluetoothState : public tinyfsm::Fsm { public: - static auto Init(NvsStorage& storage) -> void; + static auto Init(NvsStorage& storage, Bluetooth::EventHandler) -> void; static auto lock() -> std::lock_guard; - static auto devices() -> std::vector; - - static auto preferred_device() -> std::optional; - static auto preferred_device(std::optional) -> void; + static auto pairedDevice() -> std::optional; + static auto pairedDevice(std::optional) -> void; - static auto scanning() -> bool; static auto discovery() -> bool; static auto discovery(bool) -> void; - - static auto sources() -> OutputBuffers*; - static auto sources(OutputBuffers*) -> void; - - static auto event_handler(std::function) -> void; + static auto discoveredDevices() -> std::vector; virtual ~BluetoothState(){}; @@ -131,7 +171,7 @@ class BluetoothState : public tinyfsm::Fsm { virtual void react(const events::Enable& ev){}; virtual void react(const events::Disable& ev) = 0; virtual void react(const events::ConnectTimedOut& ev){}; - virtual void react(const events::PreferredDeviceChanged& ev){}; + virtual void react(const events::PairedDeviceChanged& ev){}; virtual void react(const events::SourcesChanged& ev){}; virtual void react(const events::DeviceDiscovered&); @@ -146,10 +186,9 @@ class BluetoothState : public tinyfsm::Fsm { static Scanner* sScanner_; static std::mutex sFsmMutex; - static std::map sDevices_; - static std::optional sPreferredDevice_; - - static std::optional sConnectingDevice_; + static std::map sDiscoveredDevices_; + static std::optional sPairedWith_; + static std::optional sConnectingTo_; static int sConnectAttemptsRemaining_; static std::function sEventHandler_; @@ -176,7 +215,7 @@ class Idle : public BluetoothState { void exit() override; void react(const events::Disable& ev) override; - void react(const events::PreferredDeviceChanged& ev) override; + void react(const events::PairedDeviceChanged& ev) override; void react(events::internal::Gap ev) override; @@ -188,7 +227,7 @@ class Connecting : public BluetoothState { void entry() override; void exit() override; - void react(const events::PreferredDeviceChanged& ev) override; + void react(const events::PairedDeviceChanged& ev) override; void react(const events::ConnectTimedOut& ev) override; void react(const events::Disable& ev) override; @@ -203,7 +242,7 @@ class Connected : public BluetoothState { void entry() override; void exit() override; - void react(const events::PreferredDeviceChanged& ev) override; + void react(const events::PairedDeviceChanged& ev) override; void react(const events::SourcesChanged& ev) override; void react(const events::Disable& ev) override; diff --git a/src/drivers/include/drivers/bluetooth_types.hpp b/src/drivers/include/drivers/bluetooth_types.hpp index d2e55ee5..05caee47 100644 --- a/src/drivers/include/drivers/bluetooth_types.hpp +++ b/src/drivers/include/drivers/bluetooth_types.hpp @@ -27,9 +27,12 @@ struct Device { }; enum class SimpleEvent { - kKnownDevicesChanged, kConnectionStateChanged, - kPreferredDeviceChanged, + kPairedDeviceChanged, + kKnownDevicesChanged, + kDiscoveryChanged, + kDeviceDiscovered, + // Passthrough events kPlayPause, kStop, diff --git a/src/drivers/include/drivers/nvs.hpp b/src/drivers/include/drivers/nvs.hpp index 88dd5ae0..e147c8c7 100644 --- a/src/drivers/include/drivers/nvs.hpp +++ b/src/drivers/include/drivers/nvs.hpp @@ -34,7 +34,7 @@ class Setting { dirty_ = true; } } - auto get() -> std::optional& { return val_; } + auto get() -> std::optional { return val_; } /* Reads the stored value from NVS and parses it into the correct type. */ auto load(nvs_handle_t) -> std::optional; @@ -90,12 +90,19 @@ class NvsStorage { auto LraCalibration() -> std::optional; auto LraCalibration(const LraData&) -> void; + auto FastCharge() -> bool; + auto FastCharge(bool) -> void; + auto PreferredBluetoothDevice() -> std::optional; auto PreferredBluetoothDevice(std::optional) -> void; auto BluetoothVolume(const bluetooth::mac_addr_t&) -> uint8_t; auto BluetoothVolume(const bluetooth::mac_addr_t&, uint8_t) -> void; + auto BluetoothNames() -> std::vector; + auto BluetoothName(const bluetooth::mac_addr_t&, std::optional) + -> void; + enum class Output : uint8_t { kHeadphones = 0, kBluetooth = 1, @@ -106,6 +113,9 @@ class NvsStorage { auto ScreenBrightness() -> uint_fast8_t; auto ScreenBrightness(uint_fast8_t) -> void; + auto InterfaceTheme() -> std::optional; + auto InterfaceTheme(std::string) -> void; + auto ScrollSensitivity() -> uint_fast8_t; auto ScrollSensitivity(uint_fast8_t) -> void; @@ -146,6 +156,7 @@ class NvsStorage { Setting display_rows_; Setting haptic_motor_type_; Setting lra_calibration_; + Setting fast_charge_; Setting brightness_; Setting sensitivity_; @@ -154,7 +165,12 @@ class NvsStorage { Setting amp_left_bias_; Setting input_mode_; Setting output_mode_; + + Setting theme_; + Setting bt_preferred_; + Setting> bt_names_; + Setting db_auto_index_; util::LruCache<10, bluetooth::mac_addr_t, uint8_t> bt_volumes_; diff --git a/src/drivers/include/drivers/pcm_buffer.hpp b/src/drivers/include/drivers/pcm_buffer.hpp index 968c3398..4e5fa041 100644 --- a/src/drivers/include/drivers/pcm_buffer.hpp +++ b/src/drivers/include/drivers/pcm_buffer.hpp @@ -28,8 +28,12 @@ class PcmBuffer { PcmBuffer(size_t size_in_samples); ~PcmBuffer(); - /* Adds samples to the buffer. */ - auto send(std::span) -> void; + /* + * Adds samples to the buffer. Returns the number of samples that were added, + * which may be less than the number of samples given if this PcmBuffer is + * close to full. + */ + auto send(std::span) -> size_t; /* * Fills the given span with samples. If enough samples are available in diff --git a/src/drivers/include/drivers/samd.hpp b/src/drivers/include/drivers/samd.hpp index 897e78d6..ff479225 100644 --- a/src/drivers/include/drivers/samd.hpp +++ b/src/drivers/include/drivers/samd.hpp @@ -10,6 +10,7 @@ #include #include +#include "drivers/nvs.hpp" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" @@ -17,9 +18,7 @@ namespace drivers { class Samd { public: - static auto Create() -> Samd* { return new Samd(); } - - Samd(); + Samd(NvsStorage& nvs); ~Samd(); auto Version() -> std::string; @@ -37,8 +36,14 @@ class Samd { kChargingFast, // The battery is full charged, and we are still plugged in. kFullCharge, + // Charging failed. + kFault, + // The battery status returned isn't a known enum value. + kUnknown, }; + static auto chargeStatusToString(ChargeStatus) -> std::string; + auto GetChargeStatus() -> std::optional; auto UpdateChargeStatus() -> void; @@ -68,6 +73,8 @@ class Samd { Samd& operator=(const Samd&) = delete; private: + NvsStorage& nvs_; + uint8_t version_; std::optional charge_status_; UsbStatus usb_status_; diff --git a/src/drivers/include/drivers/touchwheel.hpp b/src/drivers/include/drivers/touchwheel.hpp index 60902087..9cd925a6 100644 --- a/src/drivers/include/drivers/touchwheel.hpp +++ b/src/drivers/include/drivers/touchwheel.hpp @@ -39,7 +39,8 @@ class TouchWheel { auto Update() -> void; auto GetTouchWheelData() const -> TouchWheelData; - auto PowerDown() -> void; + auto Recalibrate() -> void; + auto LowPowerMode(bool en) -> void; private: TouchWheelData data_; diff --git a/src/drivers/nvs.cpp b/src/drivers/nvs.cpp index 5c7d2218..d004201b 100644 --- a/src/drivers/nvs.cpp +++ b/src/drivers/nvs.cpp @@ -26,8 +26,10 @@ static constexpr uint8_t kSchemaVersion = 1; static constexpr char kKeyVersion[] = "ver"; static constexpr char kKeyBluetoothPreferred[] = "bt_dev"; static constexpr char kKeyBluetoothVolumes[] = "bt_vols"; +static constexpr char kKeyBluetoothNames[] = "bt_names"; static constexpr char kKeyOutput[] = "out"; static constexpr char kKeyBrightness[] = "bright"; +static constexpr char kKeyInterfaceTheme[] = "ui_theme"; static constexpr char kKeyAmpMaxVolume[] = "hp_vol_max"; static constexpr char kKeyAmpCurrentVolume[] = "hp_vol"; static constexpr char kKeyAmpLeftBias[] = "hp_bias"; @@ -39,6 +41,7 @@ static constexpr char kKeyDisplayRows[] = "disprows"; static constexpr char kKeyHapticMotorType[] = "hapticmtype"; static constexpr char kKeyLraCalibration[] = "lra_cali"; static constexpr char kKeyDbAutoIndex[] = "dbautoindex"; +static constexpr char kKeyFastCharge[] = "fastchg"; static auto nvs_get_string(nvs_handle_t nvs, const char* key) -> std::optional { @@ -129,6 +132,69 @@ auto Setting::store(nvs_handle_t nvs, nvs_set_blob(nvs, name_, encoded.data(), encoded.size()); } +template <> +auto Setting>::load(nvs_handle_t nvs) + -> std::optional> { + auto raw = nvs_get_string(nvs, name_); + if (!raw) { + return {}; + } + auto [parsed, unused, err] = cppbor::parseWithViews( + reinterpret_cast(raw->data()), raw->size()); + if (parsed->type() != cppbor::MAP) { + return {}; + } + std::vector res; + for (const auto& i : *parsed->asMap()) { + auto mac = i.first->asViewBstr()->view(); + auto name = i.second->asViewTstr()->view(); + bluetooth::MacAndName entry{ + .mac = {}, + .name = {name.begin(), name.end()}, + }; + std::copy(mac.begin(), mac.end(), entry.mac.begin()); + res.push_back(entry); + } + return res; +} + +template <> +auto Setting>::store( + nvs_handle_t nvs, + std::vector v) -> void { + cppbor::Map cbor{}; + for (const auto& i : v) { + cbor.add(cppbor::Bstr{{i.mac.data(), i.mac.size()}}, cppbor::Tstr{i.name}); + } + auto encoded = cbor.encode(); + nvs_set_blob(nvs, name_, encoded.data(), encoded.size()); +} + +template <> +auto Setting::store( + nvs_handle_t nvs, + std::string v) -> void { + cppbor::Tstr cbor{v}; + auto encoded = cbor.encode(); + nvs_set_blob(nvs, name_, encoded.data(), encoded.size()); +} + +template <> +auto Setting::load(nvs_handle_t nvs) + -> std::optional { + auto raw = nvs_get_string(nvs, name_); + if (!raw) { + return {}; + } + auto [parsed, unused, err] = cppbor::parseWithViews( + reinterpret_cast(raw->data()), raw->size()); + if (parsed->type() != cppbor::TSTR) { + return {}; + } + auto v = parsed->asViewTstr()->view(); + return std::string{v.begin(), v.end()}; +} + template <> auto Setting::load(nvs_handle_t nvs) -> std::optional { @@ -200,6 +266,7 @@ NvsStorage::NvsStorage(nvs_handle_t handle) display_rows_(kKeyDisplayRows), haptic_motor_type_(kKeyHapticMotorType), lra_calibration_(kKeyLraCalibration), + fast_charge_(kKeyFastCharge), brightness_(kKeyBrightness), sensitivity_(kKeyScrollSensitivity), amp_max_vol_(kKeyAmpMaxVolume), @@ -207,7 +274,9 @@ NvsStorage::NvsStorage(nvs_handle_t handle) amp_left_bias_(kKeyAmpLeftBias), input_mode_(kKeyPrimaryInput), output_mode_(kKeyOutput), + theme_{kKeyInterfaceTheme}, bt_preferred_(kKeyBluetoothPreferred), + bt_names_(kKeyBluetoothNames), db_auto_index_(kKeyDbAutoIndex), bt_volumes_(), bt_volumes_dirty_(false) {} @@ -231,7 +300,9 @@ auto NvsStorage::Read() -> void { amp_left_bias_.read(handle_); input_mode_.read(handle_); output_mode_.read(handle_); + theme_.read(handle_); bt_preferred_.read(handle_); + bt_names_.read(handle_); db_auto_index_.read(handle_); readBtVolumes(); } @@ -250,7 +321,9 @@ auto NvsStorage::Write() -> bool { amp_left_bias_.write(handle_); input_mode_.write(handle_); output_mode_.write(handle_); + theme_.write(handle_); bt_preferred_.write(handle_); + bt_names_.write(handle_); db_auto_index_.write(handle_); writeBtVolumes(); return nvs_commit(handle_) == ESP_OK; @@ -341,6 +414,47 @@ auto NvsStorage::BluetoothVolume(const bluetooth::mac_addr_t& mac, uint8_t vol) bt_volumes_.Put(mac, vol); } +auto NvsStorage::BluetoothNames() -> std::vector { + std::lock_guard lock{mutex_}; + return bt_names_.get().value_or(std::vector{}); +} + +auto NvsStorage::BluetoothName(const bluetooth::mac_addr_t& mac, + std::optional name) -> void { + std::lock_guard lock{mutex_}; + auto val = bt_names_.get(); + if (!val) { + val.emplace(); + } + + bool mut = false; + bool found = false; + for (auto it = val->begin(); it != val->end(); it++) { + if (it->mac == mac) { + if (name) { + it->name = *name; + } else { + val->erase(it); + } + found = true; + mut = true; + break; + } + } + + if (!found && name) { + val->push_back(bluetooth::MacAndName{ + .mac = mac, + .name = *name, + }); + mut = true; + } + + if (mut) { + bt_names_.set(*val); + } +} + auto NvsStorage::OutputMode() -> Output { std::lock_guard lock{mutex_}; switch (output_mode_.get().value_or(0xFF)) { @@ -361,6 +475,16 @@ auto NvsStorage::OutputMode(Output out) -> void { nvs_commit(handle_); } +auto NvsStorage::FastCharge() -> bool { + std::lock_guard lock{mutex_}; + return fast_charge_.get().value_or(true); +} + +auto NvsStorage::FastCharge(bool en) -> void { + std::lock_guard lock{mutex_}; + fast_charge_.set(en); +} + auto NvsStorage::ScreenBrightness() -> uint_fast8_t { std::lock_guard lock{mutex_}; return std::clamp(brightness_.get().value_or(50), 0, 100); @@ -371,6 +495,16 @@ auto NvsStorage::ScreenBrightness(uint_fast8_t val) -> void { brightness_.set(val); } +auto NvsStorage::InterfaceTheme() -> std::optional { + std::lock_guard lock{mutex_}; + return theme_.get(); +} + +auto NvsStorage::InterfaceTheme(std::string themeFile) -> void { + std::lock_guard lock{mutex_}; + theme_.set(themeFile); +} + auto NvsStorage::ScrollSensitivity() -> uint_fast8_t { std::lock_guard lock{mutex_}; return std::clamp(sensitivity_.get().value_or(128), 0, 255); diff --git a/src/drivers/pcm_buffer.cpp b/src/drivers/pcm_buffer.cpp index 1d2bab1e..1e416301 100644 --- a/src/drivers/pcm_buffer.cpp +++ b/src/drivers/pcm_buffer.cpp @@ -17,6 +17,7 @@ #include "freertos/FreeRTOS.h" #include "esp_heap_caps.h" +#include "freertos/projdefs.h" #include "freertos/ringbuf.h" #include "portmacro.h" @@ -39,9 +40,13 @@ PcmBuffer::~PcmBuffer() { heap_caps_free(buf_); } -auto PcmBuffer::send(std::span data) -> void { - xRingbufferSend(ringbuf_, data.data(), data.size_bytes(), portMAX_DELAY); +auto PcmBuffer::send(std::span data) -> size_t { + if (!xRingbufferSend(ringbuf_, data.data(), data.size_bytes(), + pdMS_TO_TICKS(100))) { + return 0; + } sent_ += data.size(); + return data.size(); } IRAM_ATTR auto PcmBuffer::receive(std::span dest, bool mix, bool isr) @@ -67,10 +72,12 @@ IRAM_ATTR auto PcmBuffer::receive(std::span dest, bool mix, bool isr) auto PcmBuffer::clear() -> void { while (!isEmpty()) { - size_t bytes_cleared; + size_t bytes_cleared = 0; void* data = xRingbufferReceive(ringbuf_, &bytes_cleared, 0); - vRingbufferReturnItem(ringbuf_, data); - received_ += bytes_cleared / sizeof(int16_t); + if (data) { + vRingbufferReturnItem(ringbuf_, data); + received_ += bytes_cleared / sizeof(int16_t); + } } } diff --git a/src/drivers/samd.cpp b/src/drivers/samd.cpp index e4aa73ad..c2308760 100644 --- a/src/drivers/samd.cpp +++ b/src/drivers/samd.cpp @@ -5,11 +5,13 @@ */ #include "drivers/samd.hpp" +#include #include #include #include +#include "drivers/nvs.hpp" #include "esp_err.h" #include "esp_log.h" #include "hal/gpio_types.h" @@ -32,7 +34,29 @@ namespace drivers { static constexpr gpio_num_t kIntPin = GPIO_NUM_35; -Samd::Samd() { +auto Samd::chargeStatusToString(ChargeStatus status) -> std::string { + switch (status) { + case ChargeStatus::kNoBattery: + return "no_battery"; + case ChargeStatus::kBatteryCritical: + return "critical"; + case ChargeStatus::kDischarging: + return "discharging"; + case ChargeStatus::kChargingRegular: + return "charge_regular"; + case ChargeStatus::kChargingFast: + return "charge_fast"; + case ChargeStatus::kFullCharge: + return "full_charge"; + case ChargeStatus::kFault: + return "fault"; + case ChargeStatus::kUnknown: + default: + return "unknown"; + } +} + +Samd::Samd(NvsStorage& nvs) : nvs_(nvs) { gpio_set_direction(kIntPin, GPIO_MODE_INPUT); // Being able to interface with the SAMD properly is critical. To ensure we @@ -51,7 +75,7 @@ Samd::Samd() { UpdateChargeStatus(); UpdateUsbStatus(); - SetFastChargeEnabled(true); + SetFastChargeEnabled(nvs.FastCharge()); } Samd::~Samd() {} @@ -78,16 +102,38 @@ auto Samd::UpdateChargeStatus() -> void { return; } - // FIXME: Ideally we should be using the three 'charge status' bits to work - // out whether we're actually charging, or if we've got a full charge, - // critically low charge, etc. + // Lower two bits are the usb power status, next three are the BMS status. + // See 'gpio.c' in the SAMD21 firmware for how these bits get packed. + uint8_t charge_state = (raw_res & 0b11100) >> 2; uint8_t usb_state = raw_res & 0b11; - if (usb_state == 0) { - charge_status_ = ChargeStatus::kDischarging; - } else if (usb_state == 1) { - charge_status_ = ChargeStatus::kChargingRegular; - } else { - charge_status_ = ChargeStatus::kChargingFast; + switch (charge_state) { + case 0b000: + charge_status_ = ChargeStatus::kNoBattery; + break; + case 0b001: + // BMS says we're charging; work out how fast we're charging. + if (usb_state >= 0b10 && nvs_.FastCharge()) { + charge_status_ = ChargeStatus::kChargingFast; + } else { + charge_status_ = ChargeStatus::kChargingRegular; + } + break; + case 0b010: + charge_status_ = ChargeStatus::kFullCharge; + break; + case 0b011: + charge_status_ = ChargeStatus::kFault; + break; + case 0b100: + charge_status_ = ChargeStatus::kBatteryCritical; + break; + case 0b101: + charge_status_ = ChargeStatus::kDischarging; + break; + case 0b110: + case 0b111: + charge_status_ = ChargeStatus::kUnknown; + break; } } @@ -127,9 +173,15 @@ auto Samd::ResetToFlashSamd() -> void { } auto Samd::SetFastChargeEnabled(bool en) -> void { + // Always update NVS, so that the setting is right after the SAMD firmware is + // updated. + nvs_.FastCharge(en); + if (version_ < 4) { return; } + ESP_LOGI(kTag, "set fast charge %u", en); + I2CTransaction transaction; transaction.start() .write_addr(kAddress, I2C_MASTER_WRITE) diff --git a/src/drivers/spi.cpp b/src/drivers/spi.cpp index 632fe89f..40487197 100644 --- a/src/drivers/spi.cpp +++ b/src/drivers/spi.cpp @@ -41,7 +41,7 @@ esp_err_t init_spi(void) { // manages its own use of DMA-capable memory. .max_transfer_sz = 4096, .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_IOMUX_PINS, - .isr_cpu_id = ESP_INTR_CPU_AFFINITY_0, + .isr_cpu_id = ESP_INTR_CPU_AFFINITY_1, .intr_flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, }; diff --git a/src/drivers/test/test_samd.cpp b/src/drivers/test/test_samd.cpp index c466d88e..96248377 100644 --- a/src/drivers/test/test_samd.cpp +++ b/src/drivers/test/test_samd.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ +#include "drivers/nvs.hpp" #include "drivers/samd.hpp" #include @@ -16,7 +17,8 @@ namespace drivers { TEST_CASE("samd21 interface", "[integration]") { I2CFixture i2c; - auto samd = std::make_unique(); + std::unique_ptr nvs{drivers::NvsStorage::OpenSync()}; + auto samd = std::make_unique(*nvs); REQUIRE(samd); diff --git a/src/drivers/touchwheel.cpp b/src/drivers/touchwheel.cpp index 5d55c6f2..402b839d 100644 --- a/src/drivers/touchwheel.cpp +++ b/src/drivers/touchwheel.cpp @@ -137,8 +137,12 @@ TouchWheelData TouchWheel::GetTouchWheelData() const { return data_; } -auto TouchWheel::PowerDown() -> void { - WriteRegister(LOW_POWER, 0); +auto TouchWheel::Recalibrate() -> void { + WriteRegister(CALIBRATE, 1); +} + +auto TouchWheel::LowPowerMode(bool en) -> void { + WriteRegister(LOW_POWER, en ? 0 : 1); } } // namespace drivers diff --git a/src/locale/collation.cpp b/src/locale/collation.cpp index 8748742d..c3360483 100644 --- a/src/locale/collation.cpp +++ b/src/locale/collation.cpp @@ -89,8 +89,8 @@ GLibCollator::~GLibCollator() { auto GLibCollator::Transform(const std::string& in) -> std::string { size_t size = glib_strxfrm(NULL, in.c_str(), 0, locale_data_.get()); char* dest = new char[size + 1]{0}; - glib_strxfrm(dest, in.c_str(), size, locale_data_.get()); - std::string out{dest, strnlen(dest, size)}; + size = glib_strxfrm(dest, in.c_str(), size, locale_data_.get()); + std::string out{dest, size}; delete[] dest; return out; } diff --git a/src/tangara/app_console/app_console.cpp b/src/tangara/app_console/app_console.cpp index f3593e1b..21dec56a 100644 --- a/src/tangara/app_console/app_console.cpp +++ b/src/tangara/app_console/app_console.cpp @@ -418,28 +418,21 @@ int CmdBtList(int argc, char** argv) { return 1; } - auto devices = AppConsole::sServices->bluetooth().KnownDevices(); + auto devices = AppConsole::sServices->bluetooth().knownDevices(); if (argc == 2) { int index = std::atoi(argv[1]); if (index < 0 || index >= devices.size()) { std::cout << "index out of range" << std::endl; return -1; } - drivers::bluetooth::MacAndName dev{ - .mac = devices[index].address, - .name = {devices[index].name.data(), devices[index].name.size()}, - }; - AppConsole::sServices->bluetooth().SetPreferredDevice(dev); + AppConsole::sServices->bluetooth().pairedDevice(devices[index]); } else { - std::cout << "mac\t\trssi\tname" << std::endl; + std::cout << "mac\t\tname" << std::endl; for (const auto& device : devices) { - for (size_t i = 0; i < device.address.size(); i++) { + for (size_t i = 0; i < device.mac.size(); i++) { std::cout << std::hex << std::setfill('0') << std::setw(2) - << static_cast(device.address[i]); + << static_cast(device.mac[i]); } - float perc = - (static_cast(device.signal_strength) + 127.0) / 256.0 * 100; - std::cout << "\t" << std::fixed << std::setprecision(0) << perc << "%"; std::cout << "\t" << device.name << std::endl; } } @@ -472,26 +465,7 @@ int CmdSamd(int argc, char** argv) { } else if (cmd == "charge") { auto res = samd.GetChargeStatus(); if (res) { - switch (res.value()) { - case drivers::Samd::ChargeStatus::kNoBattery: - std::cout << "kNoBattery" << std::endl; - break; - case drivers::Samd::ChargeStatus::kBatteryCritical: - std::cout << "kBatteryCritical" << std::endl; - break; - case drivers::Samd::ChargeStatus::kDischarging: - std::cout << "kDischarging" << std::endl; - break; - case drivers::Samd::ChargeStatus::kChargingRegular: - std::cout << "kChargingRegular" << std::endl; - break; - case drivers::Samd::ChargeStatus::kChargingFast: - std::cout << "kChargingFast" << std::endl; - break; - case drivers::Samd::ChargeStatus::kFullCharge: - std::cout << "kFullCharge" << std::endl; - break; - } + std::cout << drivers::Samd::chargeStatusToString(*res) << std::endl; } else { std::cout << "unknown" << std::endl; } @@ -690,6 +664,26 @@ void RegisterLua() { esp_console_cmd_register(&cmd_luarun); } +int CmdSnapshot(int argc, char** argv) { + if (argc != 2) { + std::cout << "snapshot expects 1 argument" << std::endl; + return 1; + } + + events::Ui().Dispatch(ui::Screenshot{.filename = argv[1]}); + return 0; +} + +void RegisterSnapshot() { + esp_console_cmd_t cmd_snapshot{ + .command = "snapshot", + .help = "Saves a screenshot of the display to a file", + .hint = "filename", + .func = &CmdSnapshot, + .argtable = NULL}; + esp_console_cmd_register(&cmd_snapshot); +} + auto AppConsole::PrerunCallback() -> void { Console::PrerunCallback(); esp_log_level_set("*", ESP_LOG_NONE); @@ -720,6 +714,7 @@ auto AppConsole::RegisterExtraComponents() -> void { RegisterHapticEffect(); RegisterLua(); + RegisterSnapshot(); } } // namespace console diff --git a/src/tangara/audio/audio_decoder.cpp b/src/tangara/audio/audio_decoder.cpp index ee06d984..8c0b264f 100644 --- a/src/tangara/audio/audio_decoder.cpp +++ b/src/tangara/audio/audio_decoder.cpp @@ -48,7 +48,7 @@ static const char* kTag = "decoder"; * increasing its size. */ static constexpr std::size_t kCodecBufferLength = - drivers::kI2SBufferLengthFrames * sizeof(sample::Sample); + drivers::kI2SBufferLengthFrames * 2; auto Decoder::Start(std::shared_ptr sink) -> Decoder* { Decoder* task = new Decoder(sink); @@ -78,11 +78,17 @@ Decoder::Decoder(std::shared_ptr processor) * Main decoding loop. Handles watching for new streams, or continuing to nudge * along the current stream if we have one. */ +IRAM_ATTR void Decoder::Main() { for (;;) { - // Check whether there's a new stream to begin. If we're idle, then we - // simply park and wait forever for a stream to arrive. - TickType_t wait_time = stream_ ? 0 : portMAX_DELAY; + // How long should we spend waiting for a command? By default, assume we're + // idle and wait forever. + TickType_t wait_time = portMAX_DELAY; + if (!leftover_samples_.empty() || stream_) { + // If we have work to do, then don't block waiting for a new stream. + wait_time = 0; + } + NextStream* next; if (xQueueReceive(next_stream_, &next, wait_time)) { // Copy the data out of the queue, then clean up the item. @@ -103,8 +109,15 @@ void Decoder::Main() { // Start decoding the new stream. prepareDecode(new_stream); + + // Keep handling commands until the command queue is empty. + continue; } + // We should always have a stream if we returned from xQueueReceive without + // receiving a new stream. + assert(stream_); + if (!continueDecode()) { finishDecode(false); } @@ -167,16 +180,36 @@ auto Decoder::prepareDecode(std::shared_ptr stream) -> void { } auto Decoder::continueDecode() -> bool { + // First, see if we have any samples from a previous decode that still need + // to be sent. + if (!leftover_samples_.empty()) { + leftover_samples_ = processor_->continueStream(leftover_samples_); + return true; + } + + // We might have already cleaned up the codec if the last decode pass of the + // stream resulted in leftover samples. + if (!codec_) { + return false; + } + auto res = codec_->DecodeTo(codec_buffer_); if (res.has_error()) { return false; } if (res->samples_written > 0) { - processor_->continueStream(codec_buffer_.first(res->samples_written)); + leftover_samples_ = + processor_->continueStream(codec_buffer_.first(res->samples_written)); + } + + if (res->is_stream_finished) { + // The codec has finished, so make sure we don't call it again. + codec_.reset(); } - return !res->is_stream_finished; + // We're done iff the codec has finished and we sent everything. + return codec_ || !leftover_samples_.empty(); } auto Decoder::finishDecode(bool cancel) -> void { @@ -191,6 +224,7 @@ auto Decoder::finishDecode(bool cancel) -> void { processor_->endStream(cancel); // Clean up after ourselves. + leftover_samples_ = {}; stream_.reset(); codec_.reset(); track_.reset(); diff --git a/src/tangara/audio/audio_decoder.hpp b/src/tangara/audio/audio_decoder.hpp index 64561d9d..9f20ec59 100644 --- a/src/tangara/audio/audio_decoder.hpp +++ b/src/tangara/audio/audio_decoder.hpp @@ -15,6 +15,7 @@ #include "audio/processor.hpp" #include "codec.hpp" #include "database/track.hpp" +#include "sample.hpp" #include "types.hpp" namespace audio { @@ -55,6 +56,7 @@ class Decoder { std::shared_ptr track_; std::span codec_buffer_; + std::span leftover_samples_; }; } // namespace audio diff --git a/src/tangara/audio/audio_events.hpp b/src/tangara/audio/audio_events.hpp index 503664cc..91bcf48b 100644 --- a/src/tangara/audio/audio_events.hpp +++ b/src/tangara/audio/audio_events.hpp @@ -16,6 +16,7 @@ #include "tinyfsm.hpp" #include "database/track.hpp" +#include "drivers/nvs.hpp" #include "types.hpp" namespace audio { @@ -102,6 +103,7 @@ struct QueueUpdate : tinyfsm::Event { kRepeatingLastTrack, kTrackFinished, kDeserialised, + kBulkLoadingUpdate, }; Reason reason; }; @@ -117,10 +119,11 @@ struct SetVolumeBalance : tinyfsm::Event { }; /* - Event emitted when the hardware volume for a connected Bluetooth device has changed. + Event emitted when the hardware volume for a connected Bluetooth device has + changed. */ struct RemoteVolumeChanged : tinyfsm::Event { - uint_fast8_t value; // 0..127 + uint_fast8_t value; // 0..127 }; struct VolumeChanged : tinyfsm::Event { uint_fast8_t percent; @@ -137,7 +140,9 @@ struct SetVolumeLimit : tinyfsm::Event { int limit_db; }; -struct OutputModeChanged : tinyfsm::Event {}; +struct OutputModeChanged : tinyfsm::Event { + std::optional set_to; +}; namespace internal { diff --git a/src/tangara/audio/audio_fsm.cpp b/src/tangara/audio/audio_fsm.cpp index dbf1954c..ee7215cb 100644 --- a/src/tangara/audio/audio_fsm.cpp +++ b/src/tangara/audio/audio_fsm.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "audio/audio_source.hpp" @@ -103,9 +104,7 @@ void AudioState::react(const QueueUpdate& ev) { }; auto current = sServices->track_queue().current(); - if (current) { - cmd.new_track = *current; - } + cmd.new_track = current; switch (ev.reason) { case QueueUpdate::kExplicitUpdate: @@ -120,10 +119,13 @@ void AudioState::react(const QueueUpdate& ev) { cmd.new_track = std::monostate{}; } break; + case QueueUpdate::kBulkLoadingUpdate: + // Bulk loading updates are informational only; a separate QueueUpdate + // event will be sent when loading is done. case QueueUpdate::kDeserialised: - default: // The current track is deserialised separately in order to retain seek // position. + default: return; } @@ -151,7 +153,20 @@ void AudioState::react(const SetTrack& ev) { sStreamFactory->create(std::get(new_track), seek_to); } + // Always give the stream to the decoder, even if it turns out to be empty. + // This has the effect of stopping the current playback, which is generally + // what the user expects to happen when they say "Play this track!", even + // if the new track has an issue. sDecoder->open(stream); + + // ...but if the stream that failed is the front of the queue, then we + // should advance to the next track in order to keep the tunes flowing. + if (!stream) { + auto& queue = sServices->track_queue(); + if (new_track == queue.current()) { + queue.finish(); + } + } }); } @@ -183,18 +198,21 @@ void AudioState::react(const internal::DecodingFinished& ev) { sServices->bg_worker().Dispatch([=]() { auto& queue = sServices->track_queue(); auto current = queue.current(); - if (!current) { + if (std::holds_alternative(current)) { return; } auto db = sServices->database().lock(); if (!db) { return; } - auto path = db->getTrackPath(*current); - if (!path) { - return; + std::string path; + if (std::holds_alternative(current)) { + path = std::get(current); + } else if (std::holds_alternative(current)) { + auto tid = std::get(current); + path = db->getTrackPath(tid).value_or(""); } - if (*path == ev.track->uri) { + if (path == ev.track->uri) { queue.finish(); } }); @@ -208,6 +226,7 @@ void AudioState::react(const internal::StreamStarted& ev) { } sStreamCues.addCue(ev.track, ev.cue_at_sample); + sStreamCues.update(sDrainBuffer->totalReceived()); if (!sIsPaused && !is_in_state()) { transit(); @@ -223,13 +242,30 @@ void AudioState::react(const internal::StreamEnded& ev) { sStreamCues.addCue({}, ev.cue_at_sample); } +void AudioState::react(const system_fsm::HasPhonesChanged& ev) { + if (ev.has_headphones) { + events::Audio().Dispatch(audio::OutputModeChanged{ + .set_to = drivers::NvsStorage::Output::kHeadphones}); + } else { + if (sServices->bluetooth().enabled()) { + events::Audio().Dispatch(audio::OutputModeChanged{ + .set_to = drivers::NvsStorage::Output::kBluetooth}); + } + } +} + void AudioState::react(const system_fsm::BluetoothEvent& ev) { using drivers::bluetooth::SimpleEvent; if (std::holds_alternative(ev.event)) { auto simpleEvent = std::get(ev.event); switch (simpleEvent) { case SimpleEvent::kConnectionStateChanged: { - auto dev = sServices->bluetooth().ConnectedDevice(); + auto bt = sServices->bluetooth(); + if (bt.connectionState() != + drivers::Bluetooth::ConnectionState::kConnected) { + return; + } + auto dev = sServices->bluetooth().pairedDevice(); if (!dev) { return; } @@ -321,6 +357,9 @@ void AudioState::react(const SetVolumeBalance& ev) { void AudioState::react(const OutputModeChanged& ev) { ESP_LOGI(kTag, "output mode changed"); auto new_mode = sServices->nvs().OutputMode(); + if (ev.set_to) { + new_mode = *ev.set_to; + } sOutput->mode(IAudioOutput::Modes::kOff); switch (new_mode) { case drivers::NvsStorage::Output::kBluetooth: @@ -348,7 +387,7 @@ auto AudioState::commitVolume() -> void { if (mode == drivers::NvsStorage::Output::kHeadphones) { sServices->nvs().AmpCurrentVolume(vol); } else if (mode == drivers::NvsStorage::Output::kBluetooth) { - auto dev = sServices->bluetooth().ConnectedDevice(); + auto dev = sServices->bluetooth().pairedDevice(); if (!dev) { return; } @@ -385,7 +424,7 @@ void Uninitialised::react(const system_fsm::BootComplete& ev) { sOutput = sI2SOutput; } else { // Ensure Bluetooth gets enabled if it's the default sink. - sServices->bluetooth().Enable(); + sServices->bluetooth().enable(true); sOutput = sBtOutput; } sOutput->mode(IAudioOutput::Modes::kOnPaused); @@ -457,6 +496,9 @@ void Standby::react(const system_fsm::SdStateChanged& ev) { return; } + // Open the queue file + sServices->track_queue().open(); + // Restore the currently playing file before restoring the queue. This way, // we can fall back to restarting the queue's current track if there's any // issue restoring the current file. diff --git a/src/tangara/audio/audio_fsm.hpp b/src/tangara/audio/audio_fsm.hpp index 1e5184b5..134d9ffd 100644 --- a/src/tangara/audio/audio_fsm.hpp +++ b/src/tangara/audio/audio_fsm.hpp @@ -67,6 +67,7 @@ class AudioState : public tinyfsm::Fsm { virtual void react(const system_fsm::KeyLockChanged&){}; virtual void react(const system_fsm::SdStateChanged&) {} virtual void react(const system_fsm::BluetoothEvent&); + virtual void react(const system_fsm::HasPhonesChanged&); protected: auto emitPlaybackUpdate(bool paused) -> void; diff --git a/src/tangara/audio/bt_audio_output.cpp b/src/tangara/audio/bt_audio_output.cpp index 54547622..c6c64fd1 100644 --- a/src/tangara/audio/bt_audio_output.cpp +++ b/src/tangara/audio/bt_audio_output.cpp @@ -13,6 +13,7 @@ #include #include +#include "drivers/bluetooth.hpp" #include "esp_err.h" #include "esp_heap_caps.h" #include "freertos/portmacro.h" @@ -32,6 +33,8 @@ namespace audio { static constexpr uint16_t kVolumeRange = 60; +using ConnectionState = drivers::Bluetooth::ConnectionState; + BluetoothAudioOutput::BluetoothAudioOutput(drivers::Bluetooth& bt, drivers::OutputBuffers& bufs, tasks::WorkerPool& p) @@ -45,9 +48,9 @@ BluetoothAudioOutput::~BluetoothAudioOutput() {} auto BluetoothAudioOutput::changeMode(Modes mode) -> void { if (mode == Modes::kOnPlaying) { - bluetooth_.SetSources(&buffers_); + bluetooth_.sources(&buffers_); } else { - bluetooth_.SetSources(nullptr); + bluetooth_.sources(nullptr); } } @@ -60,7 +63,7 @@ auto BluetoothAudioOutput::SetVolume(uint16_t v) -> void { bg_worker_.Dispatch([&]() { float factor = pow(10, static_cast(kVolumeRange) * (volume_ - 100) / 100 / 20); - bluetooth_.SetVolumeFactor(factor); + bluetooth_.softVolume(factor); }); } @@ -95,7 +98,7 @@ auto BluetoothAudioOutput::SetVolumeDb(int_fast16_t val) -> bool { } auto BluetoothAudioOutput::AdjustVolumeUp() -> bool { - if (volume_ == 100 || !bluetooth_.IsConnected()) { + if (volume_ == 100) { return false; } volume_++; @@ -104,7 +107,7 @@ auto BluetoothAudioOutput::AdjustVolumeUp() -> bool { } auto BluetoothAudioOutput::AdjustVolumeDown() -> bool { - if (volume_ == 0 || !bluetooth_.IsConnected()) { + if (volume_ == 0) { return false; } volume_--; diff --git a/src/tangara/audio/playlist.cpp b/src/tangara/audio/playlist.cpp new file mode 100644 index 00000000..1436e2d2 --- /dev/null +++ b/src/tangara/audio/playlist.cpp @@ -0,0 +1,302 @@ +/* + * Copyright 2024 ailurux + * + * SPDX-License-Identifier: GPL-3.0-only + */ +#include "playlist.hpp" + +#include + +#include "esp_log.h" +#include "ff.h" + +#include "audio/playlist.hpp" +#include "database/database.hpp" + +namespace audio { + +[[maybe_unused]] static constexpr char kTag[] = "playlist"; + +Playlist::Playlist(const std::string& playlistFilepath) + : filepath_(playlistFilepath), + mutex_(), + total_size_(0), + pos_(-1), + file_open_(false), + file_error_(false), + offset_cache_(&memory::kSpiRamResource), + sample_size_(50) {} + +auto Playlist::open() -> bool { + std::unique_lock lock(mutex_); + if (file_open_) { + return true; + } + + FRESULT res = + f_open(&file_, filepath_.c_str(), FA_READ | FA_WRITE | FA_OPEN_ALWAYS); + if (res != FR_OK) { + ESP_LOGE(kTag, "failed to open file! res: %i", res); + return false; + } + file_open_ = true; + file_error_ = false; + + // Count the playlist size and build our offset cache. + countItems(); + // Advance to the first item. + skipToWithoutCache(0); + + return !file_error_; +} + +Playlist::~Playlist() { + if (file_open_) { + f_close(&file_); + } +} + +auto Playlist::filepath() const -> std::string { + return filepath_; +} + +auto Playlist::currentPosition() const -> size_t { + std::unique_lock lock(mutex_); + return pos_ < 0 ? 0 : pos_; +} + +auto Playlist::size() const -> size_t { + std::unique_lock lock(mutex_); + return total_size_; +} + +auto Playlist::value() const -> std::string { + std::unique_lock lock(mutex_); + return current_value_; +} + +auto Playlist::atEnd() const -> bool { + std::unique_lock lock(mutex_); + return pos_ + 1 >= total_size_; +} + +auto Playlist::next() -> void { + std::unique_lock lock(mutex_); + if (pos_ + 1 < total_size_ && !file_error_) { + advanceBy(1); + } +} + +auto Playlist::prev() -> void { + std::unique_lock lock(mutex_); + if (!file_error_) { + // Naive approach to see how that goes for now + skipToLocked(pos_ - 1); + } +} + +auto Playlist::skipTo(size_t position) -> void { + std::unique_lock lock(mutex_); + skipToLocked(position); +} + +auto Playlist::skipToLocked(size_t position) -> void { + if (!file_open_ || file_error_) { + return; + } + + // Check our cache and go to nearest entry + auto remainder = position % sample_size_; + auto quotient = (position - remainder) / sample_size_; + if (offset_cache_.size() <= quotient) { + skipToWithoutCache(position); + return; + } + + // Go to byte offset + auto entry = offset_cache_.at(quotient); + auto res = f_lseek(&file_, entry); + if (res != FR_OK) { + ESP_LOGW(kTag, "error seeking %u", res); + file_error_ = true; + return; + } + + // Count ahead entries. + advanceBy(remainder + 1); +} + +auto Playlist::skipToWithoutCache(size_t position) -> void { + if (position >= pos_) { + advanceBy(position - pos_); + } else { + pos_ = -1; + FRESULT res = f_rewind(&file_); + if (res != FR_OK) { + ESP_LOGW(kTag, "error rewinding %u", res); + file_error_ = true; + return; + } + advanceBy(position + 1); + } +} + +auto Playlist::countItems() -> void { + TCHAR buff[512]; + + for (;;) { + auto offset = f_tell(&file_); + auto next_item = nextItem(buff); + if (!next_item) { + break; + } + if (total_size_ % sample_size_ == 0) { + offset_cache_.push_back(offset); + } + total_size_++; + } + + f_rewind(&file_); +} + +auto Playlist::advanceBy(ssize_t amt) -> bool { + TCHAR buff[512]; + std::optional item; + + while (amt > 0) { + item = nextItem(buff); + if (!item) { + break; + } + pos_++; + amt--; + } + + if (item) { + current_value_ = *item; + } + + return amt == 0; +} + +auto Playlist::nextItem(std::span buf) + -> std::optional { + while (file_open_ && !file_error_ && !f_eof(&file_)) { + // FIXME: f_gets is quite slow (it does several very small reads instead of + // grabbing a whole sector at a time), and it doesn't work well for very + // long lines. We should do something smarter here. + TCHAR* str = f_gets(buf.data(), buf.size(), &file_); + if (str == NULL) { + ESP_LOGW(kTag, "Error consuming playlist file at offset %llu", + f_tell(&file_)); + file_error_ = true; + return {}; + } + + std::string_view line{str}; + if (line.starts_with("#")) { + continue; + } + if (line.ends_with('\n')) { + line = line.substr(0, line.size() - 1); + } + return line; + } + + // Got to EOF without reading a valid line. + return {}; +} + +MutablePlaylist::MutablePlaylist(const std::string& playlistFilepath) + : Playlist(playlistFilepath) {} + +auto MutablePlaylist::clear() -> bool { + std::unique_lock lock(mutex_); + + // Try to recover from any IO errors. + if (file_error_ && file_open_) { + file_error_ = false; + file_open_ = false; + f_close(&file_); + } + + FRESULT res; + if (file_open_) { + res = f_rewind(&file_); + if (res != FR_OK) { + ESP_LOGE(kTag, "error rewinding %u", res); + file_error_ = true; + return false; + } + res = f_truncate(&file_); + if (res != FR_OK) { + ESP_LOGE(kTag, "error truncating %u", res); + file_error_ = true; + return false; + } + } else { + res = f_open(&file_, filepath_.c_str(), + FA_READ | FA_WRITE | FA_CREATE_ALWAYS); + if (res != FR_OK) { + ESP_LOGE(kTag, "error opening file %u", res); + file_error_ = true; + return false; + } + file_open_ = true; + } + + total_size_ = 0; + current_value_.clear(); + offset_cache_.clear(); + pos_ = -1; + return true; +} + +auto MutablePlaylist::append(Item i) -> void { + std::unique_lock lock(mutex_); + if (!file_open_ || file_error_) { + return; + } + + auto offset = f_tell(&file_); + bool first_entry = current_value_.empty(); + + // Seek to end and append + auto end = f_size(&file_); + auto res = f_lseek(&file_, end); + if (res != FR_OK) { + ESP_LOGE(kTag, "Seek to end of file failed? Error %d", res); + file_error_ = true; + return; + } + + // TODO: Resolve paths for track id, etc + std::string path; + if (std::holds_alternative(i)) { + path = std::get(i); + f_printf(&file_, "%s\n", path.c_str()); + if (total_size_ % sample_size_ == 0) { + offset_cache_.push_back(end); + } + if (first_entry) { + current_value_ = path; + } + total_size_++; + } + + // Restore position + res = f_lseek(&file_, offset); + if (res != FR_OK) { + ESP_LOGE(kTag, "Failed to restore file position after append?"); + file_error_ = true; + return; + } + res = f_sync(&file_); + if (res != FR_OK) { + ESP_LOGE(kTag, "Failed to sync playlist file after append"); + file_error_ = true; + return; + } +} + +} // namespace audio diff --git a/src/tangara/audio/playlist.hpp b/src/tangara/audio/playlist.hpp new file mode 100644 index 00000000..ac62c82e --- /dev/null +++ b/src/tangara/audio/playlist.hpp @@ -0,0 +1,87 @@ + +/* + * Copyright 2024 ailurux + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include + +#include "ff.h" + +#include "database/database.hpp" +#include "database/track.hpp" + +namespace audio { + +/* + * Owns and manages a playlist file. + * Each line in the playlist file is the absolute filepath of the track to play. + * In order to avoid mapping to byte offsets, each line must contain only a + * filepath (ie, no comments are supported). This limitation may be removed + * later if benchmarks show that the file can be quickly scanned from 'bookmark' + * offsets. This is a subset of the m3u format and ideally will be + * import/exportable to and from this format, to better support playlists from + * beets import and other music management software. + */ +class Playlist { + public: + Playlist(const std::string& playlistFilepath); + virtual ~Playlist(); + using Item = + std::variant; + auto open() -> bool; + + auto filepath() const -> std::string; + auto currentPosition() const -> size_t; + auto size() const -> size_t; + auto value() const -> std::string; + auto atEnd() const -> bool; + + auto next() -> void; + auto prev() -> void; + auto skipTo(size_t position) -> void; + + protected: + const std::string filepath_; + + mutable std::mutex mutex_; + size_t total_size_; + ssize_t pos_; + + FIL file_; + bool file_open_; + bool file_error_; + + std::string current_value_; + + /* List of offsets determined by sample size */ + std::pmr::vector offset_cache_; + + /* + * How many tracks per offset saved (ie, a value of 100 means every 100 tracks + * the file offset is saved) This speeds up searches, especially in the case + * of shuffling a lot of tracks. + */ + const uint32_t sample_size_; + + private: + auto skipToLocked(size_t position) -> void; + auto countItems() -> void; + auto advanceBy(ssize_t amt) -> bool; + auto nextItem(std::span) -> std::optional; + auto skipToWithoutCache(size_t position) -> void; +}; + +class MutablePlaylist : public Playlist { + public: + MutablePlaylist(const std::string& playlistFilepath); + + auto clear() -> bool; + auto append(Item i) -> void; +}; + +} // namespace audio diff --git a/src/tangara/audio/processor.cpp b/src/tangara/audio/processor.cpp index 81858110..aa2604b5 100644 --- a/src/tangara/audio/processor.cpp +++ b/src/tangara/audio/processor.cpp @@ -1,69 +1,73 @@ /* - * Copyright 2023 jacqueline + * Copyright 2024 jacqueline * * SPDX-License-Identifier: GPL-3.0-only */ #include "audio/processor.hpp" -#include #include #include #include +#include #include #include -#include "audio/audio_events.hpp" -#include "audio/audio_sink.hpp" -#include "drivers/i2s_dac.hpp" -#include "drivers/pcm_buffer.hpp" +#include "assert.h" #include "esp_heap_caps.h" #include "esp_log.h" -#include "events/event_queue.hpp" +#include "esp_timer.h" #include "freertos/portmacro.h" #include "freertos/projdefs.h" +#include "audio/audio_events.hpp" +#include "audio/audio_sink.hpp" +#include "audio/i2s_audio_output.hpp" #include "audio/resample.hpp" +#include "drivers/i2s_dac.hpp" +#include "drivers/pcm_buffer.hpp" +#include "events/event_queue.hpp" #include "sample.hpp" #include "tasks.hpp" [[maybe_unused]] static constexpr char kTag[] = "mixer"; -static constexpr std::size_t kSampleBufferLength = - drivers::kI2SBufferLengthFrames * sizeof(sample::Sample) * 2; -static constexpr std::size_t kSourceBufferLength = kSampleBufferLength * 2; +static const size_t kSampleBufferLength = drivers::kI2SBufferLengthFrames * 2; +static const size_t kSourceBufferLength = kSampleBufferLength * 2; namespace audio { +/* + * The output format to convert all sources to. This is currently fixed because + * the Bluetooth output doesn't support runtime configuration of its input + * format. + */ +static const I2SAudioOutput::Format kTargetFormat{ + .sample_rate = 48000, + .num_channels = 2, + .bits_per_sample = 16, +}; + SampleProcessor::SampleProcessor(drivers::PcmBuffer& sink) - : commands_(xQueueCreate(1, sizeof(Args))), - resampler_(nullptr), - source_(xStreamBufferCreateWithCaps(kSourceBufferLength, - sizeof(sample::Sample) * 2, + : commands_(xQueueCreate(2, sizeof(Args))), + source_(xStreamBufferCreateWithCaps(kSourceBufferLength + 1, + sizeof(sample::Sample), MALLOC_CAP_DMA)), sink_(sink), - leftover_bytes_(0) { - input_buffer_ = { - reinterpret_cast(heap_caps_calloc( - kSampleBufferLength, sizeof(sample::Sample), MALLOC_CAP_DMA)), - kSampleBufferLength}; - input_buffer_as_bytes_ = {reinterpret_cast(input_buffer_.data()), - input_buffer_.size_bytes()}; - - resampled_buffer_ = { - reinterpret_cast(heap_caps_calloc( - kSampleBufferLength, sizeof(sample::Sample), MALLOC_CAP_DMA)), - kSampleBufferLength}; - + unprocessed_samples_(0) { tasks::StartPersistent([&]() { Main(); }); } SampleProcessor::~SampleProcessor() { vQueueDelete(commands_); - vStreamBufferDelete(source_); + vStreamBufferDeleteWithCaps(source_); } auto SampleProcessor::SetOutput(std::shared_ptr output) -> void { + // Make sure our fixed output format is valid. + assert(output->PrepareFormat(kTargetFormat) == kTargetFormat); + output->Configure(kTargetFormat); + // FIXME: We should add synchronisation here, but we should be careful // about not impacting performance given that the output will change only // very rarely (if ever). @@ -80,15 +84,30 @@ auto SampleProcessor::beginStream(std::shared_ptr track) -> void { xQueueSend(commands_, &args, portMAX_DELAY); } -auto SampleProcessor::continueStream(std::span input) -> void { +auto SampleProcessor::continueStream(std::span input) + -> std::span { + size_t bytes_sent = xStreamBufferSend(source_, input.data(), + input.size_bytes(), pdMS_TO_TICKS(100)); + if (!bytes_sent) { + // If nothing could be sent, then bail out early. We don't want to send a + // samples_available command with zero samples. + return input; + } + + // We should only ever be placing whole samples into the buffer. If half + // samples start being sent, then this indicates a serious bug somewhere. + size_t samples_sent = bytes_sent / sizeof(sample::Sample); + assert(samples_sent * sizeof(sample::Sample) == bytes_sent); + Args args{ .track = nullptr, - .samples_available = input.size(), + .samples_available = samples_sent, .is_end_of_stream = false, .clear_buffers = false, }; xQueueSend(commands_, &args, portMAX_DELAY); - xStreamBufferSend(source_, input.data(), input.size_bytes(), portMAX_DELAY); + + return input.subspan(samples_sent); } auto SampleProcessor::endStream(bool cancelled) -> void { @@ -101,152 +120,281 @@ auto SampleProcessor::endStream(bool cancelled) -> void { xQueueSend(commands_, &args, portMAX_DELAY); } +IRAM_ATTR auto SampleProcessor::Main() -> void { for (;;) { + // Block indefinitely if the processor is idle. Otherwise check briefly for + // new commands, then continue processing. + TickType_t wait = hasPendingWork() ? 0 : portMAX_DELAY; + Args args; - while (!xQueueReceive(commands_, &args, portMAX_DELAY)) { + if (xQueueReceive(commands_, &args, wait)) { + if (args.is_end_of_stream && args.clear_buffers) { + // The new command is telling us to clear our buffers! This includes + // discarding any commands that have backed up without being processed. + // Discard all the old commands, then immediately handle the end of + // stream. + while (!pending_commands_.empty()) { + Args discard = pending_commands_.front(); + pending_commands_.pop_front(); + discardCommand(discard); + } + handleEndStream(true); + } else { + pending_commands_.push_back(args); + } } - if (args.track) { - handleBeginStream(*args.track); - delete args.track; + // We need to finish flushing all processed samples before we can process + // more samples. + if (!output_buffer_.isEmpty() && flushOutputBuffer()) { + continue; } - if (args.samples_available) { - handleContinueStream(args.samples_available); + + // We need to finish processing all the samples we've been told about + // before we handle backed up commands. + if (unprocessed_samples_ && !processSamples(false)) { + continue; } - if (args.is_end_of_stream) { - handleEndStream(args.clear_buffers); + + while (!pending_commands_.empty()) { + args = pending_commands_.front(); + pending_commands_.pop_front(); + + if (args.track) { + handleBeginStream(*args.track); + delete args.track; + } + if (args.samples_available) { + unprocessed_samples_ += args.samples_available; + } + if (args.is_end_of_stream) { + if (processSamples(true) || args.clear_buffers) { + handleEndStream(args.clear_buffers); + } else { + // The output filled up while we were trying to flush the last + // samples of this stream, and we haven't been told to clear our + // buffers. Retry handling this command later. + pending_commands_.push_front(args); + break; + } + } } } } auto SampleProcessor::handleBeginStream(std::shared_ptr track) -> void { - if (track->format != source_format_) { - source_format_ = track->format; - // The new stream has a different format to the previous stream (or there - // was no previous stream). - // First, clean up our filters. - resampler_.reset(); - leftover_bytes_ = 0; - - // If the output is idle, then we can reconfigure it to the closest format - // to our new source. - // If the output *wasn't* idle, then we can't reconfigure without an - // audible gap in playback. So instead, we simply keep the same target - // format and begin resampling. - if (sink_.isEmpty()) { - target_format_ = output_->PrepareFormat(track->format); - output_->Configure(target_format_); + // If the new stream's sample rate doesn't match our canonical sample rate, + // then prepare to start resampling. + if (track->format.sample_rate != kTargetFormat.sample_rate) { + ESP_LOGI(kTag, "resampling %lu -> %lu", track->format.sample_rate, + kTargetFormat.sample_rate); + if (!resampler_ || resampler_->sourceRate() != track->format.sample_rate) { + // If there's already a resampler instance for this source rate, then + // reuse it to help gapless playback work smoothly. + resampler_.reset(new Resampler(track->format.sample_rate, + kTargetFormat.sample_rate, + track->format.num_channels)); } + } else { + resampler_.reset(); } + // If the new stream has only one channel, then we double it to get stereo + // audio. + // FIXME: If the Bluetooth stack allowed us to configure the number of + // channels, we could remove this. + double_samples_ = track->format.num_channels != kTargetFormat.num_channels; + events::Audio().Dispatch(internal::StreamStarted{ .track = track, - .sink_format = target_format_, + .sink_format = kTargetFormat, .cue_at_sample = sink_.totalSent(), }); } -auto SampleProcessor::handleContinueStream(size_t samples_available) -> void { - // Loop until we finish reading all the bytes indicated. There might be - // leftovers from each iteration, and from this process as a whole, - // depending on the resampling stage. - size_t bytes_read = 0; - size_t bytes_to_read = samples_available * sizeof(sample::Sample); - while (bytes_read < bytes_to_read) { - // First top up the input buffer, taking care not to overwrite anything - // remaining from a previous iteration. - size_t bytes_read_this_it = xStreamBufferReceive( - source_, input_buffer_as_bytes_.subspan(leftover_bytes_).data(), - std::min(input_buffer_as_bytes_.size() - leftover_bytes_, - bytes_to_read - bytes_read), - portMAX_DELAY); - bytes_read += bytes_read_this_it; - - // Calculate the number of whole samples that are now in the input buffer. - size_t bytes_in_buffer = bytes_read_this_it + leftover_bytes_; - size_t samples_in_buffer = bytes_in_buffer / sizeof(sample::Sample); - - size_t samples_used = handleSamples(input_buffer_.first(samples_in_buffer)); - - // Maybe the resampler didn't consume everything. Maybe the last few - // bytes we read were half a frame. Either way, we need to calculate the - // size of the remainder in bytes, then move it to the front of our - // buffer. - size_t bytes_used = samples_used * sizeof(sample::Sample); - assert(bytes_used <= bytes_in_buffer); - - leftover_bytes_ = bytes_in_buffer - bytes_used; - if (leftover_bytes_ > 0) { - std::memmove(input_buffer_as_bytes_.data(), - input_buffer_as_bytes_.data() + bytes_used, leftover_bytes_); - } - } -} +IRAM_ATTR +auto SampleProcessor::processSamples(bool finalise) -> bool { + for (;;) { + bool out_of_work = true; -auto SampleProcessor::handleSamples(std::span input) -> size_t { - if (source_format_ == target_format_) { - // The happiest possible case: the input format matches the output - // format already. - sink_.send(input); - return input.size(); - } + // First, fill up our input buffer with samples. + if (unprocessed_samples_ > 0) { + out_of_work = false; + auto input = input_buffer_.writeAcquire(); - size_t samples_used = 0; - while (samples_used < input.size()) { - std::span output_source; - if (source_format_.sample_rate != target_format_.sample_rate) { - if (resampler_ == nullptr) { - ESP_LOGI(kTag, "creating new resampler for %lu -> %lu", - source_format_.sample_rate, target_format_.sample_rate); - resampler_.reset(new Resampler(source_format_.sample_rate, - target_format_.sample_rate, - source_format_.num_channels)); - } + size_t bytes_received = xStreamBufferReceive( + source_, input.data(), + std::min(input.size_bytes(), + unprocessed_samples_ * sizeof(sample::Sample)), + 0); - size_t read, written; - std::tie(read, written) = resampler_->Process(input.subspan(samples_used), - resampled_buffer_, false); - samples_used += read; + // We should never receive a half sample. Blow up immediately if we do. + size_t samples_received = bytes_received / sizeof(sample::Sample); + assert(samples_received * sizeof(sample::Sample) == bytes_received); - if (read == 0 && written == 0) { - // Zero samples used or written. We need more input. - break; - } - output_source = resampled_buffer_.first(written); - } else { - output_source = input; - samples_used = input.size(); + unprocessed_samples_ -= samples_received; + input_buffer_.writeCommit(samples_received); } - sink_.send(output_source); - } + // Next, push input samples through the resampler. In the best case, this + // is a simple copy operation. + if (!input_buffer_.isEmpty()) { + out_of_work = false; + auto resample_input = input_buffer_.readAcquire(); + auto resample_output = resampled_buffer_.writeAcquire(); + + size_t read, wrote; + if (resampler_) { + std::tie(read, wrote) = + resampler_->Process(resample_input, resample_output, finalise); + } else { + read = wrote = std::min(resample_input.size(), resample_output.size()); + std::copy_n(resample_input.begin(), read, resample_output.begin()); + } - return samples_used; -} + input_buffer_.readCommit(read); + resampled_buffer_.writeCommit(wrote); + } -auto SampleProcessor::handleEndStream(bool clear_bufs) -> void { - if (resampler_ && !clear_bufs) { - size_t read, written; - std::tie(read, written) = resampler_->Process({}, resampled_buffer_, true); + // Next, we need to make sure the output is in stereo. This is also a simple + // copy in the best case. + if (!resampled_buffer_.isEmpty()) { + out_of_work = false; + auto channels_input = resampled_buffer_.readAcquire(); + auto channels_output = output_buffer_.writeAcquire(); + size_t read, wrote; + if (double_samples_) { + wrote = channels_output.size(); + read = wrote / 2; + if (read > channels_input.size()) { + read = channels_input.size(); + wrote = read * 2; + } + for (size_t i = 0; i < read; i++) { + channels_output[i * 2] = channels_input[i]; + channels_output[(i * 2) + 1] = channels_input[i]; + } + } else { + read = wrote = std::min(channels_input.size(), channels_output.size()); + std::copy_n(channels_input.begin(), read, channels_output.begin()); + } + resampled_buffer_.readCommit(read); + output_buffer_.writeCommit(wrote); + } - if (written > 0) { - sink_.send(resampled_buffer_.first(written)); + // Finally, flush whatever ended up in the output buffer. + if (flushOutputBuffer()) { + if (out_of_work) { + return true; + } + } else { + // The output is congested. Back off of processing for a moment. + return false; } } +} +auto SampleProcessor::handleEndStream(bool clear_bufs) -> void { if (clear_bufs) { sink_.clear(); - } - // FIXME: This discards any leftover samples, but there probably shouldn't be - // any leftover samples. Can this be an assert instead? - leftover_bytes_ = 0; + input_buffer_.clear(); + resampled_buffer_.clear(); + output_buffer_.clear(); + + size_t bytes_discarded = 0; + size_t bytes_to_discard = unprocessed_samples_ * sizeof(sample::Sample); + auto scratch_buf = output_buffer_.writeAcquire(); + while (bytes_discarded < bytes_to_discard) { + size_t bytes_read = + xStreamBufferReceive(source_, scratch_buf.data(), + std::min(scratch_buf.size_bytes(), + bytes_to_discard - bytes_discarded), + 0); + bytes_discarded += bytes_read; + } + unprocessed_samples_ = 0; + } events::Audio().Dispatch(internal::StreamEnded{ .cue_at_sample = sink_.totalSent(), }); } +auto SampleProcessor::hasPendingWork() -> bool { + return !pending_commands_.empty() || unprocessed_samples_ > 0 || + !input_buffer_.isEmpty() || !resampled_buffer_.isEmpty() || + !output_buffer_.isEmpty(); +} + +IRAM_ATTR +auto SampleProcessor::flushOutputBuffer() -> bool { + auto samples = output_buffer_.readAcquire(); + size_t sent = sink_.send(samples); + output_buffer_.readCommit(sent); + return output_buffer_.isEmpty(); +} + +auto SampleProcessor::discardCommand(Args& command) -> void { + if (command.track) { + delete command.track; + } + if (command.samples_available) { + unprocessed_samples_ += command.samples_available; + } + // End of stream commands can just be dropped without further action. +} + +SampleProcessor::Buffer::Buffer() + : buffer_(reinterpret_cast( + heap_caps_calloc(kSampleBufferLength, + sizeof(sample::Sample), + MALLOC_CAP_DMA)), + kSampleBufferLength), + samples_in_buffer_() {} + +SampleProcessor::Buffer::~Buffer() { + heap_caps_free(buffer_.data()); +} + +auto SampleProcessor::Buffer::writeAcquire() -> std::span { + return buffer_.subspan(samples_in_buffer_.size()); +} + +auto SampleProcessor::Buffer::writeCommit(size_t samples) -> void { + if (samples == 0) { + return; + } + samples_in_buffer_ = buffer_.first(samples + samples_in_buffer_.size()); +} + +auto SampleProcessor::Buffer::readAcquire() -> std::span { + return samples_in_buffer_; +} + +auto SampleProcessor::Buffer::readCommit(size_t samples) -> void { + if (samples == 0) { + return; + } + samples_in_buffer_ = samples_in_buffer_.subspan(samples); + + // Move the leftover samples to the front of the buffer, so that we're setup + // for a new write. + if (!samples_in_buffer_.empty()) { + std::memmove(buffer_.data(), samples_in_buffer_.data(), + samples_in_buffer_.size_bytes()); + samples_in_buffer_ = buffer_.first(samples_in_buffer_.size()); + } +} + +auto SampleProcessor::Buffer::isEmpty() -> bool { + return samples_in_buffer_.empty(); +} + +auto SampleProcessor::Buffer::clear() -> void { + samples_in_buffer_ = {}; +} + } // namespace audio diff --git a/src/tangara/audio/processor.hpp b/src/tangara/audio/processor.hpp index 5c4ad0fa..45e05291 100644 --- a/src/tangara/audio/processor.hpp +++ b/src/tangara/audio/processor.hpp @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include "audio/audio_events.hpp" @@ -33,18 +35,43 @@ class SampleProcessor { auto SetOutput(std::shared_ptr) -> void; + /* + * Signals to the sample processor that a new discrete stream of audio is now + * being sent. This will typically represent a new track being played. + */ auto beginStream(std::shared_ptr) -> void; - auto continueStream(std::span) -> void; + + /* + * Sends a span of PCM samples to the processor. Returns a subspan of the + * given span containing samples that were not able to be sent during this + * call, e.g. because of congestion downstream from the processor. + */ + auto continueStream(std::span) -> std::span; + + /* + * Signals to the sample processor that the current stream is ending. This + * can either be because the stream has naturally finished, or because it is + * being interrupted. + * If `cancelled` is false, the sample processor will ensure all previous + * samples are processed and sent before communicating the end of the stream + * onwards. If `cancelled` is true, any samples from the current stream that + * have not yet been played will be discarded. + */ auto endStream(bool cancelled) -> void; + SampleProcessor(const SampleProcessor&) = delete; + SampleProcessor& operator=(const SampleProcessor&) = delete; + private: auto Main() -> void; auto handleBeginStream(std::shared_ptr) -> void; - auto handleContinueStream(size_t samples_available) -> void; auto handleEndStream(bool cancel) -> void; - auto handleSamples(std::span) -> size_t; + auto processSamples(bool finalise) -> bool; + + auto hasPendingWork() -> bool; + auto flushOutputBuffer() -> bool; struct Args { std::shared_ptr* track; @@ -53,21 +80,49 @@ class SampleProcessor { bool clear_buffers; }; QueueHandle_t commands_; + std::list pending_commands_; - std::unique_ptr resampler_; + auto discardCommand(Args& command) -> void; StreamBufferHandle_t source_; drivers::PcmBuffer& sink_; - std::span input_buffer_; - std::span input_buffer_as_bytes_; + /* Internal utility for managing buffering samples between our filters. */ + class Buffer { + public: + Buffer(); + ~Buffer(); + + /* Returns a span of the unused space within the buffer. */ + auto writeAcquire() -> std::span; + /* Signals how many samples were just added to the writeAcquire span. */ + auto writeCommit(size_t) -> void; + + /* Returns a span of the samples stored within the buffer. */ + auto readAcquire() -> std::span; + /* Signals how many samples from the readAcquire span were consumed. */ + auto readCommit(size_t) -> void; - std::span resampled_buffer_; + auto isEmpty() -> bool; + auto clear() -> void; + + Buffer(const Buffer&) = delete; + Buffer& operator=(const Buffer&) = delete; + + private: + std::span buffer_; + std::span samples_in_buffer_; + }; + + Buffer input_buffer_; + Buffer resampled_buffer_; + Buffer output_buffer_; + + std::unique_ptr resampler_; + bool double_samples_; std::shared_ptr output_; - IAudioOutput::Format source_format_; - IAudioOutput::Format target_format_; - size_t leftover_bytes_; + size_t unprocessed_samples_; }; } // namespace audio diff --git a/src/tangara/audio/resample.cpp b/src/tangara/audio/resample.cpp index 143ce230..d6369022 100644 --- a/src/tangara/audio/resample.cpp +++ b/src/tangara/audio/resample.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ #include "audio/resample.hpp" +#include #include #include @@ -31,6 +32,7 @@ Resampler::Resampler(uint32_t source_sample_rate, kQuality, &err_)), num_channels_(num_channels) { + speex_resampler_skip_zeros(resampler_); assert(err_ == 0); } @@ -38,18 +40,24 @@ Resampler::~Resampler() { speex_resampler_destroy(resampler_); } +auto Resampler::sourceRate() -> uint32_t { + uint32_t input = 0; + uint32_t output = 0; + speex_resampler_get_rate(resampler_, &input, &output); + return input; +} + auto Resampler::Process(std::span input, std::span output, bool end_of_data) -> std::pair { - uint32_t samples_used = input.size() / num_channels_; - uint32_t samples_produced = output.size() / num_channels_; + uint32_t frames_used = input.size() / num_channels_; + uint32_t frames_produced = output.size() / num_channels_; int err = speex_resampler_process_interleaved_int( - resampler_, input.data(), &samples_used, output.data(), - &samples_produced); + resampler_, input.data(), &frames_used, output.data(), &frames_produced); assert(err == 0); - return {samples_used * num_channels_, samples_produced * num_channels_}; + return {frames_used * num_channels_, frames_produced * num_channels_}; } } // namespace audio diff --git a/src/tangara/audio/resample.hpp b/src/tangara/audio/resample.hpp index 4d48d47f..df285020 100644 --- a/src/tangara/audio/resample.hpp +++ b/src/tangara/audio/resample.hpp @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -24,6 +25,8 @@ class Resampler { ~Resampler(); + auto sourceRate() -> uint32_t; + auto Process(std::span input, std::span output, bool end_of_data) -> std::pair; diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 603b0de1..2c1faf96 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -26,7 +26,9 @@ #include "database/track.hpp" #include "events/event_queue.hpp" #include "memory_resource.hpp" +#include "random.hpp" #include "tasks.hpp" +#include "track_queue.hpp" #include "ui/ui_fsm.hpp" namespace audio { @@ -83,93 +85,119 @@ auto notifyChanged(bool current_changed, Reason reason) -> void { events::Audio().Dispatch(ev); } -TrackQueue::TrackQueue(tasks::WorkerPool& bg_worker) +TrackQueue::TrackQueue(tasks::WorkerPool& bg_worker, database::Handle db) : mutex_(), bg_worker_(bg_worker), - pos_(0), - tracks_(&memory::kSpiRamResource), + db_(db), + playlist_(".queue.playlist"), + position_(0), shuffle_(), repeat_(false), replay_(false) {} -auto TrackQueue::current() const -> std::optional { +auto TrackQueue::current() const -> TrackItem { const std::shared_lock lock(mutex_); - if (pos_ >= tracks_.size()) { + std::string val; + if (opened_playlist_ && position_ < opened_playlist_->size()) { + val = opened_playlist_->value(); + } else { + val = playlist_.value(); + } + if (val.empty()) { return {}; } - return tracks_[pos_]; + return val; } -auto TrackQueue::peekNext(std::size_t limit) const - -> std::vector { +auto TrackQueue::currentPosition() const -> size_t { const std::shared_lock lock(mutex_); - std::vector out; - for (size_t i = pos_ + 1; i < pos_ + limit + 1 && i < tracks_.size(); i++) { - out.push_back(i); + return position_; +} + +auto TrackQueue::totalSize() const -> size_t { + size_t sum = playlist_.size(); + if (opened_playlist_) { + sum += opened_playlist_->size(); } - return out; + return sum; } -auto TrackQueue::peekPrevious(std::size_t limit) const - -> std::vector { - const std::shared_lock lock(mutex_); - std::vector out; - for (size_t i = pos_ - 1; i < pos_ - limit - 1 && i >= tracks_.size(); i--) { - out.push_back(i); +auto TrackQueue::updateShuffler(bool andUpdatePosition) -> void { + if (shuffle_) { + shuffle_->resize(totalSize()); + if (andUpdatePosition) { + goTo(shuffle_->current()); + } } - return out; } -auto TrackQueue::currentPosition() const -> size_t { - const std::shared_lock lock(mutex_); - return pos_; +auto TrackQueue::open() -> bool { + // FIX ME: If playlist opening fails, should probably fall back to a vector of + // tracks or something so that we're not necessarily always needing mounted + // storage + return playlist_.open(); } -auto TrackQueue::totalSize() const -> size_t { - const std::shared_lock lock(mutex_); - return tracks_.size(); +auto TrackQueue::openPlaylist(const std::string& playlist_file, bool notify) + -> bool { + opened_playlist_.emplace(playlist_file); + auto res = opened_playlist_->open(); + if (!res) { + return false; + } + updateShuffler(true); + if (notify) { + notifyChanged(true, Reason::kExplicitUpdate); + } + return true; } -auto TrackQueue::insert(Item i, size_t index) -> void { +auto TrackQueue::getFilepath(database::TrackId id) + -> std::optional { + auto db = db_.lock(); + if (!db) { + return {}; + } + return db->getTrackPath(id); +} + +auto TrackQueue::append(Item i) -> void { bool was_queue_empty; bool current_changed; { const std::shared_lock lock(mutex_); - was_queue_empty = pos_ == tracks_.size(); - current_changed = was_queue_empty || index == pos_; + was_queue_empty = playlist_.currentPosition() >= playlist_.size(); + current_changed = was_queue_empty; // Dont support inserts yet } - auto update_shuffler = [=, this]() { - if (shuffle_) { - shuffle_->resize(tracks_.size()); - // If there wasn't anything already playing, then we should make sure we - // begin playback at a random point, instead of always starting with - // whatever was inserted first and *then* shuffling. - // We don't base this purely off of current_changed because we would like - // 'play this track now' (by inserting at the current pos) to work even - // when shuffling is enabled. - if (was_queue_empty) { - pos_ = shuffle_->current(); - } - } - }; - if (std::holds_alternative(i)) { { const std::unique_lock lock(mutex_); - if (index <= tracks_.size()) { - tracks_.insert(tracks_.begin() + index, std::get(i)); - update_shuffler(); + auto filename = getFilepath(std::get(i)).value_or(""); + if (!filename.empty()) { + playlist_.append(filename); } + updateShuffler(was_queue_empty); } notifyChanged(current_changed, Reason::kExplicitUpdate); + } else if (std::holds_alternative(i)) { + auto& path = std::get(i); + if (!path.empty()) { + { + const std::unique_lock lock(mutex_); + playlist_.append(std::get(i)); + updateShuffler(was_queue_empty); + } + notifyChanged(current_changed, Reason::kExplicitUpdate); + } } else if (std::holds_alternative(i)) { // Iterators can be very large, and retrieving items from them often // requires disk i/o. Handle them asynchronously so that inserting them // doesn't block. bg_worker_.Dispatch([=, this]() { database::TrackIterator it = std::get(i); - size_t working_pos = index; + + size_t next_update_at = 10; while (true) { auto next = *it; if (!next) { @@ -179,33 +207,61 @@ auto TrackQueue::insert(Item i, size_t index) -> void { // like current(). { const std::unique_lock lock(mutex_); - if (working_pos <= tracks_.size()) { - tracks_.insert(tracks_.begin() + working_pos, *next); + auto filename = getFilepath(*next).value_or(""); + if (!filename.empty()) { + playlist_.append(filename); } } - working_pos++; it++; + + // Appending very large iterators can take a while. Send out periodic + // queue updates during them so that the user has an idea what's going + // on. + if (!--next_update_at) { + next_update_at = util::sRandom->RangeInclusive(10, 20); + notifyChanged(false, Reason::kBulkLoadingUpdate); + } } + { const std::unique_lock lock(mutex_); - update_shuffler(); + updateShuffler(was_queue_empty); } notifyChanged(current_changed, Reason::kExplicitUpdate); }); } } -auto TrackQueue::append(Item i) -> void { - size_t end; +auto TrackQueue::next() -> void { + next(Reason::kExplicitUpdate); +} + +auto TrackQueue::currentPosition(size_t position) -> bool { { const std::shared_lock lock(mutex_); - end = tracks_.size(); + if (position >= totalSize()) { + return false; + } + goTo(position); } - insert(i, end); + + // If we're explicitly setting the position, we want to treat it as though + // the current track has changed, even if the position was the same + notifyChanged(true, Reason::kExplicitUpdate); + return true; } -auto TrackQueue::next() -> void { - next(Reason::kExplicitUpdate); +auto TrackQueue::goTo(size_t position) -> void { + position_ = position; + if (opened_playlist_) { + if (position_ < opened_playlist_->size()) { + opened_playlist_->skipTo(position_); + } else { + playlist_.skipTo(position_ - opened_playlist_->size()); + } + } else { + playlist_.skipTo(position_); + } } auto TrackQueue::next(Reason r) -> void { @@ -213,21 +269,19 @@ auto TrackQueue::next(Reason r) -> void { { const std::unique_lock lock(mutex_); + auto pos = position_; + if (shuffle_) { shuffle_->next(); - pos_ = shuffle_->current(); + position_ = shuffle_->current(); } else { - if (pos_ + 1 >= tracks_.size()) { - if (replay_) { - pos_ = 0; - } else { - pos_ = tracks_.size(); - changed = false; - } - } else { - pos_++; + if (position_ + 1 < totalSize()) { + position_++; } } + + goTo(position_); + changed = pos != position_; } notifyChanged(changed, r); @@ -240,18 +294,13 @@ auto TrackQueue::previous() -> void { const std::unique_lock lock(mutex_); if (shuffle_) { shuffle_->prev(); - pos_ = shuffle_->current(); + position_ = shuffle_->current(); } else { - if (pos_ == 0) { - if (repeat_) { - pos_ = tracks_.size() - 1; - } else { - changed = false; - } - } else { - pos_--; + if (position_ > 0) { + position_--; } } + goTo(position_); } notifyChanged(changed, Reason::kExplicitUpdate); @@ -265,39 +314,12 @@ auto TrackQueue::finish() -> void { } } -auto TrackQueue::skipTo(database::TrackId id) -> void { - // Defer this work to the background not because it's particularly - // long-running (although it could be), but because we want to ensure we - // only search for the given id after any previously pending iterator - // insertions have finished. - bg_worker_.Dispatch([=, this]() { - bool found = false; - { - const std::unique_lock lock(mutex_); - for (size_t i = 0; i < tracks_.size(); i++) { - if (tracks_[i] == id) { - pos_ = i; - found = true; - break; - } - } - } - if (found) { - notifyChanged(true, Reason::kExplicitUpdate); - } - }); -} - auto TrackQueue::clear() -> void { { const std::unique_lock lock(mutex_); - if (tracks_.empty()) { - return; - } - - pos_ = 0; - tracks_.clear(); - + position_ = 0; + playlist_.clear(); + opened_playlist_.reset(); if (shuffle_) { shuffle_->resize(0); } @@ -309,10 +331,8 @@ auto TrackQueue::clear() -> void { auto TrackQueue::random(bool en) -> void { { const std::unique_lock lock(mutex_); - // Don't check for en == true already; this has the side effect that - // repeated calls with en == true will re-shuffle. if (en) { - shuffle_.emplace(tracks_.size()); + shuffle_.emplace(totalSize()); shuffle_->replay(replay_); } else { shuffle_.reset(); @@ -360,15 +380,20 @@ auto TrackQueue::replay() const -> bool { auto TrackQueue::serialise() -> std::string { cppbor::Array tracks{}; - for (database::TrackId track : tracks_) { - tracks.add(cppbor::Uint(track)); - } cppbor::Map encoded; - encoded.add(cppbor::Uint{0}, cppbor::Array{ - cppbor::Uint{pos_}, - cppbor::Bool{repeat_}, - cppbor::Bool{replay_}, - }); + + cppbor::Array metadata{ + cppbor::Bool{repeat_}, + cppbor::Bool{replay_}, + cppbor::Uint{position_}, + }; + + if (opened_playlist_) { + metadata.add(cppbor::Tstr{opened_playlist_->filepath()}); + } + + encoded.add(cppbor::Uint{0}, std::move(metadata)); + if (shuffle_) { encoded.add(cppbor::Uint{1}, cppbor::Array{ cppbor::Uint{shuffle_->size()}, @@ -376,12 +401,11 @@ auto TrackQueue::serialise() -> std::string { cppbor::Uint{shuffle_->pos()}, }); } - encoded.add(cppbor::Uint{2}, std::move(tracks)); return encoded.toString(); } TrackQueue::QueueParseClient::QueueParseClient(TrackQueue& queue) - : queue_(queue), state_(State::kInit), i_(0) {} + : queue_(queue), state_(State::kInit), i_(0), position_to_set_(0) {} cppbor::ParseClient* TrackQueue::QueueParseClient::item( std::unique_ptr& item, @@ -401,9 +425,6 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::item( case 1: state_ = State::kShuffle; break; - case 2: - state_ = State::kTracks; - break; default: state_ = State::kFinished; } @@ -412,7 +433,13 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::item( if (item->type() == cppbor::ARRAY) { i_ = 0; } else if (item->type() == cppbor::UINT) { - queue_.pos_ = item->asUint()->unsignedValue(); + auto val = item->asUint()->unsignedValue(); + // Save the position so we can apply it later when we have finished + // serialising + position_to_set_ = val; + } else if (item->type() == cppbor::TSTR) { + auto val = item->asTstr(); + queue_.openPlaylist(val->value(), false); } else if (item->type() == cppbor::SIMPLE) { bool val = item->asBool()->value(); if (i_ == 0) { @@ -444,10 +471,6 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::item( } i_++; } - } else if (state_ == State::kTracks) { - if (item->type() == cppbor::UINT) { - queue_.tracks_.push_back(item->asUint()->unsignedValue()); - } } else if (state_ == State::kFinished) { } return this; @@ -461,6 +484,7 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::itemEnd( if (state_ == State::kInit) { state_ = State::kFinished; } else if (state_ == State::kRoot) { + queue_.goTo(position_to_set_); state_ = State::kFinished; } else if (state_ == State::kMetadata) { if (item->type() == cppbor::ARRAY) { @@ -470,10 +494,6 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::itemEnd( if (item->type() == cppbor::ARRAY) { state_ = State::kRoot; } - } else if (state_ == State::kTracks) { - if (item->type() == cppbor::ARRAY) { - state_ = State::kRoot; - } } else if (state_ == State::kFinished) { } return this; diff --git a/src/tangara/audio/track_queue.hpp b/src/tangara/audio/track_queue.hpp index 427d5f75..a8d1dc3a 100644 --- a/src/tangara/audio/track_queue.hpp +++ b/src/tangara/audio/track_queue.hpp @@ -16,6 +16,7 @@ #include "cppbor_parse.h" #include "database/database.hpp" #include "database/track.hpp" +#include "playlist.hpp" #include "tasks.hpp" namespace audio { @@ -64,27 +65,26 @@ class RandomIterator { */ class TrackQueue { public: - TrackQueue(tasks::WorkerPool& bg_worker); + TrackQueue(tasks::WorkerPool& bg_worker, database::Handle db); /* Returns the currently playing track. */ - auto current() const -> std::optional; - - /* Returns, in order, tracks that have been queued to be played next. */ - auto peekNext(std::size_t limit) const -> std::vector; - - /* - * Returns the tracks in the queue that have already been played, ordered - * most recently played first. - */ - auto peekPrevious(std::size_t limit) const -> std::vector; + using TrackItem = + std::variant; + auto current() const -> TrackItem; auto currentPosition() const -> size_t; + auto currentPosition(size_t position) -> bool; auto totalSize() const -> size_t; + auto open() -> bool; + auto openPlaylist(const std::string& playlist_file, bool notify = true) + -> bool; - using Item = std::variant; - auto insert(Item, size_t index = 0) -> void; + using Item = + std::variant; auto append(Item i) -> void; + auto updateShuffler(bool andUpdatePosition) -> void; + /* * Advances to the next track in the queue, placing the current track at the * front of the 'played' queue. @@ -97,8 +97,6 @@ class TrackQueue { */ auto finish() -> void; - auto skipTo(database::TrackId) -> void; - /* * Removes all tracks from all queues, and stops any currently playing track. */ @@ -122,13 +120,18 @@ class TrackQueue { private: auto next(QueueUpdate::Reason r) -> void; + auto goTo(size_t position) -> void; + auto getFilepath(database::TrackId id) -> std::optional; mutable std::shared_mutex mutex_; tasks::WorkerPool& bg_worker_; + database::Handle db_; - size_t pos_; - std::pmr::vector tracks_; + MutablePlaylist playlist_; + std::optional opened_playlist_; + + size_t position_; std::optional shuffle_; bool repeat_; @@ -159,11 +162,11 @@ class TrackQueue { kRoot, kMetadata, kShuffle, - kTracks, kFinished, }; State state_; size_t i_; + size_t position_to_set_; }; }; diff --git a/src/tangara/battery/battery.cpp b/src/tangara/battery/battery.cpp index 3cfdb20c..f68746ae 100644 --- a/src/tangara/battery/battery.cpp +++ b/src/tangara/battery/battery.cpp @@ -26,6 +26,8 @@ static const TickType_t kBatteryCheckPeriod = pdMS_TO_TICKS(60 * 1000); */ static const uint32_t kFullChargeMilliVolts = 4200; +static const uint32_t kCriticalChargeMilliVolts = 3500; + /* * Battery voltage, in millivolts, at which *we* will consider the battery to * be completely discharged. This is intentionally higher than the charger IC @@ -65,12 +67,35 @@ auto Battery::Update() -> void { // Ideally the way you're 'supposed' to measure battery charge percent is to // keep continuous track of the amps going in and out of it at any point. I'm // skeptical of this approach, and we're not set up with the hardware needed - // to do it anyway. Instead, we use a curve-fitting formula by StackOverflow - // user 'Roho' to estimate the remaining capacity based on the battery's - // voltage. This seems to work pretty good! - double v = mV / 1000.0; - uint_fast8_t percent = static_cast(std::clamp( - 123 - (123 / std::pow(1 + std::pow(v / 3.7, 80.0), 0.165)), 0.0, 100.0)); + // to do it anyway. Instead, we use a piecewise linear formula derived from + // voltage measurements of our actual cells. + uint_fast8_t percent; + if (mV > kCriticalChargeMilliVolts) { + // Above the 'critical' point, the relationship between battery voltage and + // charge percentage is close enough to linear. + percent = ((mV - kCriticalChargeMilliVolts) * 100 / + (kFullChargeMilliVolts - kCriticalChargeMilliVolts)) + + 5; + } else { + // Below the 'critical' point, battery voltage drops very very quickly. + // Give this part of the curve the lowest 5% to work with. + percent = (mV - kEmptyChargeMilliVolts) * 5 / + (kCriticalChargeMilliVolts - kEmptyChargeMilliVolts); + } + + // A full charge is always 100%. + if (charge_state == ChargeStatus::kFullCharge) { + percent = 100; + } + // Critical charge is always <= 5% + if (charge_state == ChargeStatus::kBatteryCritical) { + percent = std::min(percent, 5); + } + // When very close to full, the BMS transitions to a constant-voltage charge + // algorithm. Hold off on reporting 100% charge until this stage is finished. + if (percent >= 95 && charge_state != ChargeStatus::kFullCharge) { + percent = std::min(percent, 95); + } bool is_charging; if (!charge_state) { @@ -93,6 +118,8 @@ auto Battery::Update() -> void { .percent = percent, .millivolts = mV, .is_charging = is_charging, + .raw_status = + charge_state.value_or(drivers::Samd::ChargeStatus::kUnknown), }; EmitEvent(); } diff --git a/src/tangara/battery/battery.hpp b/src/tangara/battery/battery.hpp index 80b0f2d2..c4f631e0 100644 --- a/src/tangara/battery/battery.hpp +++ b/src/tangara/battery/battery.hpp @@ -27,6 +27,7 @@ class Battery { uint_fast8_t percent; uint32_t millivolts; bool is_charging; + drivers::Samd::ChargeStatus raw_status; bool operator==(const BatteryState& other) const { return percent == other.percent && is_charging == other.is_charging; diff --git a/src/tangara/database/database.cpp b/src/tangara/database/database.cpp index 85700431..64451f48 100644 --- a/src/tangara/database/database.cpp +++ b/src/tangara/database/database.cpp @@ -6,9 +6,6 @@ #include "database/database.hpp" -#include -#include - #include #include #include @@ -20,10 +17,8 @@ #include #include -#include "collation.hpp" #include "cppbor.h" #include "cppbor_parse.h" -#include "database/index.hpp" #include "esp_log.h" #include "esp_timer.h" #include "ff.h" @@ -37,13 +32,14 @@ #include "leveldb/status.h" #include "leveldb/write_batch.h" +#include "collation.hpp" #include "database/db_events.hpp" #include "database/env_esp.hpp" -#include "database/file_gatherer.hpp" +#include "database/index.hpp" #include "database/records.hpp" #include "database/tag_parser.hpp" #include "database/track.hpp" -#include "drivers/spi.hpp" +#include "database/track_finder.hpp" #include "events/event_queue.hpp" #include "memory_resource.hpp" #include "result.hpp" @@ -55,15 +51,19 @@ static SingletonEnv sEnv; [[maybe_unused]] static const char* kTag = "DB"; static const char kDbPath[] = "/.tangara-db"; +static const char kMusicPath[] = "Music"; static const char kKeyDbVersion[] = "schema_version"; - static const char kKeyCustom[] = "U\0"; static const char kKeyCollator[] = "collator"; -static const char kKeyTrackId[] = "next_track_id"; + +static constexpr size_t kMaxParallelism = 2; static std::atomic sIsDbOpen(false); +using std::placeholders::_1; +using std::placeholders::_2; + static auto CreateNewDatabase(leveldb::Options& options, locale::ICollator& col) -> leveldb::DB* { Database::Destroy(); @@ -122,8 +122,7 @@ static auto CheckDatabase(leveldb::DB& db, locale::ICollator& col) -> bool { return true; } -auto Database::Open(IFileGatherer& gatherer, - ITagParser& parser, +auto Database::Open(ITagParser& parser, locale::ICollator& collator, tasks::WorkerPool& bg_worker) -> cpp::result { @@ -144,10 +143,10 @@ auto Database::Open(IFileGatherer& gatherer, leveldb::Options options; options.env = sEnv.env(); - options.write_buffer_size = 4 * 1024; - options.max_file_size = 16 * 1024; + // Match the write buffer size to the MMU page size in order to + // make most efficient use of PSRAM mapping. + options.write_buffer_size = CONFIG_MMU_PAGE_SIZE; options.block_cache = cache.get(); - options.block_size = 2048; auto status = leveldb::DB::Open(options, kDbPath, &db); if (!status.ok()) { @@ -168,7 +167,7 @@ auto Database::Open(IFileGatherer& gatherer, } ESP_LOGI(kTag, "Database opened successfully"); - return new Database(db, cache.release(), gatherer, parser, + return new Database(db, cache.release(), bg_worker, parser, collator); }) .get(); @@ -182,15 +181,21 @@ auto Database::Destroy() -> void { Database::Database(leveldb::DB* db, leveldb::Cache* cache, - IFileGatherer& file_gatherer, + tasks::WorkerPool& pool, ITagParser& tag_parser, locale::ICollator& collator) : db_(db), cache_(cache), - file_gatherer_(file_gatherer), + track_finder_( + pool, + kMaxParallelism, + std::bind(&Database::processCandidateCallback, this, _1, _2), + std::bind(&Database::indexingCompleteCallback, this)), tag_parser_(tag_parser), collator_(collator), - is_updating_(false) {} + is_updating_(false) { + dbCalculateNextTrackId(); +} Database::~Database() { // Delete db_ first so that any outstanding background work finishes before @@ -244,7 +249,7 @@ auto Database::get(const std::string& key) -> std::optional { } auto Database::getTrackPath(TrackId id) -> std::optional { - auto track_data = dbGetTrackData(id); + auto track_data = dbGetTrackData(leveldb::ReadOptions(), id); if (!track_data) { return {}; } @@ -252,7 +257,7 @@ auto Database::getTrackPath(TrackId id) -> std::optional { } auto Database::getTrack(TrackId id) -> std::shared_ptr { - std::shared_ptr data = dbGetTrackData(id); + std::shared_ptr data = dbGetTrackData(leveldb::ReadOptions(), id); if (!data || data->is_tombstoned) { return {}; } @@ -275,34 +280,61 @@ auto Database::getIndexes() -> std::vector { }; } -class UpdateNotifier { - public: - UpdateNotifier(std::atomic& is_updating) : is_updating_(is_updating) { - events::Ui().Dispatch(event::UpdateStarted{}); - events::System().Dispatch(event::UpdateStarted{}); +Database::UpdateTracker::UpdateTracker() + : num_old_tracks_(0), + num_new_tracks_(0), + start_time_(esp_timer_get_time()) { + events::Ui().Dispatch(event::UpdateStarted{}); + events::System().Dispatch(event::UpdateStarted{}); +} + +Database::UpdateTracker::~UpdateTracker() { + uint64_t end_time = esp_timer_get_time(); + + uint64_t time_per_old = 0; + if (num_old_tracks_) { + time_per_old = (verification_finish_time_ - start_time_) / num_old_tracks_; } - ~UpdateNotifier() { - is_updating_ = false; - events::Ui().Dispatch(event::UpdateFinished{}); - events::System().Dispatch(event::UpdateFinished{}); + uint64_t time_per_new = 0; + if (num_new_tracks_) { + time_per_new = (end_time - verification_finish_time_) / num_new_tracks_; } - private: - std::atomic& is_updating_; -}; + ESP_LOGI( + kTag, + "processed %lu old tracks and %lu new tracks in %llu seconds (%llums " + "per old, %llums per new)", + num_old_tracks_, num_new_tracks_, (end_time - start_time_) / 1000000, + time_per_old / 1000, time_per_new / 1000); + + events::Ui().Dispatch(event::UpdateFinished{}); + events::System().Dispatch(event::UpdateFinished{}); +} + +auto Database::UpdateTracker::onTrackVerified() -> void { + events::Ui().Dispatch(event::UpdateProgress{ + .stage = event::UpdateProgress::Stage::kVerifyingExistingTracks, + .val = ++num_old_tracks_, + }); +} + +auto Database::UpdateTracker::onVerificationFinished() -> void { + verification_finish_time_ = esp_timer_get_time(); +} + +auto Database::UpdateTracker::onTrackAdded() -> void { + num_new_tracks_++; +} auto Database::updateIndexes() -> void { if (is_updating_.exchange(true)) { return; } - UpdateNotifier notifier{is_updating_}; - - uint32_t num_old_tracks = 0; - uint32_t num_new_tracks = 0; - uint64_t start_time = esp_timer_get_time(); + update_tracker_ = std::make_unique(); leveldb::ReadOptions read_options; - read_options.fill_cache = true; + read_options.fill_cache = false; + read_options.verify_checksums = true; // Stage 1: verify all existing tracks are still valid. ESP_LOGI(kTag, "verifying existing tracks"); @@ -311,11 +343,7 @@ auto Database::updateIndexes() -> void { std::string prefix = EncodeDataPrefix(); for (it->Seek(prefix); it->Valid() && it->key().starts_with(prefix); it->Next()) { - num_old_tracks++; - events::Ui().Dispatch(event::UpdateProgress{ - .stage = event::UpdateProgress::Stage::kVerifyingExistingTracks, - .val = num_old_tracks, - }); + update_tracker_->onTrackVerified(); std::shared_ptr track = ParseDataValue(it->value()); if (!track) { @@ -326,7 +354,6 @@ auto Database::updateIndexes() -> void { } if (track->is_tombstoned) { - ESP_LOGW(kTag, "skipping tombstoned %lx", track->id); continue; } @@ -349,11 +376,19 @@ auto Database::updateIndexes() -> void { // We couldn't read the tags for this track. Either they were // malformed, or perhaps the file is missing. Either way, tombstone // this record. - ESP_LOGW(kTag, "entombing missing #%lx", track->id); + ESP_LOGI(kTag, "entombing missing #%lx", track->id); + + // Remove the indexes first, so that interrupted operations don't leave + // dangling index records. dbRemoveIndexes(track); + + // Do the rest of the tombstoning as one atomic write. + leveldb::WriteBatch batch; track->is_tombstoned = true; - dbPutTrackData(*track); - db_->Delete(leveldb::WriteOptions{}, EncodePathKey(track->filepath)); + batch.Put(EncodeDataKey(track->id), EncodeDataValue(*track)); + batch.Delete(EncodePathKey(track->filepath)); + + db_->Write(leveldb::WriteOptions(), &batch); continue; } @@ -367,204 +402,181 @@ auto Database::updateIndexes() -> void { // database. ESP_LOGI(kTag, "updating hash (%llx -> %llx)", track->tags_hash, new_hash); + + // Again, we remove the old index records first so has to avoid + // dangling references. dbRemoveIndexes(track); + // Atomically correct the hash + create the new index records. + leveldb::WriteBatch batch; track->tags_hash = new_hash; - dbIngestTagHashes(*tags, track->individual_tag_hashes); - dbPutTrackData(*track); - dbPutHash(new_hash, track->id); + dbIngestTagHashes(*tags, track->individual_tag_hashes, batch); + + dbCreateIndexesForTrack(*track, *tags, batch); + batch.Put(EncodeDataKey(track->id), EncodeDataValue(*track)); + batch.Put(EncodeHashKey(new_hash), EncodeHashValue(track->id)); + db_->Write(leveldb::WriteOptions(), &batch); } } } - uint64_t verify_end_time = esp_timer_get_time(); + update_tracker_->onVerificationFinished(); // Stage 2: search for newly added files. - ESP_LOGI(kTag, "scanning for new tracks"); - uint64_t num_files = 0; - file_gatherer_.FindFiles("", [&](std::string_view path, const FILINFO& info) { - num_files++; - events::Ui().Dispatch(event::UpdateProgress{ - .stage = event::UpdateProgress::Stage::kScanningForNewTracks, - .val = num_files, - }); - - std::string unused; - if (db_->Get(read_options, EncodePathKey(path), &unused).ok()) { - // This file is already in the database; skip it. - return; - } - - std::shared_ptr tags = tag_parser_.ReadAndParseTags(path); - if (!tags || tags->encoding() == Container::kUnsupported) { - // No parseable tags; skip this fiile. - return; - } + std::string root; + FF_DIR dir; + if (f_opendir(&dir, kMusicPath) == FR_OK) { + f_closedir(&dir); + root = kMusicPath; + } + ESP_LOGI(kTag, "scanning for new tracks in '%s'", root.c_str()); + track_finder_.launch(root); +}; - // Check for any existing record with the same hash. - uint64_t hash = tags->Hash(); - std::string key = EncodeHashKey(hash); - std::optional existing_hash; - std::string raw_entry; - if (db_->Get(leveldb::ReadOptions(), key, &raw_entry).ok()) { - existing_hash = ParseHashValue(raw_entry); - } +auto Database::processCandidateCallback(FILINFO& info, std::string_view path) + -> void { + leveldb::ReadOptions read_options; + read_options.fill_cache = true; + read_options.verify_checksums = false; - std::pair modified{info.fdate, info.ftime}; - if (!existing_hash) { - // We've never met this track before! Or we have, but the entry is - // malformed. Either way, record this as a new track. - TrackId id = dbMintNewTrackId(); - ESP_LOGD(kTag, "recording new 0x%lx", id); - num_new_tracks++; - - auto data = std::make_shared(); - data->id = id; - data->filepath = path; - data->tags_hash = hash; - data->modified_at = modified; - dbIngestTagHashes(*tags, data->individual_tag_hashes); - - dbPutTrackData(*data); - dbPutHash(hash, id); - auto t = std::make_shared(data, tags); - dbCreateIndexesForTrack(*t); - db_->Put(leveldb::WriteOptions{}, EncodePathKey(path), - TrackIdToBytes(id)); - return; - } + std::string unused; + if (db_->Get(read_options, EncodePathKey(path), &unused).ok()) { + // This file is already in the database; skip it. + return; + } - std::shared_ptr existing_data = dbGetTrackData(*existing_hash); - if (!existing_data) { - // We found a hash that matches, but there's no data record? Weird. - auto new_data = std::make_shared(); - new_data->id = dbMintNewTrackId(); - new_data->filepath = path; - new_data->tags_hash = hash; - new_data->modified_at = modified; - dbIngestTagHashes(*tags, new_data->individual_tag_hashes); - dbPutTrackData(*new_data); - auto t = std::make_shared(new_data, tags); - dbCreateIndexesForTrack(*t); - db_->Put(leveldb::WriteOptions{}, EncodePathKey(path), - TrackIdToBytes(new_data->id)); - return; - } + std::shared_ptr tags = tag_parser_.ReadAndParseTags(path); + if (!tags || tags->encoding() == Container::kUnsupported) { + // No parseable tags; skip this fiile. + return; + } - if (existing_data->is_tombstoned) { - ESP_LOGI(kTag, "exhuming track %lu", existing_data->id); - existing_data->is_tombstoned = false; - existing_data->modified_at = modified; - dbPutTrackData(*existing_data); - auto t = std::make_shared(existing_data, tags); - dbCreateIndexesForTrack(*t); - db_->Put(leveldb::WriteOptions{}, EncodePathKey(path), - TrackIdToBytes(existing_data->id)); - } else if (existing_data->filepath != - std::pmr::string{path.data(), path.size()}) { + // Check for any existing track with the same hash. + uint64_t hash = tags->Hash(); + std::optional existing_id; + std::string raw_entry; + if (db_->Get(read_options, EncodeHashKey(hash), &raw_entry).ok()) { + existing_id = ParseHashValue(raw_entry); + } + + std::shared_ptr data; + if (existing_id) { + // Do we have any existing data for this track? This could be the case if + // this is a tombstoned entry. In such as case, we want to reuse the + // previous TrackData so that any extra metadata is preserved. + data = dbGetTrackData(read_options, *existing_id); + if (!data) { + data = std::make_shared(); + data->id = *existing_id; + } else if (data->filepath != path && !data->is_tombstoned) { ESP_LOGW(kTag, "hash collision: %s, %s, %s", tags->title().value_or("no title").c_str(), tags->artist().value_or("no artist").c_str(), tags->album().value_or("no album").c_str()); + // Don't commit anything if there's a hash collision, since we're + // likely to make a big mess. + return; } - }); + } else { + update_tracker_->onTrackAdded(); + data = std::make_shared(); + data->id = dbMintNewTrackId(); + } - uint64_t end_time = esp_timer_get_time(); + // Make sure the file-based metadata on the TrackData is up to date. + data->filepath = path; + data->tags_hash = hash; + data->modified_at = {info.fdate, info.ftime}; + data->is_tombstoned = false; - uint64_t time_per_old = 0; - if (num_old_tracks) { - time_per_old = (verify_end_time - start_time) / num_old_tracks; - } - uint64_t time_per_new = 0; - if (num_new_tracks) { - time_per_new = (end_time - verify_end_time) / num_new_tracks; - } + // Apply all the actual database changes as one atomic batch. This makes + // the whole 'new track' operation atomic, and also reduces the amount of + // lock contention when adding many tracks at once. + leveldb::WriteBatch batch; + dbIngestTagHashes(*tags, data->individual_tag_hashes, batch); - ESP_LOGI( - kTag, - "processed %lu old tracks and %lu new tracks in %llu seconds (%llums " - "per old, %llums per new)", - num_old_tracks, num_new_tracks, (end_time - start_time) / 1000000, - time_per_old / 1000, time_per_new / 1000); + dbCreateIndexesForTrack(*data, *tags, batch); + batch.Put(EncodeDataKey(data->id), EncodeDataValue(*data)); + batch.Put(EncodeHashKey(data->tags_hash), EncodeHashValue(data->id)); + batch.Put(EncodePathKey(path), TrackIdToBytes(data->id)); + + db_->Write(leveldb::WriteOptions(), &batch); +} + +auto Database::indexingCompleteCallback() -> void { + update_tracker_.reset(); + is_updating_ = false; } auto Database::isUpdating() -> bool { return is_updating_; } -auto Database::dbMintNewTrackId() -> TrackId { - TrackId next_id = 1; - std::string val; - auto status = db_->Get(leveldb::ReadOptions(), kKeyTrackId, &val); - if (status.ok()) { - next_id = BytesToTrackId(val).value_or(next_id); - } else if (!status.IsNotFound()) { - // TODO(jacqueline): Handle this more. - ESP_LOGE(kTag, "failed to get next track id"); +auto Database::dbCalculateNextTrackId() -> void { + std::unique_ptr it{ + db_->NewIterator(leveldb::ReadOptions())}; + + // Track data entries are of the format 'D/trackid', where track ids are + // encoded as big-endian cbor types. They can therefore be compared through + // byte ordering, which means we can determine what the next id should be by + // looking at the larged track data record in the database. + std::string prefix = EncodeDataPrefix(); + std::string prefixPlusOne = prefix; + prefixPlusOne[prefixPlusOne.size() - 1]++; + + // Seek to just past the track data section. + it->Seek(prefixPlusOne); + if (!it->Valid()) { + next_track_id_ = 1; + return; } - if (!db_->Put(leveldb::WriteOptions(), kKeyTrackId, - TrackIdToBytes(next_id + 1)) - .ok()) { - ESP_LOGE(kTag, "failed to write next track id"); + // Go back to the last track data record. + it->Prev(); + if (!it->Valid() || !it->key().starts_with(prefix)) { + next_track_id_ = 1; + return; } - return next_id; -} - -auto Database::dbEntomb(TrackId id, uint64_t hash) -> void { - std::string key = EncodeHashKey(hash); - std::string val = EncodeHashValue(id); - if (!db_->Put(leveldb::WriteOptions(), key, val).ok()) { - ESP_LOGE(kTag, "failed to entomb #%llx (id #%lx)", hash, id); + // Parse the track id back out of the key. + std::span key{it->key().data(), it->key().size()}; + auto id_part = key.subspan(prefix.size()); + if (id_part.empty()) { + next_track_id_ = 1; + return; } + + next_track_id_ = BytesToTrackId(id_part).value_or(0) + 1; } -auto Database::dbPutTrackData(const TrackData& s) -> void { - std::string key = EncodeDataKey(s.id); - std::string val = EncodeDataValue(s); - if (!db_->Put(leveldb::WriteOptions(), key, val).ok()) { - ESP_LOGE(kTag, "failed to write data for #%lx", s.id); - } +auto Database::dbMintNewTrackId() -> TrackId { + return next_track_id_++; } -auto Database::dbGetTrackData(TrackId id) -> std::shared_ptr { +auto Database::dbGetTrackData(leveldb::ReadOptions options, TrackId id) + -> std::shared_ptr { std::string key = EncodeDataKey(id); std::string raw_val; - if (!db_->Get(leveldb::ReadOptions(), key, &raw_val).ok()) { + if (!db_->Get(options, key, &raw_val).ok()) { ESP_LOGW(kTag, "no key found for #%lx", id); return {}; } return ParseDataValue(raw_val); } -auto Database::dbPutHash(const uint64_t& hash, TrackId i) -> void { - std::string key = EncodeHashKey(hash); - std::string val = EncodeHashValue(i); - if (!db_->Put(leveldb::WriteOptions(), key, val).ok()) { - ESP_LOGE(kTag, "failed to write hash for #%lx", i); - } +auto Database::dbCreateIndexesForTrack(const Track& track, + leveldb::WriteBatch& batch) -> void { + dbCreateIndexesForTrack(track.data(), track.tags(), batch); } -auto Database::dbGetHash(const uint64_t& hash) -> std::optional { - std::string key = EncodeHashKey(hash); - std::string raw_val; - if (!db_->Get(leveldb::ReadOptions(), key, &raw_val).ok()) { - ESP_LOGW(kTag, "no key found for hash #%llx", hash); - return {}; - } - return ParseHashValue(raw_val); -} - -auto Database::dbCreateIndexesForTrack(const Track& track) -> void { +auto Database::dbCreateIndexesForTrack(const TrackData& data, + const TrackTags& tags, + leveldb::WriteBatch& batch) -> void { for (const IndexInfo& index : getIndexes()) { - leveldb::WriteBatch writes; - auto entries = Index(collator_, index, track); + auto entries = Index(collator_, index, data, tags); for (const auto& it : entries) { - writes.Put(EncodeIndexKey(it.first), - {it.second.data(), it.second.size()}); + batch.Put(EncodeIndexKey(it.first), {it.second.data(), it.second.size()}); } - db_->Write(leveldb::WriteOptions(), &writes); } } @@ -573,9 +585,8 @@ auto Database::dbRemoveIndexes(std::shared_ptr data) -> void { if (!tags) { return; } - Track track{data, tags}; for (const IndexInfo& index : getIndexes()) { - auto entries = Index(collator_, index, track); + auto entries = Index(collator_, index, *data, *tags); for (auto it = entries.rbegin(); it != entries.rend(); it++) { auto key = EncodeIndexKey(it->first); auto status = db_->Delete(leveldb::WriteOptions{}, key); @@ -602,16 +613,14 @@ auto Database::dbRemoveIndexes(std::shared_ptr data) -> void { } auto Database::dbIngestTagHashes(const TrackTags& tags, - std::pmr::unordered_map& out) - -> void { - leveldb::WriteBatch batch{}; + std::pmr::unordered_map& out, + leveldb::WriteBatch& batch) -> void { for (const auto& tag : tags.allPresent()) { auto val = tags.get(tag); auto hash = tagHash(val); batch.Put(EncodeTagHashKey(hash), tagToString(val)); out[tag] = hash; } - db_->Write(leveldb::WriteOptions{}, &batch); } auto Database::dbRecoverTagsFromHashes( diff --git a/src/tangara/database/database.hpp b/src/tangara/database/database.hpp index c2e72568..18070353 100644 --- a/src/tangara/database/database.hpp +++ b/src/tangara/database/database.hpp @@ -19,23 +19,25 @@ #include "collation.hpp" #include "cppbor.h" -#include "database/file_gatherer.hpp" #include "database/index.hpp" #include "database/records.hpp" #include "database/tag_parser.hpp" #include "database/track.hpp" +#include "database/track_finder.hpp" +#include "ff.h" #include "leveldb/cache.h" #include "leveldb/db.h" #include "leveldb/iterator.h" #include "leveldb/options.h" #include "leveldb/slice.h" +#include "leveldb/write_batch.h" #include "memory_resource.hpp" #include "result.hpp" #include "tasks.hpp" namespace database { -const uint8_t kCurrentDbVersion = 6; +const uint8_t kCurrentDbVersion = 7; struct SearchKey; class Record; @@ -55,8 +57,7 @@ class Database { ALREADY_OPEN, FAILED_TO_OPEN, }; - static auto Open(IFileGatherer& file_gatherer, - ITagParser& tag_parser, + static auto Open(ITagParser& tag_parser, locale::ICollator& collator, tasks::WorkerPool& bg_worker) -> cpp::result; @@ -94,32 +95,59 @@ class Database { leveldb::DB* db_; leveldb::Cache* cache_; + TrackFinder track_finder_; + // Not owned. - IFileGatherer& file_gatherer_; ITagParser& tag_parser_; locale::ICollator& collator_; + /* Internal utility for tracking a currently in-progress index update. */ + class UpdateTracker { + public: + UpdateTracker(); + ~UpdateTracker(); + + auto onTrackVerified() -> void; + auto onVerificationFinished() -> void; + auto onTrackAdded() -> void; + + private: + uint32_t num_old_tracks_; + uint32_t num_new_tracks_; + uint64_t start_time_; + uint64_t verification_finish_time_; + }; + std::atomic is_updating_; + std::unique_ptr update_tracker_; + + std::atomic next_track_id_; Database(leveldb::DB* db, leveldb::Cache* cache, - IFileGatherer& file_gatherer, + tasks::WorkerPool& pool, ITagParser& tag_parser, locale::ICollator& collator); + auto processCandidateCallback(FILINFO&, std::string_view) -> void; + auto indexingCompleteCallback() -> void; + + auto dbCalculateNextTrackId() -> void; auto dbMintNewTrackId() -> TrackId; - auto dbEntomb(TrackId track, uint64_t hash) -> void; - auto dbPutTrackData(const TrackData& s) -> void; - auto dbGetTrackData(TrackId id) -> std::shared_ptr; - auto dbPutHash(const uint64_t& hash, TrackId i) -> void; - auto dbGetHash(const uint64_t& hash) -> std::optional; + auto dbGetTrackData(leveldb::ReadOptions, TrackId id) + -> std::shared_ptr; + + auto dbCreateIndexesForTrack(const Track&, leveldb::WriteBatch&) -> void; + auto dbCreateIndexesForTrack(const TrackData&, + const TrackTags&, + leveldb::WriteBatch&) -> void; - auto dbCreateIndexesForTrack(const Track& track) -> void; auto dbRemoveIndexes(std::shared_ptr) -> void; auto dbIngestTagHashes(const TrackTags&, - std::pmr::unordered_map&) -> void; + std::pmr::unordered_map&, + leveldb::WriteBatch&) -> void; auto dbRecoverTagsFromHashes(const std::pmr::unordered_map&) -> std::shared_ptr; diff --git a/src/tangara/database/file_gatherer.cpp b/src/tangara/database/file_gatherer.cpp deleted file mode 100644 index dd4b1138..00000000 --- a/src/tangara/database/file_gatherer.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#include "database/file_gatherer.hpp" - -#include -#include -#include -#include - -#include "ff.h" - -#include "drivers/spi.hpp" -#include "memory_resource.hpp" - -namespace database { - -static_assert(sizeof(TCHAR) == sizeof(char), "TCHAR must be CHAR"); - -auto FileGathererImpl::FindFiles( - const std::string& root, - std::function cb) -> void { - std::pmr::deque to_explore{&memory::kSpiRamResource}; - to_explore.push_back({root.data(), root.size()}); - - while (!to_explore.empty()) { - auto next_path_str = to_explore.front(); - to_explore.pop_front(); - - const TCHAR* next_path = static_cast(next_path_str.c_str()); - - FF_DIR dir; - FRESULT res = f_opendir(&dir, next_path); - if (res != FR_OK) { - // TODO: log. - continue; - } - - for (;;) { - FILINFO info; - res = f_readdir(&dir, &info); - if (res != FR_OK || info.fname[0] == 0) { - // No more files in the directory. - break; - } else if (info.fattrib & (AM_HID | AM_SYS) || info.fname[0] == '.') { - // System or hidden file. Ignore it and move on. - continue; - } else { - std::pmr::string full_path{&memory::kSpiRamResource}; - full_path += next_path_str; - full_path += "/"; - full_path += info.fname; - - if (info.fattrib & AM_DIR) { - // This is a directory. Add it to the explore queue. - to_explore.push_back(full_path); - } else { - // This is a file! Let the callback know about it. - // std::invoke(cb, full_path.str(), info); - std::invoke(cb, full_path, info); - } - } - } - - f_closedir(&dir); - } -} - -} // namespace database diff --git a/src/tangara/database/file_gatherer.hpp b/src/tangara/database/file_gatherer.hpp deleted file mode 100644 index 38558b9e..00000000 --- a/src/tangara/database/file_gatherer.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include -#include -#include -#include - -#include "ff.h" - -namespace database { - -class IFileGatherer { - public: - virtual ~IFileGatherer() {}; - - virtual auto FindFiles( - const std::string& root, - std::function cb) -> void = 0; -}; - -class FileGathererImpl : public IFileGatherer { - public: - virtual auto FindFiles(const std::string& root, - std::function - cb) -> void override; -}; - -} // namespace database diff --git a/src/tangara/database/index.cpp b/src/tangara/database/index.cpp index 93a2b1c2..dec458f4 100644 --- a/src/tangara/database/index.cpp +++ b/src/tangara/database/index.cpp @@ -52,10 +52,29 @@ const IndexInfo kAllAlbums{ .components = {Tag::kAlbum, Tag::kAlbumOrder}, }; +static auto titleOrFilename(const TrackData& data, const TrackTags& tags) + -> std::pmr::string { + auto title = tags.title(); + if (title) { + return *title; + } + auto start = data.filepath.find_last_of('/'); + if (start == std::pmr::string::npos) { + return data.filepath; + } + return data.filepath.substr(start + 1); +} + class Indexer { public: - Indexer(locale::ICollator& collator, const Track& t, const IndexInfo& idx) - : collator_(collator), track_(t), index_(idx) {} + Indexer(locale::ICollator& collator, + const IndexInfo& idx, + const TrackData& data, + const TrackTags& tags) + : collator_(collator), + index_(idx), + track_data_(data), + track_tags_(tags) {} auto index() -> std::vector>; @@ -70,14 +89,13 @@ class Indexer { auto missing_value(Tag tag) -> TagValue { switch (tag) { case Tag::kTitle: - return track_.TitleOrFilename(); + return titleOrFilename(track_data_, track_tags_); case Tag::kArtist: return "Unknown Artist"; case Tag::kAlbum: return "Unknown Album"; case Tag::kAlbumArtist: - return track_.tags().artist().value_or("Unknown Artist"); - return "Unknown Album"; + return track_tags_.artist().value_or("Unknown Artist"); case Tag::kGenres: return std::pmr::vector{}; case Tag::kDisc: @@ -91,8 +109,9 @@ class Indexer { } locale::ICollator& collator_; - const Track& track_; const IndexInfo index_; + const TrackData& track_data_; + const TrackTags& track_tags_; std::vector> out_; }; @@ -113,7 +132,7 @@ auto Indexer::index() -> std::vector> { auto Indexer::handleLevel(const IndexKey::Header& header, std::span components) -> void { Tag component = components.front(); - TagValue value = track_.tags().get(component); + TagValue value = track_tags_.get(component); if (std::holds_alternative(value)) { value = missing_value(component); } @@ -157,21 +176,17 @@ auto Indexer::handleItem(const IndexKey::Header& header, auto xfrm = collator_.Transform(value); key.item = {xfrm.data(), xfrm.size()}; } else if constexpr (std::is_same_v) { - value = std::to_string(arg); - // FIXME: this sucks lol. we should just write the number directly, - // LSB-first, but then we need to be able to parse it back properly. - std::ostringstream str; - str << std::setw(8) << std::setfill('0') << arg; - std::string encoded = str.str(); - key.item = {encoded.data(), encoded.size()}; + // CBOR's varint encoding actually works great for lexicographical + // sorting. + key.item = cppbor::Uint{arg}.toString(); } }, item); std::optional next_level; if (components.size() == 1) { - value = track_.TitleOrFilename(); - key.track = track_.data().id; + value = titleOrFilename(track_data_, track_tags_); + key.track = track_data_.id; } else { next_level = ExpandHeader(key.header, key.item); } @@ -183,10 +198,12 @@ auto Indexer::handleItem(const IndexKey::Header& header, } } -auto Index(locale::ICollator& c, - const IndexInfo& i, - const Track& t) -> std::vector> { - Indexer indexer{c, t, i}; +auto Index(locale::ICollator& collator, + const IndexInfo& index, + const TrackData& data, + const TrackTags& tags) + -> std::vector> { + Indexer indexer{collator, index, data, tags}; return indexer.index(); } diff --git a/src/tangara/database/index.hpp b/src/tangara/database/index.hpp index 8f78439b..bc01ec2f 100644 --- a/src/tangara/database/index.hpp +++ b/src/tangara/database/index.hpp @@ -63,7 +63,8 @@ struct IndexKey { auto Index(locale::ICollator&, const IndexInfo&, - const Track&) -> std::vector>; + const TrackData&, + const TrackTags&) -> std::vector>; auto ExpandHeader(const IndexKey::Header&, const std::optional&) -> IndexKey::Header; diff --git a/src/tangara/database/records.cpp b/src/tangara/database/records.cpp index 88ddbd91..17009cd8 100644 --- a/src/tangara/database/records.cpp +++ b/src/tangara/database/records.cpp @@ -19,6 +19,7 @@ #include "cppbor.h" #include "cppbor_parse.h" +#include "debug.hpp" #include "esp_log.h" #include "database/index.hpp" @@ -226,19 +227,15 @@ auto ParseIndexKey(const leveldb::Slice& slice) -> std::optional { return {}; } - std::istringstream in(key_data.substr(header_length + 1)); - std::stringbuf buffer{}; + key_data = key_data.substr(header_length + 1); + size_t last_sep = key_data.find_last_of('\0'); - in.get(buffer, kFieldSeparator); - if (buffer.str().size() > 0) { - result.item = buffer.str(); + if (last_sep > 0) { + result.item = key_data.substr(0, last_sep); } - buffer = {}; - in.get(buffer); - std::string id_str = buffer.str(); - if (id_str.size() > 1) { - result.track = BytesToTrackId(id_str.substr(1)); + if (last_sep + 1 < key_data.size()) { + result.track = BytesToTrackId(key_data.substr(last_sep + 1)); } return result; @@ -252,6 +249,7 @@ auto BytesToTrackId(std::span bytes) -> std::optional { auto [res, unused, err] = cppbor::parse( reinterpret_cast(bytes.data()), bytes.size()); if (!res || res->type() != cppbor::UINT) { + ESP_LOGE(kTag, "Track ID parsing failed!!"); return {}; } return res->asUint()->unsignedValue(); diff --git a/src/tangara/database/tag_parser.cpp b/src/tangara/database/tag_parser.cpp index d377adb1..a6a25555 100644 --- a/src/tangara/database/tag_parser.cpp +++ b/src/tangara/database/tag_parser.cpp @@ -6,14 +6,20 @@ #include "database/tag_parser.hpp" +#include #include #include +#include #include +#include #include +#include "database/track.hpp" +#include "debug.hpp" #include "drivers/spi.hpp" #include "esp_log.h" #include "ff.h" +#include "ogg/ogg.h" #include "tags.h" #include "memory_resource.hpp" @@ -106,10 +112,18 @@ static void toc(Tagctx* ctx, int ms, int offset) {} static const std::size_t kBufSize = 1024; [[maybe_unused]] static const char* kTag = "TAGS"; -TagParserImpl::TagParserImpl() {} +TagParserImpl::TagParserImpl() { + parsers_.emplace_back(new OggTagParser()); + parsers_.emplace_back(new GenericTagParser()); +} auto TagParserImpl::ReadAndParseTags(std::string_view path) -> std::shared_ptr { + if (path.empty()) { + return {}; + } + + // Check the cache first to see if we can skip parsing this file completely. { std::lock_guard lock{cache_mutex_}; std::optional> cached = @@ -119,7 +133,15 @@ auto TagParserImpl::ReadAndParseTags(std::string_view path) } } - std::shared_ptr tags = parseNew(path); + // Nothing in the cache; try each of our parsers. + std::shared_ptr tags; + for (auto& parser : parsers_) { + tags = parser->ReadAndParseTags(path); + if (tags) { + break; + } + } + if (!tags) { return {}; } @@ -135,6 +157,7 @@ auto TagParserImpl::ReadAndParseTags(std::string_view path) } } + // Store the result in the cache for later. { std::lock_guard lock{cache_mutex_}; cache_.Put({path.data(), path.size(), &memory::kSpiRamResource}, tags); @@ -143,7 +166,148 @@ auto TagParserImpl::ReadAndParseTags(std::string_view path) return tags; } -auto TagParserImpl::parseNew(std::string_view p) -> std::shared_ptr { +OggTagParser::OggTagParser() { + nameToTag_["TITLE"] = Tag::kTitle; + nameToTag_["ALBUM"] = Tag::kAlbum; + nameToTag_["ARTIST"] = Tag::kArtist; + nameToTag_["ALBUMARTIST"] = Tag::kAlbumArtist; + nameToTag_["TRACKNUMBER"] = Tag::kTrack; + nameToTag_["GENRE"] = Tag::kGenres; + nameToTag_["DISC"] = Tag::kDisc; +} + +auto OggTagParser::ReadAndParseTags(std::string_view p) + -> std::shared_ptr { + if (!p.ends_with(".ogg") && !p.ends_with(".opus") && !p.ends_with(".ogx")) { + return {}; + } + ogg_sync_state sync; + ogg_sync_init(&sync); + + ogg_page page; + ogg_stream_state stream; + bool stream_init = false; + + std::string path{p}; + FIL file; + if (f_open(&file, path.c_str(), FA_READ) != FR_OK) { + ESP_LOGW(kTag, "failed to open file '%s'", path.c_str()); + return {}; + } + + std::shared_ptr tags; + + // The comments packet is the second in the stream. This is *usually* the + // second page, sometimes overflowing onto the third page. There is no + // guarantee of this however, so we read the first five pages before giving + // up just in case. We don't try to read more pages than this as it could take + // quite some time, with no likely benefit. + for (int i = 0; i < 5; i++) { + // Load up the sync with data until we have a complete page. + while (ogg_sync_pageout(&sync, &page) != 1) { + char* buffer = ogg_sync_buffer(&sync, 512); + + UINT br; + FRESULT fres = f_read(&file, buffer, 512, &br); + if (fres != FR_OK || br == 0) { + goto finish; + } + + int res = ogg_sync_wrote(&sync, br); + if (res != 0) { + goto finish; + } + } + + // Ensure the stream has the correct serialno. pagein and packetout both + // give no results if the serialno is incorrect. + if (ogg_page_bos(&page)) { + ogg_stream_init(&stream, ogg_page_serialno(&page)); + stream_init = true; + } + + if (ogg_stream_pagein(&stream, &page) < 0) { + goto finish; + } + + // Try to pull out a packet. + ogg_packet packet; + if (ogg_stream_packetout(&stream, &packet) == 1) { + // We're interested in the second packet (packetno == 1) only. + if (packet.packetno < 1) { + continue; + } + if (packet.packetno > 1) { + goto finish; + } + + tags = TrackTags::create(); + if (memcmp(packet.packet, "OpusTags", 8) == 0) { + std::span data{packet.packet, + static_cast(packet.bytes)}; + tags->encoding(Container::kOpus); + parseComments(*tags, data.subspan(8)); + } else if (packet.packet[0] == 3 && + memcmp(packet.packet + 1, "vorbis", 6) == 0) { + std::span data{packet.packet, + static_cast(packet.bytes)}; + tags->encoding(Container::kOgg); + parseComments(*tags, data.subspan(7)); + } + break; + } + } + +finish: + if (stream_init) { + ogg_stream_clear(&stream); + } + ogg_sync_clear(&sync); + f_close(&file); + + return tags; +} + +auto OggTagParser::parseComments(TrackTags& res, std::span data) + -> void { + uint64_t vendor_len = parseLength(data); + uint64_t num_tags = parseLength(data.subspan(4 + vendor_len)); + + data = data.subspan(4 + vendor_len + 4); + for (size_t i = 0; i < num_tags; i++) { + uint64_t size = parseLength(data); + + std::string_view tag = { + reinterpret_cast(data.subspan(4).data()), + static_cast(size)}; + + auto split = tag.find("="); + + if (split != std::string::npos) { + std::string_view key = tag.substr(0, split); + std::string_view val = tag.substr(split + 1); + + std::string key_upper{key}; + std::transform(key.begin(), key.end(), key_upper.begin(), ::toupper); + + if (nameToTag_.contains(key_upper) && !val.empty()) { + res.set(nameToTag_[key_upper], val); + } + } + + data = data.subspan(4 + size); + } +} + +auto OggTagParser::parseLength(std::span data) -> uint64_t { + return static_cast(data[3]) << 24 | + static_cast(data[2]) << 16 | + static_cast(data[1]) << 8 | + static_cast(data[0]) << 0; +} + +auto GenericTagParser::ReadAndParseTags(std::string_view p) + -> std::shared_ptr { std::string path{p}; libtags::Aux aux; auto out = TrackTags::create(); @@ -151,7 +315,6 @@ auto TagParserImpl::parseNew(std::string_view p) -> std::shared_ptr { if (f_stat(path.c_str(), &aux.info) != FR_OK || f_open(&aux.file, path.c_str(), FA_READ) != FR_OK) { - ESP_LOGW(kTag, "failed to open file %s", path.c_str()); return {}; } diff --git a/src/tangara/database/tag_parser.hpp b/src/tangara/database/tag_parser.hpp index ccbc0ea9..642c4876 100644 --- a/src/tangara/database/tag_parser.hpp +++ b/src/tangara/database/tag_parser.hpp @@ -6,6 +6,7 @@ #pragma once +#include #include #include "database/track.hpp" @@ -27,7 +28,7 @@ class TagParserImpl : public ITagParser { -> std::shared_ptr override; private: - auto parseNew(std::string_view path) -> std::shared_ptr; + std::vector> parsers_; /* * Cache of tags that have already been extracted from files. Ideally this @@ -35,10 +36,25 @@ class TagParserImpl : public ITagParser { */ std::mutex cache_mutex_; util::LruCache<8, std::pmr::string, std::shared_ptr> cache_; +}; + +class OggTagParser : public ITagParser { + public: + OggTagParser(); + auto ReadAndParseTags(std::string_view path) + -> std::shared_ptr override; + + private: + auto parseComments(TrackTags&, std::span data) -> void; + auto parseLength(std::span data) -> uint64_t; + + std::unordered_map nameToTag_; +}; - // We could also consider keeping caches of artist name -> std::string and - // similar. This hasn't been done yet, as this isn't a common workload in - // any of our UI. +class GenericTagParser : public ITagParser { + public: + auto ReadAndParseTags(std::string_view path) + -> std::shared_ptr override; }; } // namespace database diff --git a/src/tangara/database/track.cpp b/src/tangara/database/track.cpp index 5bf8c3e2..cdb7543c 100644 --- a/src/tangara/database/track.cpp +++ b/src/tangara/database/track.cpp @@ -148,7 +148,7 @@ auto TrackTags::set(Tag t, std::string_view v) -> void { track(v); break; case Tag::kAlbumOrder: - // This tag is derices from disc and track, and so it can't be set. + // This tag is derived from disc and track, and so it can't be set. break; case Tag::kGenres: genres(v); @@ -293,15 +293,4 @@ auto TrackTags::Hash() const -> uint64_t { return komihash_stream_final(&stream); } -auto Track::TitleOrFilename() const -> std::pmr::string { - auto title = tags().title(); - if (title) { - return *title; - } - auto start = data().filepath.find_last_of('/'); - if (start == std::pmr::string::npos) { - return data().filepath; - } - return data().filepath.substr(start + 1); -} } // namespace database diff --git a/src/tangara/database/track.hpp b/src/tangara/database/track.hpp index b097ab52..6501e31f 100644 --- a/src/tangara/database/track.hpp +++ b/src/tangara/database/track.hpp @@ -195,8 +195,6 @@ class Track { auto data() const -> const TrackData& { return *data_; } auto tags() const -> const TrackTags& { return *tags_; } - auto TitleOrFilename() const -> std::pmr::string; - private: std::shared_ptr data_; std::shared_ptr tags_; diff --git a/src/tangara/database/track_finder.cpp b/src/tangara/database/track_finder.cpp new file mode 100644 index 00000000..21a44339 --- /dev/null +++ b/src/tangara/database/track_finder.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "database/track_finder.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "database/track_finder.hpp" +#include "ff.h" + +#include "drivers/spi.hpp" +#include "memory_resource.hpp" + +namespace database { + +static_assert(sizeof(TCHAR) == sizeof(char), "TCHAR must be CHAR"); + +CandidateIterator::CandidateIterator(std::string_view root) + : to_explore_(&memory::kSpiRamResource) { + to_explore_.push_back({root.data(), root.size()}); +} + +auto CandidateIterator::next(FILINFO& info) -> std::optional { + std::scoped_lock lock{mut_}; + while (!to_explore_.empty() || current_) { + if (!current_) { + current_.emplace(); + + // Get the next directory to iterate through. + current_->first = to_explore_.front(); + to_explore_.pop_front(); + const TCHAR* next_path = + static_cast(current_->first.data()); + + // Open it for iterating. + FRESULT res = f_opendir(¤t_->second, next_path); + if (res != FR_OK) { + current_.reset(); + continue; + } + } + + FRESULT res = f_readdir(¤t_->second, &info); + if (res != FR_OK || info.fname[0] == 0) { + // No more files in the directory. + f_closedir(¤t_->second); + current_.reset(); + continue; + } else if (info.fattrib & (AM_HID | AM_SYS) || info.fname[0] == '.') { + // System or hidden file. Ignore it and move on. + continue; + } else { + // A valid file or folder. + std::pmr::string full_path{&memory::kSpiRamResource}; + full_path += current_->first; + full_path += "/"; + full_path += info.fname; + + if (info.fattrib & AM_DIR) { + // This is a directory. Add it to the explore queue. + to_explore_.push_back(full_path); + } else { + // This is a file! We can return now. + return {{full_path.data(), full_path.size()}}; + } + } + } + + // Out of paths to explore. + return {}; +} + +TrackFinder::TrackFinder( + tasks::WorkerPool& pool, + size_t parallelism, + std::function processor, + std::function complete_cb) + : pool_{pool}, + parallelism_(parallelism), + processor_(processor), + complete_cb_(complete_cb) {} + +auto TrackFinder::launch(std::string_view root) -> void { + iterator_ = std::make_unique(root); + num_workers_ = parallelism_; + for (size_t i = 0; i < parallelism_; i++) { + schedule(); + } +} + +auto TrackFinder::schedule() -> void { + pool_.Dispatch([&]() { + FILINFO info; + auto next = iterator_->next(info); + if (next) { + std::invoke(processor_, info, *next); + schedule(); + } else { + std::scoped_lock lock{workers_mutex_}; + num_workers_ -= 1; + if (num_workers_ == 0) { + iterator_.reset(); + std::invoke(complete_cb_); + } + } + }); +} + +} // namespace database diff --git a/src/tangara/database/track_finder.hpp b/src/tangara/database/track_finder.hpp new file mode 100644 index 00000000..daaaa2f2 --- /dev/null +++ b/src/tangara/database/track_finder.hpp @@ -0,0 +1,77 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "ff.h" + +#include "tasks.hpp" + +namespace database { + +/* + * Iterator that recursively stats every file within the given directory root. + */ +class CandidateIterator { + public: + CandidateIterator(std::string_view root); + + /* + * Returns the next file. The stat result is placed within `out`. If the + * iterator has finished, returns absent. This method always modifies the + * contents of `out`, even if no file is returned. + */ + auto next(FILINFO& out) -> std::optional; + + // Cannot be copied or moved. + CandidateIterator(const CandidateIterator&) = delete; + CandidateIterator& operator=(const CandidateIterator&) = delete; + + private: + std::mutex mut_; + std::pmr::deque to_explore_; + std::optional> current_; +}; + +/* + * Utility for iterating through each file within a directory root. Iteration + * can be sharded across several tasks. + */ +class TrackFinder { + public: + TrackFinder(tasks::WorkerPool&, + size_t parallelism, + std::function processor, + std::function complete_cb); + + auto launch(std::string_view root) -> void; + + // Cannot be copied or moved. + TrackFinder(const TrackFinder&) = delete; + TrackFinder& operator=(const TrackFinder&) = delete; + + private: + tasks::WorkerPool& pool_; + const size_t parallelism_; + const std::function processor_; + const std::function complete_cb_; + + std::mutex workers_mutex_; + std::unique_ptr iterator_; + size_t num_workers_; + + auto schedule() -> void; +}; + +} // namespace database diff --git a/src/tangara/dev_console/console.cpp b/src/tangara/dev_console/console.cpp index a7f7a721..bc3a7aca 100644 --- a/src/tangara/dev_console/console.cpp +++ b/src/tangara/dev_console/console.cpp @@ -13,6 +13,7 @@ #include #include "esp_console.h" +#include "esp_intr_alloc.h" #include "esp_log.h" #include "esp_system.h" @@ -22,34 +23,47 @@ namespace console { int CmdLogLevel(int argc, char** argv) { static const std::pmr::string usage = - "usage: loglevel [VERBOSE,DEBUG,INFO,WARN,ERROR,NONE]"; - if (argc != 2) { + "usage: loglevel [tag] [VERBOSE,DEBUG,INFO,WARN,ERROR,NONE]"; + if (argc < 2 || argc > 3) { std::cout << usage << std::endl; return 1; } - std::pmr::string level_str = argv[1]; - std::transform(level_str.begin(), level_str.end(), level_str.begin(), + + std::string tag; + if (argc == 2) { + tag = "*"; + } else { + tag = argv[1]; + } + + std::string raw_level; + if (argc == 2) { + raw_level = argv[1]; + } else { + raw_level = argv[2]; + } + std::transform(raw_level.begin(), raw_level.end(), raw_level.begin(), [](unsigned char c) { return std::toupper(c); }); esp_log_level_t level; - if (level_str == "VERBOSE") { + if (raw_level == "VERBOSE") { level = ESP_LOG_VERBOSE; - } else if (level_str == "DEBUG") { + } else if (raw_level == "DEBUG") { level = ESP_LOG_DEBUG; - } else if (level_str == "INFO") { + } else if (raw_level == "INFO") { level = ESP_LOG_INFO; - } else if (level_str == "WARN") { + } else if (raw_level == "WARN") { level = ESP_LOG_WARN; - } else if (level_str == "ERROR") { + } else if (raw_level == "ERROR") { level = ESP_LOG_ERROR; - } else if (level_str == "NONE") { + } else if (raw_level == "NONE") { level = ESP_LOG_NONE; } else { std::cout << usage << std::endl; return 1; } - esp_log_level_set("*", level); + esp_log_level_set(tag.c_str(), level); return 0; } @@ -66,12 +80,34 @@ void RegisterLogLevel() { esp_console_cmd_register(&cmd); } +int CmdInterrupts(int argc, char** argv) { + static const std::pmr::string usage = "usage: intr"; + if (argc != 1) { + std::cout << usage << std::endl; + return 1; + } + esp_intr_dump(NULL); + return 0; +} + +void RegisterInterrupts() { + esp_console_cmd_t cmd{.command = "intr", + .help = "Dumps a table of all allocated interrupts", + .hint = NULL, + .func = &CmdInterrupts, + .argtable = NULL}; + esp_console_cmd_register(&cmd); + cmd.command = "interrupts"; + esp_console_cmd_register(&cmd); +} + Console::Console() {} Console::~Console() {} auto Console::RegisterCommonComponents() -> void { esp_console_register_help_command(); RegisterLogLevel(); + RegisterInterrupts(); } static Console* sInstance; diff --git a/src/tangara/input/input_device.hpp b/src/tangara/input/input_device.hpp index da2b31cd..7edded3e 100644 --- a/src/tangara/input/input_device.hpp +++ b/src/tangara/input/input_device.hpp @@ -32,6 +32,11 @@ class IInputDevice { virtual auto triggers() -> std::vector> { return {}; } + + /* Called by the LVGL driver when controls are being locked. */ + virtual auto onLock() -> void {} + /* Called by the LVGL driver when controls are being unlocked. */ + virtual auto onUnlock() -> void {} }; } // namespace input diff --git a/src/tangara/input/input_touch_wheel.cpp b/src/tangara/input/input_touch_wheel.cpp index b961bb02..a5069ae4 100644 --- a/src/tangara/input/input_touch_wheel.cpp +++ b/src/tangara/input/input_touch_wheel.cpp @@ -108,6 +108,15 @@ auto TouchWheel::triggers() return {centre_, up_, right_, down_, left_}; } +auto TouchWheel::onLock() -> void { + wheel_.LowPowerMode(true); +} + +auto TouchWheel::onUnlock() -> void { + wheel_.LowPowerMode(false); + wheel_.Recalibrate(); +} + auto TouchWheel::sensitivity() -> lua::Property& { return sensitivity_; } diff --git a/src/tangara/input/input_touch_wheel.hpp b/src/tangara/input/input_touch_wheel.hpp index cf86eced..d5cdbbfc 100644 --- a/src/tangara/input/input_touch_wheel.hpp +++ b/src/tangara/input/input_touch_wheel.hpp @@ -12,12 +12,12 @@ #include "indev/lv_indev.h" #include "drivers/haptics.hpp" +#include "drivers/nvs.hpp" +#include "drivers/touchwheel.hpp" #include "input/input_device.hpp" #include "input/input_hook.hpp" #include "input/input_trigger.hpp" #include "lua/property.hpp" -#include "drivers/nvs.hpp" -#include "drivers/touchwheel.hpp" namespace input { @@ -30,6 +30,9 @@ class TouchWheel : public IInputDevice { auto name() -> std::string override; auto triggers() -> std::vector> override; + auto onLock() -> void override; + auto onUnlock() -> void override; + auto sensitivity() -> lua::Property&; private: diff --git a/src/tangara/input/lvgl_input_driver.cpp b/src/tangara/input/lvgl_input_driver.cpp index 86f9b279..824e49cc 100644 --- a/src/tangara/input/lvgl_input_driver.cpp +++ b/src/tangara/input/lvgl_input_driver.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include "core/lv_group.h" @@ -132,6 +133,17 @@ auto LvglInputDriver::feedback(uint8_t event) -> void { } } +auto LvglInputDriver::lock(bool l) -> void { + is_locked_ = l; + for (auto&& device : inputs_) { + if (l) { + device->onLock(); + } else { + device->onUnlock(); + } + } +} + LvglInputDriver::LuaTrigger::LuaTrigger(LvglInputDriver& driver, IInputDevice& dev, TriggerHooks& trigger) diff --git a/src/tangara/input/lvgl_input_driver.hpp b/src/tangara/input/lvgl_input_driver.hpp index ddbdee55..9b62c24d 100644 --- a/src/tangara/input/lvgl_input_driver.hpp +++ b/src/tangara/input/lvgl_input_driver.hpp @@ -40,8 +40,7 @@ class LvglInputDriver { auto setGroup(lv_group_t*) -> void; auto read(lv_indev_data_t* data) -> void; auto feedback(uint8_t) -> void; - - auto lock(bool l) -> void { is_locked_ = l; } + auto lock(bool l) -> void; auto pushHooks(lua_State* L) -> int; diff --git a/src/tangara/lua/file_iterator.cpp b/src/tangara/lua/file_iterator.cpp index c3d63a16..71daf2d8 100644 --- a/src/tangara/lua/file_iterator.cpp +++ b/src/tangara/lua/file_iterator.cpp @@ -15,8 +15,8 @@ namespace lua { [[maybe_unused]] static const char* kTag = "FileIterator"; -FileIterator::FileIterator(std::string filepath) - : original_path_(filepath), current_(), offset_(-1) { +FileIterator::FileIterator(std::string filepath, bool showHidden) + : original_path_(filepath), show_hidden_(showHidden), current_(), offset_(-1) { const TCHAR* path = static_cast(filepath.c_str()); FRESULT res = f_opendir(&dir_, path); if (res != FR_OK) { @@ -33,7 +33,16 @@ auto FileIterator::value() const -> const std::optional& { } auto FileIterator::next() -> void { - iterate(false); + size_t prev_index = -1; + if (current_) { + prev_index = current_->index; + } + do { + bool res = iterate(show_hidden_); + if (!res) { + break; + } + } while (!current_ || current_->index == prev_index); } auto FileIterator::prev() -> void { @@ -45,11 +54,11 @@ auto FileIterator::prev() -> void { auto new_offset = offset_ - 1; offset_ = -1; for (int i = 0; i <= new_offset; i++) { - iterate(false); + iterate(show_hidden_); } } -auto FileIterator::iterate(bool reverse) -> bool { +auto FileIterator::iterate(bool show_hidden) -> bool { FILINFO info; auto res = f_readdir(&dir_, &info); if (res != FR_OK) { @@ -60,18 +69,21 @@ auto FileIterator::iterate(bool reverse) -> bool { // End of directory // Set value to nil current_.reset(); + return false; } else { // Update current value offset_++; - current_ = FileEntry{ - .index = offset_, - .isHidden = (info.fattrib & AM_HID) > 0, - .isDirectory = (info.fattrib & AM_DIR) > 0, - .isTrack = false, // TODO - .filepath = original_path_ + (original_path_.size() > 0 ? "/" : "") + - info.fname, - - }; + bool hidden = (info.fattrib & AM_HID) > 0 || info.fname[0] == '.'; + if (!hidden || show_hidden) { + current_ = FileEntry{ + .index = offset_, + .isHidden = hidden, + .isDirectory = (info.fattrib & AM_DIR) > 0, + .filepath = original_path_ + (original_path_.size() > 0 ? "/" : "") + + info.fname, + .name = info.fname, + }; + } } return true; } diff --git a/src/tangara/lua/file_iterator.hpp b/src/tangara/lua/file_iterator.hpp index b803062c..2d5c2d7d 100644 --- a/src/tangara/lua/file_iterator.hpp +++ b/src/tangara/lua/file_iterator.hpp @@ -19,13 +19,13 @@ struct FileEntry { int index; bool isHidden; bool isDirectory; - bool isTrack; std::string filepath; + std::string name; }; class FileIterator { public: - FileIterator(std::string filepath); + FileIterator(std::string filepath, bool showHidden); ~FileIterator(); auto value() const -> const std::optional&; @@ -35,6 +35,7 @@ class FileIterator { private: FF_DIR dir_; std::string original_path_; + bool show_hidden_; std::optional current_; int offset_; @@ -42,4 +43,4 @@ class FileIterator { auto iterate(bool reverse = false) -> bool; }; -} // namespace lua \ No newline at end of file +} // namespace lua diff --git a/src/tangara/lua/lua_filesystem.cpp b/src/tangara/lua/lua_filesystem.cpp index de51f555..9c2ea880 100644 --- a/src/tangara/lua/lua_filesystem.cpp +++ b/src/tangara/lua/lua_filesystem.cpp @@ -21,29 +21,21 @@ struct LuaFileEntry { bool isHidden; bool isDirectory; bool isTrack; - size_t path_size; - char path[]; + std::string path; + std::string name; }; -static_assert(std::is_trivially_destructible()); -static_assert(std::is_trivially_copy_assignable()); - static auto push_lua_file_entry(lua_State* L, const lua::FileEntry& r) -> void { - // Create and init the userdata. - LuaFileEntry* file_entry = reinterpret_cast( - lua_newuserdata(L, sizeof(LuaFileEntry) + r.filepath.size())); + lua::FileEntry** entry = reinterpret_cast( + lua_newuserdata(L, sizeof(uintptr_t))); + *entry = new lua::FileEntry(r); luaL_setmetatable(L, kFileEntryMetatable); +} - // Init all the fields - *file_entry = { - .isHidden = r.isHidden, - .isDirectory = r.isDirectory, - .isTrack = r.isTrack, - .path_size = r.filepath.size(), - }; - - // Copy the string data across. - std::memcpy(file_entry->path, r.filepath.data(), r.filepath.size()); +auto check_file_entry(lua_State* L, int stack_pos) -> lua::FileEntry* { + lua::FileEntry* entry = *reinterpret_cast( + luaL_checkudata(L, stack_pos, kFileEntryMetatable)); + return entry; } auto check_file_iterator(lua_State* L, int stack_pos) -> lua::FileIterator* { @@ -56,7 +48,7 @@ static auto push_iterator(lua_State* state, const lua::FileIterator& it) -> void { lua::FileIterator** data = reinterpret_cast( lua_newuserdata(state, sizeof(uintptr_t))); - *data = new lua::FileIterator(it); // TODO... + *data = new lua::FileIterator(it); luaL_setmetatable(state, kFileIteratorMetatable); } @@ -108,45 +100,48 @@ static const struct luaL_Reg kFileIteratorFuncs[] = {{"next", fs_iterate}, {NULL, NULL}}; static auto file_entry_path(lua_State* state) -> int { - LuaFileEntry* data = reinterpret_cast( - luaL_checkudata(state, 1, kFileEntryMetatable)); - lua_pushlstring(state, data->path, data->path_size); + lua::FileEntry* entry = check_file_entry(state, 1); + lua_pushlstring(state, entry->filepath.c_str(), entry->filepath.size()); return 1; } static auto file_entry_is_dir(lua_State* state) -> int { - LuaFileEntry* data = reinterpret_cast( - luaL_checkudata(state, 1, kFileEntryMetatable)); - lua_pushboolean(state, data->isDirectory); + lua::FileEntry* entry = check_file_entry(state, 1); + lua_pushboolean(state, entry->isDirectory); return 1; } static auto file_entry_is_hidden(lua_State* state) -> int { - LuaFileEntry* data = reinterpret_cast( - luaL_checkudata(state, 1, kFileEntryMetatable)); - lua_pushboolean(state, data->isHidden); + lua::FileEntry* entry = check_file_entry(state, 1); + lua_pushboolean(state, entry->isHidden); + return 1; +} + +static auto file_entry_name(lua_State* state) -> int { + lua::FileEntry* entry = check_file_entry(state, 1); + lua_pushlstring(state, entry->name.c_str(), entry->name.size()); return 1; } -static auto file_entry_is_track(lua_State* state) -> int { - LuaFileEntry* data = reinterpret_cast( - luaL_checkudata(state, 1, kFileEntryMetatable)); - lua_pushboolean(state, data->isTrack); +static auto file_entry_gc(lua_State* state) -> int { + lua::FileEntry* entry = check_file_entry(state, 1); + delete entry; return 1; } static const struct luaL_Reg kFileEntryFuncs[] = {{"filepath", file_entry_path}, + {"name", file_entry_name}, {"is_directory", file_entry_is_dir}, {"is_hidden", file_entry_is_hidden}, - {"is_track", file_entry_is_track}, - {"__tostring", file_entry_path}, + {"__tostring", file_entry_name}, + {"__gc", file_entry_gc}, {NULL, NULL}}; static auto fs_new_iterator(lua_State* state) -> int { // Takes a filepath as a string and returns a new FileIterator // on that directory std::string filepath = luaL_checkstring(state, -1); - lua::FileIterator iter(filepath); + lua::FileIterator iter(filepath, false); push_iterator(state, iter); return 1; } diff --git a/src/tangara/lua/lua_queue.cpp b/src/tangara/lua/lua_queue.cpp index bc393aa5..7eb32c62 100644 --- a/src/tangara/lua/lua_queue.cpp +++ b/src/tangara/lua/lua_queue.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ +#include "audio/audio_events.hpp" #include "lua/lua_database.hpp" #include @@ -39,6 +40,14 @@ static auto queue_add(lua_State* state) -> int { audio::TrackQueue& queue = instance->services().track_queue(); queue.append(id); }); + } else if (lua_isstring(state, 1)) { + size_t len; + const char* str = luaL_checklstring(state, 1, &len); + std::string path{str, len}; + instance->services().bg_worker().Dispatch([=]() { + audio::TrackQueue& queue = instance->services().track_queue(); + queue.append(path); + }); } else { database::Iterator* it = db_check_iterator(state, 1); instance->services().bg_worker().Dispatch([=]() { @@ -57,9 +66,24 @@ static auto queue_clear(lua_State* state) -> int { return 0; } -static const struct luaL_Reg kQueueFuncs[] = {{"add", queue_add}, - {"clear", queue_clear}, - {NULL, NULL}}; +static auto queue_open_playlist(lua_State* state) -> int { + Bridge* instance = Bridge::Get(state); + audio::TrackQueue& queue = instance->services().track_queue(); + size_t len = 0; + const char* str = luaL_checklstring(state, 1, &len); + if (!str) { + return 0; + } + queue.clear(); + queue.openPlaylist(str); + return 0; +} + +static const struct luaL_Reg kQueueFuncs[] = { + {"add", queue_add}, + {"clear", queue_clear}, + {"open_playlist", queue_open_playlist}, + {NULL, NULL}}; static auto lua_queue(lua_State* state) -> int { luaL_newlib(state, kQueueFuncs); diff --git a/src/tangara/lua/lua_screen.cpp b/src/tangara/lua/lua_screen.cpp index 8d87eebd..6bb26ec1 100644 --- a/src/tangara/lua/lua_screen.cpp +++ b/src/tangara/lua/lua_screen.cpp @@ -56,9 +56,9 @@ static auto screen_true(lua_State* state) -> int { } static const struct luaL_Reg kScreenFuncs[] = { - {"new", screen_new}, {"createUi", screen_noop}, - {"onShown", screen_noop}, {"onHidden", screen_noop}, - {"canPop", screen_true}, {NULL, NULL}}; + {"new", screen_new}, {"create_ui", screen_noop}, + {"on_show", screen_noop}, {"on_hide", screen_noop}, + {"can_pop", screen_true}, {NULL, NULL}}; static auto lua_screen(lua_State* state) -> int { luaL_newlib(state, kScreenFuncs); diff --git a/src/tangara/lua/lua_theme.cpp b/src/tangara/lua/lua_theme.cpp index 5edde104..03578778 100644 --- a/src/tangara/lua/lua_theme.cpp +++ b/src/tangara/lua/lua_theme.cpp @@ -75,8 +75,41 @@ static auto set_theme(lua_State* L) -> int { return 0; } + +static auto load_theme(lua_State* L) -> int { + std::string filename = luaL_checkstring(L, -1); + // Set the theme filename in non-volatile storage + Bridge* instance = Bridge::Get(L); + // Load the theme using lua + auto status = luaL_loadfile(L, filename.c_str()); + if (status != LUA_OK) { + lua_pushboolean(L, false); + return 1; + } + status = lua::CallProtected(L, 0, 1); + if (status == LUA_OK) { + ui::themes::Theme::instance()->Reset(); + set_theme(L); + instance->services().nvs().InterfaceTheme(filename); + lua_pushboolean(L, true); + } else { + lua_pushboolean(L, false); + } + + return 1; +} + +static auto theme_filename(lua_State* L) -> int { + Bridge* instance = Bridge::Get(L); + auto file = instance->services().nvs().InterfaceTheme().value_or("/lua/theme_light.lua"); + lua_pushstring(L, file.c_str()); + return 1; +} + static const struct luaL_Reg kThemeFuncs[] = {{"set", set_theme}, {"set_style", set_style}, + {"load_theme", load_theme}, + {"theme_filename", theme_filename}, {NULL, NULL}}; static auto lua_theme(lua_State* L) -> int { diff --git a/src/tangara/lua/property.cpp b/src/tangara/lua/property.cpp index 2b93809d..1be1fd2d 100644 --- a/src/tangara/lua/property.cpp +++ b/src/tangara/lua/property.cpp @@ -289,13 +289,14 @@ static void pushTrack(lua_State* L, const audio::TrackInfo& track) { lua_settable(L, -3); } -static void pushDevice(lua_State* L, const drivers::bluetooth::Device& dev) { +static void pushDevice(lua_State* L, + const drivers::bluetooth::MacAndName& dev) { lua_createtable(L, 0, 4); lua_pushliteral(L, "address"); auto* mac = reinterpret_cast( lua_newuserdata(L, sizeof(drivers::bluetooth::mac_addr_t))); - *mac = dev.address; + *mac = dev.mac; lua_rawset(L, -3); // What I just did there was perfectly safe. Look, I can prove it: @@ -308,14 +309,8 @@ static void pushDevice(lua_State* L, const drivers::bluetooth::Device& dev) { lua_pushlstring(L, dev.name.data(), dev.name.size()); lua_rawset(L, -3); - // FIXME: This field deserves a little more structure. - lua_pushliteral(L, "class"); - lua_pushinteger(L, dev.class_of_device); - lua_rawset(L, -3); - - lua_pushliteral(L, "signal_strength"); - lua_pushinteger(L, dev.signal_strength); - lua_rawset(L, -3); + // FIXME: Plumbing through device classes to here could be useful if we ever + // want to show cute little icons. } auto Property::pushValue(lua_State& s) -> int { @@ -332,10 +327,12 @@ auto Property::pushValue(lua_State& s) -> int { lua_pushstring(&s, arg.c_str()); } else if constexpr (std::is_same_v) { pushTrack(&s, arg); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { pushDevice(&s, arg); } else if constexpr (std::is_same_v< - T, std::vector>) { + T, + std::vector>) { lua_createtable(&s, arg.size(), 0); size_t i = 1; for (const auto& dev : arg) { @@ -364,48 +361,44 @@ auto popRichType(lua_State* L) -> LuaValue { lua_pushliteral(L, "name"); lua_gettable(L, -2); - std::pmr::string name = lua_tostring(L, -1); + std::string name = lua_tostring(L, -1); lua_pop(L, 1); - return drivers::bluetooth::Device{ - .address = mac, - .name = name, - .class_of_device = 0, - .signal_strength = 0, - }; + return drivers::bluetooth::MacAndName{.mac = mac, .name = name}; } return std::monostate{}; } auto Property::popValue(lua_State& s) -> bool { - LuaValue new_val; - switch (lua_type(&s, 2)) { - case LUA_TNIL: - new_val = std::monostate{}; - break; - case LUA_TNUMBER: - if (lua_isinteger(&s, 2)) { - new_val = lua_tointeger(&s, 2); - } else { - new_val = static_cast(std::round(lua_tonumber(&s, 2))); - } - break; - case LUA_TBOOLEAN: - new_val = static_cast(lua_toboolean(&s, 2)); - break; - case LUA_TSTRING: - new_val = lua_tostring(&s, 2); - break; - default: - if (lua_istable(&s, 2)) { - new_val = popRichType(&s); - if (std::holds_alternative(new_val)) { + LuaValue new_val{std::monostate{}}; + if (lua_gettop(&s) >= 2) { + switch (lua_type(&s, 2)) { + case LUA_TNIL: + break; + case LUA_TNUMBER: + if (lua_isinteger(&s, 2)) { + new_val = lua_tointeger(&s, 2); + } else { + new_val = static_cast(std::round(lua_tonumber(&s, 2))); + } + break; + case LUA_TBOOLEAN: + new_val = static_cast(lua_toboolean(&s, 2)); + break; + case LUA_TSTRING: + new_val = lua_tostring(&s, 2); + break; + default: + if (lua_istable(&s, 2)) { + new_val = popRichType(&s); + if (std::holds_alternative(new_val)) { + return false; + } + } else { return false; } - } else { - return false; - } + } } return set(new_val); diff --git a/src/tangara/lua/property.hpp b/src/tangara/lua/property.hpp index 9f925766..d45821bd 100644 --- a/src/tangara/lua/property.hpp +++ b/src/tangara/lua/property.hpp @@ -24,8 +24,8 @@ using LuaValue = std::variant>; + drivers::bluetooth::MacAndName, + std::vector>; using LuaFunction = std::function; diff --git a/src/tangara/system_fsm/booting.cpp b/src/tangara/system_fsm/booting.cpp index 9d505f81..1f99e3ab 100644 --- a/src/tangara/system_fsm/booting.cpp +++ b/src/tangara/system_fsm/booting.cpp @@ -87,7 +87,7 @@ auto Booting::entry() -> void { ESP_LOGI(kTag, "installing remaining drivers"); drivers::spiffs_mount(); - sServices->samd(std::unique_ptr(drivers::Samd::Create())); + sServices->samd(std::make_unique(sServices->nvs())); sServices->touchwheel( std::unique_ptr{drivers::TouchWheel::Create()}); sServices->haptics(std::make_unique(sServices->nvs())); @@ -96,16 +96,15 @@ auto Booting::entry() -> void { sServices->battery(std::make_unique( sServices->samd(), std::unique_ptr(adc))); - sServices->track_queue( - std::make_unique(sServices->bg_worker())); + sServices->track_queue(std::make_unique( + sServices->bg_worker(), sServices->database())); sServices->tag_parser(std::make_unique()); sServices->collator(locale::CreateCollator()); sServices->tts(std::make_unique()); ESP_LOGI(kTag, "init bluetooth"); sServices->bluetooth(std::make_unique( - sServices->nvs(), sServices->bg_worker())); - sServices->bluetooth().SetEventHandler(bt_event_cb); + sServices->nvs(), sServices->bg_worker(), bt_event_cb)); BootComplete ev{.services = sServices}; events::Audio().Dispatch(ev); diff --git a/src/tangara/system_fsm/idle.cpp b/src/tangara/system_fsm/idle.cpp index e499693d..2d66b01d 100644 --- a/src/tangara/system_fsm/idle.cpp +++ b/src/tangara/system_fsm/idle.cpp @@ -4,8 +4,9 @@ * SPDX-License-Identifier: GPL-3.0-only */ +#include "ui/ui_fsm.hpp" + #include "app_console/app_console.hpp" -#include "database/file_gatherer.hpp" #include "drivers/gpios.hpp" #include "freertos/portmacro.h" #include "freertos/projdefs.h" @@ -17,7 +18,6 @@ #include "events/event_queue.hpp" #include "system_fsm/system_events.hpp" #include "system_fsm/system_fsm.hpp" -#include "ui/ui_fsm.hpp" namespace system_fsm { namespace states { @@ -76,7 +76,7 @@ void Idle::react(const internal::IdleTimeout& ev) { // other state machines, etc. auto touchwheel = sServices->touchwheel(); if (touchwheel) { - touchwheel.value()->PowerDown(); + touchwheel.value()->LowPowerMode(true); } auto& gpios = sServices->gpios(); diff --git a/src/tangara/system_fsm/running.cpp b/src/tangara/system_fsm/running.cpp index c808e9da..07166e2f 100644 --- a/src/tangara/system_fsm/running.cpp +++ b/src/tangara/system_fsm/running.cpp @@ -8,7 +8,6 @@ #include "audio/audio_events.hpp" #include "database/database.hpp" #include "database/db_events.hpp" -#include "database/file_gatherer.hpp" #include "drivers/gpios.hpp" #include "drivers/spi.hpp" #include "ff.h" @@ -36,8 +35,6 @@ static void timer_callback(TimerHandle_t timer) { events::System().Dispatch(internal::UnmountTimeout{}); } -static database::IFileGatherer* sFileGatherer; - void Running::entry() { if (!sUnmountTimer) { sUnmountTimer = xTimerCreate("unmount_timeout", kTicksBeforeUnmount, false, @@ -174,10 +171,8 @@ auto Running::mountStorage() -> void { sStorage.reset(storage_res.value()); ESP_LOGI(kTag, "opening database"); - sFileGatherer = new database::FileGathererImpl(); - auto database_res = - database::Database::Open(*sFileGatherer, sServices->tag_parser(), - sServices->collator(), sServices->bg_worker()); + auto database_res = database::Database::Open( + sServices->tag_parser(), sServices->collator(), sServices->bg_worker()); if (database_res.has_error()) { unmountStorage(); return; @@ -193,6 +188,10 @@ auto Running::mountStorage() -> void { // mounted card. if (sServices->nvs().DbAutoIndex()) { sServices->bg_worker().Dispatch([&]() { + // Delay the index update for a bit, since we don't want to cause a lot + // of disk contention immediately after mounting (especially when we've + // just booted), or else we risk slowing down stuff like UI loading. + vTaskDelay(pdMS_TO_TICKS(6000)); auto db = sServices->database().lock(); if (!db) { return; diff --git a/src/tangara/test/CMakeLists.txt b/src/tangara/test/CMakeLists.txt index 728c06b0..58882f9f 100644 --- a/src/tangara/test/CMakeLists.txt +++ b/src/tangara/test/CMakeLists.txt @@ -3,5 +3,5 @@ # SPDX-License-Identifier: GPL-3.0-only idf_component_register( - SRC_DIRS "battery" + SRC_DIRS "battery" "audio" INCLUDE_DIRS "." REQUIRES catch2 cmock tangara fixtures) diff --git a/src/tangara/test/audio/test_playlist.cpp b/src/tangara/test/audio/test_playlist.cpp new file mode 100644 index 00000000..34a6bc56 --- /dev/null +++ b/src/tangara/test/audio/test_playlist.cpp @@ -0,0 +1,129 @@ +/* + * Copyright 2023 ailurux + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "audio/playlist.hpp" + +#include + +#include + +#include "catch2/catch.hpp" + +#include "drivers/gpios.hpp" +#include "drivers/i2c.hpp" +#include "drivers/spi.hpp" +#include "drivers/storage.hpp" +#include "ff.h" +#include "i2c_fixture.hpp" +#include "spi_fixture.hpp" + +namespace audio { + +static const std::string kTestFilename = "test_playlist2.m3u"; +static const std::string kTestFilePath = kTestFilename; + +TEST_CASE("playlist file", "[integration]") { + I2CFixture i2c; + SpiFixture spi; + std::unique_ptr gpios{drivers::Gpios::Create(false)}; + + if (gpios->Get(drivers::IGpios::Pin::kSdCardDetect)) { + // Skip if nothing is inserted. + SKIP("no sd card detected; skipping storage tests"); + return; + } + + { + std::unique_ptr result( + drivers::SdStorage::Create(*gpios).value()); + MutablePlaylist plist(kTestFilePath); + + SECTION("empty file appears empty") { + REQUIRE(plist.clear()); + + REQUIRE(plist.size() == 0); + REQUIRE(plist.currentPosition() == 0); + REQUIRE(plist.value().empty()); + } + + SECTION("write to the playlist file") { + plist.append("test1.mp3"); + plist.append("test2.mp3"); + plist.append("test3.mp3"); + plist.append("test4.wav"); + plist.append("directory/test1.mp3"); + plist.append("directory/test2.mp3"); + plist.append("a/really/long/directory/test1.mp3"); + plist.append("directory/and/another/test2.mp3"); + REQUIRE(plist.size() == 8); + + SECTION("read from the playlist file") { + Playlist plist2(kTestFilePath); + REQUIRE(plist2.open()); + REQUIRE(plist2.size() == 8); + REQUIRE(plist2.value() == "test1.mp3"); + plist2.next(); + REQUIRE(plist2.value() == "test2.mp3"); + plist2.prev(); + REQUIRE(plist2.value() == "test1.mp3"); + } + } + + REQUIRE(plist.clear()); + + size_t tracks = 0; + + BENCHMARK("appending items") { + plist.append("track " + std::to_string(plist.size())); + return tracks++; + }; + + BENCHMARK("opening large playlist file") { + Playlist plist2(kTestFilePath); + REQUIRE(plist2.open()); + REQUIRE(plist2.size() == tracks); + return plist2.size(); + }; + + BENCHMARK("seeking after appending a large file") { + REQUIRE(plist.size() == tracks); + + plist.skipTo(50); + REQUIRE(plist.value() == "track 50"); + plist.skipTo(99); + REQUIRE(plist.value() == "track 99"); + plist.skipTo(1); + REQUIRE(plist.value() == "track 1"); + + return plist.size(); + }; + + BENCHMARK("seeking after opening a large file") { + Playlist plist2(kTestFilePath); + REQUIRE(plist2.open()); + REQUIRE(plist.size() == tracks); + REQUIRE(tracks >= 100); + + plist.skipTo(50); + REQUIRE(plist.value() == "track 50"); + plist.skipTo(99); + REQUIRE(plist.value() == "track 99"); + plist.skipTo(1); + REQUIRE(plist.value() == "track 1"); + + return plist.size(); + }; + + BENCHMARK("opening a large file and appending") { + MutablePlaylist plist2(kTestFilePath); + REQUIRE(plist2.open()); + REQUIRE(plist2.size() >= 100); + plist2.append("A/Nother/New/Item.opus"); + return plist2.size(); + }; + } +} +} // namespace audio diff --git a/src/tangara/test/battery/test_battery.cpp b/src/tangara/test/battery/test_battery.cpp index 7b55bd59..cf6b19b0 100644 --- a/src/tangara/test/battery/test_battery.cpp +++ b/src/tangara/test/battery/test_battery.cpp @@ -26,9 +26,10 @@ class FakeAdc : public drivers::AdcBattery { TEST_CASE("battery charge state", "[unit]") { I2CFixture i2c; + std::unique_ptr nvs{drivers::NvsStorage::OpenSync()}; // FIXME: mock the SAMD21 as well. - std::unique_ptr samd{drivers::Samd::Create()}; + auto samd = std::make_unique(*nvs); FakeAdc* adc = new FakeAdc{}; // Freed by Battery. Battery battery{*samd, std::unique_ptr{adc}}; diff --git a/src/tangara/ui/lvgl_task.cpp b/src/tangara/ui/lvgl_task.cpp index e82aefc4..287f6b7e 100644 --- a/src/tangara/ui/lvgl_task.cpp +++ b/src/tangara/ui/lvgl_task.cpp @@ -38,6 +38,7 @@ UiTask::~UiTask() { assert(false); } +IRAM_ATTR auto UiTask::Main() -> void { ESP_LOGI(kTag, "start ui task"); lv_group_t* current_group = nullptr; diff --git a/src/tangara/ui/screen_lua.cpp b/src/tangara/ui/screen_lua.cpp index 301df143..b8d11ed7 100644 --- a/src/tangara/ui/screen_lua.cpp +++ b/src/tangara/ui/screen_lua.cpp @@ -29,7 +29,7 @@ Lua::~Lua() { } auto Lua::onShown() -> void { - callMethod("onShown"); + callMethod("on_show"); forEachBinding([&](lua::Binding* b) { b->active = true; lua::Binding::apply(s_, -1); @@ -37,7 +37,7 @@ auto Lua::onShown() -> void { } auto Lua::onHidden() -> void { - callMethod("onHidden"); + callMethod("on_hide"); forEachBinding([&](lua::Binding* b) { b->active = false; }); } @@ -46,7 +46,7 @@ auto Lua::canPop() -> bool { return true; } lua_rawgeti(s_, LUA_REGISTRYINDEX, *obj_ref_); - lua_pushliteral(s_, "canPop"); + lua_pushliteral(s_, "can_pop"); if (lua_gettable(s_, -2) == LUA_TFUNCTION) { // If we got a callback instead of a value, then invoke it to turn it into diff --git a/src/tangara/ui/screenshot.cpp b/src/tangara/ui/screenshot.cpp new file mode 100644 index 00000000..e4f9cc3f --- /dev/null +++ b/src/tangara/ui/screenshot.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2024 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "screenshot.hpp" +#include + +#include + +#define LODEPNG_NO_COMPILE_CPP +#include "libs/lodepng/lodepng.h" + +#include "esp_log.h" +#include "lvgl.h" + +namespace ui { + +[[maybe_unused]] static constexpr char kTag[] = "screenshot"; + +auto SaveScreenshot(lv_obj_t* obj, const std::string& path) -> void { + lv_draw_buf_t* buf = lv_snapshot_take(obj, LV_COLOR_FORMAT_RGB888); + if (!buf) { + return; + } + + // LVGL appears to output BGR data instead. Not quite sure why, but swapping + // each pair is quite easy. + for (size_t i = 0; i < buf->data_size; i += 3) { + uint8_t temp = buf->data[i]; + buf->data[i] = buf->data[i + 2]; + buf->data[i + 2] = temp; + } + + // The LVGL lodepng fork uses LVGL's file API, so an extra '/' is needed. + std::string fullpath = "//sdcard/" + path; + + auto res = lodepng_encode_file(fullpath.c_str(), buf->data, buf->header.w, + buf->header.h, LCT_RGB, 8); + + lv_draw_buf_destroy(buf); + if (res != 0) { + ESP_LOGE(kTag, "lodepng error: '%s'", lodepng_error_text(res)); + } +} + +} // namespace ui diff --git a/src/tangara/ui/screenshot.hpp b/src/tangara/ui/screenshot.hpp new file mode 100644 index 00000000..d19be0f0 --- /dev/null +++ b/src/tangara/ui/screenshot.hpp @@ -0,0 +1,17 @@ +/* + * Copyright 2024 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include + +#include "lvgl.h" + +namespace ui { + +auto SaveScreenshot(lv_obj_t* obj, const std::string& path) -> void; + +} diff --git a/src/tangara/ui/themes.cpp b/src/tangara/ui/themes.cpp index 726bd5f0..3d532d10 100644 --- a/src/tangara/ui/themes.cpp +++ b/src/tangara/ui/themes.cpp @@ -16,6 +16,7 @@ #include "widgets/bar/lv_bar.h" #include "widgets/button/lv_button.h" #include "widgets/slider/lv_slider.h" +#include "themes.hpp" namespace ui { namespace themes { @@ -81,6 +82,10 @@ void Theme::ApplyStyle(lv_obj_t* obj, std::string style_key) { } } +void Theme::Reset() { + style_map.clear(); +} + auto Theme::instance() -> Theme* { static Theme sTheme{}; return &sTheme; diff --git a/src/tangara/ui/themes.hpp b/src/tangara/ui/themes.hpp index fd576478..4826859e 100644 --- a/src/tangara/ui/themes.hpp +++ b/src/tangara/ui/themes.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include "lvgl.h" @@ -26,12 +27,15 @@ class Theme { void AddStyle(std::string key, int selector, lv_style_t* style); + void Reset(); + static auto instance() -> Theme*; private: Theme(); std::map>> style_map; lv_theme_t theme_; + std::optional filename_; }; } // namespace themes } // namespace ui diff --git a/src/tangara/ui/ui_events.hpp b/src/tangara/ui/ui_events.hpp index 05fd4483..0f371769 100644 --- a/src/tangara/ui/ui_events.hpp +++ b/src/tangara/ui/ui_events.hpp @@ -30,6 +30,10 @@ struct OnLuaError : tinyfsm::Event { struct DumpLuaStack : tinyfsm::Event {}; +struct Screenshot : tinyfsm::Event { + std::string filename; +}; + namespace internal { struct InitDisplay : tinyfsm::Event { diff --git a/src/tangara/ui/ui_fsm.cpp b/src/tangara/ui/ui_fsm.cpp index 7c4147a3..2009a888 100644 --- a/src/tangara/ui/ui_fsm.cpp +++ b/src/tangara/ui/ui_fsm.cpp @@ -7,11 +7,16 @@ #include "ui/ui_fsm.hpp" #include +#include #include #include #include #include "FreeRTOSConfig.h" +#include "draw/lv_draw_buf.h" +#include "drivers/bluetooth.hpp" +#include "lauxlib.h" +#include "lua.h" #include "lvgl.h" #include "core/lv_group.h" @@ -24,6 +29,9 @@ #include "freertos/projdefs.h" #include "lua.hpp" #include "luavgl.h" +#include "misc/lv_color.h" +#include "misc/lv_utils.h" +#include "others/snapshot/lv_snapshot.h" #include "tick/lv_tick.h" #include "tinyfsm.hpp" @@ -59,6 +67,7 @@ #include "ui/screen.hpp" #include "ui/screen_lua.hpp" #include "ui/screen_splash.hpp" +#include "ui/screenshot.hpp" #include "ui/ui_events.hpp" namespace ui { @@ -94,38 +103,72 @@ static auto lvgl_delay_cb(uint32_t ms) -> void { lua::Property UiState::sBatteryPct{0}; lua::Property UiState::sBatteryMv{0}; lua::Property UiState::sBatteryCharging{false}; +lua::Property UiState::sPowerChargeState{"unknown"}; +lua::Property UiState::sPowerFastChargeEnabled{ + false, [](const lua::LuaValue& val) { + if (!std::holds_alternative(val)) { + return false; + } + sServices->samd().SetFastChargeEnabled(std::get(val)); + return true; + }}; lua::Property UiState::sBluetoothEnabled{ false, [](const lua::LuaValue& val) { if (!std::holds_alternative(val)) { return false; } + // Note we always write the OutputMode NVS change before actually + // modifying the peripheral. We do this because ESP-IDF's Bluetooth stack + // breaks in surprising ways when repeatedly initialised/uninitialised. if (std::get(val)) { sServices->nvs().OutputMode(drivers::NvsStorage::Output::kBluetooth); - sServices->bluetooth().Enable(); + sServices->bluetooth().enable(true); } else { sServices->nvs().OutputMode(drivers::NvsStorage::Output::kHeadphones); - sServices->bluetooth().Disable(); + sServices->bluetooth().enable(false); } events::Audio().Dispatch(audio::OutputModeChanged{}); return true; }}; +lua::Property UiState::sBluetoothConnecting{false}; lua::Property UiState::sBluetoothConnected{false}; + +lua::Property UiState::sBluetoothDiscovering{ + false, [](const lua::LuaValue& val) { + if (!std::holds_alternative(val)) { + return false; + } + // Note we always write the OutputMode NVS change before actually + // modifying the peripheral. We do this because ESP-IDF's Bluetooth stack + // breaks in surprising ways when repeatedly initialised/uninitialised. + if (std::get(val)) { + sServices->bluetooth().discoveryEnabled(true); + } else { + sServices->bluetooth().discoveryEnabled(false); + } + return true; + }}; + lua::Property UiState::sBluetoothPairedDevice{ std::monostate{}, [](const lua::LuaValue& val) { - if (std::holds_alternative(val)) { - auto dev = std::get(val); - sServices->bluetooth().SetPreferredDevice( - drivers::bluetooth::MacAndName{ - .mac = dev.address, - .name = {dev.name.data(), dev.name.size()}, - }); + if (std::holds_alternative(val)) { + auto dev = std::get(val); + sServices->bluetooth().pairedDevice(dev); + } else if (std::holds_alternative(val)) { + sServices->bluetooth().pairedDevice({}); + } else { + // Don't accept any other types. + return false; } - return false; + return true; }}; -lua::Property UiState::sBluetoothDevices{ - std::vector{}}; + +lua::Property UiState::sBluetoothKnownDevices{ + std::vector{}}; +lua::Property UiState::sBluetoothDiscoveredDevices{ + std::vector{}}; lua::Property UiState::sPlaybackPlaying{ false, [](const lua::LuaValue& val) { @@ -158,7 +201,14 @@ lua::Property UiState::sPlaybackPosition{ return true; }}; -lua::Property UiState::sQueuePosition{0}; +lua::Property UiState::sQueuePosition{0, [](const lua::LuaValue& val){ + if (!std::holds_alternative(val)) { + return false; + } + int new_val = std::get(val); + // val-1 because Lua uses 1-based indexing + return sServices->track_queue().currentPosition(new_val-1); + }}; lua::Property UiState::sQueueSize{0}; lua::Property UiState::sQueueRepeat{false, [](const lua::LuaValue& val) { if (!std::holds_alternative(val)) { @@ -184,6 +234,7 @@ lua::Property UiState::sQueueRandom{false, [](const lua::LuaValue& val) { sServices->track_queue().random(new_val); return true; }}; +lua::Property UiState::sQueueLoading{false}; lua::Property UiState::sVolumeCurrentPct{ 0, [](const lua::LuaValue& val) { @@ -336,6 +387,13 @@ int UiState::PopScreen() { return sScreens.size(); } +void UiState::react(const Screenshot& ev) { + if (!sCurrentScreen) { + return; + } + SaveScreenshot(sCurrentScreen->root(), ev.filename); +} + void UiState::react(const system_fsm::KeyLockChanged& ev) { sDisplay->SetDisplayOn(!ev.locking); sInput->lock(ev.locking); @@ -367,20 +425,39 @@ void UiState::react(const system_fsm::BatteryStateChanged& ev) { sBatteryPct.setDirect(static_cast(ev.new_state.percent)); sBatteryMv.setDirect(static_cast(ev.new_state.millivolts)); sBatteryCharging.setDirect(ev.new_state.is_charging); + sPowerChargeState.setDirect( + drivers::Samd::chargeStatusToString(ev.new_state.raw_status)); + + // FIXME: Avoid calling these event handlers before boot. + if (sServices) { + sPowerFastChargeEnabled.setDirect(sServices->nvs().FastCharge()); + } } -void UiState::react(const audio::QueueUpdate&) { +void UiState::react(const audio::QueueUpdate& update) { auto& queue = sServices->track_queue(); - sQueueSize.setDirect(static_cast(queue.totalSize())); + auto queue_size = queue.totalSize(); + sQueueSize.setDirect(static_cast(queue_size)); int current_pos = queue.currentPosition(); - if (queue.current()) { + // If there is nothing in the queue, the position should be 0, otherwise, add + // one because lua + if (queue_size > 0) { current_pos++; } + if (current_pos > queue_size) { + current_pos = queue_size; + } sQueuePosition.setDirect(current_pos); sQueueRandom.setDirect(queue.random()); sQueueRepeat.setDirect(queue.repeat()); sQueueReplay.setDirect(queue.replay()); + + if (update.reason == audio::QueueUpdate::Reason::kBulkLoadingUpdate) { + sQueueLoading.setDirect(true); + } else { + sQueueLoading.setDirect(false); + } } void UiState::react(const audio::PlaybackUpdate& ev) { @@ -412,8 +489,13 @@ void UiState::react(const audio::VolumeLimitChanged& ev) { void UiState::react(const system_fsm::BluetoothEvent& ev) { using drivers::bluetooth::SimpleEvent; + using ConnectionState = drivers::Bluetooth::ConnectionState; + ConnectionState state; auto bt = sServices->bluetooth(); - auto dev = bt.ConnectedDevice(); + + std::optional dev; + std::vector devs; + if (std::holds_alternative(ev.event)) { switch (std::get(ev.event)) { case SimpleEvent::kPlayPause: @@ -438,30 +520,36 @@ void UiState::react(const system_fsm::BluetoothEvent& ev) { break; case SimpleEvent::kFastForward: break; - case SimpleEvent::kKnownDevicesChanged: - sBluetoothDevices.setDirect(bt.KnownDevices()); - break; case SimpleEvent::kConnectionStateChanged: - sBluetoothConnected.setDirect(bt.IsConnected()); + state = bt.connectionState(); + sBluetoothConnected.setDirect(state == ConnectionState::kConnected); + sBluetoothConnecting.setDirect(state == ConnectionState::kConnecting); + break; + case SimpleEvent::kPairedDeviceChanged: + dev = bt.pairedDevice(); if (dev) { - sBluetoothPairedDevice.setDirect(drivers::bluetooth::Device{ - .address = dev->mac, - .name = {dev->name.data(), dev->name.size()}, - .class_of_device = 0, - .signal_strength = 0, - }); + sBluetoothPairedDevice.setDirect(*dev); } else { sBluetoothPairedDevice.setDirect(std::monostate{}); } break; - case SimpleEvent::kPreferredDeviceChanged: + case SimpleEvent::kKnownDevicesChanged: + sBluetoothKnownDevices.setDirect(bt.knownDevices()); + break; + case SimpleEvent::kDiscoveryChanged: + sBluetoothDiscovering.setDirect(bt.discoveryEnabled()); + // Dump the old list of discovered devices when discovery is toggled. + sBluetoothDiscoveredDevices.setDirect(bt.discoveredDevices()); + break; + case SimpleEvent::kDeviceDiscovered: + sBluetoothDiscoveredDevices.setDirect(bt.discoveredDevices()); break; default: break; } } else if (std::holds_alternative( ev.event)) { - // Todo: Do something with this (ie, bt volume alert) + // TODO: Do something with this (ie, bt volume alert) ESP_LOGI( kTag, "Recieved volume changed event with new volume: %d", std::get(ev.event).new_vol); @@ -512,23 +600,53 @@ void Lua::entry() { auto& registry = lua::Registry::instance(*sServices); sLua = registry.uiThread(); - registry.AddPropertyModule("power", { - {"battery_pct", &sBatteryPct}, - {"battery_millivolts", &sBatteryMv}, - {"plugged_in", &sBatteryCharging}, - }); - registry.AddPropertyModule("bluetooth", + registry.AddPropertyModule("power", { - {"enabled", &sBluetoothEnabled}, - {"connected", &sBluetoothConnected}, - {"paired_device", &sBluetoothPairedDevice}, - {"devices", &sBluetoothDevices}, + {"battery_pct", &sBatteryPct}, + {"battery_millivolts", &sBatteryMv}, + {"plugged_in", &sBatteryCharging}, + {"charge_state", &sPowerChargeState}, + {"fast_charge", &sPowerFastChargeEnabled}, }); - registry.AddPropertyModule("playback", { - {"playing", &sPlaybackPlaying}, - {"track", &sPlaybackTrack}, - {"position", &sPlaybackPosition}, - }); + registry.AddPropertyModule( + "bluetooth", { + {"enabled", &sBluetoothEnabled}, + {"connected", &sBluetoothConnected}, + {"connecting", &sBluetoothConnecting}, + {"discovering", &sBluetoothDiscovering}, + {"paired_device", &sBluetoothPairedDevice}, + {"discovered_devices", &sBluetoothDiscoveredDevices}, + {"known_devices", &sBluetoothKnownDevices}, + {"enable", + [&](lua_State* s) { + sBluetoothEnabled.set(true); + return 0; + }}, + {"disable", + [&](lua_State* s) { + sBluetoothEnabled.set(false); + return 0; + }}, + }); + registry.AddPropertyModule( + "playback", + { + {"playing", &sPlaybackPlaying}, + {"track", &sPlaybackTrack}, + {"position", &sPlaybackPosition}, + {"is_playable", + [&](lua_State* s) { + size_t len; + const char* path = luaL_checklstring(s, 1, &len); + auto res = sServices->tag_parser().ReadAndParseTags({path, len}); + if (res) { + lua_pushboolean(s, true); + } else { + lua_pushboolean(s, false); + } + return 1; + }}, + }); registry.AddPropertyModule( "queue", { @@ -539,6 +657,7 @@ void Lua::entry() { {"replay", &sQueueReplay}, {"repeat_track", &sQueueRepeat}, {"random", &sQueueRandom}, + {"loading", &sQueueLoading}, }); registry.AddPropertyModule("volume", { @@ -601,9 +720,14 @@ void Lua::entry() { sDatabaseAutoUpdate.setDirect(sServices->nvs().DbAutoIndex()); auto bt = sServices->bluetooth(); - sBluetoothEnabled.setDirect(bt.IsEnabled()); - sBluetoothConnected.setDirect(bt.IsConnected()); - sBluetoothDevices.setDirect(bt.KnownDevices()); + sBluetoothEnabled.setDirect(bt.enabled()); + auto paired = bt.pairedDevice(); + if (paired) { + sBluetoothPairedDevice.setDirect(*paired); + } + sBluetoothKnownDevices.setDirect(bt.knownDevices()); + + sPowerFastChargeEnabled.setDirect(sServices->nvs().FastCharge()); if (sServices->sd() == drivers::SdState::kMounted) { sLua->RunScript("/sdcard/config.lua"); @@ -630,7 +754,7 @@ auto Lua::PushLuaScreen(lua_State* s, bool replace) -> int { // Call the constructor for this screen. // lua_settop(s, 1); // Make sure the screen is actually at top of stack - lua_pushliteral(s, "createUi"); + lua_pushliteral(s, "create_ui"); if (lua_gettable(s, 1) == LUA_TFUNCTION) { lua_pushvalue(s, 1); lua::CallProtected(s, 1, 0); diff --git a/src/tangara/ui/ui_fsm.hpp b/src/tangara/ui/ui_fsm.hpp index 7e34db34..32966657 100644 --- a/src/tangara/ui/ui_fsm.hpp +++ b/src/tangara/ui/ui_fsm.hpp @@ -53,6 +53,7 @@ class UiState : public tinyfsm::Fsm { /* Fallback event handler. Does nothing. */ void react(const tinyfsm::Event& ev) {} + void react(const Screenshot&); virtual void react(const OnLuaError&) {} virtual void react(const DumpLuaStack&) {} virtual void react(const internal::BackPressed&) {} @@ -100,11 +101,16 @@ class UiState : public tinyfsm::Fsm { static lua::Property sBatteryPct; static lua::Property sBatteryMv; static lua::Property sBatteryCharging; + static lua::Property sPowerChargeState; + static lua::Property sPowerFastChargeEnabled; static lua::Property sBluetoothEnabled; + static lua::Property sBluetoothConnecting; static lua::Property sBluetoothConnected; + static lua::Property sBluetoothDiscovering; static lua::Property sBluetoothPairedDevice; - static lua::Property sBluetoothDevices; + static lua::Property sBluetoothKnownDevices; + static lua::Property sBluetoothDiscoveredDevices; static lua::Property sPlaybackPlaying; @@ -116,6 +122,7 @@ class UiState : public tinyfsm::Fsm { static lua::Property sQueueReplay; static lua::Property sQueueRepeat; static lua::Property sQueueRandom; + static lua::Property sQueueLoading; static lua::Property sVolumeCurrentPct; static lua::Property sVolumeCurrentDb; diff --git a/src/tasks/tasks.cpp b/src/tasks/tasks.cpp index d3937c68..f0b567f2 100644 --- a/src/tasks/tasks.cpp +++ b/src/tasks/tasks.cpp @@ -47,7 +47,7 @@ auto AllocateStack() -> std::span { // separately. template <> auto AllocateStack() -> std::span { - constexpr std::size_t size = 14 * 1024; + constexpr std::size_t size = 20 * 1024; static StackType_t sStack[size]; return {sStack, size}; } @@ -64,7 +64,7 @@ auto AllocateStack() -> std::span { // an eye-wateringly large amount of stack. template <> auto AllocateStack() -> std::span { - std::size_t size = 64 * 1024; + std::size_t size = 32 * 1024; return {static_cast(heap_caps_malloc(size, MALLOC_CAP_SPIRAM)), size}; } @@ -83,11 +83,11 @@ auto Priority() -> UBaseType_t; // highest priority. template <> auto Priority() -> UBaseType_t { - return configMAX_PRIORITIES - 1; + return 15; } template <> auto Priority() -> UBaseType_t { - return configMAX_PRIORITIES - 1; + return 15; } // After audio issues, UI jank is the most noticeable kind of scheduling-induced // slowness that the user is likely to notice or care about. Therefore we place diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 49554be8..90778c5d 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -2,4 +2,5 @@ # # SPDX-License-Identifier: GPL-3.0-only -idf_component_register(SRCS INCLUDE_DIRS "include" REQUIRES "memory") +idf_component_register( + SRCS "random.cpp" INCLUDE_DIRS "include" REQUIRES "memory" "komihash") diff --git a/src/util/include/debug.hpp b/src/util/include/debug.hpp index 27fb2999..37c26f6a 100644 --- a/src/util/include/debug.hpp +++ b/src/util/include/debug.hpp @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -31,8 +32,8 @@ inline std::string format_hex_string(std::span data) { oss << " "; } int byte_val = (int)byte; - oss << "[0x" << std::uppercase << std::setfill('0') << std::setw(2) - << std::hex << byte_val << ']'; + oss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex + << byte_val << ' '; if (byte_val >= 32 && byte_val < 127) { ascii_values << (char)byte; } else { @@ -43,4 +44,12 @@ inline std::string format_hex_string(std::span data) { return oss.str(); } +inline std::string format_hex_string(std::span data) { + return format_hex_string(std::as_bytes(data)); +} + +inline std::string format_hex_string(std::span data) { + return format_hex_string(std::as_bytes(data)); +} + } // namespace util diff --git a/test/sdkconfig.test b/test/sdkconfig.test index c0fbf922..10d9595c 100644 --- a/test/sdkconfig.test +++ b/test/sdkconfig.test @@ -11,3 +11,4 @@ CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y CONFIG_COMPILER_STACK_CHECK=y CONFIG_ESP_TASK_WDT=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="../partitions.csv" +CONFIG_ESP_TASK_WDT_EN=n diff --git a/tools/cmake/common.cmake b/tools/cmake/common.cmake index f99c52c8..796d4cf7 100644 --- a/tools/cmake/common.cmake +++ b/tools/cmake/common.cmake @@ -5,7 +5,7 @@ # For more information about build system see # https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html -set(PROJECT_VER "0.9.3") +set(PROJECT_VER "0.12.0") # esp-idf sets the C++ standard weird. Set cmake vars to match. set(CMAKE_CXX_STANDARD 23) diff --git a/tools/fonts/mkfonts.sh b/tools/fonts/mkfonts.sh index aba0fd1f..3a87612b 100755 --- a/tools/fonts/mkfonts.sh +++ b/tools/fonts/mkfonts.sh @@ -7,6 +7,7 @@ fusion_12() { -r 0x2000-0x206F \ -r 0x20-0x7F,0xA0-0xFF \ -r 0x3000-0x303f,0x3040-0x309F,0x30A0-0x30FF,0xFF00-0xFFEF,0x4E00-0x9FAF \ + -r 0xAC00-0xD7AF \ --size 12 \ --bpp 1 --format bin -o fusion12 echo "finished fusion_12" @@ -20,6 +21,8 @@ fusion_10() { --font fusion/fusion-pixel-10px-proportional/fusion-pixel-10px-proportional-ja.ttf \ -r 0x3000-0x303f,0x3040-0x309F,0x30A0-0x30FF \ -r 0xFF00-0xFFEF,0x4E00-0x9FAF \ + --font fusion/fusion-pixel-10px-proportional/fusion-pixel-10px-proportional-ko.ttf \ + -r 0xAC00-0xD7AF \ --size 10 \ --bpp 1 --format bin -o fusion10 echo "finished fusion_10" @@ -33,6 +36,8 @@ fusion_8() { --font fusion/fusion-pixel-8px-monospaced/fusion-pixel-8px-monospaced-ja.ttf \ -r 0x3000-0x303f,0x3040-0x309F,0x30A0-0x30FF \ -r 0xFF00-0xFFEF,0x4E00-0x9FAF \ + --font fusion/fusion-pixel-8px-monospaced/fusion-pixel-8px-monospaced-ko.ttf \ + -r 0xAC00-0xD7AF \ --size 8 \ --bpp 1 --format lvgl -o font_fusion_8.c echo "finished fusion_8" @@ -41,5 +46,5 @@ fusion_8() { echo "creating all fonts" fusion_12& fusion_10& -fusion_8& +# fusion_8& wait diff --git a/tools/luals-gendoc/README.md b/tools/luals-gendoc/README.md new file mode 100644 index 00000000..b676aa16 --- /dev/null +++ b/tools/luals-gendoc/README.md @@ -0,0 +1,20 @@ +# Prerequisites + + - lua-language-server + - a Lua interpreter version >= 5.2 + +# Regenerating the Lua reference docs + +1. Invoke `lua-language-server` to parse our stubs, generating json output: + +``` +$ lua-language-server --doc=../../luals-stubs +``` + +2. The output will include the path to the raw json data. This will be a path like '/home/jacqueline/Development/lua-language-server/log/doc.json'. Pipe this file to `gendoc.lua`. The output will be quite long; consider piping to less for testing. + +``` +$ cat /home/jacqueline/Development/lua-language-server/log/doc.json | ./gendoc.lua | less +``` + +3. If updating the public-facing docs on cooltech.zone, place the resulting output in 'content/tangara/docs/lua/reference.txt'.