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