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