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