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