From 0bca6832f4247833c4b924d51888583ccd05d318 Mon Sep 17 00:00:00 2001 From: loop Date: Mon, 24 Jun 2024 11:50:40 +0800 Subject: [PATCH] feat(ble): support ble hci components --- .gitlab/ci/build.yml | 11 + .gitlab/ci/rules.yml | 16 + components/.build-rules.yml | 4 + components/bluetooth/ble_hci/CHANGELOG.md | 7 + components/bluetooth/ble_hci/CMakeLists.txt | 5 + components/bluetooth/ble_hci/README.md | 28 ++ components/bluetooth/ble_hci/README_CN.md | 17 + components/bluetooth/ble_hci/ble_hci.c | 335 ++++++++++++++++++ components/bluetooth/ble_hci/bt_hci_common.c | 127 +++++++ .../bluetooth/ble_hci/idf_component.yml | 11 + .../bluetooth/ble_hci/include/ble_hci.h | 293 +++++++++++++++ components/bluetooth/ble_hci/license.txt | 202 +++++++++++ .../ble_hci/priv_include/bt_hci_common.h | 206 +++++++++++ .../ble_hci/test_apps/CMakeLists.txt | 9 + .../ble_hci/test_apps/main/CMakeLists.txt | 3 + .../ble_hci/test_apps/main/ble_hci_test.c | 118 ++++++ .../ble_hci/test_apps/pytest_button.py | 41 +++ .../test_apps/sdkconfig.ci.c2_xtal_26mhz | 3 + .../ble_hci/test_apps/sdkconfig.defaults | 15 + docs/Doxyfile | 1 + docs/en/bluetooth/ble_hci.rst | 32 ++ docs/en/bluetooth/index.rst | 4 +- docs/zh_CN/bluetooth/ble_hci.rst | 29 ++ docs/zh_CN/bluetooth/index.rst | 2 +- 24 files changed, 1516 insertions(+), 3 deletions(-) create mode 100644 components/bluetooth/ble_hci/CHANGELOG.md create mode 100644 components/bluetooth/ble_hci/CMakeLists.txt create mode 100644 components/bluetooth/ble_hci/README.md create mode 100644 components/bluetooth/ble_hci/README_CN.md create mode 100644 components/bluetooth/ble_hci/ble_hci.c create mode 100644 components/bluetooth/ble_hci/bt_hci_common.c create mode 100644 components/bluetooth/ble_hci/idf_component.yml create mode 100644 components/bluetooth/ble_hci/include/ble_hci.h create mode 100644 components/bluetooth/ble_hci/license.txt create mode 100644 components/bluetooth/ble_hci/priv_include/bt_hci_common.h create mode 100644 components/bluetooth/ble_hci/test_apps/CMakeLists.txt create mode 100644 components/bluetooth/ble_hci/test_apps/main/CMakeLists.txt create mode 100644 components/bluetooth/ble_hci/test_apps/main/ble_hci_test.c create mode 100644 components/bluetooth/ble_hci/test_apps/pytest_button.py create mode 100644 components/bluetooth/ble_hci/test_apps/sdkconfig.ci.c2_xtal_26mhz create mode 100644 components/bluetooth/ble_hci/test_apps/sdkconfig.defaults create mode 100644 docs/en/bluetooth/ble_hci.rst create mode 100644 docs/zh_CN/bluetooth/ble_hci.rst diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index a9323f292..b498f3734 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -783,6 +783,17 @@ build_example_utilities_xz_decompress_file: variables: EXAMPLE_DIR: examples/utilities/xz_decompress_file + +build_components_bluetooth_ble_hci_test_apps: + extends: + - .build_examples_template + - .rules:build:components_bluetooth_ble_hci_test_apps + parallel: + matrix: + - IMAGE: espressif/idf:release-v5.2 + variables: + EXAMPLE_DIR: components/bluetooth/ble_hci/test_apps + build_components_button_test_apps: extends: - .build_examples_template diff --git a/.gitlab/ci/rules.yml b/.gitlab/ci/rules.yml index 5f6bbb4ae..ae4888a62 100644 --- a/.gitlab/ci/rules.yml +++ b/.gitlab/ci/rules.yml @@ -45,6 +45,10 @@ - "components/bluetooth/ble_services/**/*" - "components/tools/cmake_utilities/package_manager.cmake" +.patterns-components_bluetooth_ble_hci: &patterns-components_bluetooth_ble_hci + - "components/bluetooth/ble_hci/**/*" + - "components/tools/cmake_utilities/package_manager.cmake" + .patterns-components_bootloader_support_plus: &patterns-components_bootloader_support_plus - "components/bootloader_support_plus/**/*" - "components/utilities/xz/**/*" @@ -293,6 +297,7 @@ - "components/audio/dac_audio/include/dac_audio.h" - "components/audio/pwm_audio/include/pwm_audio.h" - "components/bluetooth/ble_conn_mgr/include/esp_ble_conn_mgr.h" + - "components/bluetooth/ble_hci/include/ble_hci.h" - "components/bus/include/spi_bus.h" - "components/button/include/iot_button.h" - "components/display/screen/interface_driver/scr_interface_driver.h" @@ -1364,6 +1369,17 @@ - <<: *if-dev-push changes: *patterns-components_audio_pwm_audio +.rules:build:components_bluetooth_ble_hci_test_apps: + rules: + - <<: *if-protected + - <<: *if-label-build + - <<: *if-label-target_test + - <<: *if-trigger-job + - <<: *if-dev-push + changes: *patterns-build_system + - <<: *if-dev-push + changes: *patterns-components_bluetooth_ble_hci + .rules:build:component_bus_test: rules: - <<: *if-protected diff --git a/components/.build-rules.yml b/components/.build-rules.yml index c128c29a6..235b89c5c 100644 --- a/components/.build-rules.yml +++ b/components/.build-rules.yml @@ -141,3 +141,7 @@ components/usb/usb_device_uac/test_apps: components/sensors/power_monitor/ina236/test_apps: enable: - if: INCLUDE_DEFAULT == 1 + +components/bluetooth/ble_hci/test_apps: + enable: + - if: IDF_TARGET in ["esp32","esp32c3","esp32s3"] diff --git a/components/bluetooth/ble_hci/CHANGELOG.md b/components/bluetooth/ble_hci/CHANGELOG.md new file mode 100644 index 000000000..d125776af --- /dev/null +++ b/components/bluetooth/ble_hci/CHANGELOG.md @@ -0,0 +1,7 @@ +# ChangeLog + +## v1.0.0 - 2024-5-30 + +First release version. + +- Support ble hci diff --git a/components/bluetooth/ble_hci/CMakeLists.txt b/components/bluetooth/ble_hci/CMakeLists.txt new file mode 100644 index 000000000..377751d8a --- /dev/null +++ b/components/bluetooth/ble_hci/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register(SRCS "bt_hci_common.c" "ble_hci.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "priv_include" + REQUIRES bt + ) diff --git a/components/bluetooth/ble_hci/README.md b/components/bluetooth/ble_hci/README.md new file mode 100644 index 000000000..7f585a031 --- /dev/null +++ b/components/bluetooth/ble_hci/README.md @@ -0,0 +1,28 @@ +# BLE HCI Component +[中文版](./README_CN.md) + +[![Component Registry](https://components.espressif.com/components/espressif/ble_hci/badge.svg)](https://components.espressif.com/components/espressif/ble_hci) + +- [User Guide](https://docs.espressif.com/projects/esp-iot-solution/en/latest/bluetooth/ble_hci.html) + +The ``ble_hci`` is used to operate the BLE Controller directly through the VHCI interface to realize broadcasting, scanning and other functions. + +Compared to initiating broadcasts and scans through the Nimble or Bluedroid stacks, using this component has the following advantages: +- Smaller memory footprint +- Smaller firmware size +- Faster initialization process + +## List of supported commands + +- Send broadcast packets +- Scan broadcast packets +- Add/Remove whitelist +- Set local address + +## Adding the component to your project + +To add the `ble_hci` to your project's dependencies, please use the command `idf.py add-dependency`. During the `CMake` step, the component will be downloaded automatically. + +``` +idf.py add-dependency "espressif/ble_hci=*" +``` diff --git a/components/bluetooth/ble_hci/README_CN.md b/components/bluetooth/ble_hci/README_CN.md new file mode 100644 index 000000000..783953ddd --- /dev/null +++ b/components/bluetooth/ble_hci/README_CN.md @@ -0,0 +1,17 @@ +# BLE HCI 组件 + +[![Component Registry](https://components.espressif.com/components/espressif/ble_hci/badge.svg)](https://components.espressif.com/components/espressif/ble_hci) + +- [User Guide](https://docs.espressif.com/projects/esp-iot-solution/zh_CN/latest/bluetooth/ble_hci.html) + +BLE HCI 组件用于通过 VHCI 接口直接操作 BLE Controller 实现广播,扫描等功能。 +相比于通过 Nimble 或 Bluedroid 协议栈发起广播和扫描,使用该组件有如下优点: +- 更少的内存占用 +- 更小的固件尺寸 +- 更快的初始化流程 + +## 支持指令列表 +- 发送广播包 +- 扫描广播包 +- 白名单 +- 设置本地地址 diff --git a/components/bluetooth/ble_hci/ble_hci.c b/components/bluetooth/ble_hci/ble_hci.c new file mode 100644 index 000000000..40d106b17 --- /dev/null +++ b/components/bluetooth/ble_hci/ble_hci.c @@ -0,0 +1,335 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "esp_log.h" +#include "esp_bt.h" +#include "esp_check.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "ble_hci.h" +#include "bt_hci_common.h" +static const char *TAG = "ble_hci"; +#define SCAN_RESULT_LEN_MAX 25 +#define CMD_WAIT_TIME (100/portTICK_PERIOD_MS) + +typedef struct { + TaskHandle_t ble_hci_task_handle; + QueueHandle_t hci_data_queue; + QueueHandle_t hci_cmd_evt_queue; + uint8_t scan_result_len; + ble_hci_scan_result_t scan_result[SCAN_RESULT_LEN_MAX]; + ble_hci_scan_cb_t cb; + uint8_t cmd_buf[128]; +} ble_hci_t; + +ble_hci_t *s_ble_hci = NULL; + +typedef struct { + uint8_t *data; + uint16_t data_len; +} host_rcv_data_t; + +typedef struct { + uint8_t opcode; + uint8_t reason; +} hci_cmd_event_t; + +static void controller_rcv_pkt_ready(void) +{ + ESP_LOGI(TAG, "controller rcv pkt ready"); +} + +static int host_rcv_pkt(uint8_t *data, uint16_t len) +{ + /* Check second byte for HCI event. If event opcode is 0x0e, the event is + * HCI Command Complete event. Sice we have received "0x0e" event, we can + * check for byte 4 for command opcode and byte 6 for it's return status. */ + host_rcv_data_t send_data; + send_data.data_len = len; + send_data.data = malloc(sizeof(uint8_t) * len); + memcpy(send_data.data, data, len); + if (xQueueSend(s_ble_hci->hci_data_queue, (void *)&send_data, (TickType_t) 0) != pdTRUE) { + ESP_LOGW(TAG, "Failed to enqueue advertising report. Queue full."); + /* If data sent successfully, then free the pointer in `xQueueReceive' + * after processing it. Or else if enqueue in not successful, free it + * here. */ + free(send_data.data); + return ESP_FAIL; + } + return ESP_OK; +} + +static esp_vhci_host_callback_t vhci_host_cb = { + controller_rcv_pkt_ready, + host_rcv_pkt +}; + +static void hci_evt_process(void *pvParameters) +{ + host_rcv_data_t rcv_data; + uint8_t *queue_data; + uint16_t data_ptr, total_data_len; + uint8_t hci_event_opcode, sub_event, num_responses; + while (1) { + total_data_len = 0; + data_ptr = 0; + if (xQueueReceive(s_ble_hci->hci_data_queue, &rcv_data, portMAX_DELAY) == pdPASS) { + queue_data = rcv_data.data; + hci_event_opcode = queue_data[++data_ptr]; + if (hci_event_opcode == LE_META_EVENTS) { + /* Set `data_ptr' to 4th entry, which will point to sub event. */ + data_ptr += 2; + sub_event = queue_data[data_ptr++]; + /* Check if sub event is LE advertising report event. */ + if (sub_event == HCI_LE_ADV_REPORT) { + /* Get number of advertising reports. */ + num_responses = queue_data[data_ptr++]; + s_ble_hci->scan_result_len = num_responses; + for (uint8_t i = 0; i < num_responses; i += 1) { + s_ble_hci->scan_result[i].search_evt = queue_data[data_ptr++]; + } + for (uint8_t i = 0; i < num_responses; i += 1) { + s_ble_hci->scan_result[i].ble_addr_type = queue_data[data_ptr++]; + } + for (int i = 0; i < num_responses; i += 1) { + for (int j = 0; j < 6; j += 1) { + s_ble_hci->scan_result[i].bda[5 - j] = queue_data[data_ptr++]; + } + } + for (int i = 0; i < num_responses; i += 1) { + s_ble_hci->scan_result[i].adv_data_len = queue_data[data_ptr++]; + total_data_len += s_ble_hci->scan_result[i].adv_data_len; + } + if (total_data_len != 0) { + for (uint8_t i = 0; i < num_responses; i += 1) { + for (uint8_t j = 0; j < s_ble_hci->scan_result[i].adv_data_len; j += 1) { + s_ble_hci->scan_result[i].ble_adv[j] = queue_data[data_ptr++]; + } + } + } + for (int i = 0; i < num_responses; i += 1) { + s_ble_hci->scan_result[i].rssi = -(0xFF - queue_data[data_ptr++]); + } + s_ble_hci->cb(s_ble_hci->scan_result, s_ble_hci->scan_result_len); + } + } else if (hci_event_opcode == LE_CMD_COMPLETE_EVENT) { + hci_cmd_event_t hci_cmd_evt; + hci_cmd_evt.opcode = queue_data[4]; + hci_cmd_evt.reason = queue_data[6]; + if (queue_data[6] == 0) { + ESP_LOGD(TAG, "Event opcode 0x%02x success.", queue_data[4]); + } else { + ESP_LOGE(TAG, "Event opcode 0x%02x fail with reason: 0x%02x.", queue_data[4], queue_data[6]); + } + xQueueSend(s_ble_hci->hci_cmd_evt_queue, &hci_cmd_evt, portMAX_DELAY); + } else { + ESP_LOGW(TAG, "Unhandled HCI event code: 0x%02x", hci_event_opcode); + } + free(rcv_data.data); + } + } +} + +esp_err_t ble_hci_reset(void) +{ + hci_cmd_event_t hci_cmd_evt; + uint16_t sz = make_cmd_reset(s_ble_hci->cmd_buf); + esp_vhci_host_send_packet(s_ble_hci->cmd_buf, sz); + if (xQueueReceive(s_ble_hci->hci_cmd_evt_queue, &hci_cmd_evt, CMD_WAIT_TIME) == pdTRUE) { + if (hci_cmd_evt.opcode == HCI_OCF_RESET) { + if (hci_cmd_evt.reason != 0) { + ESP_LOGE(TAG, "Reset failed with reason: 0x%02x", hci_cmd_evt.reason); + } + return hci_cmd_evt.reason; + } + } + return ESP_FAIL; +} + +esp_err_t ble_hci_enable_meta_event(void) +{ + hci_cmd_event_t hci_cmd_evt; + /* Set bit 61 in event mask to enable LE Meta events. */ + uint8_t evt_mask[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; + uint16_t sz = make_cmd_set_evt_mask(s_ble_hci->cmd_buf, evt_mask); + esp_vhci_host_send_packet(s_ble_hci->cmd_buf, sz); + if (xQueueReceive(s_ble_hci->hci_cmd_evt_queue, &hci_cmd_evt, CMD_WAIT_TIME) == pdTRUE) { + if (hci_cmd_evt.opcode == HCI_OCF_SET_EVT_MASK) { + return hci_cmd_evt.reason; + } + } + return ESP_FAIL; +} + +esp_err_t ble_hci_set_adv_param(ble_hci_adv_param_t *param) +{ + uint16_t sz = make_cmd_ble_set_adv_param(s_ble_hci->cmd_buf, + param->adv_int_min, + param->adv_int_max, + param->adv_type, + param->own_addr_type, + param->peer_addr_type, + param->peer_addr, + param->channel_map, + param->adv_filter_policy); + esp_vhci_host_send_packet(s_ble_hci->cmd_buf, sz); + hci_cmd_event_t hci_cmd_evt; + if (xQueueReceive(s_ble_hci->hci_cmd_evt_queue, &hci_cmd_evt, CMD_WAIT_TIME) == pdTRUE) { + if (hci_cmd_evt.opcode == HCI_OCF_WRITE_ADV_PARAMS) { + return hci_cmd_evt.reason; + } + } + return ESP_FAIL; +} + +esp_err_t ble_hci_set_adv_data(uint8_t len, uint8_t *data) +{ + uint16_t sz = make_cmd_ble_set_adv_data(s_ble_hci->cmd_buf, len, data); + esp_vhci_host_send_packet(s_ble_hci->cmd_buf, sz); + hci_cmd_event_t hci_cmd_evt; + if (xQueueReceive(s_ble_hci->hci_cmd_evt_queue, &hci_cmd_evt, CMD_WAIT_TIME) == pdTRUE) { + if (hci_cmd_evt.opcode == HCI_OCF_WRITE_ADV_DATA) { + return hci_cmd_evt.reason; + } + } + return ESP_FAIL; +} + +esp_err_t ble_hci_set_adv_enable(bool enable) +{ + uint16_t sz = make_cmd_ble_set_adv_enable(s_ble_hci->cmd_buf, enable); + esp_vhci_host_send_packet(s_ble_hci->cmd_buf, sz); + hci_cmd_event_t hci_cmd_evt; + if (xQueueReceive(s_ble_hci->hci_cmd_evt_queue, &hci_cmd_evt, CMD_WAIT_TIME) == pdTRUE) { + if (hci_cmd_evt.opcode == HCI_OCF_WRITE_ADV_ENABLE) { + return hci_cmd_evt.reason; + } + } + return ESP_FAIL; +} + +esp_err_t ble_hci_set_scan_param(ble_hci_scan_param_t *param) +{ + hci_cmd_event_t hci_cmd_evt; + uint16_t sz = make_cmd_ble_set_scan_params(s_ble_hci->cmd_buf, param->scan_type, param->scan_interval, + param->scan_window, param->own_addr_type, param->filter_policy); + esp_vhci_host_send_packet(s_ble_hci->cmd_buf, sz); + if (xQueueReceive(s_ble_hci->hci_cmd_evt_queue, &hci_cmd_evt, CMD_WAIT_TIME) == pdTRUE) { + if (hci_cmd_evt.opcode == HCI_OCF_WRITE_SCAN_PARAM) { + return hci_cmd_evt.reason; + } + } + return ESP_FAIL; +} + +esp_err_t ble_hci_set_scan_enable(bool enable, bool filter_duplicates) +{ + uint16_t sz = make_cmd_ble_set_scan_enable(s_ble_hci->cmd_buf, enable, filter_duplicates); + esp_vhci_host_send_packet(s_ble_hci->cmd_buf, sz); + hci_cmd_event_t hci_cmd_evt; + if (xQueueReceive(s_ble_hci->hci_cmd_evt_queue, &hci_cmd_evt, CMD_WAIT_TIME) == pdTRUE) { + if (hci_cmd_evt.opcode == HCI_OCF_WRITE_SCAN_ENABLE) { + return hci_cmd_evt.reason; + } + } + return ESP_FAIL; +} + +esp_err_t ble_hci_add_to_accept_list(ble_hci_addr_t addr, ble_hci_addr_type_t addr_type) +{ + uint16_t sz = make_cmd_ble_add_to_filter_accept_list(s_ble_hci->cmd_buf, addr_type, addr); + esp_vhci_host_send_packet(s_ble_hci->cmd_buf, sz); + hci_cmd_event_t hci_cmd_evt; + if (xQueueReceive(s_ble_hci->hci_cmd_evt_queue, &hci_cmd_evt, CMD_WAIT_TIME) == pdTRUE) { + if (hci_cmd_evt.opcode == HCI_OCF_ADD_TO_ACCEPT_LIST) { + return hci_cmd_evt.reason; + } + } + return ESP_FAIL; +} + +esp_err_t ble_hci_clear_accept_list() +{ + uint16_t sz = make_cmd_ble_clear_white_list(s_ble_hci->cmd_buf); + esp_vhci_host_send_packet(s_ble_hci->cmd_buf, sz); + hci_cmd_event_t hci_cmd_evt; + if (xQueueReceive(s_ble_hci->hci_cmd_evt_queue, &hci_cmd_evt, CMD_WAIT_TIME) == pdTRUE) { + if (hci_cmd_evt.opcode == HCI_OCF_CLEAR_ACCEPT_LIST) { + return hci_cmd_evt.reason; + } + } + return ESP_FAIL; +} + +esp_err_t ble_hci_set_random_address(ble_hci_addr_t addr) +{ + uint16_t sz = make_cmd_set_random_address(s_ble_hci->cmd_buf, addr); + esp_vhci_host_send_packet(s_ble_hci->cmd_buf, sz); + hci_cmd_event_t hci_cmd_evt; + if (xQueueReceive(s_ble_hci->hci_cmd_evt_queue, &hci_cmd_evt, CMD_WAIT_TIME) == pdTRUE) { + if (hci_cmd_evt.opcode == HCI_OCF_SET_RANDOM_ADDR) { + return hci_cmd_evt.reason; + } + } + return ESP_FAIL; +} + +esp_err_t ble_hci_set_register_scan_callback(ble_hci_scan_cb_t cb) +{ + if (s_ble_hci == NULL) { + ESP_LOGE(TAG, "ble_hci not init"); + return ESP_ERR_INVALID_STATE; + } + s_ble_hci->cb = cb; + return ESP_OK; +} + +esp_err_t ble_hci_init(void) +{ + if (s_ble_hci != NULL) { + ESP_LOGW(TAG, "ble_hci already init"); + return ESP_OK; + } + s_ble_hci = calloc(1, sizeof(ble_hci_t)); + ESP_RETURN_ON_FALSE(s_ble_hci, ESP_ERR_NO_MEM, TAG, "Failed to allocate memory for s_ble_hci"); + + s_ble_hci->hci_data_queue = xQueueCreate(15, sizeof(host_rcv_data_t)); + s_ble_hci->hci_cmd_evt_queue = xQueueCreate(5, sizeof(hci_cmd_event_t)); + + esp_bt_controller_config_t config_opts = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + + ESP_ERROR_CHECK(esp_bt_controller_init(&config_opts)); + + ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE)); + + esp_vhci_host_register_callback(&vhci_host_cb); + + BaseType_t res = xTaskCreatePinnedToCore(&hci_evt_process, "hci_evt_process", 2048, NULL, 6, &s_ble_hci->ble_hci_task_handle, 0); + ESP_RETURN_ON_FALSE(res, ESP_ERR_NO_MEM, TAG, "Failed create hci evt process"); + + return ESP_OK; +} + +esp_err_t ble_hci_deinit(void) +{ + if (s_ble_hci == NULL) { + ESP_LOGW(TAG, "ble_hci already deinit"); + return ESP_OK; + } + while (eTaskGetState(s_ble_hci->ble_hci_task_handle) == eRunning) { + vTaskDelay(pdTICKS_TO_MS(10)); + } + vTaskDelete(s_ble_hci->ble_hci_task_handle); + ESP_ERROR_CHECK(esp_bt_controller_disable()); + ESP_ERROR_CHECK(esp_bt_controller_deinit()); + + vQueueDelete(s_ble_hci->hci_data_queue); + vQueueDelete(s_ble_hci->hci_cmd_evt_queue); + + free(s_ble_hci); + s_ble_hci = NULL; + return ESP_OK; +} diff --git a/components/bluetooth/ble_hci/bt_hci_common.c b/components/bluetooth/ble_hci/bt_hci_common.c new file mode 100644 index 000000000..89297d590 --- /dev/null +++ b/components/bluetooth/ble_hci/bt_hci_common.c @@ -0,0 +1,127 @@ +/* + * Basic functionality for Bluetooth Host Controller Interface Layer. + * + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include "bt_hci_common.h" + +uint16_t make_cmd_set_evt_mask(uint8_t *buf, uint8_t *evt_mask) +{ + UINT8_TO_STREAM(buf, H4_TYPE_COMMAND); + UINT16_TO_STREAM(buf, HCI_SET_EVT_MASK); + UINT8_TO_STREAM(buf, HCIC_PARAM_SIZE_SET_EVENT_MASK); + ARRAY_TO_STREAM(buf, evt_mask, HCIC_PARAM_SIZE_SET_EVENT_MASK); + return HCI_H4_CMD_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_EVENT_MASK; +} + +uint16_t make_cmd_ble_set_scan_enable(uint8_t *buf, uint8_t scan_enable, + uint8_t filter_duplicates) +{ + UINT8_TO_STREAM(buf, H4_TYPE_COMMAND); + UINT16_TO_STREAM(buf, HCI_BLE_WRITE_SCAN_ENABLE); + UINT8_TO_STREAM(buf, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE); + UINT8_TO_STREAM(buf, scan_enable); + UINT8_TO_STREAM(buf, filter_duplicates); + return HCI_H4_CMD_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE; +} + +uint16_t make_cmd_ble_set_scan_params(uint8_t *buf, uint8_t scan_type, + uint16_t scan_interval, uint16_t scan_window, + uint8_t own_addr_type, uint8_t filter_policy) +{ + UINT8_TO_STREAM(buf, H4_TYPE_COMMAND); + UINT16_TO_STREAM(buf, HCI_BLE_WRITE_SCAN_PARAM); + UINT8_TO_STREAM(buf, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM); + UINT8_TO_STREAM(buf, scan_type); + UINT16_TO_STREAM(buf, scan_interval); + UINT16_TO_STREAM(buf, scan_window); + UINT8_TO_STREAM(buf, own_addr_type); + UINT8_TO_STREAM(buf, filter_policy); + return HCI_H4_CMD_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM; +} + +uint16_t make_cmd_ble_set_adv_enable(uint8_t *buf, uint8_t adv_enable) +{ + UINT8_TO_STREAM(buf, H4_TYPE_COMMAND); + UINT16_TO_STREAM(buf, HCI_BLE_WRITE_ADV_ENABLE); + UINT8_TO_STREAM(buf, HCIC_PARAM_SIZE_WRITE_ADV_ENABLE); + UINT8_TO_STREAM(buf, adv_enable); + return HCI_H4_CMD_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_ADV_ENABLE; +} + +uint16_t make_cmd_ble_set_adv_param(uint8_t *buf, uint16_t adv_int_min, uint16_t adv_int_max, + uint8_t adv_type, uint8_t addr_type_own, + uint8_t addr_type_dir, bd_addr_t direct_bda, + uint8_t channel_map, uint8_t adv_filter_policy) +{ + UINT8_TO_STREAM(buf, H4_TYPE_COMMAND); + UINT16_TO_STREAM(buf, HCI_BLE_WRITE_ADV_PARAMS); + UINT8_TO_STREAM(buf, HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS); + + UINT16_TO_STREAM(buf, adv_int_min); + UINT16_TO_STREAM(buf, adv_int_max); + UINT8_TO_STREAM(buf, adv_type); + UINT8_TO_STREAM(buf, addr_type_own); + UINT8_TO_STREAM(buf, addr_type_dir); + BDADDR_TO_STREAM(buf, direct_bda); + UINT8_TO_STREAM(buf, channel_map); + UINT8_TO_STREAM(buf, adv_filter_policy); + return HCI_H4_CMD_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS; +} + +uint16_t make_cmd_reset(uint8_t *buf) +{ + UINT8_TO_STREAM(buf, H4_TYPE_COMMAND); + UINT16_TO_STREAM(buf, HCI_RESET); + UINT8_TO_STREAM(buf, 0); + return HCI_H4_CMD_PREAMBLE_SIZE; +} + +uint16_t make_cmd_ble_set_adv_data(uint8_t *buf, uint8_t data_len, uint8_t *p_data) +{ + UINT8_TO_STREAM(buf, H4_TYPE_COMMAND); + UINT16_TO_STREAM(buf, HCI_BLE_WRITE_ADV_DATA); + UINT8_TO_STREAM(buf, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1); + + memset(buf, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA); + + if (p_data != NULL && data_len > 0) { + if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA) { + data_len = HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA; + } + + UINT8_TO_STREAM(buf, data_len); + + ARRAY_TO_STREAM(buf, p_data, data_len); + } + return HCI_H4_CMD_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1; +} + +uint16_t make_cmd_ble_add_to_filter_accept_list(uint8_t *buf, uint8_t addr_type, bd_addr_t addr) +{ + UINT8_TO_STREAM(buf, H4_TYPE_COMMAND); + UINT16_TO_STREAM(buf, HCI_BLE_ADD_TO_ACCEPT_LIST); + UINT8_TO_STREAM(buf, HCIC_PARAM_SIZE_BLE_ADD_TO_WHITE_LIST); + UINT8_TO_STREAM(buf, addr_type); + BDADDR_TO_STREAM(buf, addr); + return HCI_H4_CMD_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ADD_TO_WHITE_LIST; +} + +uint16_t make_cmd_ble_clear_white_list(uint8_t *buf) +{ + UINT8_TO_STREAM(buf, H4_TYPE_COMMAND); + UINT16_TO_STREAM(buf, HCI_BLE_CLEAR_ACCEPT_LIST); + return HCI_H4_CMD_PREAMBLE_SIZE; +} + +uint16_t make_cmd_set_random_address(uint8_t *buf, bd_addr_t addr) +{ + UINT8_TO_STREAM(buf, H4_TYPE_COMMAND); + UINT16_TO_STREAM(buf, HCI_BLE_SET_RANDOM_ADDR); + UINT8_TO_STREAM(buf, HCIC_PARAM_SIZE_BLE_SET_RANDOM_ADDR); + BDADDR_TO_STREAM(buf, addr); + return HCI_H4_CMD_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_RANDOM_ADDR; +} diff --git a/components/bluetooth/ble_hci/idf_component.yml b/components/bluetooth/ble_hci/idf_component.yml new file mode 100644 index 000000000..33cf25467 --- /dev/null +++ b/components/bluetooth/ble_hci/idf_component.yml @@ -0,0 +1,11 @@ +version: "1.0.0" +description: ble hci component +url: https://github.com/espressif/esp-iot-solution/tree/master/components/bluetooth/ble_hci +repository: https://github.com/espressif/esp-iot-solution.git +documentation: https://docs.espressif.com/projects/esp-iot-solution/en/latest/bluetooth/ble_hci.html +issues: https://github.com/espressif/esp-iot-solution/issues +dependencies: + idf: ">=5.0" + cmake_utilities: "0.*" +examples: + - path: ../../../examples/bluetooth/ble_hci diff --git a/components/bluetooth/ble_hci/include/ble_hci.h b/components/bluetooth/ble_hci/include/ble_hci.h new file mode 100644 index 000000000..8612738c5 --- /dev/null +++ b/components/bluetooth/ble_hci/include/ble_hci.h @@ -0,0 +1,293 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdbool.h" +#include "esp_err.h" + +/// Advertising data maximum length +#define ESP_BLE_ADV_DATA_LEN_MAX 31 +/// Scan response data maximum length +#define ESP_BLE_SCAN_RSP_DATA_LEN_MAX 31 +/// BLE Address Length +#define BLE_HCI_ADDR_LEN 6 + +/// Bluetooth device address +typedef uint8_t ble_hci_addr_t[BLE_HCI_ADDR_LEN]; + +/** + * @brief Sub Event of BLE_HCI_BLE_SCAN_RESULT_EVT + * + */ +typedef enum { + BLE_HCI_SEARCH_INQ_RES_EVT = 0, /*!< Inquiry result for a peer device. */ + BLE_HCI_SEARCH_INQ_CMPL_EVT = 1, /*!< Inquiry complete. */ + BLE_HCI_SEARCH_DISC_RES_EVT = 2, /*!< Discovery result for a peer device. */ + BLE_HCI_SEARCH_DISC_BLE_RES_EVT = 3, /*!< Discovery result for BLE GATT based service on a peer device. */ + BLE_HCI_SEARCH_DISC_CMPL_EVT = 4, /*!< Discovery complete. */ + BLE_HCI_SEARCH_DI_DISC_CMPL_EVT = 5, /*!< Discovery complete. */ + BLE_HCI_SEARCH_SEARCH_CANCEL_CMPL_EVT = 6, /*!< Search cancelled */ + BLE_HCI_SEARCH_INQ_DISCARD_NUM_EVT = 7, /*!< The number of pkt discarded by flow control */ +} ble_hci_search_evt_t; + +/** + * @brief BLE address type + * + */ +typedef enum { + BLE_ADDR_TYPE_PUBLIC = 0x00, /*!< Public Device Address */ + BLE_ADDR_TYPE_RANDOM = 0x01, /*!< Random Device Address. */ + BLE_ADDR_TYPE_RPA_PUBLIC = 0x02, /*!< Resolvable Private Address (RPA) with public identity address */ + BLE_ADDR_TYPE_RPA_RANDOM = 0x03, /*!< Resolvable Private Address (RPA) with random identity address. */ +} ble_hci_addr_type_t; + +/** + * @brief Bluetooth device type + * + */ +typedef enum { + BLE_HCI_DEVICE_TYPE_BREDR = 0x01, + BLE_HCI_DEVICE_TYPE_BLE = 0x02, + BLE_HCI_DEVICE_TYPE_DUMO = 0x03, +} ble_hci_dev_type_t; + +/** + * @brief BLE advertising type + * + */ +typedef enum { + ADV_TYPE_IND = 0x00, + ADV_TYPE_DIRECT_IND_HIGH = 0x01, + ADV_TYPE_SCAN_IND = 0x02, + ADV_TYPE_NONCONN_IND = 0x03, + ADV_TYPE_DIRECT_IND_LOW = 0x04, +} ble_hci_adv_type_t; + +/** + * @brief BLE scan result struct + * + */ +typedef struct { + ble_hci_search_evt_t search_evt; /*!< Search event type */ + ble_hci_dev_type_t dev_type; /*!< Device type */ + ble_hci_addr_t bda; /*!< Bluetooth device address which has been searched */ + ble_hci_addr_type_t ble_addr_type; /*!< Ble device address type */ + uint8_t ble_adv[ESP_BLE_ADV_DATA_LEN_MAX + ESP_BLE_SCAN_RSP_DATA_LEN_MAX]; /*!< Received EIR */ + uint8_t adv_data_len; /*!< Adv data length */ + uint8_t scan_rsp_len; /*!< Scan response length */ + int rssi; /*!< Searched device's RSSI */ +} ble_hci_scan_result_t; + +/** + * @brief Advertising channel mask + * + */ +typedef enum { + ADV_CHNL_37 = 0x01, + ADV_CHNL_38 = 0x02, + ADV_CHNL_39 = 0x04, + ADV_CHNL_ALL = 0x07, +} ble_hci_adv_channel_t; + +/** + * @brief Ble scan type + * + */ +typedef enum { + BLE_SCAN_TYPE_PASSIVE = 0x0, /*!< Passive scan */ + BLE_SCAN_TYPE_ACTIVE = 0x1, /*!< Active scan */ +} ble_hci_scan_type_t; + +/** + * @brief Ble adv filteer type + * + */ +typedef enum { + ///Allow both scan and connection requests from anyone + ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY = 0x00, + ///Allow both scan req from White List devices only and connection req from anyone + ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY, + ///Allow both scan req from anyone and connection req from White List devices only + ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST, + ///Allow scan and connection requests from White List devices only + ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST, + ///Enumeration end value for advertising filter policy value check +} ble_hci_adv_filter_t; + +/** + * @brief Ble adv parameters + * + */ +typedef struct { + uint16_t adv_int_min; /*!< Time = N × 0.625 ms Range: 0x0020 to 0x4000 */ + uint16_t adv_int_max; /*!< Time = N × 0.625 ms Range: 0x0020 to 0x4000 */ + ble_hci_adv_type_t adv_type; /*!< Advertising Type */ + ble_hci_addr_type_t own_addr_type; /*!< Own Address Type */ + ble_hci_addr_t peer_addr; /*!< Peer device bluetooth device address */ + ble_hci_addr_type_t peer_addr_type; /*!< Peer device bluetooth device address type, only support public address type and random address type */ + ble_hci_adv_channel_t channel_map; /*!< Advertising channel map */ + ble_hci_adv_filter_t adv_filter_policy; /*!< Advertising Filter Policy: */ +} ble_hci_adv_param_t; + +/** + * @brief Ble sccan parameters + * + */ +typedef struct { + ble_hci_scan_type_t scan_type; /*!< Scan Type */ + uint16_t scan_interval; /*!< Time = N × 0.625 ms Range: 0x0004 to 0x4000 */ + uint16_t scan_window; /*!< Time = N × 0.625 ms Range: 0x0004 to 0x4000 */ + ble_hci_addr_type_t own_addr_type; /*!< Own Address Type */ + ble_hci_adv_filter_t filter_policy; /*!< Scanning Filter Policy */ +} ble_hci_scan_param_t; + +/** + * @brief BLE HCI scan callback function type + * @param scan_result : ble advertisement scan result + * @param result_len : length of scan result + */ +typedef void (*ble_hci_scan_cb_t)(ble_hci_scan_result_t *scan_result, uint16_t result_len); + +/** + * @brief BLE HCI initialization + * + * @return esp_err_t + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_init(void); + +/** + * @brief BLE HCI de-initialization + * + * @return esp_err_t + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_deinit(void); + +/** + * @brief BLE HCI reset controller + * + * @return esp_err_t + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_reset(void); + +/** + * @brief Enable BLE HCI meta event + * + * @return esp_err_t + */ +esp_err_t ble_hci_enable_meta_event(void); + +/** + * @brief Set BLE HCI advertising parameters + * + * @param param : advertising parameters + * + * @return esp_err_t + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_set_adv_param(ble_hci_adv_param_t *param); + +/** + * @brief Set BLE HCI advertising data + * + * @param len : advertising data length + * @param data : advertising data + * + * @return esp_err_t + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_set_adv_data(uint8_t len, uint8_t *data); + +/** + * @brief Set BLE HCI advertising enable + * + * @param enable : true for enable advertising + * + * @return esp_err_t + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_set_adv_enable(bool enable); + +/** + * @brief Set BLE HCI scan parameters + * + * @param param : scan parameters + * + * @return esp_err_t + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_set_scan_param(ble_hci_scan_param_t* param); + +/** + * @brief Set BLE HCI scan enable + * + * @param enable : enable or disable scan + * @param filter_duplicates : filter duplicates or not + * + * @return esp_err_t + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_set_scan_enable(bool enable, bool filter_duplicates); + +/** + * @brief Set BLE HCI scan callback + * + * @param cb : scan callback function pointer + * + * @return esp_err_t + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_set_register_scan_callback(ble_hci_scan_cb_t cb); + +/** + * @brief Add BLE white list + * + * @param addr : address to be added to white list + * @param addr_type : address type to be added to white list + * + * @return esp_err_t + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_add_to_accept_list(ble_hci_addr_t addr, ble_hci_addr_type_t addr_type); + +/** + * @brief Clear BLE white list + * + * @return esp_err_t + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_clear_accept_list(void); + +/** + * @brief Set BLE owner address + * + * @param addr : owner address + * @return + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t ble_hci_set_random_address(ble_hci_addr_t addr); + +#ifdef __cplusplus +} +#endif diff --git a/components/bluetooth/ble_hci/license.txt b/components/bluetooth/ble_hci/license.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/components/bluetooth/ble_hci/license.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/components/bluetooth/ble_hci/priv_include/bt_hci_common.h b/components/bluetooth/ble_hci/priv_include/bt_hci_common.h new file mode 100644 index 000000000..8b9075ebf --- /dev/null +++ b/components/bluetooth/ble_hci/priv_include/bt_hci_common.h @@ -0,0 +1,206 @@ +/* + * Basic macros and functions for Bluetooth Host Controller Interface Layer. + * + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdio.h" +#include "string.h" + +#define HCI_H4_CMD_PREAMBLE_SIZE (4) + +/* HCI Command Opcode group Field (OGF) */ +#define HCI_GRP_HOST_CONT_BASEBAND_CMDS (0x03 << 10) /* 0x0C00 */ +#define HCI_GRP_BLE_CMDS (0x08 << 10) + +/* HCI Command Opcode Command Field (OCF) */ +#define HCI_OCF_RESET (0x0003) +#define HCI_OCF_SET_EVT_MASK (0x0001) +#define HCI_OCF_SET_RANDOM_ADDR (0x0005) +#define HCI_OCF_WRITE_ADV_ENABLE (0x000A) +#define HCI_OCF_WRITE_ADV_DATA (0x0008) +#define HCI_OCF_WRITE_ADV_PARAMS (0x0006) +#define HCI_OCF_WRITE_SCAN_PARAM (0x000B) +#define HCI_OCF_WRITE_SCAN_ENABLE (0x000C) +#define HCI_OCF_READ_WHITE_LIST_SIZE (0x000F) +#define HCI_OCF_CLEAR_ACCEPT_LIST (0x0010) +#define HCI_OCF_ADD_TO_ACCEPT_LIST (0x0011) + +/* HCI Command Opcode Command Field (OCF) */ +#define HCI_RESET (HCI_OCF_RESET | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_EVT_MASK (HCI_OCF_SET_EVT_MASK | HCI_GRP_HOST_CONT_BASEBAND_CMDS) + +/* HCI Random Address Set */ +#define HCI_BLE_SET_RANDOM_ADDR (HCI_OCF_SET_RANDOM_ADDR | HCI_GRP_BLE_CMDS) +/* Advertising Commands. */ +#define HCI_BLE_WRITE_ADV_ENABLE (HCI_OCF_WRITE_ADV_ENABLE | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_ADV_DATA (HCI_OCF_WRITE_ADV_DATA | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_ADV_PARAMS (HCI_OCF_WRITE_ADV_PARAMS | HCI_GRP_BLE_CMDS) +/* Scan commands */ +#define HCI_BLE_WRITE_SCAN_PARAM (HCI_OCF_WRITE_SCAN_PARAM | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_SCAN_ENABLE (HCI_OCF_WRITE_SCAN_ENABLE | HCI_GRP_BLE_CMDS) + +/* Filter Update commands*/ +#define HCI_BLE_READ_WHITE_LIST_SIZE (HCI_OCF_READ_WHITE_LIST_SIZE | HCI_GRP_BLE_CMDS) +#define HCI_BLE_CLEAR_ACCEPT_LIST (HCI_OCF_CLEAR_ACCEPT_LIST | HCI_GRP_BLE_CMDS) +#define HCI_BLE_ADD_TO_ACCEPT_LIST (HCI_OCF_ADD_TO_ACCEPT_LIST | HCI_GRP_BLE_CMDS) + +/* HCI Command length. */ +#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE (1) +#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS (15) +#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA (31) +#define HCIC_PARAM_SIZE_BLE_SET_RANDOM_ADDR (6) +#define HCIC_PARAM_SIZE_BLE_ADD_TO_WHITE_LIST (7) +#define HCIC_PARAM_SIZE_SET_EVENT_MASK (8) +#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM (7) +#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE (2) + +/* LE Meta Events. */ +#define LE_META_EVENTS (0x3E) +#define HCI_LE_ADV_REPORT (0x02) + +#define LE_CMD_COMPLETE_EVENT (0x0E) + +#define BD_ADDR_LEN (6) /* Device address length */ +typedef uint8_t bd_addr_t[BD_ADDR_LEN]; /* Device address */ + +#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);} +#define UINT8_TO_STREAM(p, u8) {*(p)++ = (uint8_t)(u8);} +#define BDADDR_TO_STREAM(p, a) {int ijk; for (ijk = 0; ijk < BD_ADDR_LEN; ijk++) *(p)++ = (uint8_t) a[BD_ADDR_LEN - 1 - ijk];} +#define ARRAY_TO_STREAM(p, a, len) {int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (uint8_t) a[ijk];} + +enum { + H4_TYPE_COMMAND = 1, + H4_TYPE_ACL = 2, + H4_TYPE_SCO = 3, + H4_TYPE_EVENT = 4 +}; + +/** + * @brief Writes reset bit in buf and returns size of input buffer after + * writing in it. + * + * @param buf Input buffer to write which will be sent to controller. + * + * @return Size of buf after writing into it. + */ +uint16_t make_cmd_reset(uint8_t *buf); + +/** + * @brief This function is used to request the Controller to start or stop advertising. + * + * @param buf Input buffer to write which will be sent to controller. + * @param adv_enable 1 to enable advertising and 0 to disable. + * + * @return Size of buf after writing into it. + */ +uint16_t make_cmd_ble_set_adv_enable(uint8_t *buf, uint8_t adv_enable); + +/** + * @brief This function is used by the Host to set the advertising parameters. + * + * @param buf Input buffer to write which will be sent to controller. + * @param adv_int_min Minimum advertising interval. + * @param adv_int_max Maximum advertising interval. + * @param adv_type Advertising type. + * @param addr_type_own Own advertising type. + * @param addr_type_peer Peer device's address type. + * @param peer_addr Peer device's BD address. + * @param channel_map Advertising channel map. + * @param adv_filter_policy Advertising Filter Policy. + * + * @return Size of buf after writing into it. + */ +uint16_t make_cmd_ble_set_adv_param(uint8_t *buf, uint16_t adv_int_min, uint16_t adv_int_max, + uint8_t adv_type, uint8_t addr_type_own, + uint8_t addr_type_peer, bd_addr_t peer_addr, + uint8_t channel_map, uint8_t adv_filter_policy); + +/** + * @brief This function is used to set the data used in advertising packets that have a data field. + * + * @param buf Input buffer to write which will be sent to controller. + * @param data_len Length of p_data. + * @param p_data Data to be set. + * + * @return Size of buf after writing into it. + */ +uint16_t make_cmd_ble_set_adv_data(uint8_t *buf, uint8_t data_len, uint8_t *p_data); + +/** + * @brief This function is used to control which LE events are generated by the HCI for the Host. + * The event mask allows the Host to control which events will interrupt it. + * + * @param buf Input buffer to write which will be sent to controller. + * @param evt_mask 8 byte data as per spec. + * + * @return Size of buf after writing into it. + */ +uint16_t make_cmd_set_evt_mask(uint8_t *buf, uint8_t *evt_mask); + +/** + * @brief This function is used to set the scan parameters. + * + * @param buf Input buffer to write which will be sent to controller. + * @param scan_type Active or Passive scanning. + * @param scan_interval Set scan_interval. + * @param scan_window Set scan_window. + * @param own_addr_type Set own address type. + * @param filter_policy Scanning filter policy. + * + * @return Size of buf after writing into it. + */ +uint16_t make_cmd_ble_set_scan_params(uint8_t *buf, uint8_t scan_type, + uint16_t scan_interval, uint16_t scan_window, uint8_t own_addr_type, + uint8_t filter_policy); + +/** + * @brief This function is used to set the data used in advertising packets that have a data field. + * + * @param buf Input buffer to write which will be sent to controller. + * @param scan_enable Enable or disable scanning. + * @param filter_duplicates Filter duplicates enable or disable. + * + * @return Size of buf after writing into it. + */ +uint16_t make_cmd_ble_set_scan_enable(uint8_t *buf, uint8_t scan_enable, + uint8_t filter_duplicates); + +/** + * @brief This function is used to add a single device to the Filter Accept List stored in the Controller. + * + * @param buf Input buffer to write which will be sent to controller. + * @param addr_type device's address type. 0x00 for public and 0x01 for random. + * @param peer_addr device's BD address. + * @return Size of buf after writing into it. + */ +uint16_t make_cmd_ble_add_to_filter_accept_list(uint8_t *buf, uint8_t addr_type, bd_addr_t addr); + +/** + * @brief This function is used to clear the white list stored in the controller. + * + * @param buf Input buffer to write which will be sent to controller. + * @return Size of buf after writing into it. + */ +uint16_t make_cmd_ble_clear_white_list(uint8_t *buf); + +/** + * @brief This function is used to set random address. + * + * @param buf Input buffer to write which will be sent to controller. + * @param addr Random address to be set. + * @return Size of buf after writing into it. + */ +uint16_t make_cmd_set_random_address(uint8_t *buf, bd_addr_t addr); + +#ifdef __cplusplus +} +#endif diff --git a/components/bluetooth/ble_hci/test_apps/CMakeLists.txt b/components/bluetooth/ble_hci/test_apps/CMakeLists.txt new file mode 100644 index 000000000..1363d2eee --- /dev/null +++ b/components/bluetooth/ble_hci/test_apps/CMakeLists.txt @@ -0,0 +1,9 @@ + +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components" + "../../ble_hci") +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_hci_test) diff --git a/components/bluetooth/ble_hci/test_apps/main/CMakeLists.txt b/components/bluetooth/ble_hci/test_apps/main/CMakeLists.txt new file mode 100644 index 000000000..8922c27ae --- /dev/null +++ b/components/bluetooth/ble_hci/test_apps/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRC_DIRS "." + PRIV_INCLUDE_DIRS "." + PRIV_REQUIRES unity ble_hci ${PRIVREQ}) diff --git a/components/bluetooth/ble_hci/test_apps/main/ble_hci_test.c b/components/bluetooth/ble_hci/test_apps/main/ble_hci_test.c new file mode 100644 index 000000000..1dbef84bc --- /dev/null +++ b/components/bluetooth/ble_hci/test_apps/main/ble_hci_test.c @@ -0,0 +1,118 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "ble_hci.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" + +#define TEST_MEMORY_LEAK_THRESHOLD (-460) + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void ble_hci_scan_cb(ble_hci_scan_result_t *scan_result, uint16_t result_len) +{ + for (int i = 0; i < result_len; i++) { + printf("%2x:%2x:%2x:%2x:%2x:%2x\n", + scan_result[i].bda[0], scan_result[i].bda[1], scan_result[i].bda[2], + scan_result[i].bda[3], scan_result[i].bda[4], scan_result[i].bda[5]); + } +} + +TEST_CASE("ble_hci_test", "[ble hci adv]") +{ + ble_hci_init(); + + uint8_t own_addr[6] = {0xff, 0x22, 0x33, 0x44, 0x55, 0x66}; + ble_hci_set_random_address(own_addr); + + ble_hci_adv_param_t adv_param = { + .adv_int_min = 0x20, + .adv_int_max = 0x40, + .adv_type = ADV_TYPE_NONCONN_IND, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .peer_addr_type = BLE_ADDR_TYPE_PUBLIC, + .channel_map = ADV_CHNL_ALL, + .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + }; + uint8_t peer_addr[6] = {0x80, 0x81, 0x82, 0x83, 0x84, 0x85}; + memcpy(adv_param.peer_addr, peer_addr, BLE_HCI_ADDR_LEN); + ble_hci_set_adv_param(&adv_param); + + char *adv_name = "ESP-BLE-1"; + uint8_t name_len = (uint8_t)strlen(adv_name); + uint8_t adv_data[31] = { + 0x02, 0x01, 0x06, 0x0, 0x09 + }; + uint8_t adv_data_len; + adv_data[3] = name_len + 1; + memcpy(adv_data + 5, adv_name, name_len); + adv_data_len = 5 + name_len; + ble_hci_set_adv_data(adv_data_len, adv_data); + + ble_hci_set_adv_enable(true); + + vTaskDelay(5000 / portTICK_PERIOD_MS); + + ble_hci_set_adv_enable(false); + ble_hci_deinit(); +} + +TEST_CASE("ble_hci_test", "[ble hci scan]") +{ + ble_hci_init(); + + ble_hci_reset(); + ble_hci_enable_meta_event(); + + ble_hci_scan_param_t scan_param = { + .scan_type = BLE_SCAN_TYPE_PASSIVE, + .scan_interval = 0x50, + .scan_window = 0x50, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + .filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY, + }; + + ble_hci_set_scan_param(&scan_param); + ble_hci_set_register_scan_callback(&ble_hci_scan_cb); + uint8_t peer_addr[6] = {0xff, 0x22, 0x33, 0x44, 0x55, 0x66}; + ble_hci_add_to_accept_list(peer_addr, BLE_ADDR_TYPE_RANDOM); + ble_hci_set_scan_enable(true, false); + + vTaskDelay(5000 / portTICK_PERIOD_MS); + + ble_hci_set_scan_enable(false, false); + ble_hci_deinit(); +} + +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 >= TEST_MEMORY_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"); +} + +void app_main(void) +{ + printf("ble_hci_adv_test\n"); + unity_run_menu(); +} diff --git a/components/bluetooth/ble_hci/test_apps/pytest_button.py b/components/bluetooth/ble_hci/test_apps/pytest_button.py new file mode 100644 index 000000000..c355aa85d --- /dev/null +++ b/components/bluetooth/ble_hci/test_apps/pytest_button.py @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: 2024Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +''' +Steps to run these cases: +- Build + - . ${IDF_PATH}/export.sh + - pip install idf_build_apps + - python tools/build_apps.py components/bluetooth/ble_hci/test_apps -t esp32 +- Test + - pip install -r tools/requirements/requirement.pytest.txt + - pytest components/bluetooth/ble_hci/test_apps --target esp32 +''' + +import pytest +from pytest_embedded import Dut + +@pytest.mark.target('esp32') +@pytest.mark.target('esp32c3') +@pytest.mark.target('esp32c6') +@pytest.mark.target('esp32s3') +@pytest.mark.env('generic') +@pytest.mark.parametrize( + 'config', + [ + 'defaults', + ], +) +def test_ble_hci(dut: Dut)-> None: + dut.run_all_single_board_cases() + +@pytest.mark.target('esp32c2') +@pytest.mark.env('xtal_26mhz') +@pytest.mark.parametrize( + 'config , baud', + [ + ('c2_xtal_26mhz', '74880'), + ], +) +def test_ble_hci_esp32c2(dut: Dut)-> None: + dut.run_all_single_board_cases() diff --git a/components/bluetooth/ble_hci/test_apps/sdkconfig.ci.c2_xtal_26mhz b/components/bluetooth/ble_hci/test_apps/sdkconfig.ci.c2_xtal_26mhz new file mode 100644 index 000000000..965ee5dec --- /dev/null +++ b/components/bluetooth/ble_hci/test_apps/sdkconfig.ci.c2_xtal_26mhz @@ -0,0 +1,3 @@ +CONFIG_IDF_TARGET="esp32c2" +CONFIG_XTAL_FREQ=26 +CONFIG_XTAL_FREQ_26=y diff --git a/components/bluetooth/ble_hci/test_apps/sdkconfig.defaults b/components/bluetooth/ble_hci/test_apps/sdkconfig.defaults new file mode 100644 index 000000000..d72e03f2e --- /dev/null +++ b/components/bluetooth/ble_hci/test_apps/sdkconfig.defaults @@ -0,0 +1,15 @@ +# Override some defaults so BT stack is enabled +# in this example + +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT_EN=n + +# +# BT config +# +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n +CONFIG_BTDM_CTRL_MODE_BTDM=n +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_CONTROLLER_ONLY=y diff --git a/docs/Doxyfile b/docs/Doxyfile index 1f8c9b393..5e6f3ff31 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -24,6 +24,7 @@ INPUT = \ $(PROJECT_PATH)/components/audio/dac_audio/include/dac_audio.h \ $(PROJECT_PATH)/components/audio/pwm_audio/include/pwm_audio.h \ $(PROJECT_PATH)/components/bluetooth/ble_conn_mgr/include/esp_ble_conn_mgr.h \ + $(PROJECT_PATH)/components/bluetooth/ble_hci/include/ble_hci.h \ $(PROJECT_PATH)/components/bluetooth/ble_profiles/std/ble_anp/include/esp_anp.h \ $(PROJECT_PATH)/components/bluetooth/ble_profiles/std/ble_hrp/include/esp_hrp.h \ $(PROJECT_PATH)/components/bluetooth/ble_profiles/std/ble_htp/include/esp_htp.h \ diff --git a/docs/en/bluetooth/ble_hci.rst b/docs/en/bluetooth/ble_hci.rst new file mode 100644 index 000000000..439ef18cb --- /dev/null +++ b/docs/en/bluetooth/ble_hci.rst @@ -0,0 +1,32 @@ +BLE HCI Components +============================== +:link_to_translation:`zh_CN:[中文]` + +The BLE HCI component is used to directly operate the BLE Controller via the VHCI interface to achieve functionalities like broadcasting and scanning. Compared to initiating broadcasting and scanning through the Nimble or Bluedroid protocol stacks, using this component offers the following advantages: + +- Lower memory usage +- Smaller firmware size +- Faster initialization process + +How to Use BLE HCI +---------------------------- + +For Broadcasting Applications: +1.Initialize BLE HCI: Use :cpp:func:`ble_hci_init` function to initialize. +2.Set Local Random Address (Optional): If you need to use a random address for broadcasting, set it using the :cpp:func:`ble_hci_set_random_address` function. +3.Configure Broadcast Parameters: Use :cpp:func:`ble_hci_set_adv_param` function to configure broadcast parameters. +4.Set Broadcast Data: Use :cpp:func:`ble_hci_set_adv_data` function to specify the data to be broadcast. +5.Start Broadcasting: Use :cpp:func:`ble_hci_set_adv_enable` function. + +For Scanning Applications: +1.Initialize BLE HCI: Use :cpp:func:`ble_hci_init` function to initialize. +2.Configure Scanning Parameters: Use :cpp:func:`ble_hci_set_scan_param` function to configure scanning parameters. +3.Enable Meta Event: Use :cpp:func:`ble_hci_enable_meta_event` function to enable interrupt events. +4.Register Scanning Event Function: Use :cpp:func:`ble_hci_set_register_scan_callback` function to register the interrupt event. +5.Start Scanning: Use the :cpp:func:`ble_hci_set_scan_enable` function. + + +API Reference +----------------- + +.. include-build-file:: inc/ble_hci.inc \ No newline at end of file diff --git a/docs/en/bluetooth/index.rst b/docs/en/bluetooth/index.rst index b3f055205..15a953200 100644 --- a/docs/en/bluetooth/index.rst +++ b/docs/en/bluetooth/index.rst @@ -1,5 +1,5 @@ -Bluetooth +Bluetooth ************************* :link_to_translation:`zh_CN:[中文]` @@ -10,4 +10,4 @@ Bluetooth BLE Connection Management BLE Services BLE Profiles - + BLE HCI diff --git a/docs/zh_CN/bluetooth/ble_hci.rst b/docs/zh_CN/bluetooth/ble_hci.rst new file mode 100644 index 000000000..074388600 --- /dev/null +++ b/docs/zh_CN/bluetooth/ble_hci.rst @@ -0,0 +1,29 @@ +BLE HCI 组件 +============================== +:link_to_translation:`en:[English]` + +BLE HCI 组件用于通过 VHCI 接口直接操作 BLE Controller 实现广播,扫描等功能。 +相比于通过 Nimble 或 Bluedroid 协议栈发起广播和扫描,使用该组件有如下优点: +- 更少的内存占用 +- 更小的固件尺寸 +- 更快的初始化流程 + +BLE HCI 使用方法 +----------------- +对于广播应用: +1.初始化 BLE HCI: 使用 :cpp:func:`ble_hci_init` 函数进行初始化。 +2.设定本机随机地址(可选): 如果需要使用随机地址作为广播地址,使用:cpp:func:`ble_hci_set_random_address`函数进行设定。 +3.配置广播参数:使用 :cpp:func:`ble_hci_set_adv_param` 配置广播参数。 +4.配置广播数据:使用 :cpp:func:`ble_hci_set_adv_data` 设定需要广播的数据内容。 +5.开始广播: 使用 :cpp:func:`ble_hci_set_adv_enable`。 + +对于扫描应用: +1.初始化 BLE HCI: 使用 :cpp:func:`ble_hci_init` 函数进行初始化。 +2.配置扫描参数:使用 :cpp:func:`ble_hci_set_scan_param` 配置扫描参数。 +3.使能meta事件: 使用 :cpp:func:`ble_hci_enable_meta_event` 使能中断事件。 +4.注册扫描事件函数: 使用 :cpp:func:`ble_hci_set_register_scan_callback` 注册中断事件。 +5.开始扫描: 使用 :cpp:func:`ble_hci_set_scan_enable`。 + +API 参考 +--------------------------------------------- +.. include-build-file:: inc/ble_hci.inc \ No newline at end of file diff --git a/docs/zh_CN/bluetooth/index.rst b/docs/zh_CN/bluetooth/index.rst index 33aa74a2a..df0f8dc2e 100644 --- a/docs/zh_CN/bluetooth/index.rst +++ b/docs/zh_CN/bluetooth/index.rst @@ -10,4 +10,4 @@ BLE 连接管理 BLE 服务 BLE 配置文件 - + BLE HCI