/* * 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 = bt_conn_ref(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 %s\n", addr, reason, bt_hci_err_to_str(reason)); bt_conn_unref(default_conn); default_conn = NULL; } static struct bt_conn_cb conn_callbacks = { .connected = connected, .disconnected = disconnected, }; static const struct bt_data sd[] = { BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), }; int 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 0; } 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 0; } err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, NULL, 0, sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return 0; } 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 0; } 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 0; } printk("Periodic sync lost.\n"); } while (true); return 0; }