1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stddef.h>
8 #include <string.h>
9 #include <errno.h>
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/types.h>
14 #include <zephyr/sys/ring_buffer.h>
15
16 #include <zephyr/bluetooth/bluetooth.h>
17 #include <zephyr/bluetooth/hci.h>
18 #include <zephyr/bluetooth/conn.h>
19 #include <zephyr/bluetooth/uuid.h>
20 #include <zephyr/bluetooth/gatt.h>
21
22 #include <openthread.h>
23
24 /* OpenThread BLE driver API */
25 #include <openthread/error.h>
26 #include <openthread/platform/ble.h>
27 #include <openthread/tcat.h>
28
29 /* Zephyr Logging */
30
31 #define LOG_MODULE_NAME net_openthread_tcat
32 #define LOG_LEVEL CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL
33
34 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
35
36 /* BLE connection constants as defined in thread specification. */
37 #define TOBLE_SERVICE_UUID 0xfffb
38 #define RX_CHARACTERISTIC_UUID \
39 BT_UUID_128_ENCODE(0x6bd10d8b, 0x85a7, 0x4e5a, 0xba2d, 0xc83558a5f220)
40 #define TX_CHARACTERISTIC_UUID \
41 BT_UUID_128_ENCODE(0x7fddf61f, 0x280a, 0x4773, 0xb448, 0xba1b8fe0dd69)
42
43 #define BT_UUID_TCAT_SERVICE BT_UUID_DECLARE_16(TOBLE_SERVICE_UUID)
44 #define BT_UUID_TCAT_SERVICE_RX BT_UUID_DECLARE_128(RX_CHARACTERISTIC_UUID)
45 #define BT_UUID_TCAT_SERVICE_TX BT_UUID_DECLARE_128(TX_CHARACTERISTIC_UUID)
46
47 #define PLAT_BLE_THREAD_DEALY 500
48 #define PLAT_BLE_MSG_DATA_MAX CONFIG_BT_L2CAP_TX_MTU /* must match the maximum MTU size used */
49
50 #define PLAT_BLE_MSG_CONNECT (PLAT_BLE_MSG_DATA_MAX + 1U)
51 #define PLAT_BLE_MSG_DISCONNECT (PLAT_BLE_MSG_CONNECT + 1U)
52
53 /* Zephyr Kernel Objects */
54
55 static void ot_plat_ble_thread(void *, void *, void *);
56 static uint8_t ot_plat_ble_msg_buf[PLAT_BLE_MSG_DATA_MAX];
57
58 static K_SEM_DEFINE(ot_plat_ble_init_semaphore, 0, 1);
59 static K_SEM_DEFINE(ot_plat_ble_event_semaphore, 0, K_SEM_MAX_LIMIT);
60 RING_BUF_DECLARE(ot_plat_ble_ring_buf, CONFIG_OPENTHREAD_BLE_TCAT_RING_BUF_SIZE);
61 static K_THREAD_DEFINE(ot_plat_ble_tid, CONFIG_OPENTHREAD_BLE_TCAT_THREAD_STACK_SIZE,
62 ot_plat_ble_thread, NULL, NULL, NULL, 5, 0, PLAT_BLE_THREAD_DEALY);
63
64 /* OpenThread Objects */
65
66 static otInstance *ble_openthread_instance;
67
68 /* BLE service Objects */
69
70 /* forward declaration for callback functions */
71 static ssize_t on_receive(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
72 uint16_t len, uint16_t offset, uint8_t flags);
73 static void on_cccd_changed(const struct bt_gatt_attr *attr, uint16_t value);
74
75 /* Service Declaration and Registration */
76 BT_GATT_SERVICE_DEFINE(my_service, BT_GATT_PRIMARY_SERVICE(BT_UUID_TCAT_SERVICE),
77 BT_GATT_CHARACTERISTIC(BT_UUID_TCAT_SERVICE_RX,
78 BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
79 BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, NULL,
80 on_receive, NULL),
81 BT_GATT_CHARACTERISTIC(BT_UUID_TCAT_SERVICE_TX, BT_GATT_CHRC_NOTIFY,
82 BT_GATT_PERM_READ, NULL, NULL, NULL),
83 BT_GATT_CCC(on_cccd_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),);
84
85 /* Zephyr BLE Objects */
86
87 /* forward declaration for callback functions */
88 static void connected(struct bt_conn *conn, uint8_t err);
89 static void disconnected(struct bt_conn *conn, uint8_t reason);
90 static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param);
91 static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency,
92 uint16_t timeout);
93
94 static struct bt_conn *ot_plat_ble_connection;
95
96 static struct bt_conn_cb conn_callbacks = {.connected = connected,
97 .disconnected = disconnected,
98 .le_param_req = le_param_req,
99 .le_param_updated = le_param_updated};
100
101 static uint8_t service_data[OT_TCAT_ADVERTISEMENT_MAX_LEN] = {0};
102 static const uint8_t service_data_size = ARRAY_SIZE(service_data);
103
104 static struct bt_data ad[] = {
105 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
106 BT_DATA(BT_DATA_SVC_DATA16, service_data, service_data_size),
107 };
108
109 static struct bt_data sd[] = {
110 BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(TOBLE_SERVICE_UUID)),
111 BT_DATA(BT_DATA_SVC_DATA16, service_data, service_data_size),
112 };
113
114 /* Zephyr BLE Message Queue and Thread */
115
ot_plat_ble_queue_msg(const uint8_t * aData,uint16_t aLen,int8_t aRssi)116 static bool ot_plat_ble_queue_msg(const uint8_t *aData, uint16_t aLen, int8_t aRssi)
117 {
118 otError error = OT_ERROR_NONE;
119 uint16_t len = 0;
120
121 if (aLen <= PLAT_BLE_MSG_DATA_MAX && aData == NULL) {
122 return OT_ERROR_INVALID_ARGS;
123 }
124
125 k_sched_lock();
126
127 len = sizeof(aLen) + sizeof(aRssi) + ((aLen <= PLAT_BLE_MSG_DATA_MAX) ? aLen : 0);
128
129 if (ring_buf_space_get(&ot_plat_ble_ring_buf) >= len) {
130 ring_buf_put(&ot_plat_ble_ring_buf, (uint8_t *)&aLen, sizeof(aLen));
131 ring_buf_put(&ot_plat_ble_ring_buf, &aRssi, sizeof(aRssi));
132 if (aLen <= PLAT_BLE_MSG_DATA_MAX) {
133 ring_buf_put(&ot_plat_ble_ring_buf, aData, aLen);
134 }
135 k_sem_give(&ot_plat_ble_event_semaphore);
136 } else {
137 error = OT_ERROR_NO_BUFS;
138 }
139
140 k_sched_unlock();
141
142 return error;
143 }
144
ot_plat_ble_thread(void * unused1,void * unused2,void * unused3)145 static void ot_plat_ble_thread(void *unused1, void *unused2, void *unused3)
146 {
147 ARG_UNUSED(unused1);
148 ARG_UNUSED(unused2);
149 ARG_UNUSED(unused3);
150
151 uint16_t len;
152 int8_t rssi;
153 otBleRadioPacket my_packet;
154
155 LOG_INF("%s started", __func__);
156
157 while (1) {
158 k_sem_take(&ot_plat_ble_event_semaphore, K_FOREVER);
159 ring_buf_get(&ot_plat_ble_ring_buf, (uint8_t *)&len, sizeof(len));
160 ring_buf_get(&ot_plat_ble_ring_buf, &rssi, sizeof(rssi));
161 if (len <= PLAT_BLE_MSG_DATA_MAX) {
162 ring_buf_get(&ot_plat_ble_ring_buf, ot_plat_ble_msg_buf, len);
163 }
164
165 openthread_mutex_lock();
166
167 if (len <= PLAT_BLE_MSG_DATA_MAX) {
168 /* The packet parameter in otPlatBleGattServerOnWriteRequest is not const.
169 * Re-write all members.
170 */
171 my_packet.mValue = ot_plat_ble_msg_buf;
172 my_packet.mPower = rssi;
173 my_packet.mLength = len;
174 otPlatBleGattServerOnWriteRequest(ble_openthread_instance, 0, &my_packet);
175 } else if (len == PLAT_BLE_MSG_CONNECT) {
176 otPlatBleGapOnConnected(ble_openthread_instance, 0);
177 } else if (len == PLAT_BLE_MSG_DISCONNECT) {
178 otPlatBleGapOnDisconnected(ble_openthread_instance, 0);
179 }
180 openthread_mutex_unlock();
181 }
182 }
183
184 /* Zephyr BLE service callbacks */
185
186 /* This function is called whenever the RX Characteristic has been written to by a Client */
on_receive(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)187 static ssize_t on_receive(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
188 uint16_t len, uint16_t offset, uint8_t flags)
189 {
190 LOG_DBG("Received data, handle %" PRIu16 ", len %" PRIu16, attr->handle, len);
191
192 otError error = ot_plat_ble_queue_msg(buf, len, 0);
193
194 if (error != OT_ERROR_NONE) {
195 LOG_WRN("Error queuing message: %s", otThreadErrorToString(error));
196 }
197
198 return len;
199 }
200
201 /* This function is called whenever a Notification has been sent by the TX Characteristic */
on_sent(struct bt_conn * conn,void * user_data)202 static void on_sent(struct bt_conn *conn, void *user_data)
203 {
204 ARG_UNUSED(conn);
205 ARG_UNUSED(user_data);
206
207 LOG_DBG("Data sent");
208 }
209
210 /* This function is called whenever the CCCD register has been changed by the client */
on_cccd_changed(const struct bt_gatt_attr * attr,uint16_t value)211 void on_cccd_changed(const struct bt_gatt_attr *attr, uint16_t value)
212 {
213 uint16_t mtu;
214 otError error = OT_ERROR_NONE;
215
216 ARG_UNUSED(attr);
217
218 switch (value) {
219 case BT_GATT_CCC_NOTIFY:
220
221 error = ot_plat_ble_queue_msg(NULL, PLAT_BLE_MSG_CONNECT, 0);
222 if (error != OT_ERROR_NONE) {
223 LOG_WRN("Error queuing message: %s", otThreadErrorToString(error));
224 }
225
226 error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu);
227 if (error != OT_ERROR_NONE) {
228 LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error));
229 }
230
231 LOG_INF("CCCD update (mtu=%" PRIu16 ")!", mtu);
232
233 break;
234
235 default:
236 break;
237 }
238 }
239
otPlatBleGattServerIndicate(otInstance * aInstance,uint16_t aHandle,const otBleRadioPacket * aPacket)240 otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle,
241 const otBleRadioPacket *aPacket)
242 {
243 ARG_UNUSED(aInstance);
244
245 /* TO DO change to indications. */
246 const struct bt_gatt_attr *attr = &my_service.attrs[3];
247
248 struct bt_gatt_notify_params params = {.uuid = BT_UUID_TCAT_SERVICE_TX,
249 .attr = attr,
250 .data = aPacket->mValue,
251 .len = aPacket->mLength,
252 .func = on_sent};
253
254 LOG_DBG("Send data, handle %d, len %d", attr->handle, aPacket->mLength);
255
256 /* Only one connection supported */
257 if (aHandle != 0) {
258 return OT_ERROR_INVALID_ARGS;
259 }
260
261 if (ot_plat_ble_connection == NULL) {
262 return OT_ERROR_INVALID_STATE;
263 }
264
265 /* Check whether notifications are enabled or not */
266 if (bt_gatt_is_subscribed(ot_plat_ble_connection, attr, BT_GATT_CCC_NOTIFY)) {
267 if (bt_gatt_notify_cb(ot_plat_ble_connection, ¶ms)) {
268 LOG_WRN("Error, unable to send notification");
269 return OT_ERROR_INVALID_ARGS;
270 }
271 } else {
272 LOG_WRN("Warning, notification not enabled on the selected attribute");
273 return OT_ERROR_INVALID_STATE;
274 }
275
276 return OT_ERROR_NONE;
277 }
278
otPlatBleGattMtuGet(otInstance * aInstance,uint16_t * aMtu)279 otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu)
280 {
281 ARG_UNUSED(aInstance);
282
283 if (ot_plat_ble_connection == NULL) {
284 return OT_ERROR_FAILED;
285 }
286
287 if (aMtu != NULL) {
288 *aMtu = bt_gatt_get_mtu(ot_plat_ble_connection);
289 }
290
291 return OT_ERROR_NONE;
292 }
293
otPlatBleGapDisconnect(otInstance * aInstance)294 otError otPlatBleGapDisconnect(otInstance *aInstance)
295 {
296 ARG_UNUSED(aInstance);
297
298 if (ot_plat_ble_connection == NULL) {
299 return OT_ERROR_INVALID_STATE;
300 }
301
302 if (bt_conn_disconnect(ot_plat_ble_connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN)) {
303 return OT_ERROR_INVALID_STATE;
304 }
305
306 return OT_ERROR_NONE;
307 }
308
309 /* Zephyr BLE callbacks */
310
connected(struct bt_conn * conn,uint8_t err)311 static void connected(struct bt_conn *conn, uint8_t err)
312 {
313 struct bt_conn_info info;
314 char addr[BT_ADDR_LE_STR_LEN];
315 uint16_t mtu;
316 otError error = OT_ERROR_NONE;
317
318 ot_plat_ble_connection = bt_conn_ref(conn);
319
320 if (err) {
321 LOG_WRN("Connection failed err %u %s",
322 err, bt_hci_err_to_str(err));
323 return;
324 } else if (bt_conn_get_info(conn, &info)) {
325 LOG_WRN("Could not parse connection info");
326 } else {
327 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
328
329 error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu);
330 if (error != OT_ERROR_NONE) {
331 LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error));
332 }
333
334 LOG_INF("Connection established (mtu=%" PRIu16 ")!", mtu);
335 }
336 }
337
disconnected(struct bt_conn * conn,uint8_t reason)338 static void disconnected(struct bt_conn *conn, uint8_t reason)
339 {
340 otError error = OT_ERROR_NONE;
341
342 LOG_INF("Disconnected, reason 0x%02x %s", reason, bt_hci_err_to_str(reason));
343
344 if (ot_plat_ble_connection) {
345 bt_conn_unref(ot_plat_ble_connection);
346 ot_plat_ble_connection = NULL;
347
348 error = ot_plat_ble_queue_msg(NULL, PLAT_BLE_MSG_DISCONNECT, 0);
349 if (error != OT_ERROR_NONE) {
350 LOG_WRN("Error queuing message: %s", otThreadErrorToString(error));
351 }
352 }
353 }
354
le_param_req(struct bt_conn * conn,struct bt_le_conn_param * param)355 static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
356 {
357 return true;
358 }
359
le_param_updated(struct bt_conn * conn,uint16_t interval,uint16_t latency,uint16_t timeout)360 static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency,
361 uint16_t timeout)
362 {
363 struct bt_conn_info info;
364 char addr[BT_ADDR_LE_STR_LEN];
365 uint16_t mtu;
366 otError error = OT_ERROR_NONE;
367
368 if (bt_conn_get_info(conn, &info)) {
369 LOG_INF("Could not parse connection info");
370 } else {
371 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
372
373 error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu);
374
375 if (error != OT_ERROR_NONE) {
376 LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error));
377 }
378
379 LOG_INF("Connection parameters updated (mtu=%" PRIu16 ")!", mtu);
380 }
381 }
382
bt_ready(int err)383 static void bt_ready(int err)
384 {
385 if (err) {
386 LOG_WRN("BLE init failed with error code %d", err);
387 return;
388 }
389
390 bt_conn_cb_register(&conn_callbacks);
391 k_sem_give(&ot_plat_ble_init_semaphore); /* BLE stack up an running */
392 }
393
otPlatBleGetLinkCapabilities(otInstance * aInstance,otBleLinkCapabilities * aBleLinkCapabilities)394 void otPlatBleGetLinkCapabilities(otInstance *aInstance,
395 otBleLinkCapabilities *aBleLinkCapabilities)
396 {
397 ARG_UNUSED(aInstance);
398
399 aBleLinkCapabilities->mGattNotifications = 1;
400 aBleLinkCapabilities->mL2CapDirect = 0;
401 aBleLinkCapabilities->mRsv = 0;
402 }
403
otPlatBleSupportsMultiRadio(otInstance * aInstance)404 bool otPlatBleSupportsMultiRadio(otInstance *aInstance)
405 {
406 OT_UNUSED_VARIABLE(aInstance);
407
408 return IS_ENABLED(CONFIG_OPENTHREAD_TCAT_MULTIRADIO_CAPABILITIES);
409 }
410
otPlatBleGetAdvertisementBuffer(otInstance * aInstance,uint8_t ** aAdvertisementBuffer)411 otError otPlatBleGetAdvertisementBuffer(otInstance *aInstance, uint8_t **aAdvertisementBuffer)
412 {
413 ARG_UNUSED(aInstance);
414
415 *aAdvertisementBuffer = service_data;
416
417 return OT_ERROR_NONE;
418 }
419
otPlatBleGapAdvSetData(otInstance * aInstance,uint8_t * aAdvertisementData,uint16_t aAdvertisementLen)420 otError otPlatBleGapAdvSetData(otInstance *aInstance, uint8_t *aAdvertisementData,
421 uint16_t aAdvertisementLen)
422 {
423 ARG_UNUSED(aInstance);
424
425 if (aAdvertisementLen > OT_TCAT_ADVERTISEMENT_MAX_LEN || aAdvertisementData == NULL) {
426 LOG_ERR("Invalid TCAT Advertisement parameters advlen: %d", aAdvertisementLen);
427 return OT_ERROR_INVALID_ARGS;
428 }
429
430 ad[1].data_len = (uint8_t)aAdvertisementLen;
431 sd[1].data_len = (uint8_t)aAdvertisementLen;
432 return OT_ERROR_NONE;
433 }
434
otPlatBleGapAdvUpdateData(otInstance * aInstance,uint8_t * aAdvertisementData,uint16_t aAdvertisementLen)435 otError otPlatBleGapAdvUpdateData(otInstance *aInstance, uint8_t *aAdvertisementData,
436 uint16_t aAdvertisementLen)
437 {
438 ARG_UNUSED(aInstance);
439
440 int err;
441
442 if (aAdvertisementLen > OT_TCAT_ADVERTISEMENT_MAX_LEN || aAdvertisementData == NULL) {
443 LOG_ERR("Invalid TCAT Advertisement parameters advlen: %d", aAdvertisementLen);
444 return OT_ERROR_INVALID_ARGS;
445 }
446
447 ad[1].data_len = (uint8_t)aAdvertisementLen;
448 sd[1].data_len = (uint8_t)aAdvertisementLen;
449
450 err = bt_le_adv_update_data(ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
451
452 if (err != 0) {
453 return OT_ERROR_FAILED;
454 }
455
456 return OT_ERROR_NONE;
457 }
458
otPlatBleGapAdvStart(otInstance * aInstance,uint16_t aInterval)459 otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval)
460 {
461 ARG_UNUSED(aInstance);
462 ARG_UNUSED(aInterval);
463
464 int err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_2, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
465
466 if (err != 0 && err != -EALREADY) {
467 LOG_WRN("Advertising failed to start (err %d)", err);
468 return OT_ERROR_INVALID_STATE;
469 }
470
471 LOG_INF("Advertising successfully started");
472
473 return OT_ERROR_NONE;
474 }
475
otPlatBleGapAdvStop(otInstance * aInstance)476 otError otPlatBleGapAdvStop(otInstance *aInstance)
477 {
478 ARG_UNUSED(aInstance);
479
480 int err = bt_le_adv_stop();
481
482 if (err != 0 && err != -EALREADY) {
483 LOG_WRN("Advertisement failed to stop (err %d)", err);
484 return OT_ERROR_FAILED;
485 }
486 return OT_ERROR_NONE;
487 }
488
489 /* Zephyr BLE initialization */
490
otPlatBleEnable(otInstance * aInstance)491 otError otPlatBleEnable(otInstance *aInstance)
492 {
493 int err;
494
495 ble_openthread_instance = aInstance;
496 err = bt_enable(bt_ready);
497
498 if (err != 0 && err != -EALREADY) {
499 LOG_WRN("BLE enable failed with error code %d", err);
500 return OT_ERROR_FAILED;
501 } else if (err == -EALREADY) {
502 bt_conn_cb_register(&conn_callbacks);
503 return OT_ERROR_NONE;
504 }
505
506 err = k_sem_take(&ot_plat_ble_init_semaphore, K_MSEC(500));
507
508 if (!err) {
509 LOG_INF("Bluetooth initialized");
510 } else {
511 LOG_INF("BLE initialization did not complete in time");
512 return OT_ERROR_FAILED;
513 }
514
515 return OT_ERROR_NONE;
516 }
517
otPlatBleDisable(otInstance * aInstance)518 otError otPlatBleDisable(otInstance *aInstance)
519 {
520 ARG_UNUSED(aInstance);
521 /* This function intentionally does nothing since disabling advertisement disables BLE
522 * stack.
523 */
524 return OT_ERROR_NONE;
525 }
526