1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stddef.h>
8 #include <errno.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/types.h>
11 #include <zephyr/bluetooth/bluetooth.h>
12 #include <zephyr/bluetooth/hci.h>
13 #include <zephyr/bluetooth/conn.h>
14 #include <zephyr/bluetooth/uuid.h>
15 #include <zephyr/bluetooth/gatt.h>
16 #include <zephyr/bluetooth/att.h>
17
18 #include "babblekit/testcase.h"
19 #include "babblekit/flags.h"
20 #include "babblekit/sync.h"
21 #include "common.h"
22
23 DEFINE_FLAG_STATIC(flag_discover_complete);
24
25 extern enum bst_result_t bst_result;
26
27 DEFINE_FLAG_STATIC(flag_is_connected);
28
29 static struct bt_conn *g_conn;
30
connected(struct bt_conn * conn,uint8_t err)31 static void connected(struct bt_conn *conn, uint8_t err)
32 {
33 char addr[BT_ADDR_LE_STR_LEN];
34
35 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
36
37 if (err != 0) {
38 TEST_FAIL("Failed to connect to %s (%u)", addr, err);
39 return;
40 }
41
42 printk("Connected to %s\n", addr);
43 g_conn = bt_conn_ref(conn);
44 SET_FLAG(flag_is_connected);
45 }
46
disconnected(struct bt_conn * conn,uint8_t reason)47 static void disconnected(struct bt_conn *conn, uint8_t reason)
48 {
49 char addr[BT_ADDR_LE_STR_LEN];
50
51 if (conn != g_conn) {
52 return;
53 }
54
55 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
56
57 printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
58
59 bt_conn_unref(g_conn);
60
61 g_conn = NULL;
62 UNSET_FLAG(flag_is_connected);
63 }
64
65 BT_CONN_CB_DEFINE(conn_callbacks) = {
66 .connected = connected,
67 .disconnected = disconnected,
68 };
69
70 static uint16_t chrc_handle;
71
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)72 static uint8_t discover_func(struct bt_conn *conn,
73 const struct bt_gatt_attr *attr,
74 struct bt_gatt_discover_params *params)
75 {
76 int err;
77
78 if (attr == NULL) {
79 if (chrc_handle == 0) {
80 TEST_FAIL("Did not discover chrc (%x)", chrc_handle);
81 }
82
83 (void)memset(params, 0, sizeof(*params));
84
85 SET_FLAG(flag_discover_complete);
86
87 return BT_GATT_ITER_STOP;
88 }
89
90 printk("[ATTRIBUTE] handle %u\n", attr->handle);
91
92 if (params->type == BT_GATT_DISCOVER_PRIMARY &&
93 bt_uuid_cmp(params->uuid, TEST_SERVICE_UUID) == 0) {
94 printk("Found test service\n");
95 params->uuid = NULL;
96 params->start_handle = attr->handle + 1;
97 params->type = BT_GATT_DISCOVER_CHARACTERISTIC;
98
99 err = bt_gatt_discover(conn, params);
100 if (err != 0) {
101 TEST_FAIL("Discover failed (err %d)", err);
102 }
103
104 return BT_GATT_ITER_STOP;
105 } else if (params->type == BT_GATT_DISCOVER_CHARACTERISTIC) {
106 const struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data;
107
108 if (bt_uuid_cmp(chrc->uuid, TEST_CHRC_UUID) == 0) {
109 printk("Found chrc value\n");
110 chrc_handle = chrc->value_handle;
111 params->type = BT_GATT_DISCOVER_DESCRIPTOR;
112 }
113 }
114
115 return BT_GATT_ITER_CONTINUE;
116 }
117
gatt_discover(void)118 static void gatt_discover(void)
119 {
120 struct bt_gatt_discover_params discover_params;
121 int err;
122
123 printk("Discovering services and characteristics\n");
124
125 discover_params.uuid = TEST_SERVICE_UUID;
126 discover_params.func = discover_func;
127 discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
128 discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
129 discover_params.type = BT_GATT_DISCOVER_PRIMARY;
130 discover_params.chan_opt = BT_ATT_CHAN_OPT_NONE;
131
132 err = bt_gatt_discover(g_conn, &discover_params);
133 if (err != 0) {
134 TEST_FAIL("Discover failed(err %d)", err);
135 }
136
137 printk("Discovery complete\n");
138 WAIT_FOR_FLAG(flag_discover_complete);
139 }
140
notify_cb(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)141 static uint8_t notify_cb(struct bt_conn *conn,
142 struct bt_gatt_subscribe_params *params,
143 const void *data, uint16_t length)
144 {
145 if (!data) {
146 params->value_handle = 0U;
147 return BT_GATT_ITER_STOP;
148 }
149
150 return BT_GATT_ITER_CONTINUE;
151 }
152
subscribed_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_subscribe_params * params)153 void subscribed_cb(struct bt_conn *conn, uint8_t err,
154 struct bt_gatt_subscribe_params *params)
155 {
156 printk("Subscribed ccc %x val %x\n",
157 params->value_handle,
158 params->ccc_handle);
159
160 printk("Sending sync to peer\n");
161 bk_sync_send();
162 }
163
164 static struct bt_gatt_discover_params disc_params;
165 static struct bt_gatt_subscribe_params subscribe_params;
gatt_subscribe(void)166 static void gatt_subscribe(void)
167 {
168 int err;
169
170 subscribe_params.value_handle = chrc_handle;
171 subscribe_params.notify = notify_cb;
172 subscribe_params.subscribe = subscribed_cb;
173
174 subscribe_params.ccc_handle = BT_GATT_AUTO_DISCOVER_CCC_HANDLE;
175 subscribe_params.disc_params = &disc_params,
176 subscribe_params.value = BT_GATT_CCC_NOTIFY;
177 subscribe_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
178 subscribe_params.chan_opt = BT_ATT_CHAN_OPT_NONE;
179
180 printk("Subscribing: val %x\n", chrc_handle);
181 err = bt_gatt_subscribe(g_conn, &subscribe_params);
182 if (err != 0) {
183 TEST_FAIL("Subscription failed(err %d)", err);
184 }
185 }
186
test_main(void)187 static void test_main(void)
188 {
189 int err;
190 const struct bt_data ad[] = {
191 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR))
192 };
193
194 TEST_ASSERT(bk_sync_init() == 0, "Failed to open backchannel");
195
196 err = bt_enable(NULL);
197 if (err != 0) {
198 TEST_FAIL("Bluetooth init failed (err %d)", err);
199 return;
200 }
201
202 printk("Bluetooth initialized\n");
203
204 err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
205 if (err != 0) {
206 TEST_FAIL("Advertising failed to start (err %d)", err);
207 return;
208 }
209
210 printk("Advertising successfully started\n");
211
212 WAIT_FOR_FLAG(flag_is_connected);
213
214 /* Wait for the channels to be connected */
215 while (bt_eatt_count(g_conn) < CONFIG_BT_EATT_MAX) {
216 k_sleep(K_TICKS(1));
217 }
218
219 /* Subscribe to the server characteristic. */
220 gatt_discover();
221 gatt_subscribe();
222
223 printk("Waiting for final sync\n");
224 bk_sync_wait();
225
226 TEST_PASS("Server Passed");
227 }
228
229 static const struct bst_test_instance test_server[] = {
230 {
231 .test_id = "server",
232 .test_main_f = test_main
233 },
234 BSTEST_END_MARKER
235 };
236
test_server_install(struct bst_test_list * tests)237 struct bst_test_list *test_server_install(struct bst_test_list *tests)
238 {
239 return bst_add_tests(tests, test_server);
240 }
241