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