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