2 * This file is part of the sigrok 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/>.
21 * Scan support for Bluetooth LE devices is modelled after the MIT licensed
22 * https://github.com/carsonmcdonald/bluez-experiments experiments/scantest.c
23 * example source code which is:
25 * The MIT License (MIT)
27 * Copyright (c) 2013 Carson McDonald
29 * Permission is hereby granted, free of charge, to any person obtaining a copy of
30 * this software and associated documentation files (the "Software"), to deal in
31 * the Software without restriction, including without limitation the rights to
32 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
33 * the Software, and to permit persons to whom the Software is furnished to do so,
34 * subject to the following conditions:
36 * The above copyright notice and this permission notice shall be included in all
37 * copies or substantial portions of the Software.
39 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
41 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
42 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
43 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
44 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48 * This file implements an internal platform agnostic API of libsigrok
49 * for Bluetooth communication, as well as the first implementation on a
50 * specific platform which is based on the BlueZ library and got tested
54 * - Separate the "common" from the "bluez specific" parts. The current
55 * implementation uses the fact that HAVE_BLUETOOTH exclusively depends
56 * on HAVE_LIBBLUEZ, and thus both are identical.
57 * - Add missing features to the Linux platform support: Scan without
58 * root privileges, UUID to handle translation.
59 * - Add support for other platforms.
64 /* Unconditionally compile the source, optionally end up empty. */
68 #include <bluetooth/bluetooth.h>
69 #include <bluetooth/hci.h>
70 #include <bluetooth/hci_lib.h>
71 #include <bluetooth/l2cap.h>
72 #include <bluetooth/rfcomm.h>
82 #include <sys/socket.h>
86 #include <libsigrok/libsigrok.h>
87 #include "libsigrok-internal.h"
90 #define LOG_PREFIX "bt-bluez"
93 #define STORE_MAC_REVERSE 1
94 #define ACCEPT_NONSEP_MAC 1
96 /* Silence warning about (currently) unused routine. */
97 #define WITH_WRITE_TYPE_HANDLE 0
99 /* {{{ compat decls */
101 * The availability of conversion helpers in <bluetooth/bluetooth.h>
102 * appears to be version dependent. Let's provide the helper here if
103 * the header doesn't.
106 #if !defined HAVE_BT_PUT_LE16
107 static inline void bt_put_le16(uint16_t v, uint8_t *p)
109 p[0] = (v >> 0) & 0xff;
110 p[1] = (v >> 8) & 0xff;
114 /* }}} compat decls */
115 /* {{{ Linux socket specific decls */
117 #define BLE_ATT_ERROR_RESP 0x01
118 #define BLE_ATT_EXCHANGE_MTU_REQ 0x02
119 #define BLE_ATT_EXCHANGE_MTU_RESP 0x03
120 #define BLE_ATT_FIND_INFORMATION_REQ 0x04
121 #define BLE_ATT_FIND_INFORMATION_RESP 0x05
122 #define BLE_ATT_FIND_BY_TYPE_REQ 0x06
123 #define BLE_ATT_FIND_BY_TYPE_RESP 0x07
124 #define BLE_ATT_READ_BY_TYPE_REQ 0x08
125 #define BLE_ATT_READ_BY_TYPE_RESP 0x09
126 #define BLE_ATT_READ_REQ 0x0a
127 #define BLE_ATT_READ_RESP 0x0b
128 #define BLE_ATT_READ_BLOB_REQ 0x0c
129 #define BLE_ATT_READ_BLOB_RESP 0x0d
130 #define BLE_ATT_READ_MULTIPLE_REQ 0x0e
131 #define BLE_ATT_READ_MULTIPLE_RESP 0x0f
132 #define BLE_ATT_READ_BY_GROUP_REQ 0x10
133 #define BLE_ATT_READ_BY_GROUP_RESP 0x11
134 #define BLE_ATT_WRITE_REQ 0x12
135 #define BLE_ATT_WRITE_RESP 0x13
136 #define BLE_ATT_WRITE_CMD 0x16
137 #define BLE_ATT_HANDLE_NOTIFICATION 0x1b
138 #define BLE_ATT_HANDLE_INDICATION 0x1d
139 #define BLE_ATT_HANDLE_CONFIRMATION 0x1e
140 #define BLE_ATT_SIGNED_WRITE_CMD 0x52
142 /* }}} Linux socket specific decls */
146 * Convert textual MAC presentation to array of bytes. In contrast to
147 * BlueZ conversion, accept colon or dash separated input as well as a
148 * dense format without separators (001122334455). We expect to use the
149 * library in an environment where colons are not always available as a
150 * separator in user provided specs, while users do want to use some
151 * separator for readability.
153 * TODO Instead of doing the actual conversion here (and dealing with
154 * BlueZ' internal byte order for device address bytes), we might as
155 * well just transform the input string to an output string, and always
156 * use the officially provided str2ba() conversion routine.
158 static int sr_bt_mac_text_to_bytes(const char *text, uint8_t *buf)
166 if (STORE_MAC_REVERSE)
169 while (len && endp && *endp) {
171 if (ACCEPT_NONSEP_MAC) {
173 numbuf[1] = endp[0] ? endp[1] : '\0';
177 v = strtol(ACCEPT_NONSEP_MAC ? numbuf : text, &endp, 16);
180 if (*endp != ':' && *endp != '-' && *endp != '\0')
182 if (v < 0 || v > 255)
184 if (STORE_MAC_REVERSE)
189 if (ACCEPT_NONSEP_MAC)
190 endp = (char *)text + (endp - numbuf);
191 if (*endp == ':' || *endp == '-')
196 sr_err("Failed to parse MAC, too few bytes in '%s'", text);
199 while (isspace(*endp))
202 sr_err("Failed to parse MAC, excess data in '%s'", text);
212 SR_PRIV const char *sr_bt_adapter_get_address(size_t idx)
215 struct hci_dev_info info;
218 rc = hci_devinfo(idx, &info);
219 sr_dbg("DIAG: hci_devinfo(%zu) => rc %d", idx, rc);
223 rc = ba2str(&info.bdaddr, addr);
224 sr_dbg("DIAG: ba2str() => rc %d", rc);
228 return g_strdup(addr);
235 /* User servicable options. */
236 sr_bt_scan_cb scan_cb;
238 sr_bt_data_cb data_cb;
241 char remote_addr[20];
242 size_t rfcomm_channel;
243 uint16_t read_handle;
244 uint16_t write_handle;
245 uint16_t cccd_handle;
247 /* Internal state. */
250 struct hci_filter orig_filter;
253 static int sr_bt_desc_open(struct sr_bt_desc *desc, int *id_ref);
254 static void sr_bt_desc_close(struct sr_bt_desc *desc);
255 static int sr_bt_check_socket_usable(struct sr_bt_desc *desc);
256 static ssize_t sr_bt_write_type(struct sr_bt_desc *desc, uint8_t type);
257 #if WITH_WRITE_TYPE_HANDLE
258 static ssize_t sr_bt_write_type_handle(struct sr_bt_desc *desc,
259 uint8_t type, uint16_t handle);
261 static ssize_t sr_bt_write_type_handle_bytes(struct sr_bt_desc *desc,
262 uint8_t type, uint16_t handle, const uint8_t *data, size_t len);
263 static ssize_t sr_bt_char_write_req(struct sr_bt_desc *desc,
264 uint16_t handle, const void *data, size_t len);
266 SR_PRIV struct sr_bt_desc *sr_bt_desc_new(void)
268 struct sr_bt_desc *desc;
270 desc = g_malloc0(sizeof(*desc));
280 SR_PRIV void sr_bt_desc_free(struct sr_bt_desc *desc)
285 sr_bt_desc_close(desc);
289 SR_PRIV int sr_bt_config_cb_scan(struct sr_bt_desc *desc,
290 sr_bt_scan_cb cb, void *cb_data)
296 desc->scan_cb_data = cb_data;
301 SR_PRIV int sr_bt_config_cb_data(struct sr_bt_desc *desc,
302 sr_bt_data_cb cb, void *cb_data)
308 desc->data_cb_data = cb_data;
313 SR_PRIV int sr_bt_config_addr_local(struct sr_bt_desc *desc, const char *addr)
321 if (!addr || !addr[0]) {
322 desc->local_addr[0] = '\0';
326 rc = sr_bt_mac_text_to_bytes(addr, &mac_bytes.b[0]);
330 rc = ba2str(&mac_bytes, desc->local_addr);
337 SR_PRIV int sr_bt_config_addr_remote(struct sr_bt_desc *desc, const char *addr)
345 if (!addr || !addr[0]) {
346 desc->remote_addr[0] = '\0';
350 rc = sr_bt_mac_text_to_bytes(addr, &mac_bytes.b[0]);
354 rc = ba2str(&mac_bytes, desc->remote_addr);
361 SR_PRIV int sr_bt_config_rfcomm(struct sr_bt_desc *desc, size_t channel)
366 desc->rfcomm_channel = channel;
371 SR_PRIV int sr_bt_config_notify(struct sr_bt_desc *desc,
372 uint16_t read_handle, uint16_t write_handle,
373 uint16_t cccd_handle, uint16_t cccd_value)
379 desc->read_handle = read_handle;
380 desc->write_handle = write_handle;
381 desc->cccd_handle = cccd_handle;
382 desc->cccd_value = cccd_value;
387 static int sr_bt_desc_open(struct sr_bt_desc *desc, int *id_ref)
396 sr_spew("get devid");
397 if (desc->local_addr[0]) {
398 id = hci_devid(desc->local_addr);
399 } else if (desc->remote_addr[0]) {
400 str2ba(desc->remote_addr, &mac);
401 id = hci_get_route(&mac);
403 id = hci_get_route(NULL);
406 sr_spew("devid failed");
413 sr_spew("open HCI socket");
414 sock = hci_open_dev(id);
416 perror("open HCI socket");
424 static void sr_bt_desc_close(struct sr_bt_desc *desc)
431 hci_close_dev(desc->fd);
440 #define EIR_NAME_COMPLETE 9
442 static int sr_bt_scan_prep(struct sr_bt_desc *desc)
445 uint8_t type, owntype, filter;
446 uint16_t ival, window;
450 struct hci_filter scan_filter;
454 sr_dbg("BLE scan prep");
456 /* TODO Replace magic values with symbolic identifiers. */
457 sr_spew("set LE scan params");
458 type = 0x01; /* LE public? */
459 ival = htobs(0x0010);
460 window = htobs(0x0010);
461 owntype = 0x00; /* any? */
464 rc = hci_le_set_scan_parameters(desc->fd,
465 type, ival, window, owntype, filter, timeout);
467 perror("set LE scan params");
471 sr_spew("set LE scan enable");
475 rc = hci_le_set_scan_enable(desc->fd, enable, dup, timeout);
477 perror("set LE scan enable");
481 /* Save the current filter. For later restoration. */
482 sr_spew("get HCI filter");
483 slen = sizeof(desc->orig_filter);
484 rc = getsockopt(desc->fd, SOL_HCI, HCI_FILTER,
485 &desc->orig_filter, &slen);
487 perror("getsockopt(HCI_FILTER)");
491 sr_spew("set HCI filter");
492 hci_filter_clear(&scan_filter);
493 hci_filter_set_ptype(HCI_EVENT_PKT, &scan_filter);
494 hci_filter_set_event(EVT_LE_META_EVENT, &scan_filter);
495 rc = setsockopt(desc->fd, SOL_HCI, HCI_FILTER,
496 &scan_filter, sizeof(scan_filter));
498 perror("setsockopt(HCI_FILTER)");
505 static int sr_bt_scan_post(struct sr_bt_desc *desc)
513 sr_dbg("BLE scan post");
515 /* Restore previous HCI filter. */
516 sr_spew("set HCI filter");
517 rc = setsockopt(desc->fd, SOL_HCI, HCI_FILTER,
518 &desc->orig_filter, sizeof(desc->orig_filter));
520 perror("setsockopt(HCI_FILTER)");
524 sr_spew("set LE scan enable");
528 rc = hci_le_set_scan_enable(desc->fd, enable, dup, timeout);
535 static int sr_bt_scan_proc(struct sr_bt_desc *desc,
536 sr_bt_scan_cb scan_cb, void *cb_data,
537 uint8_t *data, size_t dlen, le_advertising_info *info)
546 if (type == EIR_NAME_COMPLETE) {
547 ba2str(&info->bdaddr, addr);
548 name = g_strndup((const char *)&data[1], dlen - 1);
550 scan_cb(cb_data, addr, name);
555 /* Unknown or unsupported type, ignore silently. */
559 SR_PRIV int sr_bt_scan_le(struct sr_bt_desc *desc, int duration)
563 uint8_t buf[HCI_MAX_EVENT_SIZE];
564 ssize_t rdlen, rdpos;
565 evt_le_meta_event *meta;
566 le_advertising_info *info;
572 sr_dbg("BLE scan (LE)");
574 sr_spew("desc open");
575 rc = sr_bt_desc_open(desc, NULL);
579 sr_spew("scan prep");
580 rc = sr_bt_scan_prep(desc);
584 sr_spew("scan loop");
585 deadline = time(NULL);
586 deadline += duration;
587 while (time(NULL) <= deadline) {
589 if (sr_bt_check_socket_usable(desc) < 0)
591 rdlen = sr_bt_read(desc, buf, sizeof(buf));
595 sr_spew("usleep() start");
597 sr_spew("usleep() done");
600 if (rdlen < 1 + HCI_EVENT_HDR_SIZE)
602 meta = (void *)&buf[1 + HCI_EVENT_HDR_SIZE];
603 rdlen -= 1 + HCI_EVENT_HDR_SIZE;
604 if (meta->subevent != EVT_LE_ADVERTISING_REPORT)
606 info = (void *)&meta->data[1];
607 sr_spew("evt: type %d, len %d", info->evt_type, info->length);
612 while (rdpos < rdlen) {
613 datalen = info->data[rdpos];
614 dataptr = &info->data[1 + rdpos];
615 if (rdpos + 1 + datalen > info->length)
617 rdpos += 1 + datalen;
618 rc = sr_bt_scan_proc(desc,
619 desc->scan_cb, desc->scan_cb_data,
620 dataptr, datalen, info);
626 sr_spew("scan post");
627 rc = sr_bt_scan_post(desc);
631 sr_bt_desc_close(desc);
636 SR_PRIV int sr_bt_scan_bt(struct sr_bt_desc *desc, int duration)
638 int dev_id, sock, rsp_max;
642 size_t rsp_count, idx;
648 sr_dbg("BLE scan (BT)");
650 sock = sr_bt_desc_open(desc, &dev_id);
655 info = g_malloc0(rsp_max * sizeof(*info));
656 flags = 0 /* | IREQ_CACHE_FLUSH */;
657 inq_rc = hci_inquiry(dev_id, duration, rsp_max, NULL, &info, flags);
659 perror("hci_inquiry");
662 for (idx = 0; idx < rsp_count; idx++) {
663 memset(addr, 0, sizeof(addr));
664 ba2str(&info[idx].bdaddr, addr);
665 memset(name, 0, sizeof(name));
666 if (hci_read_remote_name(sock, &info[idx].bdaddr, sizeof(name), name, 0) < 0)
667 snprintf(name, sizeof(name), "[unknown]");
669 desc->scan_cb(desc->scan_cb_data, addr, name);
673 sr_bt_desc_close(desc);
679 /* {{{ connect/disconnect */
681 SR_PRIV int sr_bt_connect_ble(struct sr_bt_desc *desc)
683 struct sockaddr_l2 sl2;
689 if (!desc->remote_addr[0])
691 sr_dbg("BLE connect, remote addr %s", desc->remote_addr);
694 s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, 0);
696 perror("socket create");
702 memset(&sl2, 0, sizeof(sl2));
703 sl2.l2_family = AF_BLUETOOTH;
705 if (desc->local_addr[0])
706 str2ba(desc->local_addr, &mac);
709 memcpy(&sl2.l2_bdaddr, &mac, sizeof(sl2.l2_bdaddr));
710 sl2.l2_cid = L2CAP_FC_CONNLESS;
711 sl2.l2_bdaddr_type = BDADDR_LE_PUBLIC;
712 ret = bind(s, (void *)&sl2, sizeof(sl2));
719 struct bt_security buf = {
720 .level = BT_SECURITY_LOW,
724 ret = setsockopt(s, SOL_BLUETOOTH, BT_SECURITY, &buf, sizeof(buf));
726 perror("setsockopt");
731 sr_spew("connect()");
732 str2ba(desc->remote_addr, &mac);
733 memcpy(&sl2.l2_bdaddr, &mac, sizeof(sl2.l2_bdaddr));
734 sl2.l2_bdaddr_type = BDADDR_LE_PUBLIC;
735 ret = connect(s, (void *)&sl2, sizeof(sl2));
737 * Cope with "in progress" condition. Keep polling the status
738 * until connect() completes, then get the error by means of
739 * getsockopt(). See the connect(2) manpage for details.
741 if (ret < 0 && errno == EINPROGRESS) {
742 struct pollfd fds[1];
747 * We seem to get here ("connect in progress") even when
748 * the specified peer is not around at all. Which results
749 * in extended periods of time where nothing happens, and
750 * an application timeout seems to be required.
752 sr_spew("in progress ...");
755 sr_spew("poll(OUT)");
756 memset(fds, 0, sizeof(fds));
758 fds[0].events = POLLOUT;
759 ret = poll(fds, ARRAY_SIZE(fds), -1);
766 if (!(fds[0].revents & POLLOUT))
769 sr_spew("poll(INVAL)");
770 memset(fds, 0, sizeof(fds));
772 fds[0].events = POLLNVAL;
773 ret = poll(fds, 1, 0);
775 perror("poll(INVAL)");
779 /* socket fd is invalid(?) */
784 sr_spew("getsocktop(SO_ERROR)");
785 solen = sizeof(soerror);
786 ret = getsockopt(s, SOL_SOCKET, SO_ERROR, &soerror, &solen);
788 perror("getsockopt(SO_ERROR)");
792 /* connect(2) failed, SO_ERROR has the error code. */
794 perror("connect(PROGRESS)");
799 * TODO Get the receive MTU here?
800 * getsockopt(SOL_BLUETOOTH, BT_RCVMTU, u16);
803 sr_spew("connect() => rc %d, fd %d", ret, desc->fd);
812 SR_PRIV int sr_bt_connect_rfcomm(struct sr_bt_desc *desc)
814 struct sockaddr_rc addr;
819 if (!desc->remote_addr[0])
821 sr_dbg("RFCOMM connect, remote addr %s, channel %zu",
822 desc->remote_addr, desc->rfcomm_channel);
824 if (!desc->rfcomm_channel)
825 desc->rfcomm_channel = 1;
828 fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
835 sr_spew("connect()");
836 memset(&addr, 0, sizeof(addr));
837 addr.rc_family = AF_BLUETOOTH;
838 str2ba(desc->remote_addr, &addr.rc_bdaddr);
839 addr.rc_channel = desc->rfcomm_channel;
840 rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
845 sr_spew("connected");
850 SR_PRIV void sr_bt_disconnect(struct sr_bt_desc *desc)
852 sr_dbg("BLE disconnect");
856 sr_bt_desc_close(desc);
859 static int sr_bt_check_socket_usable(struct sr_bt_desc *desc)
861 struct pollfd fds[1];
864 sr_spew("socket usability check");
870 memset(fds, 0, sizeof(fds));
871 fds[0].fd = desc->fd;
872 fds[0].events = POLLERR | POLLHUP;
873 ret = poll(fds, ARRAY_SIZE(fds), 0);
878 if (fds[0].revents & POLLHUP)
880 if (fds[0].revents & POLLERR)
882 if (fds[0].revents & POLLNVAL)
888 /* }}} connect/disconnect */
889 /* {{{ indication/notification */
891 SR_PRIV int sr_bt_start_notify(struct sr_bt_desc *desc)
893 uint8_t buf[sizeof(desc->cccd_value)];
898 sr_dbg("BLE start notify");
900 if (sr_bt_check_socket_usable(desc) < 0)
904 bt_put_le16(desc->cccd_value, buf);
905 wrlen = sr_bt_char_write_req(desc, desc->cccd_handle, buf, sizeof(buf));
906 if (wrlen != sizeof(buf))
912 SR_PRIV int sr_bt_check_notify(struct sr_bt_desc *desc)
917 uint16_t packet_handle;
918 uint8_t *packet_data;
921 sr_dbg("BLE check notify");
925 if (sr_bt_check_socket_usable(desc) < 0)
928 /* Get another message from the Bluetooth socket. */
929 sr_spew("read() non-blocking");
930 rdlen = sr_bt_read(desc, buf, sizeof(buf));
931 sr_spew("read() => %zd", rdlen);
936 sr_spew("read() len %zd, type 0x%02x", rdlen, buf[0]);
938 /* Get header fields and references to the payload data. */
940 packet_handle = 0x0000;
944 packet_type = buf[0];
946 packet_handle = bt_get_le16(&buf[1]);
947 packet_data = &buf[3];
948 packet_dlen = rdlen - 3;
951 /* Dispatch according to the message type. */
952 switch (packet_type) {
953 case BLE_ATT_ERROR_RESP:
954 sr_spew("error response");
957 case BLE_ATT_WRITE_RESP:
958 sr_spew("write response");
961 case BLE_ATT_HANDLE_INDICATION:
962 sr_spew("handle indication");
963 sr_bt_write_type(desc, BLE_ATT_HANDLE_CONFIRMATION);
964 if (packet_handle != desc->read_handle)
970 return desc->data_cb(desc->data_cb_data, packet_data, packet_dlen);
971 case BLE_ATT_HANDLE_NOTIFICATION:
972 sr_spew("handle notification");
973 if (packet_handle != desc->read_handle)
979 return desc->data_cb(desc->data_cb_data, packet_data, packet_dlen);
981 sr_spew("unsupported type 0x%02x", packet_type);
988 /* }}} indication/notification */
991 SR_PRIV ssize_t sr_bt_write(struct sr_bt_desc *desc,
992 const void *data, size_t len)
994 sr_dbg("BLE write (raw)");
1000 if (sr_bt_check_socket_usable(desc) < 0)
1003 /* Send TX data to the writable characteristics for BLE UART services. */
1004 if (desc->write_handle)
1005 return sr_bt_char_write_req(desc, desc->write_handle, data, len);
1007 /* Send raw TX data to the RFCOMM socket for BT Classic channels. */
1008 return write(desc->fd, data, len);
1011 static ssize_t sr_bt_write_type(struct sr_bt_desc *desc, uint8_t type)
1015 sr_dbg("BLE write (type)");
1021 if (sr_bt_check_socket_usable(desc) < 0)
1024 wrlen = write(desc->fd, &type, sizeof(type));
1027 if (wrlen < (ssize_t)sizeof(type))
1033 #if WITH_WRITE_TYPE_HANDLE
1034 static ssize_t sr_bt_write_type_handle(struct sr_bt_desc *desc,
1035 uint8_t type, uint16_t handle)
1037 sr_dbg("BLE write (type, handle)");
1038 return sr_bt_write_type_handle_bytes(desc, type, handle, NULL, 0);
1042 static ssize_t sr_bt_write_type_handle_bytes(struct sr_bt_desc *desc,
1043 uint8_t type, uint16_t handle, const uint8_t *data, size_t len)
1045 uint8_t header[sizeof(uint8_t) + sizeof(uint16_t)];
1046 struct iovec iov[2] = {
1047 { .iov_base = header, .iov_len = sizeof(header), },
1048 { .iov_base = (void *)data, .iov_len = len, },
1052 sr_dbg("BLE write (type, handle, data)");
1058 if (sr_bt_check_socket_usable(desc) < 0)
1062 bt_put_le16(handle, &header[1]);
1065 wrlen = writev(desc->fd, iov, ARRAY_SIZE(iov));
1067 wrlen = write(desc->fd, header, sizeof(header));
1071 if (wrlen < (ssize_t)sizeof(header))
1073 wrlen -= sizeof(header);
1078 /* Returns negative upon error, or returns the number of _payload_ bytes written. */
1079 static ssize_t sr_bt_char_write_req(struct sr_bt_desc *desc,
1080 uint16_t handle, const void *data, size_t len)
1082 sr_dbg("BLE write-char req");
1084 return sr_bt_write_type_handle_bytes(desc, BLE_ATT_WRITE_REQ,
1088 SR_PRIV ssize_t sr_bt_read(struct sr_bt_desc *desc, void *data, size_t len)
1090 struct pollfd fds[1];
1094 sr_dbg("BLE read (non-blocking)");
1100 if (sr_bt_check_socket_usable(desc) < 0)
1103 sr_spew("poll(POLLIN)");
1104 memset(fds, 0, sizeof(fds));
1105 fds[0].fd = desc->fd;
1106 fds[0].events = POLLIN;
1107 ret = poll(fds, ARRAY_SIZE(fds), 0);
1108 sr_spew("poll(%d, POLLIN) => 0x%x", desc->fd, fds[0].revents);
1113 if (!(fds[0].revents & POLLIN))
1117 rdlen = read(desc->fd, data, len);
1118 sr_spew("read() => %zd", rdlen);
1123 /* }}} indication/notification */