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