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