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(&param, 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