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