Bluetooth: samples: Add central ISO sample
Adds a sample of setting up and using an ISO central as a source of ISO data. This will periodically send ISO data to a connected ISO peripheral with varying sizes. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
ea48757a9a
commit
a71fec83bd
5 changed files with 300 additions and 0 deletions
11
samples/bluetooth/central_iso/CMakeLists.txt
Normal file
11
samples/bluetooth/central_iso/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.13.1)
|
||||||
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
project(central)
|
||||||
|
|
||||||
|
target_sources(app PRIVATE
|
||||||
|
src/main.c
|
||||||
|
)
|
||||||
|
|
||||||
|
zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)
|
27
samples/bluetooth/central_iso/README.rst
Normal file
27
samples/bluetooth/central_iso/README.rst
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
.. _bluetooth_central_iso:
|
||||||
|
|
||||||
|
Bluetooth: Central ISO
|
||||||
|
######################
|
||||||
|
|
||||||
|
Overview
|
||||||
|
********
|
||||||
|
|
||||||
|
Application demonstrating a connected isochronous channel functional as the
|
||||||
|
central role, by scanning for peripheral devices and establishing a connection
|
||||||
|
to the first one with a strong enough signal.
|
||||||
|
The application then attempts to setup a connected isochronous channel and
|
||||||
|
starts sending data.
|
||||||
|
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
************
|
||||||
|
|
||||||
|
* BlueZ running on the host, or
|
||||||
|
* A board with Bluetooth Low Energy 5.2 support
|
||||||
|
|
||||||
|
Building and Running
|
||||||
|
********************
|
||||||
|
This sample can be found under :zephyr_file:`samples/bluetooth/central_iso` in
|
||||||
|
the Zephyr tree.
|
||||||
|
|
||||||
|
See :ref:`bluetooth samples section <bluetooth-samples>` for details.
|
4
samples/bluetooth/central_iso/prj.conf
Normal file
4
samples/bluetooth/central_iso/prj.conf
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
CONFIG_BT=y
|
||||||
|
CONFIG_BT_DEBUG_LOG=y
|
||||||
|
CONFIG_BT_CENTRAL=y
|
||||||
|
CONFIG_BT_ISO=y
|
8
samples/bluetooth/central_iso/sample.yaml
Normal file
8
samples/bluetooth/central_iso/sample.yaml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
sample:
|
||||||
|
description: Bluetooth ISO central (client) sample
|
||||||
|
name: Bluetooth ISO central (client) sample
|
||||||
|
tests:
|
||||||
|
sample.bluetooth.central_iso:
|
||||||
|
harness: bluetooth
|
||||||
|
platform_allow: qemu_cortex_m3 qemu_x86
|
||||||
|
tags: bluetooth
|
250
samples/bluetooth/central_iso/src/main.c
Normal file
250
samples/bluetooth/central_iso/src/main.c
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <sys/printk.h>
|
||||||
|
|
||||||
|
#include <bluetooth/bluetooth.h>
|
||||||
|
#include <bluetooth/hci.h>
|
||||||
|
#include <bluetooth/conn.h>
|
||||||
|
#include <bluetooth/uuid.h>
|
||||||
|
#include <bluetooth/gatt.h>
|
||||||
|
#include <bluetooth/iso.h>
|
||||||
|
#include <sys/byteorder.h>
|
||||||
|
|
||||||
|
#define MAX_ISO_APP_DATA (CONFIG_BT_ISO_TX_MTU - BT_ISO_CHAN_SEND_RESERVE)
|
||||||
|
|
||||||
|
static void start_scan(void);
|
||||||
|
|
||||||
|
static struct bt_conn *default_conn;
|
||||||
|
static struct k_delayed_work iso_send_work;
|
||||||
|
static struct bt_iso_chan iso_chan;
|
||||||
|
NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, CONFIG_BT_ISO_TX_MTU, NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send ISO data on timeout
|
||||||
|
*
|
||||||
|
* This will send an increasing amount of ISO data, starting from 1 octet.
|
||||||
|
*
|
||||||
|
* First iteration : 0x00
|
||||||
|
* Second iteration: 0x00 0x01
|
||||||
|
* Third iteration : 0x00 0x01 0x02
|
||||||
|
*
|
||||||
|
* And so on, until it wraps around the configured ISO TX MTU (CONFIG_BT_ISO_TX_MTU)
|
||||||
|
*
|
||||||
|
* @param work Pointer to the work structure
|
||||||
|
*/
|
||||||
|
static void iso_timer_timeout(struct k_work *work)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
static uint8_t buf_data[MAX_ISO_APP_DATA];
|
||||||
|
static bool data_initialized;
|
||||||
|
struct net_buf *buf;
|
||||||
|
static size_t len_to_send = 1;
|
||||||
|
|
||||||
|
if (!data_initialized) {
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(buf_data); i++) {
|
||||||
|
buf_data[i] = (uint8_t)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = net_buf_alloc(&tx_pool, K_FOREVER);
|
||||||
|
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
|
||||||
|
|
||||||
|
net_buf_add_mem(buf, buf_data, len_to_send);
|
||||||
|
|
||||||
|
ret = bt_iso_chan_send(&iso_chan, buf);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
printk("Failed to send ISO data (%d)\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
k_delayed_work_submit(&iso_send_work, K_MSEC(1000));
|
||||||
|
|
||||||
|
len_to_send++;
|
||||||
|
if (len_to_send > ARRAY_SIZE(buf_data)) {
|
||||||
|
len_to_send = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
|
||||||
|
struct net_buf_simple *ad)
|
||||||
|
{
|
||||||
|
char addr_str[BT_ADDR_LE_STR_LEN];
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (default_conn) {
|
||||||
|
/* Already connected */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're only interested in connectable events */
|
||||||
|
if (type != BT_GAP_ADV_TYPE_ADV_IND && type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
|
||||||
|
printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
|
||||||
|
|
||||||
|
/* connect only to devices in close proximity */
|
||||||
|
if (rssi < -70) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bt_le_scan_stop()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT,
|
||||||
|
&default_conn);
|
||||||
|
if (err) {
|
||||||
|
printk("Create conn to %s failed (%u)\n", addr_str, err);
|
||||||
|
start_scan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start_scan(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* This demo doesn't require active scan */
|
||||||
|
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||||
|
if (err) {
|
||||||
|
printk("Scanning failed to start (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Scanning successfully started\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iso_connected(struct bt_iso_chan *chan)
|
||||||
|
{
|
||||||
|
printk("ISO Channel %p connected\n", chan);
|
||||||
|
|
||||||
|
/* Start send timer */
|
||||||
|
k_delayed_work_submit(&iso_send_work, K_MSEC(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iso_disconnected(struct bt_iso_chan *chan)
|
||||||
|
{
|
||||||
|
printk("ISO Channel %p disconnected\n", chan);
|
||||||
|
k_delayed_work_cancel(&iso_send_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bt_iso_chan_ops iso_ops = {
|
||||||
|
.connected = iso_connected,
|
||||||
|
.disconnected = iso_disconnected,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct bt_iso_chan_io_qos iso_tx = {
|
||||||
|
.interval = 10 * USEC_PER_MSEC, /* us */
|
||||||
|
.latency = 10,
|
||||||
|
.sdu = CONFIG_BT_ISO_TX_MTU,
|
||||||
|
.phy = BT_GAP_LE_PHY_2M,
|
||||||
|
.rtn = 1,
|
||||||
|
.path = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct bt_iso_chan_qos iso_qos = {
|
||||||
|
.sca = BT_GAP_SCA_UNKNOWN,
|
||||||
|
.packing = 0,
|
||||||
|
.framing = 0,
|
||||||
|
.tx = &iso_tx,
|
||||||
|
.rx = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void connected(struct bt_conn *conn, uint8_t err)
|
||||||
|
{
|
||||||
|
char addr[BT_ADDR_LE_STR_LEN];
|
||||||
|
int iso_err;
|
||||||
|
struct bt_conn *conns[1];
|
||||||
|
struct bt_iso_chan *channels[1];
|
||||||
|
|
||||||
|
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
printk("Failed to connect to %s (%u)\n", addr, err);
|
||||||
|
|
||||||
|
bt_conn_unref(default_conn);
|
||||||
|
default_conn = NULL;
|
||||||
|
|
||||||
|
start_scan();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn != default_conn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Connected: %s\n", addr);
|
||||||
|
|
||||||
|
conns[0] = default_conn;
|
||||||
|
channels[0] = &iso_chan;
|
||||||
|
|
||||||
|
iso_err = bt_iso_chan_bind(conns, ARRAY_SIZE(conns), channels);
|
||||||
|
|
||||||
|
if (iso_err) {
|
||||||
|
printk("Failed to bind iso to connection (%d)\n", iso_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_err = bt_iso_chan_connect(channels, ARRAY_SIZE(channels));
|
||||||
|
|
||||||
|
if (iso_err) {
|
||||||
|
printk("Failed to connect iso (%d)\n", iso_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void disconnected(struct bt_conn *conn, uint8_t reason)
|
||||||
|
{
|
||||||
|
char addr[BT_ADDR_LE_STR_LEN];
|
||||||
|
|
||||||
|
if (conn != default_conn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||||
|
|
||||||
|
printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
|
||||||
|
|
||||||
|
bt_conn_unref(default_conn);
|
||||||
|
default_conn = NULL;
|
||||||
|
|
||||||
|
start_scan();
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bt_conn_cb conn_callbacks = {
|
||||||
|
.connected = connected,
|
||||||
|
.disconnected = disconnected,
|
||||||
|
};
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_enable(NULL);
|
||||||
|
if (err) {
|
||||||
|
printk("Bluetooth init failed (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Bluetooth initialized\n");
|
||||||
|
|
||||||
|
bt_conn_cb_register(&conn_callbacks);
|
||||||
|
|
||||||
|
iso_chan.ops = &iso_ops;
|
||||||
|
iso_chan.qos = &iso_qos;
|
||||||
|
|
||||||
|
start_scan();
|
||||||
|
|
||||||
|
k_delayed_work_init(&iso_send_work, iso_timer_timeout);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue