]> sigrok.org Git - libsigrok.git/blame - src/serial_bt.c
serial_bt: support the dialog DA14580 chip (seen in TC66C)
[libsigrok.git] / src / serial_bt.c
CommitLineData
b79c3422
GS
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2018-2019 Gerhard Sittig <gerhard.sittig@gmx.net>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <config.h>
21#include <glib.h>
22#include <libsigrok/libsigrok.h>
23#include "libsigrok-internal.h"
24#include <string.h>
25#include <memory.h>
26
b79c3422 27#define LOG_PREFIX "serial-bt"
b79c3422
GS
28
29#ifdef HAVE_SERIAL_COMM
30#ifdef HAVE_BLUETOOTH
31
32#define SER_BT_CONN_PREFIX "bt"
33#define SER_BT_CHUNK_SIZE 1200
34
0e4a85a9
GS
35#define SER_BT_PARAM_PREFIX_CHANNEL "channel="
36#define SER_BT_PARAM_PREFIX_HDL_RX "handle_rx="
37#define SER_BT_PARAM_PREFIX_HDL_TX "handle_tx="
38#define SER_BT_PARAM_PREFIX_HDL_CCCD "handle_cccd="
39#define SER_BT_PARAM_PREFIX_VAL_CCCD "value_cccd="
25d7c995 40#define SER_BT_PARAM_PREFIX_BLE_MTU "mtu="
0e4a85a9 41
b79c3422
GS
42/**
43 * @file
44 *
45 * Serial port handling, wraps the external BT/BLE dependencies.
46 */
47
48/**
49 * @defgroup grp_serial_bt Serial port handling, BT/BLE group
50 *
51 * Make serial-over-BT communication appear like a regular serial port.
52 *
53 * @{
54 */
55
56/* {{{ support for serial-over-BT channels */
57
ca98f7ae
GS
58/*
59 * This builtin database of known devices (keyed by their names as
60 * provided during BT/BLE scans) can help improve the presentation of
61 * scan results. Ideally users could take the output and pass it to
62 * subsequent program invocations, not having to "come up with" the
63 * conn= spec, or only having to touch it up minimally. GUI dialogs
64 * could present scan results such that users just need to pick an
65 * item to open a connection.
66 *
67 * The current implementation guesses connection types from device
68 * names, and optionally amends them with additional parameters if
69 * experience shows that individual devices need these extra specs.
70 *
71 * This database may have to move to a separate source file should
72 * its size grow to amounts that are considered inappropriate here
73 * in the serial transport's BT dispatcher. For now the item count
74 * is small.
75 */
76
b79c3422
GS
77static const struct scan_supported_item {
78 const char *name;
79 enum ser_bt_conn_t type;
c622c88c 80 const char *add_params;
b79c3422 81} scan_supported_items[] = {
c622c88c
GS
82 { "121GW", SER_BT_CONN_BLE122, NULL, },
83 { "Adafruit Bluefruit LE 8134", SER_BT_CONN_NRF51, NULL, },
d0a73799
GS
84 { "DL24M_BLE", SER_BT_CONN_AC6328, NULL, },
85 { "DL24M_SPP", SER_BT_CONN_RFCOMM, "/channel=2", },
c622c88c 86 { "HC-05", SER_BT_CONN_RFCOMM, NULL, },
d0a73799
GS
87 { "UC96_BLE", SER_BT_CONN_AC6328, NULL, },
88 { "UC96_SPP", SER_BT_CONN_RFCOMM, "/channel=2", },
c622c88c
GS
89 { "UM25C", SER_BT_CONN_RFCOMM, NULL, },
90 { NULL, SER_BT_CONN_UNKNOWN, NULL, },
b79c3422
GS
91};
92
ca98f7ae
GS
93static const struct scan_supported_item *scan_is_supported(const char *name)
94{
95 size_t idx;
96 const struct scan_supported_item *item;
97
98 for (idx = 0; idx < ARRAY_SIZE(scan_supported_items); idx++) {
99 item = &scan_supported_items[idx];
100 if (!item->name)
101 break;
102 if (strcmp(name, item->name) != 0)
103 continue;
104 return item;
105 }
106
107 return NULL;
108}
109
b79c3422
GS
110static const char *ser_bt_conn_names[SER_BT_CONN_MAX] = {
111 [SER_BT_CONN_UNKNOWN] = "<type>",
112 [SER_BT_CONN_RFCOMM] = "rfcomm",
113 [SER_BT_CONN_BLE122] = "ble122",
114 [SER_BT_CONN_NRF51] = "nrf51",
115 [SER_BT_CONN_CC254x] = "cc254x",
d0a73799 116 [SER_BT_CONN_AC6328] = "ac6328",
329ef9d8 117 [SER_BT_CONN_DIALOG] = "dialog",
dae34e30 118 [SER_BT_CONN_NOTIFY] = "notify",
b79c3422
GS
119};
120
121static enum ser_bt_conn_t lookup_conn_name(const char *name)
122{
123 size_t idx;
124 const char *item;
125
126 if (!name || !*name)
127 return SER_BT_CONN_UNKNOWN;
128 idx = ARRAY_SIZE(ser_bt_conn_names);
129 while (idx-- > 0) {
130 item = ser_bt_conn_names[idx];
131 if (strcmp(item, name) == 0)
132 return idx;
133 }
134
135 return SER_BT_CONN_UNKNOWN;
136}
137
138static const char *conn_name_text(enum ser_bt_conn_t type)
139{
140 if (type >= ARRAY_SIZE(ser_bt_conn_names))
141 type = SER_BT_CONN_UNKNOWN;
142
143 return ser_bt_conn_names[type];
144}
145
146/**
147 * Parse conn= specs for serial over Bluetooth communication.
148 *
149 * @param[in] serial The serial port that is about to get opened.
150 * @param[in] spec The caller provided conn= specification.
151 * @param[out] conn_type The type of BT comm (BT RFCOMM, BLE notify).
152 * @param[out] remote_addr The remote device address.
153 * @param[out] rfcomm_channel The RFCOMM channel (if applicable).
154 * @param[out] read_hdl The BLE notify read handle (if applicable).
155 * @param[out] write_hdl The BLE notify write handle (if applicable).
156 * @param[out] cccd_hdl The BLE notify CCCD handle (if applicable).
157 * @param[out] cccd_val The BLE notify CCCD value (if applicable).
158 *
159 * @return 0 upon success, non-zero upon failure.
160 *
b79c3422
GS
161 * Summary of parsing rules as they are implemented:
162 * - Implementor's note: Automatic scan for available devices is not
163 * yet implemented. So strictly speaking some parts of the input
164 * spec are optional, but fallbacks may not take effect ATM.
165 * - Insist on the "bt" prefix. Accept "bt" alone without any other
166 * additional field.
167 * - The first field that follows is the connection type. Supported
168 * types are 'rfcomm', 'ble122', 'cc254x', and potentially others
169 * in a future implementation.
170 * - The next field is the remote device's address, either separated
171 * by colons or dashes or spaces, or not separated at all.
172 * - Other parameters (RFCOMM channel, notify handles and write values)
ee617d62
GS
173 * get derived from the connection type.
174 * - More fields after the remote address are options which override
175 * builtin defaults (RFCOMM channels, BLE handles, etc).
b79c3422
GS
176 *
177 * Supported formats resulting from these rules:
ee617d62 178 * bt/<conn>/<addr>[/<param>]...
b79c3422
GS
179 *
180 * Examples:
181 * bt/rfcomm/11-22-33-44-55-66
ee617d62 182 * bt/rfcomm/11-22-33-44-55-66/channel=2
b79c3422
GS
183 * bt/ble122/88:6b:12:34:56:78
184 * bt/cc254x/0123456789ab
185 *
186 * It's assumed that users easily can create those conn= specs from
187 * available information, or that scan routines will create such specs
188 * that copy'n'paste results (or GUI choices from previous scan results)
189 * can get processed here.
190 */
191static int ser_bt_parse_conn_spec(
192 struct sr_serial_dev_inst *serial, const char *spec,
193 enum ser_bt_conn_t *conn_type, const char **remote_addr,
194 size_t *rfcomm_channel,
195 uint16_t *read_hdl, uint16_t *write_hdl,
25d7c995
GS
196 uint16_t *cccd_hdl, uint16_t *cccd_val,
197 uint16_t *ble_mtu)
b79c3422 198{
819277b5 199 char **fields, *field;
b79c3422
GS
200 enum ser_bt_conn_t type;
201 const char *addr;
0e4a85a9
GS
202 int ret_parse, ret;
203 size_t fields_count, field_idx;
204 char *endp;
205 unsigned long parm_val;
b79c3422
GS
206
207 if (conn_type)
208 *conn_type = SER_BT_CONN_UNKNOWN;
209 if (remote_addr)
210 *remote_addr = NULL;
211 if (rfcomm_channel)
212 *rfcomm_channel = 0;
213 if (read_hdl)
214 *read_hdl = 0;
215 if (write_hdl)
216 *write_hdl = 0;
217 if (cccd_hdl)
218 *cccd_hdl = 0;
219 if (cccd_val)
220 *cccd_val = 0;
25d7c995
GS
221 if (ble_mtu)
222 *ble_mtu = 0;
b79c3422 223
b79c3422
GS
224 if (!serial || !spec || !spec[0])
225 return SR_ERR_ARG;
226
227 /* Evaluate the mandatory first three fields. */
228 fields = g_strsplit_set(spec, "/", 0);
229 if (!fields)
230 return SR_ERR_ARG;
231 if (g_strv_length(fields) < 3) {
232 g_strfreev(fields);
233 return SR_ERR_ARG;
234 }
235 field = fields[0];
236 if (strcmp(field, SER_BT_CONN_PREFIX) != 0) {
237 g_strfreev(fields);
238 return SR_ERR_ARG;
239 }
240 field = fields[1];
241 type = lookup_conn_name(field);
242 if (!type) {
243 g_strfreev(fields);
244 return SR_ERR_ARG;
245 }
246 if (conn_type)
247 *conn_type = type;
248 field = fields[2];
249 if (!field || !*field) {
250 g_strfreev(fields);
251 return SR_ERR_ARG;
252 }
253 addr = g_strdup(field);
254 if (remote_addr)
255 *remote_addr = addr;
256
257 /* Derive default parameters that match the connection type. */
258 /* TODO Lookup defaults from a table? */
259 switch (type) {
260 case SER_BT_CONN_RFCOMM:
261 if (rfcomm_channel)
262 *rfcomm_channel = 1;
263 break;
264 case SER_BT_CONN_BLE122:
265 if (read_hdl)
266 *read_hdl = 8;
267 if (write_hdl)
268 *write_hdl = 0;
269 if (cccd_hdl)
270 *cccd_hdl = 9;
271 if (cccd_val)
272 *cccd_val = 0x0003;
273 break;
274 case SER_BT_CONN_NRF51:
275 /* TODO
276 * Are these values appropriate? Check the learn article at
277 * https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-uart-friend?view=all
278 */
279 if (read_hdl)
280 *read_hdl = 13;
281 if (write_hdl)
282 *write_hdl = 11;
283 if (cccd_hdl)
284 *cccd_hdl = 14;
285 if (cccd_val)
286 *cccd_val = 0x0001;
287 /* TODO 'random' type, sec-level=high */
288 break;
289 case SER_BT_CONN_CC254x:
290 /* TODO Are these values appropriate? Just guessing here. */
291 if (read_hdl)
292 *read_hdl = 20;
293 if (write_hdl)
294 *write_hdl = 0;
295 if (cccd_hdl)
296 *cccd_hdl = 21;
297 if (cccd_val)
298 *cccd_val = 0x0001;
299 break;
d0a73799
GS
300 case SER_BT_CONN_AC6328:
301 if (read_hdl)
302 *read_hdl = 12;
303 if (write_hdl)
304 *write_hdl = 15;
305 if (cccd_hdl)
306 *cccd_hdl = 13;
307 if (cccd_val)
308 *cccd_val = 0x0001;
309 break;
329ef9d8
GS
310 case SER_BT_CONN_DIALOG:
311 if (read_hdl)
312 *read_hdl = 23;
313 if (write_hdl)
314 *write_hdl = 18;
315 if (cccd_hdl)
316 *cccd_hdl = 0;
317 if (cccd_val)
318 *cccd_val = 0x0001;
319 if (ble_mtu)
320 *ble_mtu = 400;
321 break;
dae34e30
GS
322 case SER_BT_CONN_NOTIFY:
323 /* All other values must be provided externally. */
324 if (cccd_val)
325 *cccd_val = 0x0001;
326 break;
b79c3422
GS
327 default:
328 return SR_ERR_ARG;
329 }
330
0e4a85a9
GS
331 /*
332 * Preset a successful return value for the conn= parse call.
333 * Scan optional additional fields which specify more params.
334 * Update the defaults which were setup above. Pessimize the
335 * routine's return value in error paths.
336 */
337 ret_parse = SR_OK;
338 fields_count = g_strv_length(fields);
339 for (field_idx = 3; field_idx < fields_count; field_idx++) {
340 field = fields[field_idx];
341 if (!field || !*field)
342 continue;
343 if (g_str_has_prefix(field, SER_BT_PARAM_PREFIX_CHANNEL)) {
344 field += strlen(SER_BT_PARAM_PREFIX_CHANNEL);
345 endp = NULL;
346 ret = sr_atoul_base(field, &parm_val, &endp, 0);
347 if (ret != SR_OK || !endp || *endp != '\0') {
348 ret_parse = SR_ERR_ARG;
349 break;
350 }
351 if (rfcomm_channel)
352 *rfcomm_channel = parm_val;
353 continue;
354 }
355 if (g_str_has_prefix(field, SER_BT_PARAM_PREFIX_HDL_RX)) {
356 field += strlen(SER_BT_PARAM_PREFIX_HDL_RX);
357 endp = NULL;
358 ret = sr_atoul_base(field, &parm_val, &endp, 0);
359 if (ret != SR_OK || !endp || *endp != '\0') {
360 ret_parse = SR_ERR_ARG;
361 break;
362 }
363 if (read_hdl)
364 *read_hdl = parm_val;
365 continue;
366 }
367 if (g_str_has_prefix(field, SER_BT_PARAM_PREFIX_HDL_TX)) {
368 field += strlen(SER_BT_PARAM_PREFIX_HDL_TX);
369 endp = NULL;
370 ret = sr_atoul_base(field, &parm_val, &endp, 0);
371 if (ret != SR_OK || !endp || *endp != '\0') {
372 ret_parse = SR_ERR_ARG;
373 break;
374 }
375 if (write_hdl)
376 *write_hdl = parm_val;
377 continue;
378 }
379 if (g_str_has_prefix(field, SER_BT_PARAM_PREFIX_HDL_CCCD)) {
380 field += strlen(SER_BT_PARAM_PREFIX_HDL_CCCD);
381 endp = NULL;
382 ret = sr_atoul_base(field, &parm_val, &endp, 0);
383 if (ret != SR_OK || !endp || *endp != '\0') {
384 ret_parse = SR_ERR_ARG;
385 break;
386 }
387 if (cccd_hdl)
388 *cccd_hdl = parm_val;
389 continue;
390 }
391 if (g_str_has_prefix(field, SER_BT_PARAM_PREFIX_VAL_CCCD)) {
392 field += strlen(SER_BT_PARAM_PREFIX_VAL_CCCD);
393 endp = NULL;
394 ret = sr_atoul_base(field, &parm_val, &endp, 0);
395 if (ret != SR_OK || !endp || *endp != '\0') {
396 ret_parse = SR_ERR_ARG;
397 break;
398 }
399 if (cccd_val)
400 *cccd_val = parm_val;
401 continue;
402 }
25d7c995
GS
403 if (g_str_has_prefix(field, SER_BT_PARAM_PREFIX_BLE_MTU)) {
404 field += strlen(SER_BT_PARAM_PREFIX_BLE_MTU);
405 endp = NULL;
406 ret = sr_atoul_base(field, &parm_val, &endp, 0);
407 if (ret != SR_OK || !endp || *endp != '\0') {
408 ret_parse = SR_ERR_ARG;
409 break;
410 }
411 if (ble_mtu)
412 *ble_mtu = parm_val;
413 continue;
414 }
0e4a85a9
GS
415 return SR_ERR_DATA;
416 }
b79c3422
GS
417
418 g_strfreev(fields);
0e4a85a9 419 return ret_parse;
b79c3422
GS
420}
421
422static void ser_bt_mask_databits(struct sr_serial_dev_inst *serial,
423 uint8_t *data, size_t len)
424{
425 uint32_t mask32;
426 uint8_t mask;
427 size_t idx;
428
429 if ((serial->comm_params.data_bits % 8) == 0)
430 return;
431
432 mask32 = (1UL << serial->comm_params.data_bits) - 1;
433 mask = mask32 & 0xff;
434 for (idx = 0; idx < len; idx++)
435 data[idx] &= mask;
436}
437
438static int ser_bt_data_cb(void *cb_data, uint8_t *data, size_t dlen)
439{
440 struct sr_serial_dev_inst *serial;
441
442 serial = cb_data;
443 if (!serial)
444 return -1;
445
a8b0e6f5
GS
446 if (!data && dlen)
447 return -1;
448 if (!data || !dlen)
449 return 0;
450
b79c3422
GS
451 ser_bt_mask_databits(serial, data, dlen);
452 sr_ser_queue_rx_data(serial, data, dlen);
453
454 return 0;
455}
456
457/* }}} */
458/* {{{ wrap serial-over-BT operations in a common serial.c API */
459
460/* See if a serial port's name refers to a BT type. */
461SR_PRIV int ser_name_is_bt(struct sr_serial_dev_inst *serial)
462{
463 size_t off;
464 char sep;
465
466 if (!serial)
467 return 0;
468 if (!serial->port || !*serial->port)
469 return 0;
470
471 /* Accept either "bt" alone, or "bt/" as a prefix. */
472 if (!g_str_has_prefix(serial->port, SER_BT_CONN_PREFIX))
473 return 0;
474 off = strlen(SER_BT_CONN_PREFIX);
475 sep = serial->port[off];
476 if (sep != '\0' && sep != '/')
477 return 0;
478
479 return 1;
480}
481
482/* The open() wrapper for BT ports. */
483static int ser_bt_open(struct sr_serial_dev_inst *serial, int flags)
484{
485 enum ser_bt_conn_t conn_type;
486 const char *remote_addr;
487 size_t rfcomm_channel;
488 uint16_t read_hdl, write_hdl, cccd_hdl, cccd_val;
25d7c995 489 uint16_t ble_mtu;
b79c3422
GS
490 int rc;
491 struct sr_bt_desc *desc;
492
493 (void)flags;
494
495 /* Derive BT specific parameters from the port spec. */
496 rc = ser_bt_parse_conn_spec(serial, serial->port,
497 &conn_type, &remote_addr,
498 &rfcomm_channel,
499 &read_hdl, &write_hdl,
25d7c995
GS
500 &cccd_hdl, &cccd_val,
501 &ble_mtu);
b79c3422
GS
502 if (rc != SR_OK)
503 return SR_ERR_ARG;
504
505 if (!conn_type || !remote_addr || !remote_addr[0]) {
506 /* TODO Auto-search for available connections? */
507 return SR_ERR_NA;
508 }
509
510 /* Create the connection. Only store params after successful use. */
511 desc = sr_bt_desc_new();
512 if (!desc)
513 return SR_ERR;
514 serial->bt_desc = desc;
515 rc = sr_bt_config_addr_remote(desc, remote_addr);
516 if (rc < 0)
517 return SR_ERR;
518 serial->bt_addr_remote = g_strdup(remote_addr);
519 switch (conn_type) {
520 case SER_BT_CONN_RFCOMM:
521 rc = sr_bt_config_rfcomm(desc, rfcomm_channel);
522 if (rc < 0)
523 return SR_ERR;
524 serial->bt_rfcomm_channel = rfcomm_channel;
525 break;
526 case SER_BT_CONN_BLE122:
527 case SER_BT_CONN_NRF51:
528 case SER_BT_CONN_CC254x:
d0a73799 529 case SER_BT_CONN_AC6328:
329ef9d8 530 case SER_BT_CONN_DIALOG:
dae34e30 531 case SER_BT_CONN_NOTIFY:
b79c3422 532 rc = sr_bt_config_notify(desc,
25d7c995
GS
533 read_hdl, write_hdl, cccd_hdl, cccd_val,
534 ble_mtu);
b79c3422
GS
535 if (rc < 0)
536 return SR_ERR;
537 serial->bt_notify_handle_read = read_hdl;
538 serial->bt_notify_handle_write = write_hdl;
539 serial->bt_notify_handle_cccd = cccd_hdl;
540 serial->bt_notify_value_cccd = cccd_val;
25d7c995 541 serial->bt_ble_mtu = ble_mtu;
b79c3422
GS
542 break;
543 default:
544 /* Unsupported type, or incomplete implementation. */
545 return SR_ERR_ARG;
546 }
547 serial->bt_conn_type = conn_type;
548
549 /* Make sure the receive buffer can accept input data. */
550 if (!serial->rcv_buffer)
551 serial->rcv_buffer = g_string_sized_new(SER_BT_CHUNK_SIZE);
552 rc = sr_bt_config_cb_data(desc, ser_bt_data_cb, serial);
553 if (rc < 0)
554 return SR_ERR;
555
556 /* Open the connection. */
557 switch (conn_type) {
558 case SER_BT_CONN_RFCOMM:
559 rc = sr_bt_connect_rfcomm(desc);
560 if (rc < 0)
561 return SR_ERR;
562 break;
563 case SER_BT_CONN_BLE122:
564 case SER_BT_CONN_NRF51:
565 case SER_BT_CONN_CC254x:
d0a73799 566 case SER_BT_CONN_AC6328:
329ef9d8 567 case SER_BT_CONN_DIALOG:
dae34e30 568 case SER_BT_CONN_NOTIFY:
b79c3422
GS
569 rc = sr_bt_connect_ble(desc);
570 if (rc < 0)
571 return SR_ERR;
572 rc = sr_bt_start_notify(desc);
573 if (rc < 0)
574 return SR_ERR;
575 break;
576 default:
577 return SR_ERR_ARG;
578 }
579
580 return SR_OK;
581}
582
583static int ser_bt_close(struct sr_serial_dev_inst *serial)
584{
585 if (!serial)
586 return SR_ERR_ARG;
587
588 if (!serial->bt_desc)
589 return SR_OK;
590
591 sr_bt_disconnect(serial->bt_desc);
592 sr_bt_desc_free(serial->bt_desc);
593 serial->bt_desc = NULL;
594
595 g_free(serial->bt_addr_local);
596 serial->bt_addr_local = NULL;
597 g_free(serial->bt_addr_remote);
598 serial->bt_addr_remote = NULL;
599 g_slist_free_full(serial->bt_source_args, g_free);
600 serial->bt_source_args = NULL;
601
602 return SR_OK;
603}
604
605/* Flush, discards pending RX data, empties buffers. */
606static int ser_bt_flush(struct sr_serial_dev_inst *serial)
607{
608 (void)serial;
609 /* EMPTY */
610
611 return SR_OK;
612}
613
614/* Drain, waits for completion of pending TX data. */
615static int ser_bt_drain(struct sr_serial_dev_inst *serial)
616{
617 (void)serial;
618 /* EMPTY */ /* TODO? */
619
620 return SR_ERR_BUG;
621}
622
623static int ser_bt_write(struct sr_serial_dev_inst *serial,
624 const void *buf, size_t count,
625 int nonblocking, unsigned int timeout_ms)
626{
627 ssize_t wrlen;
628
629 /*
630 * TODO Support chunked transmission when callers' requests
631 * exceed the BT channel's capacity? See ser_hid_write().
632 */
633
634 switch (serial->bt_conn_type) {
635 case SER_BT_CONN_RFCOMM:
636 (void)nonblocking;
637 (void)timeout_ms;
638 wrlen = sr_bt_write(serial->bt_desc, buf, count);
639 if (wrlen < 0)
640 return SR_ERR_IO;
641 return wrlen;
642 case SER_BT_CONN_BLE122:
643 case SER_BT_CONN_NRF51:
644 case SER_BT_CONN_CC254x:
d0a73799 645 case SER_BT_CONN_AC6328:
329ef9d8 646 case SER_BT_CONN_DIALOG:
dae34e30 647 case SER_BT_CONN_NOTIFY:
b79c3422
GS
648 /*
649 * Assume that when applications call the serial layer's
650 * write routine, then the BLE chip/module does support
651 * a TX handle. Just call the serial-BT library's write
652 * routine.
653 */
654 (void)nonblocking;
655 (void)timeout_ms;
656 wrlen = sr_bt_write(serial->bt_desc, buf, count);
657 if (wrlen < 0)
658 return SR_ERR_IO;
659 return wrlen;
660 default:
661 return SR_ERR_ARG;
662 }
663 /* UNREACH */
664}
665
666static int ser_bt_read(struct sr_serial_dev_inst *serial,
667 void *buf, size_t count,
668 int nonblocking, unsigned int timeout_ms)
669{
670 gint64 deadline_us, now_us;
671 uint8_t buffer[SER_BT_CHUNK_SIZE];
672 ssize_t rdlen;
673 int rc;
674 size_t dlen;
675
676 /*
677 * Immediately satisfy the caller's request from the RX buffer
678 * if the requested amount of data is available already.
679 */
bf6b9e7b
UH
680 if (sr_ser_has_queued_data(serial) >= count)
681 return sr_ser_unqueue_rx_data(serial, buf, count);
b79c3422
GS
682
683 /*
684 * When a timeout was specified, then determine the deadline
685 * where to stop reception.
686 */
687 deadline_us = 0;
b79c3422
GS
688 if (timeout_ms) {
689 now_us = g_get_monotonic_time();
690 deadline_us = now_us + timeout_ms * 1000;
691 }
692
693 /*
694 * Keep receiving from the port until the caller's requested
695 * amount of data has become available, or the timeout has
696 * expired. In the absence of a timeout, stop reading when an
697 * attempt no longer yields receive data.
698 */
699 while (TRUE) {
700 /* Run another attempt to receive data. */
701 switch (serial->bt_conn_type) {
702 case SER_BT_CONN_RFCOMM:
703 rdlen = sr_bt_read(serial->bt_desc, buffer, sizeof(buffer));
704 if (rdlen <= 0)
705 break;
706 rc = ser_bt_data_cb(serial, buffer, rdlen);
707 if (rc < 0)
708 rdlen = -1;
709 break;
710 case SER_BT_CONN_BLE122:
711 case SER_BT_CONN_NRF51:
712 case SER_BT_CONN_CC254x:
d0a73799 713 case SER_BT_CONN_AC6328:
329ef9d8 714 case SER_BT_CONN_DIALOG:
dae34e30 715 case SER_BT_CONN_NOTIFY:
b79c3422
GS
716 dlen = sr_ser_has_queued_data(serial);
717 rc = sr_bt_check_notify(serial->bt_desc);
718 if (rc < 0)
719 rdlen = -1;
720 else if (sr_ser_has_queued_data(serial) != dlen)
721 rdlen = +1;
722 else
723 rdlen = 0;
724 break;
725 default:
726 rdlen = -1;
727 break;
728 }
729
730 /*
731 * Stop upon receive errors, or timeout expiration. Only
732 * stop upon empty reception in the absence of a timeout.
733 */
734 if (rdlen < 0)
735 break;
736 if (nonblocking && !rdlen)
737 break;
738 if (deadline_us) {
739 now_us = g_get_monotonic_time();
740 if (now_us > deadline_us)
741 break;
742 }
743
744 /* Also stop when sufficient data has become available. */
745 if (sr_ser_has_queued_data(serial) >= count)
746 break;
747 }
748
749 /*
750 * Satisfy the caller's demand for receive data from previously
751 * queued incoming data.
752 */
753 dlen = sr_ser_has_queued_data(serial);
754 if (dlen > count)
755 dlen = count;
756 if (!dlen)
757 return 0;
758
759 return sr_ser_unqueue_rx_data(serial, buf, dlen);
760}
761
b79c3422
GS
762struct bt_source_args_t {
763 /* The application callback. */
764 sr_receive_data_callback cb;
765 void *cb_data;
766 /* The serial device, to store RX data. */
767 struct sr_serial_dev_inst *serial;
768};
769
770/*
771 * Gets periodically invoked by the glib main loop. "Drives" (checks)
772 * progress of BT communication, and invokes the application's callback
773 * which processes RX data (when some has become available), as well as
774 * handles application level timeouts.
775 */
776static int bt_source_cb(int fd, int revents, void *cb_data)
777{
778 struct bt_source_args_t *args;
779 struct sr_serial_dev_inst *serial;
780 uint8_t rx_buf[SER_BT_CHUNK_SIZE];
781 ssize_t rdlen;
782 size_t dlen;
783 int rc;
784
785 args = cb_data;
786 if (!args)
787 return -1;
788 serial = args->serial;
789 if (!serial)
790 return -1;
791 if (!serial->bt_conn_type)
792 return -1;
793
794 /*
795 * Drain receive data which the channel might have pending.
796 * This is "a copy" of the "background part" of ser_bt_read(),
797 * without the timeout support code, and not knowing how much
798 * data the application is expecting.
799 */
800 do {
801 switch (serial->bt_conn_type) {
802 case SER_BT_CONN_RFCOMM:
803 rdlen = sr_bt_read(serial->bt_desc, rx_buf, sizeof(rx_buf));
804 if (rdlen <= 0)
805 break;
806 rc = ser_bt_data_cb(serial, rx_buf, rdlen);
807 if (rc < 0)
808 rdlen = -1;
809 break;
810 case SER_BT_CONN_BLE122:
811 case SER_BT_CONN_NRF51:
812 case SER_BT_CONN_CC254x:
d0a73799 813 case SER_BT_CONN_AC6328:
329ef9d8 814 case SER_BT_CONN_DIALOG:
dae34e30 815 case SER_BT_CONN_NOTIFY:
b79c3422
GS
816 dlen = sr_ser_has_queued_data(serial);
817 rc = sr_bt_check_notify(serial->bt_desc);
818 if (rc < 0)
819 rdlen = -1;
820 else if (sr_ser_has_queued_data(serial) != dlen)
821 rdlen = +1;
822 else
823 rdlen = 0;
824 break;
825 default:
826 rdlen = -1;
827 break;
828 }
829 } while (rdlen > 0);
830
831 /*
832 * When RX data became available (now or earlier), pass this
833 * condition to the application callback. Always periodically
834 * run the application callback, since it handles timeouts and
835 * might carry out other tasks as well like signalling progress.
836 */
837 if (sr_ser_has_queued_data(args->serial))
838 revents |= G_IO_IN;
839 rc = args->cb(fd, revents, args->cb_data);
840
841 return rc;
842}
843
844/* TODO Can we use the Bluetooth socket's file descriptor? Probably not portably. */
845#define WITH_MAXIMUM_TIMEOUT_VALUE 0
846static int ser_bt_setup_source_add(struct sr_session *session,
847 struct sr_serial_dev_inst *serial,
848 int events, int timeout,
849 sr_receive_data_callback cb, void *cb_data)
850{
851 struct bt_source_args_t *args;
852 int rc;
853
854 (void)events;
855
856 /* Optionally enforce a minimum poll period. */
857 if (WITH_MAXIMUM_TIMEOUT_VALUE && timeout > WITH_MAXIMUM_TIMEOUT_VALUE)
858 timeout = WITH_MAXIMUM_TIMEOUT_VALUE;
859
860 /* Allocate status container for background data reception. */
861 args = g_malloc0(sizeof(*args));
862 args->cb = cb;
863 args->cb_data = cb_data;
864 args->serial = serial;
865
866 /*
867 * Have a periodic timer installed. Register the allocated block
868 * with the serial device, since the GSource's finalizer won't
869 * free the memory, and we haven't bothered to create a custom
870 * BT specific GSource.
871 */
872 rc = sr_session_source_add(session, -1, events, timeout, bt_source_cb, args);
873 if (rc != SR_OK) {
874 g_free(args);
875 return rc;
876 }
877 serial->bt_source_args = g_slist_append(serial->bt_source_args, args);
878
879 return SR_OK;
880}
881
882static int ser_bt_setup_source_remove(struct sr_session *session,
883 struct sr_serial_dev_inst *serial)
884{
885 (void)serial;
886
887 (void)sr_session_source_remove(session, -1);
888 /* Release callback args here already? */
889
890 return SR_OK;
891}
892
b79c3422
GS
893struct bt_scan_args_t {
894 GSList *port_list;
895 sr_ser_list_append_t append;
896 GSList *addr_list;
897 const char *bt_type;
898};
899
900static void scan_cb(void *cb_args, const char *addr, const char *name)
901{
902 struct bt_scan_args_t *scan_args;
903 GSList *l;
904 char addr_text[20];
c622c88c 905 const struct scan_supported_item *item;
b79c3422
GS
906 enum ser_bt_conn_t type;
907 char *port_name, *port_desc;
908 char *addr_copy;
909
910 scan_args = cb_args;
911 if (!scan_args)
912 return;
913 sr_info("BT scan, found: %s - %s\n", addr, name);
914
915 /* Check whether the device was seen before. */
916 for (l = scan_args->addr_list; l; l = l->next) {
bf6b9e7b 917 if (strcmp(addr, l->data) == 0)
b79c3422 918 return;
b79c3422
GS
919 }
920
921 /* Substitute colons in the address by dashes. */
922 if (!addr || !*addr)
923 return;
924 snprintf(addr_text, sizeof(addr_text), "%s", addr);
925 g_strcanon(addr_text, "0123456789abcdefABCDEF", '-');
926
927 /* Create a port name, and a description. */
c622c88c
GS
928 item = scan_is_supported(name);
929 type = item ? item->type : SER_BT_CONN_UNKNOWN;
930 port_name = g_strdup_printf("%s/%s/%s%s",
931 SER_BT_CONN_PREFIX, conn_name_text(type), addr_text,
932 (item && item->add_params) ? item->add_params : "");
b79c3422
GS
933 port_desc = g_strdup_printf("%s (%s)", name, scan_args->bt_type);
934
935 scan_args->port_list = scan_args->append(scan_args->port_list, port_name, port_desc);
936 g_free(port_name);
937 g_free(port_desc);
938
939 /* Keep track of the handled address. */
940 addr_copy = g_strdup(addr);
941 scan_args->addr_list = g_slist_append(scan_args->addr_list, addr_copy);
942}
943
944static GSList *ser_bt_list(GSList *list, sr_ser_list_append_t append)
945{
a1b80f9d 946 static const int scan_duration = 3;
b79c3422
GS
947
948 struct bt_scan_args_t scan_args;
949 struct sr_bt_desc *desc;
950
951 /*
952 * Implementor's note: This "list" routine is best-effort. We
953 * assume that registering callbacks always succeeds. Silently
954 * ignore failure to scan for devices. Just return those which
955 * we happen to find.
956 */
957
958 desc = sr_bt_desc_new();
959 if (!desc)
960 return list;
961
962 memset(&scan_args, 0, sizeof(scan_args));
963 scan_args.port_list = list;
964 scan_args.append = append;
965
966 scan_args.addr_list = NULL;
967 scan_args.bt_type = "BT";
968 (void)sr_bt_config_cb_scan(desc, scan_cb, &scan_args);
969 (void)sr_bt_scan_bt(desc, scan_duration);
970 g_slist_free_full(scan_args.addr_list, g_free);
971
972 scan_args.addr_list = NULL;
973 scan_args.bt_type = "BLE";
974 (void)sr_bt_config_cb_scan(desc, scan_cb, &scan_args);
975 (void)sr_bt_scan_le(desc, scan_duration);
976 g_slist_free_full(scan_args.addr_list, g_free);
977
978 sr_bt_desc_free(desc);
979
980 return scan_args.port_list;
981}
982
983static struct ser_lib_functions serlib_bt = {
984 .open = ser_bt_open,
985 .close = ser_bt_close,
986 .flush = ser_bt_flush,
987 .drain = ser_bt_drain,
988 .write = ser_bt_write,
989 .read = ser_bt_read,
c0aa074e
UH
990 /*
991 * Bluetooth communication has no concept of bitrate, so ignore
992 * these arguments silently. Neither need we pass the frame format
993 * down to internal BT comm routines, nor need we keep the values
994 * here, since the caller will cache/register them already.
995 */
996 .set_params = std_dummy_set_params,
3ad30b4e 997 .set_handshake = std_dummy_set_handshake,
b79c3422
GS
998 .setup_source_add = ser_bt_setup_source_add,
999 .setup_source_remove = ser_bt_setup_source_remove,
1000 .list = ser_bt_list,
1001 .get_frame_format = NULL,
1002};
1003SR_PRIV struct ser_lib_functions *ser_lib_funcs_bt = &serlib_bt;
1004
1005/* }}} */
1006#else
1007
1008SR_PRIV int ser_name_is_bt(struct sr_serial_dev_inst *serial)
1009{
1010 (void)serial;
1011
1012 return 0;
1013}
1014
1015SR_PRIV struct ser_lib_functions *ser_lib_funcs_bt = NULL;
1016
1017#endif
1018#endif
1019
1020/** @} */