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