libsigrok  0.5.2
sigrok hardware access and backend library
serial_bt.c
Go to the documentation of this file.
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 
53 static 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 
64 static 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 
72 static 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 
89 static 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  */
142 static 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 
257 static 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 
273 static 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. */
291 SR_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. */
313 static 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 
403 static 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. */
426 static 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. */
435 static 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 
443 static 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 
483 static 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  */
497  if (sr_ser_has_queued_data(serial) >= count)
498  return sr_ser_unqueue_rx_data(serial, buf, count);
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 
577 struct bt_source_args_t {
578  /* The application callback. */
580  void *cb_data;
581  /* The serial device, to store RX data. */
582  struct sr_serial_dev_inst *serial;
583 };
584 
585 /*
586  * Gets periodically invoked by the glib main loop. "Drives" (checks)
587  * progress of BT communication, and invokes the application's callback
588  * which processes RX data (when some has become available), as well as
589  * handles application level timeouts.
590  */
591 static int bt_source_cb(int fd, int revents, void *cb_data)
592 {
593  struct bt_source_args_t *args;
594  struct sr_serial_dev_inst *serial;
595  uint8_t rx_buf[SER_BT_CHUNK_SIZE];
596  ssize_t rdlen;
597  size_t dlen;
598  int rc;
599 
600  args = cb_data;
601  if (!args)
602  return -1;
603  serial = args->serial;
604  if (!serial)
605  return -1;
606  if (!serial->bt_conn_type)
607  return -1;
608 
609  /*
610  * Drain receive data which the channel might have pending.
611  * This is "a copy" of the "background part" of ser_bt_read(),
612  * without the timeout support code, and not knowing how much
613  * data the application is expecting.
614  */
615  do {
616  switch (serial->bt_conn_type) {
617  case SER_BT_CONN_RFCOMM:
618  rdlen = sr_bt_read(serial->bt_desc, rx_buf, sizeof(rx_buf));
619  if (rdlen <= 0)
620  break;
621  rc = ser_bt_data_cb(serial, rx_buf, rdlen);
622  if (rc < 0)
623  rdlen = -1;
624  break;
625  case SER_BT_CONN_BLE122:
626  case SER_BT_CONN_NRF51:
627  case SER_BT_CONN_CC254x:
628  dlen = sr_ser_has_queued_data(serial);
629  rc = sr_bt_check_notify(serial->bt_desc);
630  if (rc < 0)
631  rdlen = -1;
632  else if (sr_ser_has_queued_data(serial) != dlen)
633  rdlen = +1;
634  else
635  rdlen = 0;
636  break;
637  default:
638  rdlen = -1;
639  break;
640  }
641  } while (rdlen > 0);
642 
643  /*
644  * When RX data became available (now or earlier), pass this
645  * condition to the application callback. Always periodically
646  * run the application callback, since it handles timeouts and
647  * might carry out other tasks as well like signalling progress.
648  */
649  if (sr_ser_has_queued_data(args->serial))
650  revents |= G_IO_IN;
651  rc = args->cb(fd, revents, args->cb_data);
652 
653  return rc;
654 }
655 
656 /* TODO Can we use the Bluetooth socket's file descriptor? Probably not portably. */
657 #define WITH_MAXIMUM_TIMEOUT_VALUE 0
658 static int ser_bt_setup_source_add(struct sr_session *session,
659  struct sr_serial_dev_inst *serial,
660  int events, int timeout,
661  sr_receive_data_callback cb, void *cb_data)
662 {
663  struct bt_source_args_t *args;
664  int rc;
665 
666  (void)events;
667 
668  /* Optionally enforce a minimum poll period. */
669  if (WITH_MAXIMUM_TIMEOUT_VALUE && timeout > WITH_MAXIMUM_TIMEOUT_VALUE)
670  timeout = WITH_MAXIMUM_TIMEOUT_VALUE;
671 
672  /* Allocate status container for background data reception. */
673  args = g_malloc0(sizeof(*args));
674  args->cb = cb;
675  args->cb_data = cb_data;
676  args->serial = serial;
677 
678  /*
679  * Have a periodic timer installed. Register the allocated block
680  * with the serial device, since the GSource's finalizer won't
681  * free the memory, and we haven't bothered to create a custom
682  * BT specific GSource.
683  */
684  rc = sr_session_source_add(session, -1, events, timeout, bt_source_cb, args);
685  if (rc != SR_OK) {
686  g_free(args);
687  return rc;
688  }
689  serial->bt_source_args = g_slist_append(serial->bt_source_args, args);
690 
691  return SR_OK;
692 }
693 
694 static int ser_bt_setup_source_remove(struct sr_session *session,
695  struct sr_serial_dev_inst *serial)
696 {
697  (void)serial;
698 
699  (void)sr_session_source_remove(session, -1);
700  /* Release callback args here already? */
701 
702  return SR_OK;
703 }
704 
705 static enum ser_bt_conn_t scan_is_supported(const char *name)
706 {
707  size_t idx;
708  const struct scan_supported_item *item;
709 
710  for (idx = 0; idx < ARRAY_SIZE(scan_supported_items); idx++) {
711  item = &scan_supported_items[idx];
712  if (!item->name)
713  break;
714  if (strcmp(name, item->name) != 0)
715  continue;
716  return item->type;
717  }
718 
719  return SER_BT_CONN_UNKNOWN;
720 }
721 
722 struct bt_scan_args_t {
723  GSList *port_list;
724  sr_ser_list_append_t append;
725  GSList *addr_list;
726  const char *bt_type;
727 };
728 
729 static void scan_cb(void *cb_args, const char *addr, const char *name)
730 {
731  struct bt_scan_args_t *scan_args;
732  GSList *l;
733  char addr_text[20];
734  enum ser_bt_conn_t type;
735  char *port_name, *port_desc;
736  char *addr_copy;
737 
738  scan_args = cb_args;
739  if (!scan_args)
740  return;
741  sr_info("BT scan, found: %s - %s\n", addr, name);
742 
743  /* Check whether the device was seen before. */
744  for (l = scan_args->addr_list; l; l = l->next) {
745  if (strcmp(addr, l->data) == 0)
746  return;
747  }
748 
749  /* Substitute colons in the address by dashes. */
750  if (!addr || !*addr)
751  return;
752  snprintf(addr_text, sizeof(addr_text), "%s", addr);
753  g_strcanon(addr_text, "0123456789abcdefABCDEF", '-');
754 
755  /* Create a port name, and a description. */
756  type = scan_is_supported(name);
757  port_name = g_strdup_printf("%s/%s/%s",
758  SER_BT_CONN_PREFIX, conn_name_text(type), addr_text);
759  port_desc = g_strdup_printf("%s (%s)", name, scan_args->bt_type);
760 
761  scan_args->port_list = scan_args->append(scan_args->port_list, port_name, port_desc);
762  g_free(port_name);
763  g_free(port_desc);
764 
765  /* Keep track of the handled address. */
766  addr_copy = g_strdup(addr);
767  scan_args->addr_list = g_slist_append(scan_args->addr_list, addr_copy);
768 }
769 
770 static GSList *ser_bt_list(GSList *list, sr_ser_list_append_t append)
771 {
772  static const int scan_duration = 2;
773 
774  struct bt_scan_args_t scan_args;
775  struct sr_bt_desc *desc;
776 
777  /*
778  * Implementor's note: This "list" routine is best-effort. We
779  * assume that registering callbacks always succeeds. Silently
780  * ignore failure to scan for devices. Just return those which
781  * we happen to find.
782  */
783 
784  desc = sr_bt_desc_new();
785  if (!desc)
786  return list;
787 
788  memset(&scan_args, 0, sizeof(scan_args));
789  scan_args.port_list = list;
790  scan_args.append = append;
791 
792  scan_args.addr_list = NULL;
793  scan_args.bt_type = "BT";
794  (void)sr_bt_config_cb_scan(desc, scan_cb, &scan_args);
795  (void)sr_bt_scan_bt(desc, scan_duration);
796  g_slist_free_full(scan_args.addr_list, g_free);
797 
798  scan_args.addr_list = NULL;
799  scan_args.bt_type = "BLE";
800  (void)sr_bt_config_cb_scan(desc, scan_cb, &scan_args);
801  (void)sr_bt_scan_le(desc, scan_duration);
802  g_slist_free_full(scan_args.addr_list, g_free);
803 
804  sr_bt_desc_free(desc);
805 
806  return scan_args.port_list;
807 }
808 
809 static struct ser_lib_functions serlib_bt = {
810  .open = ser_bt_open,
811  .close = ser_bt_close,
812  .flush = ser_bt_flush,
813  .drain = ser_bt_drain,
814  .write = ser_bt_write,
815  .read = ser_bt_read,
816  /*
817  * Bluetooth communication has no concept of bitrate, so ignore
818  * these arguments silently. Neither need we pass the frame format
819  * down to internal BT comm routines, nor need we keep the values
820  * here, since the caller will cache/register them already.
821  */
822  .set_params = std_dummy_set_params,
823  .setup_source_add = ser_bt_setup_source_add,
824  .setup_source_remove = ser_bt_setup_source_remove,
825  .list = ser_bt_list,
826  .get_frame_format = NULL,
827 };
828 SR_PRIV struct ser_lib_functions *ser_lib_funcs_bt = &serlib_bt;
829 
830 /* }}} */
831 #else
832 
833 SR_PRIV int ser_name_is_bt(struct sr_serial_dev_inst *serial)
834 {
835  (void)serial;
836 
837  return 0;
838 }
839 
840 SR_PRIV struct ser_lib_functions *ser_lib_funcs_bt = NULL;
841 
842 #endif
843 #endif
844 
845 /** @} */
Generic/unspecified error.
Definition: libsigrok.h:68
No error.
Definition: libsigrok.h:67
The public libsigrok header file to be used by frontends.
int(* sr_receive_data_callback)(int fd, int revents, void *cb_data)
Type definition for callback function for data reception.
Definition: libsigrok.h:134
Not applicable.
Definition: libsigrok.h:73
#define SR_PRIV
Definition: libsigrok.h:128
Function argument error.
Definition: libsigrok.h:70
Input/output error.
Definition: libsigrok.h:78
Errors hinting at internal bugs.
Definition: libsigrok.h:71
Opaque structure representing a libsigrok session.
Definition: libsigrok.h:456