diff --git a/samples/bluetooth/peripheral_past/CMakeLists.txt b/samples/bluetooth/peripheral_past/CMakeLists.txt new file mode 100644 index 0000000000..eb0f6dd00e --- /dev/null +++ b/samples/bluetooth/peripheral_past/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(peripheral_past) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/bluetooth/peripheral_past/README.rst b/samples/bluetooth/peripheral_past/README.rst new file mode 100644 index 0000000000..fc5226ed7f --- /dev/null +++ b/samples/bluetooth/peripheral_past/README.rst @@ -0,0 +1,27 @@ +.. _bluetooth-peripheral-past-sample: + +Bluetooth: Periodic Advertising Synchronization Transfer +######################################################## + +Overview +******** + +A simple application demonstrating the BLE Periodic Advertising Synchronization +Transfer (PAST) functionality as the receiver. + +Requirements +************ + +* A board with BLE 5.1 support + +Building and Running +******************** + +This sample can be found under :zephyr_file:`samples/bluetooth/peripheral_past` +in the Zephyr tree. + +Use the sample found under :zephyr_file:`samples/bluetooth/central_past` on +another board that will connect to this and transfer a periodic advertisement +sync. + +See :ref:`bluetooth samples section ` for details. diff --git a/samples/bluetooth/peripheral_past/prj.conf b/samples/bluetooth/peripheral_past/prj.conf new file mode 100644 index 0000000000..81d0231d82 --- /dev/null +++ b/samples/bluetooth/peripheral_past/prj.conf @@ -0,0 +1,7 @@ +CONFIG_BT=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y +CONFIG_BT_PER_ADV_SYNC=y +CONFIG_BT_DEBUG_LOG=y +CONFIG_BT_DEVICE_NAME="Peripheral PAST" diff --git a/samples/bluetooth/peripheral_past/sample.yaml b/samples/bluetooth/peripheral_past/sample.yaml new file mode 100644 index 0000000000..29a8cc648a --- /dev/null +++ b/samples/bluetooth/peripheral_past/sample.yaml @@ -0,0 +1,7 @@ +sample: + name: Bluetooth Peripheral Periodic Advertising Synchronization Transfer (PAST) +tests: + sample.bluetooth.peripheral_past: + harness: bluetooth + platform_allow: qemu_cortex_m3 qemu_x86 nrf52_bsim + tags: bluetooth diff --git a/samples/bluetooth/peripheral_past/src/main.c b/samples/bluetooth/peripheral_past/src/main.c new file mode 100644 index 0000000000..7f7f8ffc53 --- /dev/null +++ b/samples/bluetooth/peripheral_past/src/main.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +static struct bt_conn *default_conn; + +static K_SEM_DEFINE(sem_per_sync, 0, 1); +static K_SEM_DEFINE(sem_per_sync_lost, 0, 1); + +static void sync_cb(struct bt_le_per_adv_sync *sync, + struct bt_le_per_adv_sync_synced_info *info) +{ + char le_addr[BT_ADDR_LE_STR_LEN]; + char past_peer_addr[BT_ADDR_LE_STR_LEN]; + + if (!info->conn) { + printk("Sync not from PAST\n"); + return; + } + + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + + bt_addr_le_to_str(bt_conn_get_dst(info->conn), past_peer_addr, + sizeof(past_peer_addr)); + + printk("PER_ADV_SYNC[%u]: [DEVICE]: %s synced, Interval 0x%04x (%u ms). PAST peer %s\n", + bt_le_per_adv_sync_get_index(sync), le_addr, info->interval, + info->interval * 5 / 4, past_peer_addr); + + k_sem_give(&sem_per_sync); +} + +static void term_cb(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_term_info *info) +{ + char le_addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + + printk("PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n", + bt_le_per_adv_sync_get_index(sync), le_addr); + + k_sem_give(&sem_per_sync_lost); +} + +static void recv_cb(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_recv_info *info, + struct net_buf_simple *buf) +{ + char le_addr[BT_ADDR_LE_STR_LEN]; + char data_str[129]; + + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + bin2hex(buf->data, buf->len, data_str, sizeof(data_str)); + + printk("PER_ADV_SYNC[%u]: [DEVICE]: %s, tx_power %i, RSSI %i, CTE %u, data length %u, " + "data: %s\n", bt_le_per_adv_sync_get_index(sync), le_addr, + info->tx_power, info->rssi, info->cte_type, buf->len, data_str); +} + +static struct bt_le_per_adv_sync_cb sync_callbacks = { + .synced = sync_cb, + .term = term_cb, + .recv = recv_cb +}; + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (default_conn == NULL) { + default_conn = conn; + } + + if (conn != default_conn) { + return; + } + + printk("Connected: %s\n", addr); +} + +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; +} + +static struct bt_conn_cb conn_callbacks = { + .connected = connected, + .disconnected = disconnected, +}; + +void main(void) +{ + struct bt_le_per_adv_sync_transfer_param past_param; + int err; + + printk("Starting Peripheral Periodic Advertising Synchronization Transfer (PAST) Demo\n"); + + /* Initialize the Bluetooth Subsystem */ + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return; + } + + printk("Connection callbacks register..."); + bt_conn_cb_register(&conn_callbacks); + printk("Success\n"); + + printk("Periodic Advertising callbacks register..."); + bt_le_per_adv_sync_cb_register(&sync_callbacks); + printk("Success.\n"); + + printk("Subscribing to periodic advertising sync transfers\n"); + past_param.skip = 1; + past_param.timeout = 1000; /* 10 seconds */ + err = bt_le_per_adv_sync_transfer_subscribe(NULL /* any peer */, + &past_param); + if (err) { + printk("PAST subscribe failed (err %d)\n", err); + return; + } + + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, NULL, 0, NULL, 0); + if (err) { + printk("Advertising failed to start (err %d)\n", err); + return; + } + + do { + printk("Waiting for periodic sync...\n"); + err = k_sem_take(&sem_per_sync, K_FOREVER); + if (err) { + printk("failed (err %d)\n", err); + return; + } + printk("Periodic sync established.\n"); + + printk("Waiting for periodic sync lost...\n"); + err = k_sem_take(&sem_per_sync_lost, K_FOREVER); + if (err) { + printk("failed (err %d)\n", err); + return; + } + printk("Periodic sync lost.\n"); + } while (true); +}