1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "bs_bt_utils.h"
8 #include "utils.h"
9
10 BUILD_ASSERT(CONFIG_BT_MAX_PAIRED >= 2, "CONFIG_BT_MAX_PAIRED is too small.");
11 BUILD_ASSERT(CONFIG_BT_ID_MAX >= 3, "CONFIG_BT_ID_MAX is too small.");
12 BUILD_ASSERT(CONFIG_BT_MAX_CONN == 2, "CONFIG_BT_MAX_CONN should be equal to two.");
13 BUILD_ASSERT(CONFIG_BT_GATT_CLIENT, "CONFIG_BT_GATT_CLIENT is disabled.");
14
test_tick(bs_time_t HW_device_time)15 void test_tick(bs_time_t HW_device_time)
16 {
17 bs_trace_debug_time(0, "Simulation ends now.\n");
18 if (bst_result != Passed) {
19 bst_result = Failed;
20 bs_trace_error("Test did not pass before simulation ended.\n");
21 }
22 }
23
test_init(void)24 void test_init(void)
25 {
26 bst_ticker_set_next_tick_absolute(TEST_TIMEOUT_SIMULATED);
27 bst_result = In_progress;
28 }
29
30 DEFINE_FLAG(flag_has_new_conn);
31 struct bt_conn *new_conn;
32
33 DEFINE_FLAG(flag_has_disconnected);
34
clear_conn(struct bt_conn * conn)35 void clear_conn(struct bt_conn *conn)
36 {
37 if (new_conn == conn) {
38 new_conn = NULL;
39 }
40
41 ASSERT(conn, "Test error: No new_conn!\n");
42 bt_conn_unref(conn);
43 }
44
wait_connected(struct bt_conn ** conn)45 void wait_connected(struct bt_conn **conn)
46 {
47 WAIT_FOR_FLAG(flag_has_new_conn);
48 UNSET_FLAG(flag_has_new_conn);
49
50 ASSERT(new_conn, "connection unpopulated.");
51 *conn = new_conn;
52 new_conn = NULL;
53 }
54
wait_disconnected(void)55 void wait_disconnected(void)
56 {
57 WAIT_FOR_FLAG(flag_has_disconnected);
58 UNSET_FLAG(flag_has_disconnected);
59 }
60
print_conn_state_transition(const char * prefix,struct bt_conn * conn)61 static void print_conn_state_transition(const char *prefix, struct bt_conn *conn)
62 {
63 int err;
64 struct bt_conn_info info;
65 char addr_str[BT_ADDR_LE_STR_LEN];
66
67 err = bt_conn_get_info(conn, &info);
68 ASSERT(!err, "Unexpected conn info result.");
69
70 bt_addr_le_to_str(info.le.dst, addr_str, sizeof(addr_str));
71 printk("%s: %s\n", prefix, addr_str);
72 }
73
disconnected(struct bt_conn * conn,uint8_t reason)74 static void disconnected(struct bt_conn *conn, uint8_t reason)
75 {
76 print_conn_state_transition("Disonnected", conn);
77 SET_FLAG(flag_has_disconnected);
78 }
79
connected(struct bt_conn * conn,uint8_t err)80 static void connected(struct bt_conn *conn, uint8_t err)
81 {
82 ASSERT((!new_conn || (conn == new_conn)), "Unexpected new connection.");
83
84 if (!new_conn) {
85 new_conn = bt_conn_ref(conn);
86 }
87
88 if (err != 0) {
89 clear_conn(conn);
90 return;
91 }
92
93 print_conn_state_transition("Connected", conn);
94 SET_FLAG(flag_has_new_conn);
95 }
96
97 BT_CONN_CB_DEFINE(conn_callbacks) = {
98 .connected = connected,
99 .disconnected = disconnected,
100 };
101
102 DEFINE_FLAG(flag_pairing_completed);
103
pairing_complete(struct bt_conn * conn,bool bonded)104 static void pairing_complete(struct bt_conn *conn, bool bonded)
105 {
106 print_conn_state_transition("Paired", conn);
107 SET_FLAG(flag_pairing_completed);
108 }
109
110 static struct bt_conn_auth_info_cb bt_conn_auth_info_cb = {
111 .pairing_complete = pairing_complete,
112 };
113
set_security(struct bt_conn * conn,bt_security_t sec)114 void set_security(struct bt_conn *conn, bt_security_t sec)
115 {
116 int err;
117
118 err = bt_conn_set_security(conn, sec);
119 ASSERT(!err, "Err bt_conn_set_security %d", err);
120 }
121
wait_pairing_completed(void)122 void wait_pairing_completed(void)
123 {
124 WAIT_FOR_FLAG(flag_pairing_completed);
125 UNSET_FLAG(flag_pairing_completed);
126 }
127
bs_bt_utils_setup(void)128 void bs_bt_utils_setup(void)
129 {
130 int err;
131
132 err = bt_enable(NULL);
133 ASSERT(!err, "bt_enable failed.\n");
134 err = bt_conn_auth_info_cb_register(&bt_conn_auth_info_cb);
135 ASSERT(!err, "bt_conn_auth_info_cb_register failed.\n");
136
137 err = settings_load();
138 ASSERT(!err, "settings_load failed.\n");
139 }
140
scan_connect_to_first_result__device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)141 static void scan_connect_to_first_result__device_found(const bt_addr_le_t *addr, int8_t rssi,
142 uint8_t type, struct net_buf_simple *ad)
143 {
144 char addr_str[BT_ADDR_LE_STR_LEN];
145 int err;
146
147 /* We're only interested in connectable events */
148 if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) {
149 FAIL("Unexpected advertisement type.");
150 }
151
152 bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
153 printk("Got scan result, connecting.. dst %s, RSSI %d\n", addr_str, rssi);
154
155 err = bt_le_scan_stop();
156 ASSERT(!err, "Err bt_le_scan_stop %d", err);
157
158 err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &new_conn);
159 ASSERT(!err, "Err bt_conn_le_create %d", err);
160 }
161
scan_connect_to_first_result(void)162 void scan_connect_to_first_result(void)
163 {
164 int err;
165
166 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, scan_connect_to_first_result__device_found);
167 ASSERT(!err, "Err bt_le_scan_start %d", err);
168 }
169
disconnect(struct bt_conn * conn)170 void disconnect(struct bt_conn *conn)
171 {
172 int err;
173
174 err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
175 ASSERT(!err, "Err bt_conn_disconnect %d", err);
176 }
177
178 DEFINE_FLAG(flag_bas_has_notification);
179
180 static uint8_t bas_level = 50;
181
bas_notify_func(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)182 static uint8_t bas_notify_func(struct bt_conn *conn,
183 struct bt_gatt_subscribe_params *params,
184 const void *data, uint16_t length)
185 {
186 const uint8_t *lvl8 = data;
187
188 if ((length == 1) && (*lvl8 == bas_level)) {
189 printk("BAS notification\n");
190 SET_FLAG(flag_bas_has_notification);
191 }
192
193 return BT_GATT_ITER_CONTINUE;
194 }
195
wait_bas_notification(void)196 void wait_bas_notification(void)
197 {
198 WAIT_FOR_FLAG(flag_bas_has_notification);
199 UNSET_FLAG(flag_bas_has_notification);
200 }
201
202 /* Not actually used, see below why we also have this on the central */
203 BT_GATT_SERVICE_DEFINE(bas,
204 BT_GATT_PRIMARY_SERVICE(BT_UUID_BAS),
205 BT_GATT_CHARACTERISTIC(BT_UUID_BAS_BATTERY_LEVEL,
206 BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
207 BT_GATT_PERM_READ, NULL, NULL, &bas_level),
208 BT_GATT_CCC(NULL,
209 BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
210 );
211
bas_subscribe(struct bt_conn * conn)212 void bas_subscribe(struct bt_conn *conn)
213 {
214 int err;
215 static struct bt_gatt_subscribe_params subscribe_params = {0};
216
217 /* This is a bit of a shortcut: to skip discovery, we assume the handles
218 * will be the same on the central & peripheral images.
219 */
220 subscribe_params.ccc_handle = bt_gatt_attr_get_handle(&bas.attrs[3]);
221 subscribe_params.value_handle = bt_gatt_attr_get_handle(&bas.attrs[2]);
222 subscribe_params.value = BT_GATT_CCC_NOTIFY;
223 subscribe_params.notify = bas_notify_func;
224
225 err = bt_gatt_subscribe(conn, &subscribe_params);
226 ASSERT(!err, "bt_gatt_subscribe failed (err %d)\n", err);
227 }
228