samples: bluetooth: Add sample demonstrating direct advertising

This sample shows how to run BLE direct advertising towards central
with enabled privacy.

Signed-off-by: Michal morsisko <morsisko@gmail.com>
This commit is contained in:
Michal morsisko 2022-09-18 21:36:58 +02:00 committed by Carles Cufí
commit 3b26d50012
5 changed files with 238 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(direct_adv)
target_sources(app PRIVATE
src/main.c
)

View file

@ -0,0 +1,32 @@
.. _ble_direct_adv:
Bluetooth: Direct Advertising
#############################
Overview
********
Application demonstrating the BLE Direct Advertising capability. If no device is bonded
to the peripheral, casual advertising will be performed. Once bonded, on every subsequent
boot direct advertising to the bonded central will be performed. Additionally this sample
provides two BLE characteristics. To perform write, devices need to be bonded, while read
can be done just after connection (no bonding required).
Please note that direct advertising towards iOS based devices is not allowed.
For more information about designing BLE devices for Apple products refer to
"Accessory Design Guidelines for Apple Devices".
Requirements
************
* A board with BLE support
* Second BLE device acting as a central with enabled privacy. For example another Zephyr board
or any modern smartphone
Building and Running
********************
This sample can be found under :zephyr_file:`samples/bluetooth/direct_adv` in the
Zephyr tree.
See :ref:`bluetooth samples section <bluetooth-samples>` for details.

View file

@ -0,0 +1,22 @@
# 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="Direct Adv"
CONFIG_BT_DEVICE_APPEARANCE=833
CONFIG_BT_KEYS_OVERWRITE_OLDEST=y
CONFIG_BT_SETTINGS=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 Direct Advertising
tests:
sample.bluetooth.direct_adv:
harness: bluetooth
platform_allow: qemu_cortex_m3 qemu_x86
tags: bluetooth

View file

@ -0,0 +1,168 @@
/*
* 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 <string.h>
#include <errno.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/reboot.h>
#include <zephyr/settings/settings.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.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 bt_addr_le_t bond_addr;
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)),
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 copy_last_bonded_addr(const struct bt_bond_info *info, void *data)
{
bt_addr_le_copy(&bond_addr, &info->addr);
}
static void bt_ready(void)
{
int err;
char addr[BT_ADDR_LE_STR_LEN];
printk("Bluetooth initialized\n");
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
bt_addr_le_copy(&bond_addr, BT_ADDR_LE_NONE);
bt_foreach_bond(BT_ID_DEFAULT, copy_last_bonded_addr, NULL);
/* Address is equal to BT_ADDR_LE_NONE if compare returns 0.
* This means there is no bond yet.
*/
if (bt_addr_le_cmp(&bond_addr, BT_ADDR_LE_NONE) != 0) {
bt_addr_le_to_str(&bond_addr, addr, sizeof(addr));
printk("Direct advertising to %s\n", addr);
adv_param = *BT_LE_ADV_CONN_DIR_LOW_DUTY(&bond_addr);
adv_param.options |= BT_LE_ADV_OPT_DIR_ADDR_RPA;
err = bt_le_adv_start(&adv_param, NULL, 0, NULL, 0);
} else {
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
}
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);
}
}