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