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