/* * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include "utils.h" #include "gatt_utils.h" #include #include DEFINE_FLAG(flag_is_connected); DEFINE_FLAG(flag_test_end); void wait_connected(void) { UNSET_FLAG(flag_is_connected); WAIT_FOR_FLAG(flag_is_connected); printk("connected\n"); } void wait_disconnected(void) { SET_FLAG(flag_is_connected); WAIT_FOR_FLAG_UNSET(flag_is_connected); printk("disconnected\n"); } static void disconnected(struct bt_conn *conn, uint8_t reason) { bt_conn_unref(conn); UNSET_FLAG(flag_is_connected); gatt_clear_flags(); } static void connected(struct bt_conn *conn, uint8_t err) { if (err != 0) { return; } bt_conn_ref(conn); SET_FLAG(flag_is_connected); } DEFINE_FLAG(flag_encrypted); void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { __ASSERT(err == 0, "Error setting security (err %u)\n", err); printk("Encrypted\n"); SET_FLAG(flag_encrypted); } BT_CONN_CB_DEFINE(conn_callbacks) = { .connected = connected, .disconnected = disconnected, .security_changed = security_changed, }; static void scan_connect_to_first_result_device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad) { struct bt_conn *conn; char addr_str[BT_ADDR_LE_STR_LEN]; int err; /* We're only interested in connectable events */ if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) { FAIL("Unexpected advertisement type."); } bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); printk("Got scan result, connecting.. dst %s, RSSI %d\n", addr_str, rssi); err = bt_le_scan_stop(); __ASSERT(!err, "Err bt_le_scan_stop %d", err); err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &conn); __ASSERT(!err, "Err bt_conn_le_create %d", err); } void scan_connect_to_first_result(void) { int err; printk("start scanner\n"); err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, scan_connect_to_first_result_device_found); __ASSERT(!err, "Err bt_le_scan_start %d", err); } void advertise_connectable(void) { printk("start advertiser\n"); int err; struct bt_le_adv_param param = {}; param.interval_min = 0x0020; param.interval_max = 0x4000; param.options |= BT_LE_ADV_OPT_ONE_TIME; param.options |= BT_LE_ADV_OPT_CONNECTABLE; err = bt_le_adv_start(¶m, NULL, 0, NULL, 0); __ASSERT(err == 0, "Advertising failed to start (err %d)\n", err); } void disconnect(struct bt_conn *conn) { int err; err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); __ASSERT(!err, "Failed to initate disconnection (err %d)", err); printk("Waiting for disconnection...\n"); WAIT_FOR_FLAG_UNSET(flag_is_connected); } static void get_active_conn_cb(struct bt_conn *src, void *dst) { *(struct bt_conn **)dst = src; } struct bt_conn *get_conn(void) { struct bt_conn *ret; bt_conn_foreach(BT_CONN_TYPE_LE, get_active_conn_cb, &ret); return ret; } DEFINE_FLAG(flag_pairing_complete); static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason) { FAIL("Pairing failed (unexpected): reason %u", reason); } static void pairing_complete(struct bt_conn *conn, bool bonded) { __ASSERT(bonded, "Bonding failed\n"); printk("Paired\n"); SET_FLAG(flag_pairing_complete); } static struct bt_conn_auth_info_cb bt_conn_auth_info_cb = { .pairing_failed = pairing_failed, .pairing_complete = pairing_complete, }; void set_security(struct bt_conn *conn, bt_security_t sec) { int err; UNSET_FLAG(flag_encrypted); err = bt_conn_set_security(conn, sec); __ASSERT(!err, "Err bt_conn_set_security %d", err); WAIT_FOR_FLAG(flag_encrypted); } void wait_secured(void) { UNSET_FLAG(flag_encrypted); WAIT_FOR_FLAG(flag_encrypted); } void bond(struct bt_conn *conn) { UNSET_FLAG(flag_pairing_complete); int err = bt_conn_auth_info_cb_register(&bt_conn_auth_info_cb); __ASSERT(!err, "bt_conn_auth_info_cb_register failed.\n"); set_security(conn, BT_SECURITY_L2); WAIT_FOR_FLAG(flag_pairing_complete); } void wait_bonded(void) { UNSET_FLAG(flag_encrypted); UNSET_FLAG(flag_pairing_complete); int err = bt_conn_auth_info_cb_register(&bt_conn_auth_info_cb); __ASSERT(!err, "bt_conn_auth_info_cb_register failed.\n"); WAIT_FOR_FLAG(flag_encrypted); WAIT_FOR_FLAG(flag_pairing_complete); } struct bt_conn *connect_as_central(void) { struct bt_conn *conn; scan_connect_to_first_result(); wait_connected(); conn = get_conn(); return conn; } struct bt_conn *connect_as_peripheral(void) { struct bt_conn *conn; advertise_connectable(); wait_connected(); conn = get_conn(); return conn; }