1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "common.h"
8
9 extern enum bst_result_t bst_result;
10
11 CREATE_FLAG(flag_is_connected);
12 CREATE_FLAG(flag_short_subscribe);
13 CREATE_FLAG(flag_long_subscribe);
14
15 static struct bt_conn *g_conn;
16
17 #define ARRAY_ITEM(i, _) i
18 const uint8_t chrc_data[] = { LISTIFY(CHRC_SIZE, ARRAY_ITEM, (,)) }; /* 1, 2, 3 ... */
19 const uint8_t long_chrc_data[] = { LISTIFY(LONG_CHRC_SIZE, ARRAY_ITEM, (,)) }; /* 1, 2, 3 ... */
20
connected(struct bt_conn * conn,uint8_t err)21 static void connected(struct bt_conn *conn, uint8_t err)
22 {
23 char addr[BT_ADDR_LE_STR_LEN];
24
25 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
26
27 if (err != 0) {
28 FAIL("Failed to connect to %s (%u)\n", addr, err);
29 return;
30 }
31
32 printk("Connected to %s\n", addr);
33
34 g_conn = bt_conn_ref(conn);
35 SET_FLAG(flag_is_connected);
36 }
37
disconnected(struct bt_conn * conn,uint8_t reason)38 static void disconnected(struct bt_conn *conn, uint8_t reason)
39 {
40 char addr[BT_ADDR_LE_STR_LEN];
41
42 if (conn != g_conn) {
43 return;
44 }
45
46 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
47
48 printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
49
50 bt_conn_unref(g_conn);
51
52 g_conn = NULL;
53 UNSET_FLAG(flag_is_connected);
54 }
55
56 BT_CONN_CB_DEFINE(conn_callbacks) = {
57 .connected = connected,
58 .disconnected = disconnected,
59 };
60
read_test_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)61 static ssize_t read_test_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
62 uint16_t len, uint16_t offset)
63 {
64 printk("Read short\n");
65 return bt_gatt_attr_read(conn, attr, buf, len, offset, (void *)chrc_data,
66 sizeof(chrc_data));
67 }
68
read_long_test_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)69 static ssize_t read_long_test_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
70 uint16_t len, uint16_t offset)
71 {
72 printk("Read long\n");
73 return bt_gatt_attr_read(conn, attr, buf, len, offset, (void *)long_chrc_data,
74 sizeof(long_chrc_data));
75 }
76
short_subscribe(const struct bt_gatt_attr * attr,uint16_t value)77 static void short_subscribe(const struct bt_gatt_attr *attr, uint16_t value)
78 {
79 const bool notif_enabled = (value == BT_GATT_CCC_NOTIFY);
80
81 if (notif_enabled) {
82 SET_FLAG(flag_short_subscribe);
83 }
84
85 printk("Short notifications %s\n", notif_enabled ? "enabled" : "disabled");
86 }
87
long_subscribe(const struct bt_gatt_attr * attr,uint16_t value)88 static void long_subscribe(const struct bt_gatt_attr *attr, uint16_t value)
89 {
90 const bool notif_enabled = (value == BT_GATT_CCC_NOTIFY);
91
92 if (notif_enabled) {
93 SET_FLAG(flag_long_subscribe);
94 }
95
96 printk("Long notifications %s\n", notif_enabled ? "enabled" : "disabled");
97 }
98
99 BT_GATT_SERVICE_DEFINE(test_svc, BT_GATT_PRIMARY_SERVICE(TEST_SERVICE_UUID),
100 BT_GATT_CHARACTERISTIC(TEST_CHRC_UUID,
101 BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_READ,
102 BT_GATT_PERM_READ, read_test_chrc, NULL, NULL),
103 BT_GATT_CUD("Short test_svc format description", BT_GATT_PERM_READ),
104 BT_GATT_CCC(short_subscribe, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
105 BT_GATT_CHARACTERISTIC(TEST_LONG_CHRC_UUID,
106 BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_READ,
107 BT_GATT_PERM_READ, read_long_test_chrc, NULL, NULL),
108 BT_GATT_CCC(long_subscribe, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE));
109
110 static volatile size_t num_notifications_sent;
111
notification_sent(struct bt_conn * conn,void * user_data)112 static void notification_sent(struct bt_conn *conn, void *user_data)
113 {
114 size_t *length = user_data;
115
116 printk("Sent notification #%u with length %d\n", num_notifications_sent++, *length);
117 }
118
short_notify(enum bt_att_chan_opt opt)119 static void short_notify(enum bt_att_chan_opt opt)
120 {
121 static size_t length = CHRC_SIZE;
122 static struct bt_gatt_notify_params params = {
123 .attr = &attr_test_svc[1],
124 .data = chrc_data,
125 .len = CHRC_SIZE,
126 .func = notification_sent,
127 .user_data = &length,
128 .uuid = NULL,
129 };
130 int err;
131
132 params.chan_opt = opt;
133
134 do {
135 err = bt_gatt_notify_cb(g_conn, ¶ms);
136
137 if (err == -ENOMEM) {
138 k_sleep(K_MSEC(10));
139 } else if (err) {
140 FAIL("Short notify failed (err %d)\n", err);
141 }
142 } while (err);
143 }
144
long_notify(enum bt_att_chan_opt opt)145 static void long_notify(enum bt_att_chan_opt opt)
146 {
147 static size_t length = LONG_CHRC_SIZE;
148 static struct bt_gatt_notify_params params = {
149 .attr = &attr_test_svc[5],
150 .data = long_chrc_data,
151 .len = LONG_CHRC_SIZE,
152 .func = notification_sent,
153 .user_data = &length,
154 .uuid = NULL,
155 };
156 int err;
157
158 params.chan_opt = opt;
159
160 do {
161 err = bt_gatt_notify_cb(g_conn, ¶ms);
162
163 if (err == -ENOMEM) {
164 k_sleep(K_MSEC(10));
165 } else if (err) {
166 FAIL("Long notify failed (err %d)\n", err);
167 }
168 } while (err);
169 }
170
setup(void)171 static void setup(void)
172 {
173 int err;
174 const struct bt_data ad[] = {
175 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
176 };
177
178 err = bt_enable(NULL);
179 if (err != 0) {
180 FAIL("Bluetooth init failed (err %d)\n", err);
181 return;
182 }
183
184 printk("Bluetooth initialized\n");
185
186 err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
187 if (err != 0) {
188 FAIL("Advertising failed to start (err %d)\n", err);
189 return;
190 }
191
192 printk("Advertising successfully started\n");
193
194 WAIT_FOR_FLAG(flag_is_connected);
195
196 while (bt_eatt_count(g_conn) < CONFIG_BT_EATT_MAX) {
197 k_sleep(K_MSEC(100));
198 }
199 printk("EATT connected\n");
200
201 WAIT_FOR_FLAG(flag_short_subscribe);
202 WAIT_FOR_FLAG(flag_long_subscribe);
203 }
204
test_main_none(void)205 static void test_main_none(void)
206 {
207 setup();
208
209 for (int i = 0; i < NOTIFICATION_COUNT / 2; i++) {
210 short_notify(BT_ATT_CHAN_OPT_NONE);
211 long_notify(BT_ATT_CHAN_OPT_NONE);
212 }
213
214 while (num_notifications_sent < NOTIFICATION_COUNT) {
215 k_sleep(K_MSEC(100));
216 }
217
218 PASS("GATT server passed\n");
219 }
220
test_main_enhanced(void)221 static void test_main_enhanced(void)
222 {
223 setup();
224
225 for (int i = 0; i < NOTIFICATION_COUNT / 2; i++) {
226 short_notify(BT_ATT_CHAN_OPT_ENHANCED_ONLY);
227 long_notify(BT_ATT_CHAN_OPT_ENHANCED_ONLY);
228 }
229
230 while (num_notifications_sent < NOTIFICATION_COUNT) {
231 k_sleep(K_MSEC(100));
232 }
233
234 PASS("GATT server passed\n");
235 }
236
test_main_unenhanced(void)237 static void test_main_unenhanced(void)
238 {
239 setup();
240
241 for (int i = 0; i < NOTIFICATION_COUNT / 2; i++) {
242 short_notify(BT_ATT_CHAN_OPT_UNENHANCED_ONLY);
243 long_notify(BT_ATT_CHAN_OPT_UNENHANCED_ONLY);
244 }
245
246 while (num_notifications_sent < NOTIFICATION_COUNT) {
247 k_sleep(K_MSEC(100));
248 }
249
250 PASS("GATT server passed\n");
251 }
252
test_main_mixed(void)253 static void test_main_mixed(void)
254 {
255 setup();
256
257 for (int i = 0; i < NOTIFICATION_COUNT / 2; i++) {
258 short_notify(BT_ATT_CHAN_OPT_UNENHANCED_ONLY);
259 long_notify(BT_ATT_CHAN_OPT_ENHANCED_ONLY);
260 }
261
262 while (num_notifications_sent < NOTIFICATION_COUNT) {
263 k_sleep(K_MSEC(100));
264 }
265
266 PASS("GATT server passed\n");
267 }
268
269 static const struct bst_test_instance test_gatt_server[] = {
270 {
271 .test_id = "gatt_server_none",
272 .test_pre_init_f = test_init,
273 .test_tick_f = test_tick,
274 .test_main_f = test_main_none,
275 },
276 {
277 .test_id = "gatt_server_unenhanced",
278 .test_pre_init_f = test_init,
279 .test_tick_f = test_tick,
280 .test_main_f = test_main_unenhanced,
281 },
282 {
283 .test_id = "gatt_server_enhanced",
284 .test_pre_init_f = test_init,
285 .test_tick_f = test_tick,
286 .test_main_f = test_main_enhanced,
287 },
288 {
289 .test_id = "gatt_server_mixed",
290 .test_pre_init_f = test_init,
291 .test_tick_f = test_tick,
292 .test_main_f = test_main_mixed,
293 },
294 BSTEST_END_MARKER,
295 };
296
test_gatt_server_install(struct bst_test_list * tests)297 struct bst_test_list *test_gatt_server_install(struct bst_test_list *tests)
298 {
299 return bst_add_tests(tests, test_gatt_server);
300 }
301