/* Copyright (c) 2023 Nordic Semiconductor ASA * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "settings.h" #include "argparse.h" #include "bs_pc_backchannel.h" #define SERVER_CHAN 0 CREATE_FLAG(connected_flag); CREATE_FLAG(disconnected_flag); CREATE_FLAG(security_updated_flag); CREATE_FLAG(notification_received_flag); #define BT_UUID_DUMMY_SERVICE BT_UUID_DECLARE_128(DUMMY_SERVICE_TYPE) #define BT_UUID_DUMMY_SERVICE_NOTIFY BT_UUID_DECLARE_128(DUMMY_SERVICE_NOTIFY_TYPE) static struct bt_conn *default_conn; static struct bt_conn_cb central_cb; CREATE_FLAG(gatt_subscribed_flag); static uint8_t notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) { uint8_t value; if (conn == NULL || data == NULL) { /* Peer unpaired or subscription was removed */ UNSET_FLAG(gatt_subscribed_flag); return BT_GATT_ITER_STOP; } __ASSERT_NO_MSG(length == sizeof(value)); value = *(uint8_t *)data; LOG_DBG("#%d notification received", value); SET_FLAG(notification_received_flag); return BT_GATT_ITER_CONTINUE; } static void subscribe_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_subscribe_params *params) { if (err) { return; } SET_FLAG(gatt_subscribed_flag); } static struct bt_gatt_subscribe_params subscribe_params; static void ccc_subscribe(void) { int err; UNSET_FLAG(gatt_subscribed_flag); subscribe_params.notify = notify_cb; subscribe_params.subscribe = subscribe_cb; subscribe_params.ccc_handle = CCC_HANDLE; subscribe_params.value_handle = VAL_HANDLE; subscribe_params.value = BT_GATT_CCC_NOTIFY; err = bt_gatt_subscribe(default_conn, &subscribe_params); if (err) { FAIL("Failed to subscribe (att err %d)", err); } WAIT_FOR_FLAG(gatt_subscribed_flag); } static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad) { int err; char addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); LOG_DBG("Device found: %s (RSSI %d)", addr_str, rssi); err = bt_le_scan_stop(); if (err) { FAIL("Failed to stop scanner (err %d)\n", err); } err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &default_conn); if (err) { FAIL("Could not connect to peer: %s (err %d)\n", addr_str, err); } } static void connected(struct bt_conn *conn, uint8_t err) { const bt_addr_le_t *addr; char addr_str[BT_ADDR_LE_STR_LEN]; addr = bt_conn_get_dst(conn); bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); if (err) { FAIL("Failed to connect to %s (err %d)\n", addr_str, err); } LOG_DBG("Connected: %s", addr_str); if (conn == default_conn) { SET_FLAG(connected_flag); } } static void disconnected(struct bt_conn *conn, uint8_t reason) { char addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str)); LOG_DBG("Disconnected: %s (reason 0x%02x)", addr_str, reason); SET_FLAG(disconnected_flag); if (default_conn != conn) { return; } bt_conn_unref(default_conn); default_conn = NULL; } static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { char addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str)); if (!err) { LOG_DBG("Security changed: %s level %u", addr_str, level); SET_FLAG(security_updated_flag); } else { LOG_DBG("Security failed: %s level %u err %d", addr_str, level, err); } } static void start_scan(void) { int err; err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); if (err) { FAIL("Scanning failed to start (err %d)\n", err); } LOG_DBG("Scanning successfully started"); } static void disconnect(void) { int err; err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); if (err) { FAIL("Disconnection failed (err %d)\n", err); } WAIT_FOR_FLAG(disconnected_flag); UNSET_FLAG(disconnected_flag); } /* Test steps */ static void connect_pair_subscribe(void) { int err; start_scan(); WAIT_FOR_FLAG(connected_flag); UNSET_FLAG(connected_flag); err = bt_conn_set_security(default_conn, BT_SECURITY_L2); if (err != 0) { FAIL("Failed to set security (err %d)\n", err); } WAIT_FOR_FLAG(security_updated_flag); UNSET_FLAG(security_updated_flag); /* subscribe while being paired */ ccc_subscribe(); /* confirm to server that we subscribed */ backchannel_sync_send(SERVER_CHAN, SERVER_ID); /* wait for server to check that the subscribtion is well registered */ backchannel_sync_wait(SERVER_CHAN, SERVER_ID); WAIT_FOR_FLAG(notification_received_flag); UNSET_FLAG(notification_received_flag); } static void connect_restore_sec(void) { int err; start_scan(); WAIT_FOR_FLAG(connected_flag); UNSET_FLAG(connected_flag); err = bt_conn_set_security(default_conn, BT_SECURITY_L2); if (err != 0) { FAIL("Failed to set security (err %d)\n", err); } WAIT_FOR_FLAG(security_updated_flag); UNSET_FLAG(security_updated_flag); /* check local subscription state */ if (GET_FLAG(gatt_subscribed_flag) == false) { FAIL("Not subscribed\n"); } /* notify the end of security update to server */ backchannel_sync_send(SERVER_CHAN, SERVER_ID); /* wait for server to check that the subscribtion has been restored */ backchannel_sync_wait(SERVER_CHAN, SERVER_ID); WAIT_FOR_FLAG(notification_received_flag); UNSET_FLAG(notification_received_flag); } /* Util functions */ void central_backchannel_init(void) { uint device_number = get_device_nbr(); uint channel_numbers[1] = { 0, }; uint device_numbers[1]; uint num_ch = 1; uint *ch; device_numbers[0] = SERVER_ID; LOG_DBG("Opening back channels for device %d", device_number); ch = bs_open_back_channel(device_number, device_numbers, channel_numbers, num_ch); if (!ch) { FAIL("Unable to open backchannel\n"); } LOG_DBG("Back channels for device %d opened", device_number); } static void set_public_addr(void) { bt_addr_le_t addr = {BT_ADDR_LE_RANDOM, {{0x0A, 0x89, 0x67, 0x45, 0x23, 0xC1}}}; bt_id_create(&addr, NULL); } /* Main functions */ void run_central(int times) { int err; central_cb.connected = connected; central_cb.disconnected = disconnected; central_cb.security_changed = security_changed; central_backchannel_init(); set_public_addr(); err = bt_enable(NULL); if (err) { FAIL("Bluetooth init failed (err %d)\n", err); } LOG_DBG("Bluetooth initialized"); bt_conn_cb_register(¢ral_cb); err = settings_load(); if (err) { FAIL("Settings load failed (err %d)\n", err); } err = bt_unpair(BT_ID_DEFAULT, BT_ADDR_LE_ANY); if (err) { FAIL("Unpairing failed (err %d)\n", err); } connect_pair_subscribe(); disconnect(); for (int i = 0; i < times; i++) { connect_restore_sec(); disconnect(); } PASS("Central test passed\n"); }