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
test_tick(bs_time_t HW_device_time)14 void test_tick(bs_time_t HW_device_time)
15 {
16 bs_trace_debug_time(0, "Simulation ends now.\n");
17 if (bst_result != Passed) {
18 bst_result = Failed;
19 bs_trace_error("Test did not pass before simulation ended.\n");
20 }
21 }
22
test_init(void)23 void test_init(void)
24 {
25 bst_ticker_set_next_tick_absolute(TEST_TIMEOUT_SIMULATED);
26 bst_result = In_progress;
27 }
28
29 DEFINE_FLAG(flag_has_new_conn);
30 struct bt_conn *new_conn;
31
32 DEFINE_FLAG(flag_has_disconnected);
33
clear_conn(struct bt_conn * conn)34 void clear_conn(struct bt_conn *conn)
35 {
36 if (new_conn == conn) {
37 new_conn = NULL;
38 }
39
40 ASSERT(conn, "Test error: No new_conn!\n");
41 bt_conn_unref(conn);
42 }
43
wait_connected(struct bt_conn ** conn)44 void wait_connected(struct bt_conn **conn)
45 {
46 WAIT_FOR_FLAG(flag_has_new_conn);
47 UNSET_FLAG(flag_has_new_conn);
48
49 ASSERT(new_conn, "connection unpopulated.");
50 *conn = new_conn;
51 new_conn = NULL;
52 }
53
wait_disconnected(void)54 void wait_disconnected(void)
55 {
56 WAIT_FOR_FLAG(flag_has_disconnected);
57 UNSET_FLAG(flag_has_disconnected);
58 }
59
print_conn_state_transition(const char * prefix,struct bt_conn * conn)60 static void print_conn_state_transition(const char *prefix, struct bt_conn *conn)
61 {
62 int err;
63 struct bt_conn_info info;
64 char addr_str[BT_ADDR_LE_STR_LEN];
65
66 err = bt_conn_get_info(conn, &info);
67 ASSERT(!err, "Unexpected conn info result.");
68
69 bt_addr_le_to_str(info.le.dst, addr_str, sizeof(addr_str));
70 printk("%s: %s\n", prefix, addr_str);
71 }
72
disconnected(struct bt_conn * conn,uint8_t reason)73 static void disconnected(struct bt_conn *conn, uint8_t reason)
74 {
75 print_conn_state_transition("Disonnected", conn);
76 SET_FLAG(flag_has_disconnected);
77 }
78
connected(struct bt_conn * conn,uint8_t err)79 static void connected(struct bt_conn *conn, uint8_t err)
80 {
81 ASSERT((!new_conn || (conn == new_conn)), "Unexpected new connection.");
82
83 if (!new_conn) {
84 new_conn = bt_conn_ref(conn);
85 }
86
87 if (err != 0) {
88 clear_conn(conn);
89 return;
90 }
91
92 print_conn_state_transition("Connected", conn);
93 SET_FLAG(flag_has_new_conn);
94 }
95
96 BT_CONN_CB_DEFINE(conn_callbacks) = {
97 .connected = connected,
98 .disconnected = disconnected,
99 };
100
101 DEFINE_FLAG(flag_pairing_completed);
102
pairing_complete(struct bt_conn * conn,bool bonded)103 static void pairing_complete(struct bt_conn *conn, bool bonded)
104 {
105 print_conn_state_transition("Paired", conn);
106 SET_FLAG(flag_pairing_completed);
107 }
108
109 static struct bt_conn_auth_info_cb bt_conn_auth_info_cb = {
110 .pairing_complete = pairing_complete,
111 };
112
set_security(struct bt_conn * conn,bt_security_t sec)113 void set_security(struct bt_conn *conn, bt_security_t sec)
114 {
115 int err;
116
117 err = bt_conn_set_security(conn, sec);
118 ASSERT(!err, "Err bt_conn_set_security %d", err);
119 }
120
wait_pairing_completed(void)121 void wait_pairing_completed(void)
122 {
123 WAIT_FOR_FLAG(flag_pairing_completed);
124 UNSET_FLAG(flag_pairing_completed);
125 }
126
bs_bt_utils_setup(void)127 void bs_bt_utils_setup(void)
128 {
129 int err;
130
131 err = bt_enable(NULL);
132 ASSERT(!err, "bt_enable failed.\n");
133 err = bt_conn_auth_info_cb_register(&bt_conn_auth_info_cb);
134 ASSERT(!err, "bt_conn_auth_info_cb_register failed.\n");
135
136 err = settings_load();
137 ASSERT(!err, "settings_load failed.\n");
138 }
139
disconnect(struct bt_conn * conn)140 void disconnect(struct bt_conn *conn)
141 {
142 int err;
143
144 err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
145 ASSERT(!err, "Err bt_conn_disconnect %d", err);
146 }
147
advertise_connectable(int id)148 void advertise_connectable(int id)
149 {
150 int err;
151 struct bt_le_adv_param param = {};
152
153 param.id = id;
154 param.interval_min = 0x0020;
155 param.interval_max = 0x4000;
156 param.options |= BT_LE_ADV_OPT_CONN;
157
158 err = bt_le_adv_start(¶m, NULL, 0, NULL, 0);
159 ASSERT(!err, "Advertising failed to start (err %d)\n", err);
160 }
161
162 DEFINE_FLAG(flag_bas_ccc_subscribed);
163 static uint8_t bas_level = 50;
164
bas_ccc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)165 static void bas_ccc_cfg_changed(const struct bt_gatt_attr *attr,
166 uint16_t value)
167 {
168 ARG_UNUSED(attr);
169
170 if (value == BT_GATT_CCC_NOTIFY) {
171 printk("BAS CCCD: notification enabled\n");
172 SET_FLAG(flag_bas_ccc_subscribed);
173 }
174 }
175
wait_bas_ccc_subscription(void)176 void wait_bas_ccc_subscription(void)
177 {
178 WAIT_FOR_FLAG(flag_bas_ccc_subscribed);
179 UNSET_FLAG(flag_bas_ccc_subscribed);
180 }
181
bas_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)182 static ssize_t bas_read(struct bt_conn *conn,
183 const struct bt_gatt_attr *attr, void *buf,
184 uint16_t len, uint16_t offset)
185 {
186 uint8_t lvl8 = bas_level;
187
188 return bt_gatt_attr_read(conn, attr, buf, len, offset, &lvl8,
189 sizeof(lvl8));
190 }
191
192 BT_GATT_SERVICE_DEFINE(bas,
193 BT_GATT_PRIMARY_SERVICE(BT_UUID_BAS),
194 BT_GATT_CHARACTERISTIC(BT_UUID_BAS_BATTERY_LEVEL,
195 BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
196 BT_GATT_PERM_READ, bas_read, NULL, &bas_level),
197 BT_GATT_CCC(bas_ccc_cfg_changed,
198 BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
199 );
200
bas_notify(struct bt_conn * conn)201 void bas_notify(struct bt_conn *conn)
202 {
203 int err;
204
205 err = bt_gatt_notify(conn, &bas.attrs[2], &bas_level, sizeof(bas_level));
206 ASSERT(!err, "bt_gatt_notify failed (err %d)\n", err);
207 }
208
209 DEFINE_FLAG(flag_bas_has_notification);
210