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 <morsisko@gmail.com>
This commit is contained in:
Michal morsisko 2022-12-31 17:19:18 +01:00 committed by Carles Cufí
commit c3619edf42
5 changed files with 242 additions and 0 deletions

View file

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

View file

@ -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 <bluetooth-samples>` for details.

View file

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

View file

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

View file

@ -0,0 +1,170 @@
/*
* Copyright (c) 2022 Michal Morsisko
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <stddef.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/reboot.h>
#include <zephyr/settings/settings.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
/* 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);
}
}