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