Kaynağa Gözat

bluetooth: Added HCI example for combined scanning and advertising.

Chinmay Chhajed 6 yıl önce
ebeveyn
işleme
6dbb993071

+ 7 - 0
examples/bluetooth/hci/README.md

@@ -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.

+ 9 - 0
examples/bluetooth/hci/ble_adv_scan_combined/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)
+
+# 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 - 0
examples/bluetooth/hci/ble_adv_scan_combined/Makefile

@@ -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 - 0
examples/bluetooth/hci/ble_adv_scan_combined/README.md

@@ -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.

+ 2 - 0
examples/bluetooth/hci/ble_adv_scan_combined/main/CMakeLists.txt

@@ -0,0 +1,2 @@
+idf_component_register(SRCS "app_bt.c"
+                    INCLUDE_DIRS ".")

+ 446 - 0
examples/bluetooth/hci/ble_adv_scan_combined/main/app_bt.c

@@ -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);
+}

+ 4 - 0
examples/bluetooth/hci/ble_adv_scan_combined/main/component.mk

@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

+ 12 - 0
examples/bluetooth/hci/ble_adv_scan_combined/sdkconfig.defaults

@@ -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

+ 37 - 3
examples/bluetooth/hci/hci_common_component/bt_hci_common.c

@@ -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);

+ 58 - 7
examples/bluetooth/hci/hci_common_component/include/bt_hci_common.h

@@ -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