From c3619edf42729895cb540826994f8007fabf54fd Mon Sep 17 00:00:00 2001 From: Michal morsisko Date: Sat, 31 Dec 2022 17:19:18 +0100 Subject: [PATCH] samples: bluetooth: Add sample demonstrating accept fliter list Add new sample that shows how to use BLE filter accept list during advertising. Signed-off-by: Michal morsisko --- .../peripheral_accept_list/CMakeLists.txt | 9 + .../peripheral_accept_list/README.rst | 33 ++++ .../bluetooth/peripheral_accept_list/prj.conf | 23 +++ .../peripheral_accept_list/sample.yaml | 7 + .../peripheral_accept_list/src/main.c | 170 ++++++++++++++++++ 5 files changed, 242 insertions(+) create mode 100644 samples/bluetooth/peripheral_accept_list/CMakeLists.txt create mode 100644 samples/bluetooth/peripheral_accept_list/README.rst create mode 100644 samples/bluetooth/peripheral_accept_list/prj.conf create mode 100644 samples/bluetooth/peripheral_accept_list/sample.yaml create mode 100644 samples/bluetooth/peripheral_accept_list/src/main.c diff --git a/samples/bluetooth/peripheral_accept_list/CMakeLists.txt b/samples/bluetooth/peripheral_accept_list/CMakeLists.txt new file mode 100644 index 00000000000..8c9cd31f53c --- /dev/null +++ b/samples/bluetooth/peripheral_accept_list/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(peripheral_accept_list) + +target_sources(app PRIVATE + src/main.c +) diff --git a/samples/bluetooth/peripheral_accept_list/README.rst b/samples/bluetooth/peripheral_accept_list/README.rst new file mode 100644 index 00000000000..bc45d525874 --- /dev/null +++ b/samples/bluetooth/peripheral_accept_list/README.rst @@ -0,0 +1,33 @@ +.. _ble_peripheral_accept_list: + +Bluetooth: Peripheral Accept List +################################# + +Overview +******** + +This application demonstrates the BLE advertising accept filter list feature. +If no device is bonded to the peripheral, casual advertising will be performed. +Once a device is bonded, on subsequent boots, connection requests will only be +accepted if the central device is on the accept list. Additionally, scan response +data will only be sent to devices that are on the accept list. As a result, some +BLE central devices (such as Android smartphones) might not display the device +in the scan results if the central device is not on the accept list. + +This sample also provides two BLE characteristics. To perform a write, devices need +to be bonded, while a read can be done immediately after a connection +(no bonding required). + +Requirements +************ + +* A board with BLE support +* Second BLE device acting as a central. For example another Zephyr board or smartphone + +Building and Running +******************** + +This sample can be found under :zephyr_file:`samples/bluetooth/peripheral_accept_list` in the +Zephyr tree. + +See :ref:`bluetooth samples section ` for details. diff --git a/samples/bluetooth/peripheral_accept_list/prj.conf b/samples/bluetooth/peripheral_accept_list/prj.conf new file mode 100644 index 00000000000..3ec06755119 --- /dev/null +++ b/samples/bluetooth/peripheral_accept_list/prj.conf @@ -0,0 +1,23 @@ +# Increased stack due to settings API usage +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +CONFIG_BT=y +CONFIG_BT_DEBUG_LOG=y +CONFIG_BT_SMP=y +CONFIG_BT_SIGNING=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DIS=y +CONFIG_BT_ATT_PREPARE_COUNT=1 +CONFIG_BT_PRIVACY=y +CONFIG_BT_DEVICE_NAME="Accept list" +CONFIG_BT_DEVICE_APPEARANCE=833 + +CONFIG_BT_KEYS_OVERWRITE_OLDEST=y +CONFIG_BT_SETTINGS=y +CONFIG_BT_FILTER_ACCEPT_LIST=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_SETTINGS=y +CONFIG_REBOOT=y diff --git a/samples/bluetooth/peripheral_accept_list/sample.yaml b/samples/bluetooth/peripheral_accept_list/sample.yaml new file mode 100644 index 00000000000..af516502e16 --- /dev/null +++ b/samples/bluetooth/peripheral_accept_list/sample.yaml @@ -0,0 +1,7 @@ +sample: + name: Bluetooh Peripheral Accept List +tests: + sample.bluetooth.peripheral_accept_list: + harness: bluetooth + platform_allow: qemu_cortex_m3 qemu_x86 + tags: bluetooth diff --git a/samples/bluetooth/peripheral_accept_list/src/main.c b/samples/bluetooth/peripheral_accept_list/src/main.c new file mode 100644 index 00000000000..2b2af761f7f --- /dev/null +++ b/samples/bluetooth/peripheral_accept_list/src/main.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2022 Michal Morsisko + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Custom Service Variables */ +#define BT_UUID_CUSTOM_SERVICE_VAL \ + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0) + +static struct bt_uuid_128 primary_service_uuid = BT_UUID_INIT_128( + BT_UUID_CUSTOM_SERVICE_VAL); + +static struct bt_uuid_128 read_characteristic_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); + +static struct bt_uuid_128 write_characteristic_uuid = BT_UUID_INIT_128( + BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2)); + +static int signed_value; +static struct bt_le_adv_param adv_param; +static int bond_count; + +static ssize_t read_signed(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) +{ + int *value = &signed_value; + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, + sizeof(signed_value)); +} + +static ssize_t write_signed(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + int *value = &signed_value; + + if (offset + len > sizeof(signed_value)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + + return len; +} + +/* Vendor Primary Service Declaration */ +BT_GATT_SERVICE_DEFINE(primary_service, + BT_GATT_PRIMARY_SERVICE(&primary_service_uuid), + BT_GATT_CHARACTERISTIC(&read_characteristic_uuid.uuid, + BT_GATT_CHRC_READ, + BT_GATT_PERM_READ, + read_signed, NULL, NULL), + BT_GATT_CHARACTERISTIC(&write_characteristic_uuid.uuid, + BT_GATT_CHRC_WRITE, + BT_GATT_PERM_WRITE_ENCRYPT, + NULL, write_signed, NULL), +); + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)) +}; + +static const struct bt_data sd[] = { + BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL) +}; + +static void connected(struct bt_conn *conn, uint8_t err) +{ + if (err) { + printk("Connection failed (err 0x%02x)\n", err); + } else { + printk("Connected\n"); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + printk("Disconnected (reason 0x%02x)\n", reason); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected +}; + +static void add_bonded_addr_to_filter_list(const struct bt_bond_info *info, void *data) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_le_filter_accept_list_add(&info->addr); + bt_addr_le_to_str(&info->addr, addr_str, sizeof(addr_str)); + printk("Added %s to advertising accept filter list\n", addr_str); + bond_count++; +} + +static void bt_ready(void) +{ + int err; + + printk("Bluetooth initialized\n"); + + if (IS_ENABLED(CONFIG_SETTINGS)) { + settings_load(); + } + + bond_count = 0; + bt_foreach_bond(BT_ID_DEFAULT, add_bonded_addr_to_filter_list, NULL); + + adv_param = *BT_LE_ADV_CONN_NAME; + + /* If we have got at least one bond, activate the filter */ + if (bond_count) { + /* BT_LE_ADV_OPT_FILTER_CONN is required to activate accept filter list, + * BT_LE_ADV_OPT_FILTER_SCAN_REQ will prevent sending scan response data to + * devices, that are not on the accept filter list + */ + adv_param.options |= BT_LE_ADV_OPT_FILTER_CONN | BT_LE_ADV_OPT_FILTER_SCAN_REQ; + } + + err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); + + if (err) { + printk("Advertising failed to start (err %d)\n", err); + } else { + printk("Advertising successfully started\n"); + } +} + +void pairing_complete(struct bt_conn *conn, bool bonded) +{ + printk("Pairing completed. Rebooting in 5 seconds...\n"); + + k_sleep(K_SECONDS(5)); + sys_reboot(SYS_REBOOT_WARM); +} + +static struct bt_conn_auth_info_cb bt_conn_auth_info = { + .pairing_complete = pairing_complete +}; + +void main(void) +{ + int err; + + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return; + } + + bt_ready(); + bt_conn_auth_info_cb_register(&bt_conn_auth_info); + + while (1) { + k_sleep(K_FOREVER); + } +}