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