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