mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
bluetooth: Added HCI example for combined scanning and advertising.
This commit is contained in:
parent
abb79e4fb5
commit
6dbb993071
@ -18,6 +18,13 @@ Demonstrates interaction with controller though virtual HCI layer. In this examp
|
||||
|
||||
See the [README.md](./controller_vhci_ble_adv/README.md) file in the example [controller_vhci_ble_adv](./controller_vhci_ble_adv).
|
||||
|
||||
## ble_adv_scan_combined
|
||||
|
||||
Demonstrates interaction with controller. In this example, BLE advertising and scanning is done. Also scanned advertising reports are parsed and displayed.
|
||||
|
||||
See the [README.md](./ble_adv_scan_combined/README.md) file in the example [ble_adv_scan_combined](./ble_adv_scan_combined).
|
||||
|
||||
|
||||
## hci_common_component
|
||||
|
||||
This is separate component adding functionalities for HCI Layer. Since this component is just used by HCI examples, it is not placed in global components.
|
||||
|
@ -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)
|
||||
|
||||
# This example uses an extra component for common functions for Bluetooth HCI layer.
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/hci/hci_common_component)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ble_adv_scan)
|
10
examples/bluetooth/hci/ble_adv_scan_combined/Makefile
Normal file
10
examples/bluetooth/hci/ble_adv_scan_combined/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := ble_adv_scan
|
||||
|
||||
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/bluetooth/hci/hci_common_component
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
9
examples/bluetooth/hci/ble_adv_scan_combined/README.md
Normal file
9
examples/bluetooth/hci/ble_adv_scan_combined/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
ESP-IDF Combined Bluetooth advertising and scanning
|
||||
===================================================
|
||||
|
||||
This is a Bluetooth advertising and scanning demo with virtual HCI interface. Send Reset, ADV_PARAM, ADV_DATA and HCI_ADV_ENABLE command for BLE advertising. And SET_EVENT_MASK, SCAN_PARAMS and SCAN_START commands for BLE scanning. Scanned advertising reports from other devices are also displayed.
|
||||
|
||||
In this example no host is used. But some of the functionalities of a host are implemented.
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "app_bt.c"
|
||||
INCLUDE_DIRS ".")
|
446
examples/bluetooth/hci/ble_adv_scan_combined/main/app_bt.c
Normal file
446
examples/bluetooth/hci/ble_adv_scan_combined/main/app_bt.c
Normal file
@ -0,0 +1,446 @@
|
||||
/* BLE Combined Advertising and Scanning Example.
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_bt.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "bt_hci_common.h"
|
||||
|
||||
static const char *TAG = "BLE_ADV_SCAN";
|
||||
|
||||
typedef struct {
|
||||
char scan_local_name[32];
|
||||
uint8_t name_len;
|
||||
} ble_scan_local_name_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *q_data;
|
||||
uint16_t q_data_len;
|
||||
} host_rcv_data_t;
|
||||
|
||||
static uint8_t hci_cmd_buf[128];
|
||||
|
||||
static uint16_t scanned_count = 0;
|
||||
static QueueHandle_t adv_queue;
|
||||
|
||||
static void periodic_timer_callback(void *arg)
|
||||
{
|
||||
ESP_LOGI(TAG, "Number of received advertising reports: %d", scanned_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: BT controller callback function, used to notify the upper layer that
|
||||
* controller is ready to receive command
|
||||
*/
|
||||
static void controller_rcv_pkt_ready(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "controller rcv pkt ready");
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: BT controller callback function to transfer data packet to
|
||||
* the host
|
||||
*/
|
||||
static int host_rcv_pkt(uint8_t *data, uint16_t len)
|
||||
{
|
||||
host_rcv_data_t send_data;
|
||||
uint8_t *data_pkt;
|
||||
/* Check second byte for HCI event. If event opcode is 0x0e, the event is
|
||||
* HCI Command Complete event. Sice we have recieved "0x0e" event, we can
|
||||
* check for byte 4 for command opcode and byte 6 for it's return status. */
|
||||
if (data[1] == 0x0e) {
|
||||
if (data[6] == 0) {
|
||||
ESP_LOGI(TAG, "Event opcode 0x%02x success.", data[4]);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Event opcode 0x%02x fail with reason: 0x%02x.", data[4], data[6]);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
data_pkt = (uint8_t *)malloc(sizeof(uint8_t) * len);
|
||||
if (data_pkt == NULL) {
|
||||
ESP_LOGE(TAG, "Malloc data_pkt failed!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
memcpy(data_pkt, data, len);
|
||||
send_data.q_data = data_pkt;
|
||||
send_data.q_data_len = len;
|
||||
if (xQueueSend(adv_queue, (void *)&send_data, ( TickType_t ) 0) != pdTRUE) {
|
||||
ESP_LOGD(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(data_pkt);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_vhci_host_callback_t vhci_host_cb = {
|
||||
controller_rcv_pkt_ready,
|
||||
host_rcv_pkt
|
||||
};
|
||||
|
||||
static void hci_cmd_send_reset(void)
|
||||
{
|
||||
uint16_t sz = make_cmd_reset (hci_cmd_buf);
|
||||
esp_vhci_host_send_packet(hci_cmd_buf, sz);
|
||||
}
|
||||
|
||||
static void hci_cmd_send_set_evt_mask(void)
|
||||
{
|
||||
/* 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(hci_cmd_buf, evt_mask);
|
||||
esp_vhci_host_send_packet(hci_cmd_buf, sz);
|
||||
}
|
||||
|
||||
static void hci_cmd_send_ble_scan_params(void)
|
||||
{
|
||||
/* Set scan type to 0x01 for active scanning and 0x00 for passive scanning. */
|
||||
uint8_t scan_type = 0x01;
|
||||
|
||||
/* Scan window and Scan interval are set in terms of number of slots. Each slot is of 625 microseconds. */
|
||||
uint16_t scan_interval = 0x50; /* 50 ms */
|
||||
uint16_t scan_window = 0x30; /* 30 ms */
|
||||
|
||||
uint8_t own_addr_type = 0x00; /* Public Device Address (default). */
|
||||
uint8_t filter_policy = 0x00; /* Accept all packets excpet directed advertising packets (default). */
|
||||
uint16_t sz = make_cmd_ble_set_scan_params(hci_cmd_buf, scan_type, scan_interval, scan_window, own_addr_type, filter_policy);
|
||||
esp_vhci_host_send_packet(hci_cmd_buf, sz);
|
||||
}
|
||||
|
||||
static void hci_cmd_send_ble_scan_start(void)
|
||||
{
|
||||
uint8_t scan_enable = 0x01; /* Scanning enabled. */
|
||||
uint8_t filter_duplicates = 0x00; /* Duplicate filtering disabled. */
|
||||
uint16_t sz = make_cmd_ble_set_scan_enable(hci_cmd_buf, scan_enable, filter_duplicates);
|
||||
esp_vhci_host_send_packet(hci_cmd_buf, sz);
|
||||
ESP_LOGI(TAG, "BLE Scanning started..");
|
||||
}
|
||||
|
||||
static void hci_cmd_send_ble_adv_start(void)
|
||||
{
|
||||
uint16_t sz = make_cmd_ble_set_adv_enable (hci_cmd_buf, 1);
|
||||
esp_vhci_host_send_packet(hci_cmd_buf, sz);
|
||||
ESP_LOGI(TAG, "BLE Advertising started..");
|
||||
}
|
||||
|
||||
static void hci_cmd_send_ble_set_adv_param(void)
|
||||
{
|
||||
/* Minimum and maximum Advertising interval are set in terms of slots. Each slot is of 625 microseconds. */
|
||||
uint16_t adv_intv_min = 0x100;
|
||||
uint16_t adv_intv_max = 0x100;
|
||||
|
||||
/* Connectable undirected advertising (ADV_IND). */
|
||||
uint8_t adv_type = 0;
|
||||
|
||||
/* Own address is public address. */
|
||||
uint8_t own_addr_type = 0;
|
||||
|
||||
/* Public Device Address */
|
||||
uint8_t peer_addr_type = 0;
|
||||
uint8_t peer_addr[6] = {0x80, 0x81, 0x82, 0x83, 0x84, 0x85};
|
||||
|
||||
/* Channel 37, 38 and 39 for advertising. */
|
||||
uint8_t adv_chn_map = 0x07;
|
||||
|
||||
/* Process scan and connection requests from all devices (i.e., the White List is not in use). */
|
||||
uint8_t adv_filter_policy = 0;
|
||||
|
||||
uint16_t sz = make_cmd_ble_set_adv_param(hci_cmd_buf,
|
||||
adv_intv_min,
|
||||
adv_intv_max,
|
||||
adv_type,
|
||||
own_addr_type,
|
||||
peer_addr_type,
|
||||
peer_addr,
|
||||
adv_chn_map,
|
||||
adv_filter_policy);
|
||||
esp_vhci_host_send_packet(hci_cmd_buf, sz);
|
||||
}
|
||||
|
||||
static void hci_cmd_send_ble_set_adv_data(void)
|
||||
{
|
||||
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;
|
||||
for (int i = 0; i < name_len; i++) {
|
||||
adv_data[5 + i] = (uint8_t)adv_name[i];
|
||||
}
|
||||
adv_data_len = 5 + name_len;
|
||||
|
||||
uint16_t sz = make_cmd_ble_set_adv_data(hci_cmd_buf, adv_data_len, (uint8_t *)adv_data);
|
||||
esp_vhci_host_send_packet(hci_cmd_buf, sz);
|
||||
ESP_LOGI(TAG, "Starting BLE advertising with name \"%s\"", adv_name);
|
||||
}
|
||||
|
||||
static esp_err_t get_local_name (uint8_t *data_msg, uint8_t data_len, ble_scan_local_name_t *scanned_packet)
|
||||
{
|
||||
uint8_t curr_ptr = 0, curr_len, curr_type;
|
||||
while (curr_ptr < data_len) {
|
||||
curr_len = data_msg[curr_ptr++];
|
||||
curr_type = data_msg[curr_ptr++];
|
||||
if (curr_len == 0) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Search for current data type and see if it contains name as data (0x08 or 0x09). */
|
||||
if (curr_type == 0x08 || curr_type == 0x09) {
|
||||
for (uint8_t i = 0; i < curr_len - 1; i += 1) {
|
||||
scanned_packet->scan_local_name[i] = data_msg[curr_ptr + i];
|
||||
}
|
||||
scanned_packet->name_len = curr_len - 1;
|
||||
return ESP_OK;
|
||||
} else {
|
||||
/* Search for next data. Current length includes 1 octate for AD Type (2nd octate). */
|
||||
curr_ptr += curr_len - 1;
|
||||
}
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
void hci_evt_process(void *pvParameters)
|
||||
{
|
||||
host_rcv_data_t *rcv_data = (host_rcv_data_t *)malloc(sizeof(host_rcv_data_t));
|
||||
if (rcv_data == NULL) {
|
||||
ESP_LOGE(TAG, "Malloc rcv_data failed!");
|
||||
return;
|
||||
}
|
||||
esp_err_t ret;
|
||||
|
||||
while (1) {
|
||||
uint8_t sub_event, num_responses, total_data_len, data_msg_ptr, hci_event_opcode;
|
||||
uint8_t *queue_data = NULL, *event_type = NULL, *addr_type = NULL, *addr = NULL, *data_len = NULL, *data_msg = NULL;
|
||||
short int *rssi = NULL;
|
||||
uint16_t data_ptr;
|
||||
ble_scan_local_name_t *scanned_name = NULL;
|
||||
total_data_len = 0;
|
||||
data_msg_ptr = 0;
|
||||
if (xQueueReceive(adv_queue, rcv_data, portMAX_DELAY) != pdPASS) {
|
||||
ESP_LOGE(TAG, "Queue receive error");
|
||||
} else {
|
||||
/* `data_ptr' keeps track of current position in the received data. */
|
||||
data_ptr = 0;
|
||||
queue_data = rcv_data->q_data;
|
||||
|
||||
/* Parsing `data' and copying in various fields. */
|
||||
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) {
|
||||
|
||||
scanned_count += 1;
|
||||
|
||||
/* Get number of advertising reports. */
|
||||
num_responses = queue_data[data_ptr++];
|
||||
event_type = (uint8_t *)malloc(sizeof(uint8_t) * num_responses);
|
||||
if (event_type == NULL) {
|
||||
ESP_LOGE(TAG, "Malloc event_type failed!");
|
||||
goto reset;
|
||||
}
|
||||
for (uint8_t i = 0; i < num_responses; i += 1) {
|
||||
event_type[i] = queue_data[data_ptr++];
|
||||
}
|
||||
|
||||
/* Get advertising type for every report. */
|
||||
addr_type = (uint8_t *)malloc(sizeof(uint8_t) * num_responses);
|
||||
if (addr_type == NULL) {
|
||||
ESP_LOGE(TAG, "Malloc addr_type failed!");
|
||||
goto reset;
|
||||
}
|
||||
for (uint8_t i = 0; i < num_responses; i += 1) {
|
||||
addr_type[i] = queue_data[data_ptr++];
|
||||
}
|
||||
|
||||
/* Get BD address in every advetising report and store in
|
||||
* single array of length `6 * num_responses' as each address
|
||||
* will take 6 spaces. */
|
||||
addr = (uint8_t *)malloc(sizeof(uint8_t) * 6 * num_responses);
|
||||
if (addr == NULL) {
|
||||
ESP_LOGE(TAG, "Malloc addr failed!");
|
||||
goto reset;
|
||||
}
|
||||
for (int i = 0; i < num_responses; i += 1) {
|
||||
for (int j = 0; j < 6; j += 1) {
|
||||
addr[(6 * i) + j] = queue_data[data_ptr++];
|
||||
}
|
||||
}
|
||||
|
||||
/* Get length of data for each advertising report. */
|
||||
data_len = (uint8_t *)malloc(sizeof(uint8_t) * num_responses);
|
||||
if (data_len == NULL) {
|
||||
ESP_LOGE(TAG, "Malloc data_len failed!");
|
||||
goto reset;
|
||||
}
|
||||
for (uint8_t i = 0; i < num_responses; i += 1) {
|
||||
data_len[i] = queue_data[data_ptr];
|
||||
total_data_len += queue_data[data_ptr++];
|
||||
}
|
||||
|
||||
if (total_data_len != 0) {
|
||||
/* Get all data packets. */
|
||||
data_msg = (uint8_t *)malloc(sizeof(uint8_t) * total_data_len);
|
||||
if (data_msg == NULL) {
|
||||
ESP_LOGE(TAG, "Malloc data_msg failed!");
|
||||
goto reset;
|
||||
}
|
||||
for (uint8_t i = 0; i < num_responses; i += 1) {
|
||||
for (uint8_t j = 0; j < data_len[i]; j += 1) {
|
||||
data_msg[data_msg_ptr++] = queue_data[data_ptr++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Counts of advertisements done. This count is set in advertising data every time before advertising. */
|
||||
rssi = (short int *)malloc(sizeof(short int) * num_responses);
|
||||
if (data_len == NULL) {
|
||||
ESP_LOGE(TAG, "Malloc rssi failed!");
|
||||
goto reset;
|
||||
}
|
||||
for (uint8_t i = 0; i < num_responses; i += 1) {
|
||||
rssi[i] = -(0xFF - queue_data[data_ptr++]);
|
||||
}
|
||||
|
||||
/* Extracting advertiser's name. */
|
||||
data_msg_ptr = 0;
|
||||
scanned_name = (ble_scan_local_name_t *)malloc(num_responses * sizeof(ble_scan_local_name_t));
|
||||
if (data_len == NULL) {
|
||||
ESP_LOGE(TAG, "Malloc scanned_name failed!");
|
||||
goto reset;
|
||||
}
|
||||
for (uint8_t i = 0; i < num_responses; i += 1) {
|
||||
ret = get_local_name(&data_msg[data_msg_ptr], data_len[i], scanned_name);
|
||||
|
||||
/* Print the data if adv report has a valid name. */
|
||||
if (ret == ESP_OK) {
|
||||
printf("******** Response %d/%d ********\n", i + 1, num_responses);
|
||||
printf("Event type: %02x\nAddress type: %02x\nAddress: ", event_type[i], addr_type[i]);
|
||||
for (int j = 5; j >= 0; j -= 1) {
|
||||
printf("%02x", addr[(6 * i) + j]);
|
||||
if (j > 0) {
|
||||
printf(":");
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nData length: %d", data_len[i]);
|
||||
data_msg_ptr += data_len[i];
|
||||
printf("\nAdvertisement Name: ");
|
||||
for (int k = 0; k < scanned_name->name_len; k += 1 ) {
|
||||
printf("%c", scanned_name->scan_local_name[k]);
|
||||
}
|
||||
printf("\nRSSI: %ddB\n", rssi[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Freeing all spaces allocated. */
|
||||
reset:
|
||||
free(scanned_name);
|
||||
free(rssi);
|
||||
free(data_msg);
|
||||
free(data_len);
|
||||
free(addr);
|
||||
free(addr_type);
|
||||
free(event_type);
|
||||
}
|
||||
}
|
||||
#if (CONFIG_LOG_DEFAULT_LEVEL_DEBUG || CONFIG_LOG_DEFAULT_LEVEL_VERBOSE)
|
||||
printf("Raw Data:");
|
||||
for (uint8_t j = 0; j < rcv_data->q_data_len; j += 1) {
|
||||
printf(" %02x", queue_data[j]);
|
||||
}
|
||||
printf("\nQueue free size: %d\n", uxQueueSpacesAvailable(adv_queue));
|
||||
#endif
|
||||
free(queue_data);
|
||||
}
|
||||
memset(rcv_data, 0, sizeof(host_rcv_data_t));
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
bool continue_commands = 1;
|
||||
int cmd_cnt = 0;
|
||||
|
||||
const esp_timer_create_args_t periodic_timer_args = {
|
||||
.callback = &periodic_timer_callback,
|
||||
.name = "periodic"
|
||||
};
|
||||
|
||||
/* Create timer for logging scanned devices. */
|
||||
esp_timer_handle_t periodic_timer;
|
||||
ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
|
||||
|
||||
/* Start periodic timer for 5 sec. */
|
||||
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 5000000));
|
||||
|
||||
/* Initialize NVS — it is used to store PHY calibration data */
|
||||
esp_err_t 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 );
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
|
||||
ret = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
if (ret) {
|
||||
ESP_LOGI(TAG, "Bluetooth controller release classic bt memory failed: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
|
||||
ESP_LOGI(TAG, "Bluetooth controller initialize failed: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) {
|
||||
ESP_LOGI(TAG, "Bluetooth controller enable failed: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
/* A queue for storing received HCI packets. */
|
||||
adv_queue = xQueueCreate(15, sizeof(host_rcv_data_t));
|
||||
if (adv_queue == NULL) {
|
||||
ESP_LOGE(TAG, "Queue creation failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
esp_vhci_host_register_callback(&vhci_host_cb);
|
||||
while (continue_commands) {
|
||||
if (continue_commands && esp_vhci_host_check_send_available()) {
|
||||
switch (cmd_cnt) {
|
||||
case 0: hci_cmd_send_reset(); ++cmd_cnt; break;
|
||||
case 1: hci_cmd_send_set_evt_mask(); ++cmd_cnt; break;
|
||||
|
||||
/* Send advertising commands. */
|
||||
case 2: hci_cmd_send_ble_set_adv_param(); ++cmd_cnt; break;
|
||||
case 3: hci_cmd_send_ble_set_adv_data(); ++cmd_cnt; break;
|
||||
case 4: hci_cmd_send_ble_adv_start(); ++cmd_cnt; break;
|
||||
|
||||
/* Send scan commands. */
|
||||
case 5: hci_cmd_send_ble_scan_params(); ++cmd_cnt; break;
|
||||
case 6: hci_cmd_send_ble_scan_start(); ++cmd_cnt; break;
|
||||
default: continue_commands = 0; break;
|
||||
}
|
||||
ESP_LOGI(TAG, "BLE Advertise, cmd_sent: %d", cmd_cnt);
|
||||
}
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
}
|
||||
xTaskCreatePinnedToCore(&hci_evt_process, "hci_evt_process", 2048, NULL, 6, NULL, 0);
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -0,0 +1,12 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# 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
|
@ -9,6 +9,40 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
@ -20,9 +54,9 @@ uint16_t make_cmd_ble_set_adv_enable (uint8_t *buf, uint8_t 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_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);
|
||||
|
@ -24,14 +24,26 @@ extern "C" {
|
||||
|
||||
/* HCI Command Opcode Command Field (OCF) */
|
||||
#define HCI_RESET (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
|
||||
#define HCI_SET_EVT_MASK (0x0001 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
|
||||
/* Advertising Commands. */
|
||||
#define HCI_BLE_WRITE_ADV_ENABLE (0x000A | HCI_GRP_BLE_CMDS)
|
||||
#define HCI_BLE_WRITE_ADV_DATA (0x0008 | HCI_GRP_BLE_CMDS)
|
||||
#define HCI_BLE_WRITE_ADV_PARAMS (0x0006 | HCI_GRP_BLE_CMDS)
|
||||
/* Scan commands */
|
||||
#define HCI_BLE_WRITE_SCAN_PARAM (0x000B | HCI_GRP_BLE_CMDS)
|
||||
#define HCI_BLE_WRITE_SCAN_ENABLE (0x000C | 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_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 BD_ADDR_LEN (6) /* Device address length */
|
||||
typedef uint8_t bd_addr_t[BD_ADDR_LEN]; /* Device address */
|
||||
@ -84,21 +96,60 @@ uint16_t make_cmd_ble_set_adv_enable (uint8_t *buf, uint8_t adv_enable);
|
||||
* @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);
|
||||
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.
|
||||
* @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.
|
||||
* @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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user