1 /* Copyright (c) 2023 Nordic Semiconductor ASA
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 
5 #include <stdint.h>
6 #include <zephyr/bluetooth/bluetooth.h>
7 #include <zephyr/bluetooth/conn.h>
8 #include <zephyr/bluetooth/gatt.h>
9 #include <zephyr/bluetooth/gatt.h>
10 #include <zephyr/bluetooth/l2cap.h>
11 #include <zephyr/bluetooth/uuid.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/sys/__assert.h>
15 #include <zephyr/sys/util_macro.h>
16 
17 #include <testlib/conn.h>
18 
19 #include <zephyr/logging/log.h>
20 LOG_MODULE_REGISTER(bt_testlib_conn_wait, LOG_LEVEL_DBG);
21 
22 static K_MUTEX_DEFINE(conn_wait_mutex);
23 static K_CONDVAR_DEFINE(conn_recycled);
24 static K_CONDVAR_DEFINE(something_changed);
25 
on_change(struct bt_conn * conn,uint8_t err)26 static void on_change(struct bt_conn *conn, uint8_t err)
27 {
28 	k_mutex_lock(&conn_wait_mutex, K_FOREVER);
29 	k_condvar_broadcast(&something_changed);
30 	k_mutex_unlock(&conn_wait_mutex);
31 }
32 
on_conn_recycled(void)33 static void on_conn_recycled(void)
34 {
35 	k_mutex_lock(&conn_wait_mutex, K_FOREVER);
36 	k_condvar_broadcast(&conn_recycled);
37 	k_mutex_unlock(&conn_wait_mutex);
38 }
39 
40 BT_CONN_CB_DEFINE(conn_callbacks) = {
41 	.connected = on_change,
42 	.disconnected = on_change,
43 	.recycled = on_conn_recycled,
44 };
45 
bt_conn_state(struct bt_conn * conn)46 static enum bt_conn_state bt_conn_state(struct bt_conn *conn)
47 {
48 	int err;
49 	struct bt_conn_info info;
50 
51 	__ASSERT(conn != NULL, "Invalid connection");
52 	err = bt_conn_get_info(conn, &info);
53 	__ASSERT(err == 0, "Failed to get connection info");
54 
55 	return info.state;
56 }
57 
bt_testlib_wait_connected(struct bt_conn * conn)58 int bt_testlib_wait_connected(struct bt_conn *conn)
59 {
60 	__ASSERT_NO_MSG(conn != NULL);
61 	k_mutex_lock(&conn_wait_mutex, K_FOREVER);
62 	while (bt_conn_state(conn) != BT_CONN_STATE_CONNECTED) {
63 		k_condvar_wait(&something_changed, &conn_wait_mutex, K_FOREVER);
64 	}
65 	k_mutex_unlock(&conn_wait_mutex);
66 	return 0;
67 }
68 
bt_testlib_wait_disconnected(struct bt_conn * conn)69 int bt_testlib_wait_disconnected(struct bt_conn *conn)
70 {
71 	__ASSERT_NO_MSG(conn != NULL);
72 	k_mutex_lock(&conn_wait_mutex, K_FOREVER);
73 	while (bt_conn_state(conn) != BT_CONN_STATE_DISCONNECTED) {
74 		k_condvar_wait(&something_changed, &conn_wait_mutex, K_FOREVER);
75 	}
76 	k_mutex_unlock(&conn_wait_mutex);
77 	return 0;
78 }
79 
bt_testlib_conn_wait_free(void)80 void bt_testlib_conn_wait_free(void)
81 {
82 	if (!IS_ENABLED(CONFIG_BT_CONN)) {
83 		__ASSERT_NO_MSG(false);
84 		return;
85 	}
86 
87 	/* The mutex must be held duing the initial check loop to buffer
88 	 * any `conn_cb.released` events.
89 	 *
90 	 * This ensures that any connection slots that become free
91 	 * during the loop execution are detected.
92 	 */
93 	k_mutex_lock(&conn_wait_mutex, K_FOREVER);
94 
95 	for (size_t i = 0; i < CONFIG_BT_MAX_CONN; i++) {
96 		struct bt_conn *conn = bt_testlib_conn_unindex(BT_CONN_TYPE_LE, i);
97 
98 		if (!conn) {
99 			goto done;
100 		}
101 
102 		bt_testlib_conn_unref(&conn);
103 	}
104 
105 	k_condvar_wait(&conn_recycled, &conn_wait_mutex, K_FOREVER);
106 
107 done:
108 	k_mutex_unlock(&conn_wait_mutex);
109 }
110