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