1 /*
2  * Copyright (c) 2015-2016 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/types.h>
8 #include <stddef.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <zephyr/sys/printk.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/kernel.h>
14 
15 #include <zephyr/settings/settings.h>
16 
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/bluetooth/hci.h>
19 #include <zephyr/bluetooth/conn.h>
20 #include <zephyr/bluetooth/uuid.h>
21 #include <zephyr/bluetooth/gatt.h>
22 
23 #include <gatt/services.h>
24 
25 #include "edtt_driver.h"
26 #include "bs_tracing.h"
27 #include "commands.h"
28 
29 #define DEVICE_NAME		CONFIG_BT_DEVICE_NAME
30 #define DEVICE_NAME_LEN		(sizeof(DEVICE_NAME) - 1)
31 
32 static const struct bt_data ad[] = {
33 	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
34 	BT_DATA_BYTES(BT_DATA_UUID16_ALL,
35 		      BT_UUID_16_ENCODE(BT_UUID_HRS_VAL),
36 		      BT_UUID_16_ENCODE(BT_UUID_BAS_VAL),
37 		      BT_UUID_16_ENCODE(BT_UUID_CTS_VAL)),
38 	BT_DATA_BYTES(BT_DATA_UUID128_ALL,
39 		      0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
40 		      0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12),
41 };
42 
43 static const struct bt_data sd[] = {
44 	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
45 };
46 
47 static int service_set;
48 
start_advertising(void)49 static int start_advertising(void)
50 {
51 	int err;
52 
53 	err = bt_le_adv_start(BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONN | BT_LE_ADV_OPT_USE_IDENTITY,
54 					      BT_GAP_ADV_FAST_INT_MIN_1, BT_GAP_ADV_FAST_INT_MAX_1,
55 					      NULL),
56 			      ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
57 	if (err) {
58 		printk("Advertising failed to start (err %d)\n", err);
59 	}
60 
61 	return err;
62 }
63 
connected(struct bt_conn * conn,uint8_t err)64 static void connected(struct bt_conn *conn, uint8_t err)
65 {
66 	if (err) {
67 		printk("Connection failed (err %u)\n", err);
68 	} else {
69 		printk("Connected\n");
70 	}
71 }
72 
disconnected(struct bt_conn * conn,uint8_t reason)73 static void disconnected(struct bt_conn *conn, uint8_t reason)
74 {
75 	printk("Disconnected (reason 0x%02x)\n", reason);
76 }
77 
recycled(void)78 static void recycled(void)
79 {
80 	start_advertising();
81 }
82 
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)83 static void security_changed(struct bt_conn *conn, bt_security_t level,
84 			     enum bt_security_err err)
85 {
86 	char addr[BT_ADDR_LE_STR_LEN];
87 
88 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
89 
90 	printk("Security changed: %s level %u\n", addr, level);
91 }
92 
93 BT_CONN_CB_DEFINE(conn_callbacks) = {
94 	.connected = connected,
95 	.disconnected = disconnected,
96 	.recycled = recycled,
97 	.security_changed = security_changed,
98 };
99 
service_setup(int set)100 static void service_setup(int set)
101 {
102 	if (set == service_set) {
103 		printk("Ignored request to change GATT services set to #%d - "
104 			"already selected!\n", set);
105 		return;
106 	}
107 	switch (service_set) {
108 	case 0:
109 		break;
110 	case 1:
111 		service_c_2_1_remove();
112 		service_f_1_remove();
113 		service_c_1_1_remove();
114 		service_b_5_1_remove();
115 		service_b_2_1_remove();
116 		service_b_1_1_remove();
117 		service_b_3_1_remove();
118 		service_b_4_1_remove();
119 		service_a_1_remove();
120 		service_d_1_remove();
121 		break;
122 	case 2:
123 		service_e_2_remove();
124 		service_b_5_2_remove();
125 		service_b_2_2_remove();
126 		service_b_3_2_remove();
127 		service_a_2_remove();
128 		service_b_1_2_remove();
129 		service_d_2_remove();
130 		service_b_4_2_remove();
131 		service_c_1_2_remove();
132 		service_c_2_2_remove();
133 		break;
134 	case 3:
135 		service_e_3_remove();
136 		service_c_2_3_remove();
137 		service_b_2_3_remove();
138 		service_c_1_3_remove();
139 		service_a_3_remove();
140 		service_b_3_3_remove();
141 		service_b_4_3_remove();
142 		service_b_5_3_remove();
143 		service_d_3_remove();
144 		service_b_1_3_remove();
145 		break;
146 	default:
147 		break;
148 	}
149 
150 	switch (set) {
151 	case 0:
152 		break;
153 	case 1:
154 		service_d_1_init();
155 		service_a_1_init();
156 		service_b_4_1_init();
157 		service_b_3_1_init();
158 		service_b_1_1_init();
159 		service_b_2_1_init();
160 		service_b_5_1_init();
161 		service_c_1_1_init();
162 		service_f_1_init();
163 		service_c_2_1_init();
164 		break;
165 	case 2:
166 		service_c_2_2_init();
167 		service_c_1_2_init();
168 		service_b_4_2_init();
169 		service_d_2_init();
170 		service_b_1_2_init();
171 		service_a_2_init();
172 		service_b_3_2_init();
173 		service_b_2_2_init();
174 		service_b_5_2_init();
175 		service_e_2_init();
176 		break;
177 	case 3:
178 		service_b_1_3_init();
179 		service_d_3_init();
180 		service_b_5_3_init();
181 		service_b_4_3_init();
182 		service_b_3_3_init();
183 		service_a_3_init();
184 		service_c_1_3_init();
185 		service_b_2_3_init();
186 		service_c_2_3_init();
187 		service_e_3_init();
188 		break;
189 	default:
190 		break;
191 	}
192 	service_set = set;
193 	printk("Switched to GATT services set to #%d\n", set);
194 }
195 
service_notify(void)196 static void service_notify(void)
197 {
198 	switch (service_set) {
199 	case 0:
200 		break;
201 	case 1:
202 		service_b_3_1_value_v6_notify();
203 		break;
204 	case 2:
205 		service_b_3_2_value_v6_notify();
206 		break;
207 	case 3:
208 		service_b_3_3_value_v6_notify();
209 		break;
210 	default:
211 		break;
212 	}
213 }
214 
service_indicate(void)215 static void service_indicate(void)
216 {
217 	switch (service_set) {
218 	case 0:
219 		break;
220 	case 1:
221 		break;
222 	case 2:
223 		service_b_3_2_value_v6_indicate();
224 		break;
225 	case 3:
226 		service_b_3_3_value_v6_indicate();
227 		break;
228 	default:
229 		break;
230 	}
231 }
232 
bt_ready(int err)233 static void bt_ready(int err)
234 {
235 	if (err) {
236 		printk("Bluetooth init failed (err %d)\n", err);
237 		return;
238 	}
239 
240 	printk("Bluetooth initialized\n");
241 
242 	service_setup(1);
243 
244 	printk("GATT Services initialized\n");
245 
246 	if (IS_ENABLED(CONFIG_SETTINGS)) {
247 		settings_load();
248 	}
249 
250 	err = start_advertising();
251 
252 	if (!err) {
253 		printk("Advertising successfully started\n");
254 	}
255 }
256 
auth_passkey_display(struct bt_conn * conn,unsigned int passkey)257 static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
258 {
259 	char addr[BT_ADDR_LE_STR_LEN];
260 
261 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
262 
263 	printk("Passkey for %s: %06u\n", addr, passkey);
264 }
265 
auth_cancel(struct bt_conn * conn)266 static void auth_cancel(struct bt_conn *conn)
267 {
268 	char addr[BT_ADDR_LE_STR_LEN];
269 
270 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
271 
272 	printk("Pairing cancelled: %s\n", addr);
273 }
274 
275 static struct bt_conn_auth_cb auth_cb_display = {
276 	.passkey_display = auth_passkey_display,
277 	.passkey_entry = NULL,
278 	.cancel = auth_cancel,
279 };
280 
281 /**
282  * @brief Clean out excess bytes from the input buffer
283  */
read_excess_bytes(uint16_t size)284 static void read_excess_bytes(uint16_t size)
285 {
286 	if (size > 0) {
287 		uint8_t buffer[size];
288 
289 		edtt_read((uint8_t *)buffer, size, EDTTT_BLOCK);
290 		printk("command size wrong! (%u extra bytes removed)", size);
291 	}
292 }
293 
294 /**
295  * @brief Switch GATT Service Set
296  */
switch_service_set(uint16_t size)297 static void switch_service_set(uint16_t size)
298 {
299 	uint16_t response = sys_cpu_to_le16(CMD_GATT_SERVICE_SET_RSP);
300 	uint8_t  set;
301 
302 	if (size > 0) {
303 		edtt_read((uint8_t *)&set, sizeof(set), EDTTT_BLOCK);
304 		service_setup((int)set);
305 		size -= sizeof(set);
306 	}
307 	read_excess_bytes(size);
308 	size = 0;
309 
310 	edtt_write((uint8_t *)&response, sizeof(response), EDTTT_BLOCK);
311 	edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK);
312 }
313 
314 /**
315  * @brief Send Notifications from GATT Service Set
316  */
handle_service_notify(uint16_t size)317 static void handle_service_notify(uint16_t size)
318 {
319 	uint16_t response = sys_cpu_to_le16(CMD_GATT_SERVICE_NOTIFY_RSP);
320 
321 	service_notify();
322 	read_excess_bytes(size);
323 	size = 0;
324 
325 	edtt_write((uint8_t *)&response, sizeof(response), EDTTT_BLOCK);
326 	edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK);
327 }
328 
329 /**
330  * @brief Send Indications from GATT Service Set
331  */
handle_service_indicate(uint16_t size)332 static void handle_service_indicate(uint16_t size)
333 {
334 	uint16_t response = sys_cpu_to_le16(CMD_GATT_SERVICE_INDICATE_RSP);
335 
336 	service_indicate();
337 	read_excess_bytes(size);
338 	size = 0;
339 
340 	edtt_write((uint8_t *)&response, sizeof(response), EDTTT_BLOCK);
341 	edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK);
342 }
343 
main(void)344 int main(void)
345 {
346 	int err;
347 	uint16_t command;
348 	uint16_t size;
349 
350 	err = bt_enable(bt_ready);
351 	if (err) {
352 		printk("Bluetooth init failed (err %d)\n", err);
353 		return 0;
354 	}
355 
356 	bt_conn_auth_cb_register(&auth_cb_display);
357 
358 	/**
359 	 * Initialize and start EDTT system
360 	 */
361 #if defined(CONFIG_ARCH_POSIX)
362 	enable_edtt_mode();
363 	set_edtt_autoshutdown(true);
364 #endif
365 	edtt_start();
366 
367 	/* Implement notification. At the moment there is no suitable way
368 	 * of starting delayed work so we do it here
369 	 */
370 	while (1) {
371 		/**
372 		 * Wait for a command to arrive - then read and execute command
373 		 */
374 		edtt_read((uint8_t *)&command, sizeof(command), EDTTT_BLOCK);
375 		command = sys_le16_to_cpu(command);
376 		edtt_read((uint8_t *)&size, sizeof(size), EDTTT_BLOCK);
377 		size = sys_le16_to_cpu(size);
378 		bs_trace_raw_time(4, "command 0x%04X received (size %u)\n",
379 				command, size);
380 
381 		switch (command) {
382 		case CMD_GATT_SERVICE_SET_REQ:
383 			switch_service_set(size);
384 			break;
385 		case CMD_GATT_SERVICE_NOTIFY_REQ:
386 			handle_service_notify(size);
387 			break;
388 		case CMD_GATT_SERVICE_INDICATE_REQ:
389 			handle_service_indicate(size);
390 			break;
391 		default:
392 			break;
393 		}
394 	}
395 	return 0;
396 }
397