2 * This file is part of the libsigrok project.
4 * Copyright (C) 2018-2019 Gerhard Sittig <gerhard.sittig@gmx.net>
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.
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.
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/>.
22 #include <libsigrok/libsigrok.h>
23 #include "libsigrok-internal.h"
27 #define LOG_PREFIX "serial-bt"
29 #ifdef HAVE_SERIAL_COMM
32 #define SER_BT_CONN_PREFIX "bt"
33 #define SER_BT_CHUNK_SIZE 1200
38 * Serial port handling, wraps the external BT/BLE dependencies.
42 * @defgroup grp_serial_bt Serial port handling, BT/BLE group
44 * Make serial-over-BT communication appear like a regular serial port.
49 /* {{{ support for serial-over-BT channels */
51 static const struct scan_supported_item {
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, },
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",
70 static enum ser_bt_conn_t lookup_conn_name(const char *name)
76 return SER_BT_CONN_UNKNOWN;
77 idx = ARRAY_SIZE(ser_bt_conn_names);
79 item = ser_bt_conn_names[idx];
80 if (strcmp(item, name) == 0)
84 return SER_BT_CONN_UNKNOWN;
87 static const char *conn_name_text(enum ser_bt_conn_t type)
89 if (type >= ARRAY_SIZE(ser_bt_conn_names))
90 type = SER_BT_CONN_UNKNOWN;
92 return ser_bt_conn_names[type];
96 * Parse conn= specs for serial over Bluetooth communication.
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).
108 * @return 0 upon success, non-zero upon failure.
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
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.
125 * Supported formats resulting from these rules:
129 * bt/rfcomm/11-22-33-44-55-66
130 * bt/ble122/88:6b:12:34:56:78
131 * bt/cc254x/0123456789ab
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.
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)
145 enum ser_bt_conn_t type;
147 char **fields, *field;
150 *conn_type = SER_BT_CONN_UNKNOWN;
164 type = SER_BT_CONN_UNKNOWN;
167 if (!serial || !spec || !spec[0])
170 /* Evaluate the mandatory first three fields. */
171 fields = g_strsplit_set(spec, "/", 0);
174 if (g_strv_length(fields) < 3) {
179 if (strcmp(field, SER_BT_CONN_PREFIX) != 0) {
184 type = lookup_conn_name(field);
192 if (!field || !*field) {
196 addr = g_strdup(field);
200 /* Derive default parameters that match the connection type. */
201 /* TODO Lookup defaults from a table? */
203 case SER_BT_CONN_RFCOMM:
207 case SER_BT_CONN_BLE122:
217 case SER_BT_CONN_NRF51:
219 * Are these values appropriate? Check the learn article at
220 * https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-uart-friend?view=all
230 /* TODO 'random' type, sec-level=high */
232 case SER_BT_CONN_CC254x:
233 /* TODO Are these values appropriate? Just guessing here. */
247 /* TODO Evaluate optionally trailing fields, override defaults? */
253 static void ser_bt_mask_databits(struct sr_serial_dev_inst *serial,
254 uint8_t *data, size_t len)
260 if ((serial->comm_params.data_bits % 8) == 0)
263 mask32 = (1UL << serial->comm_params.data_bits) - 1;
264 mask = mask32 & 0xff;
265 for (idx = 0; idx < len; idx++)
269 static int ser_bt_data_cb(void *cb_data, uint8_t *data, size_t dlen)
271 struct sr_serial_dev_inst *serial;
277 ser_bt_mask_databits(serial, data, dlen);
278 sr_ser_queue_rx_data(serial, data, dlen);
284 /* {{{ wrap serial-over-BT operations in a common serial.c API */
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)
294 if (!serial->port || !*serial->port)
297 /* Accept either "bt" alone, or "bt/" as a prefix. */
298 if (!g_str_has_prefix(serial->port, SER_BT_CONN_PREFIX))
300 off = strlen(SER_BT_CONN_PREFIX);
301 sep = serial->port[off];
302 if (sep != '\0' && sep != '/')
308 /* The open() wrapper for BT ports. */
309 static int ser_bt_open(struct sr_serial_dev_inst *serial, int flags)
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;
316 struct sr_bt_desc *desc;
320 /* Derive BT specific parameters from the port spec. */
321 rc = ser_bt_parse_conn_spec(serial, serial->port,
322 &conn_type, &remote_addr,
324 &read_hdl, &write_hdl,
325 &cccd_hdl, &cccd_val);
329 if (!conn_type || !remote_addr || !remote_addr[0]) {
330 /* TODO Auto-search for available connections? */
334 /* Create the connection. Only store params after successful use. */
335 desc = sr_bt_desc_new();
338 serial->bt_desc = desc;
339 rc = sr_bt_config_addr_remote(desc, remote_addr);
342 serial->bt_addr_remote = g_strdup(remote_addr);
344 case SER_BT_CONN_RFCOMM:
345 rc = sr_bt_config_rfcomm(desc, rfcomm_channel);
348 serial->bt_rfcomm_channel = rfcomm_channel;
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);
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;
363 /* Unsupported type, or incomplete implementation. */
366 serial->bt_conn_type = conn_type;
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);
375 /* Open the connection. */
377 case SER_BT_CONN_RFCOMM:
378 rc = sr_bt_connect_rfcomm(desc);
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);
388 rc = sr_bt_start_notify(desc);
399 static int ser_bt_close(struct sr_serial_dev_inst *serial)
404 if (!serial->bt_desc)
407 sr_bt_disconnect(serial->bt_desc);
408 sr_bt_desc_free(serial->bt_desc);
409 serial->bt_desc = NULL;
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;
421 /* Flush, discards pending RX data, empties buffers. */
422 static int ser_bt_flush(struct sr_serial_dev_inst *serial)
430 /* Drain, waits for completion of pending TX data. */
431 static int ser_bt_drain(struct sr_serial_dev_inst *serial)
434 /* EMPTY */ /* TODO? */
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)
446 * TODO Support chunked transmission when callers' requests
447 * exceed the BT channel's capacity? See ser_hid_write().
450 switch (serial->bt_conn_type) {
451 case SER_BT_CONN_RFCOMM:
454 wrlen = sr_bt_write(serial->bt_desc, buf, count);
458 case SER_BT_CONN_BLE122:
459 case SER_BT_CONN_NRF51:
460 case SER_BT_CONN_CC254x:
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
469 wrlen = sr_bt_write(serial->bt_desc, buf, count);
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)
483 gint64 deadline_us, now_us;
484 uint8_t buffer[SER_BT_CHUNK_SIZE];
490 * Immediately satisfy the caller's request from the RX buffer
491 * if the requested amount of data is available already.
493 if (sr_ser_has_queued_data(serial) >= count)
494 return sr_ser_unqueue_rx_data(serial, buf, count);
497 * When a timeout was specified, then determine the deadline
498 * where to stop reception.
501 now_us = 0; /* Silence a (false) compiler warning. */
503 now_us = g_get_monotonic_time();
504 deadline_us = now_us + timeout_ms * 1000;
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.
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));
520 rc = ser_bt_data_cb(serial, buffer, rdlen);
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);
531 else if (sr_ser_has_queued_data(serial) != dlen)
542 * Stop upon receive errors, or timeout expiration. Only
543 * stop upon empty reception in the absence of a timeout.
547 if (nonblocking && !rdlen)
550 now_us = g_get_monotonic_time();
551 if (now_us > deadline_us)
555 /* Also stop when sufficient data has become available. */
556 if (sr_ser_has_queued_data(serial) >= count)
561 * Satisfy the caller's demand for receive data from previously
562 * queued incoming data.
564 dlen = sr_ser_has_queued_data(serial);
570 return sr_ser_unqueue_rx_data(serial, buf, dlen);
573 struct bt_source_args_t {
574 /* The application callback. */
575 sr_receive_data_callback cb;
577 /* The serial device, to store RX data. */
578 struct sr_serial_dev_inst *serial;
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.
587 static int bt_source_cb(int fd, int revents, void *cb_data)
589 struct bt_source_args_t *args;
590 struct sr_serial_dev_inst *serial;
591 uint8_t rx_buf[SER_BT_CHUNK_SIZE];
599 serial = args->serial;
602 if (!serial->bt_conn_type)
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.
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));
617 rc = ser_bt_data_cb(serial, rx_buf, rdlen);
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);
628 else if (sr_ser_has_queued_data(serial) != dlen)
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.
645 if (sr_ser_has_queued_data(args->serial))
647 rc = args->cb(fd, revents, args->cb_data);
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)
659 struct bt_source_args_t *args;
664 /* Optionally enforce a minimum poll period. */
665 if (WITH_MAXIMUM_TIMEOUT_VALUE && timeout > WITH_MAXIMUM_TIMEOUT_VALUE)
666 timeout = WITH_MAXIMUM_TIMEOUT_VALUE;
668 /* Allocate status container for background data reception. */
669 args = g_malloc0(sizeof(*args));
671 args->cb_data = cb_data;
672 args->serial = serial;
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.
680 rc = sr_session_source_add(session, -1, events, timeout, bt_source_cb, args);
685 serial->bt_source_args = g_slist_append(serial->bt_source_args, args);
690 static int ser_bt_setup_source_remove(struct sr_session *session,
691 struct sr_serial_dev_inst *serial)
695 (void)sr_session_source_remove(session, -1);
696 /* Release callback args here already? */
701 static enum ser_bt_conn_t scan_is_supported(const char *name)
704 const struct scan_supported_item *item;
706 for (idx = 0; idx < ARRAY_SIZE(scan_supported_items); idx++) {
707 item = &scan_supported_items[idx];
710 if (strcmp(name, item->name) != 0)
715 return SER_BT_CONN_UNKNOWN;
718 struct bt_scan_args_t {
720 sr_ser_list_append_t append;
725 static void scan_cb(void *cb_args, const char *addr, const char *name)
727 struct bt_scan_args_t *scan_args;
730 enum ser_bt_conn_t type;
731 char *port_name, *port_desc;
737 sr_info("BT scan, found: %s - %s\n", addr, name);
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)
745 /* Substitute colons in the address by dashes. */
748 snprintf(addr_text, sizeof(addr_text), "%s", addr);
749 g_strcanon(addr_text, "0123456789abcdefABCDEF", '-');
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);
757 scan_args->port_list = scan_args->append(scan_args->port_list, port_name, port_desc);
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);
766 static GSList *ser_bt_list(GSList *list, sr_ser_list_append_t append)
768 static const int scan_duration = 2;
770 struct bt_scan_args_t scan_args;
771 struct sr_bt_desc *desc;
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
780 desc = sr_bt_desc_new();
784 memset(&scan_args, 0, sizeof(scan_args));
785 scan_args.port_list = list;
786 scan_args.append = append;
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);
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);
800 sr_bt_desc_free(desc);
802 return scan_args.port_list;
805 static struct ser_lib_functions serlib_bt = {
807 .close = ser_bt_close,
808 .flush = ser_bt_flush,
809 .drain = ser_bt_drain,
810 .write = ser_bt_write,
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.
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,
822 .get_frame_format = NULL,
824 SR_PRIV struct ser_lib_functions *ser_lib_funcs_bt = &serlib_bt;
829 SR_PRIV int ser_name_is_bt(struct sr_serial_dev_inst *serial)
836 SR_PRIV struct ser_lib_functions *ser_lib_funcs_bt = NULL;