X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=blobdiff_plain;f=src%2Fserial_bt.c;h=a9041ce874cda66f47c4baf90b436bd9aab79697;hp=9d7cfb2b2699fbedbddd8348ff6fa0a1a13f8eba;hb=c622c88c446a2f5e1c045657ef233c147a1f43d4;hpb=3ad30b4e19211eda2f4e00f78c76feeea3323b49 diff --git a/src/serial_bt.c b/src/serial_bt.c index 9d7cfb2b..a9041ce8 100644 --- a/src/serial_bt.c +++ b/src/serial_bt.c @@ -32,6 +32,12 @@ #define SER_BT_CONN_PREFIX "bt" #define SER_BT_CHUNK_SIZE 1200 +#define SER_BT_PARAM_PREFIX_CHANNEL "channel=" +#define SER_BT_PARAM_PREFIX_HDL_RX "handle_rx=" +#define SER_BT_PARAM_PREFIX_HDL_TX "handle_tx=" +#define SER_BT_PARAM_PREFIX_HDL_CCCD "handle_cccd=" +#define SER_BT_PARAM_PREFIX_VAL_CCCD "value_cccd=" + /** * @file * @@ -51,12 +57,14 @@ static const struct scan_supported_item { const char *name; enum ser_bt_conn_t type; + const char *add_params; } scan_supported_items[] = { /* Guess connection types from device names (useful for scans). */ - { "121GW", SER_BT_CONN_BLE122, }, - { "Adafruit Bluefruit LE 8134", SER_BT_CONN_NRF51, }, - { "HC-05", SER_BT_CONN_RFCOMM, }, - { NULL, SER_BT_CONN_UNKNOWN, }, + { "121GW", SER_BT_CONN_BLE122, NULL, }, + { "Adafruit Bluefruit LE 8134", SER_BT_CONN_NRF51, NULL, }, + { "HC-05", SER_BT_CONN_RFCOMM, NULL, }, + { "UM25C", SER_BT_CONN_RFCOMM, NULL, }, + { NULL, SER_BT_CONN_UNKNOWN, NULL, }, }; static const char *ser_bt_conn_names[SER_BT_CONN_MAX] = { @@ -119,14 +127,16 @@ static const char *conn_name_text(enum ser_bt_conn_t type) * - The next field is the remote device's address, either separated * by colons or dashes or spaces, or not separated at all. * - Other parameters (RFCOMM channel, notify handles and write values) - * get derived from the connection type. A future implementation may - * accept more fields, but the syntax is yet to get developed. + * get derived from the connection type. + * - More fields after the remote address are options which override + * builtin defaults (RFCOMM channels, BLE handles, etc). * * Supported formats resulting from these rules: - * bt// + * bt//[/]... * * Examples: * bt/rfcomm/11-22-33-44-55-66 + * bt/rfcomm/11-22-33-44-55-66/channel=2 * bt/ble122/88:6b:12:34:56:78 * bt/cc254x/0123456789ab * @@ -142,9 +152,13 @@ static int ser_bt_parse_conn_spec( uint16_t *read_hdl, uint16_t *write_hdl, uint16_t *cccd_hdl, uint16_t *cccd_val) { + char **fields, *field; enum ser_bt_conn_t type; const char *addr; - char **fields, *field; + int ret_parse, ret; + size_t fields_count, field_idx; + char *endp; + unsigned long parm_val; if (conn_type) *conn_type = SER_BT_CONN_UNKNOWN; @@ -161,9 +175,6 @@ static int ser_bt_parse_conn_spec( if (cccd_val) *cccd_val = 0; - type = SER_BT_CONN_UNKNOWN; - addr = NULL; - if (!serial || !spec || !spec[0]) return SR_ERR_ARG; @@ -244,10 +255,83 @@ static int ser_bt_parse_conn_spec( return SR_ERR_ARG; } - /* TODO Evaluate optionally trailing fields, override defaults? */ + /* + * Preset a successful return value for the conn= parse call. + * Scan optional additional fields which specify more params. + * Update the defaults which were setup above. Pessimize the + * routine's return value in error paths. + */ + ret_parse = SR_OK; + fields_count = g_strv_length(fields); + for (field_idx = 3; field_idx < fields_count; field_idx++) { + field = fields[field_idx]; + if (!field || !*field) + continue; + if (g_str_has_prefix(field, SER_BT_PARAM_PREFIX_CHANNEL)) { + field += strlen(SER_BT_PARAM_PREFIX_CHANNEL); + endp = NULL; + ret = sr_atoul_base(field, &parm_val, &endp, 0); + if (ret != SR_OK || !endp || *endp != '\0') { + ret_parse = SR_ERR_ARG; + break; + } + if (rfcomm_channel) + *rfcomm_channel = parm_val; + continue; + } + if (g_str_has_prefix(field, SER_BT_PARAM_PREFIX_HDL_RX)) { + field += strlen(SER_BT_PARAM_PREFIX_HDL_RX); + endp = NULL; + ret = sr_atoul_base(field, &parm_val, &endp, 0); + if (ret != SR_OK || !endp || *endp != '\0') { + ret_parse = SR_ERR_ARG; + break; + } + if (read_hdl) + *read_hdl = parm_val; + continue; + } + if (g_str_has_prefix(field, SER_BT_PARAM_PREFIX_HDL_TX)) { + field += strlen(SER_BT_PARAM_PREFIX_HDL_TX); + endp = NULL; + ret = sr_atoul_base(field, &parm_val, &endp, 0); + if (ret != SR_OK || !endp || *endp != '\0') { + ret_parse = SR_ERR_ARG; + break; + } + if (write_hdl) + *write_hdl = parm_val; + continue; + } + if (g_str_has_prefix(field, SER_BT_PARAM_PREFIX_HDL_CCCD)) { + field += strlen(SER_BT_PARAM_PREFIX_HDL_CCCD); + endp = NULL; + ret = sr_atoul_base(field, &parm_val, &endp, 0); + if (ret != SR_OK || !endp || *endp != '\0') { + ret_parse = SR_ERR_ARG; + break; + } + if (cccd_hdl) + *cccd_hdl = parm_val; + continue; + } + if (g_str_has_prefix(field, SER_BT_PARAM_PREFIX_VAL_CCCD)) { + field += strlen(SER_BT_PARAM_PREFIX_VAL_CCCD); + endp = NULL; + ret = sr_atoul_base(field, &parm_val, &endp, 0); + if (ret != SR_OK || !endp || *endp != '\0') { + ret_parse = SR_ERR_ARG; + break; + } + if (cccd_val) + *cccd_val = parm_val; + continue; + } + return SR_ERR_DATA; + } g_strfreev(fields); - return SR_OK; + return ret_parse; } static void ser_bt_mask_databits(struct sr_serial_dev_inst *serial, @@ -498,7 +582,6 @@ static int ser_bt_read(struct sr_serial_dev_inst *serial, * where to stop reception. */ deadline_us = 0; - now_us = 0; /* Silence a (false) compiler warning. */ if (timeout_ms) { now_us = g_get_monotonic_time(); deadline_us = now_us + timeout_ms * 1000; @@ -698,7 +781,7 @@ static int ser_bt_setup_source_remove(struct sr_session *session, return SR_OK; } -static enum ser_bt_conn_t scan_is_supported(const char *name) +static const struct scan_supported_item *scan_is_supported(const char *name) { size_t idx; const struct scan_supported_item *item; @@ -709,10 +792,10 @@ static enum ser_bt_conn_t scan_is_supported(const char *name) break; if (strcmp(name, item->name) != 0) continue; - return item->type; + return item; } - return SER_BT_CONN_UNKNOWN; + return NULL; } struct bt_scan_args_t { @@ -727,6 +810,7 @@ static void scan_cb(void *cb_args, const char *addr, const char *name) struct bt_scan_args_t *scan_args; GSList *l; char addr_text[20]; + const struct scan_supported_item *item; enum ser_bt_conn_t type; char *port_name, *port_desc; char *addr_copy; @@ -749,9 +833,11 @@ static void scan_cb(void *cb_args, const char *addr, const char *name) g_strcanon(addr_text, "0123456789abcdefABCDEF", '-'); /* Create a port name, and a description. */ - type = scan_is_supported(name); - port_name = g_strdup_printf("%s/%s/%s", - SER_BT_CONN_PREFIX, conn_name_text(type), addr_text); + item = scan_is_supported(name); + type = item ? item->type : SER_BT_CONN_UNKNOWN; + port_name = g_strdup_printf("%s/%s/%s%s", + SER_BT_CONN_PREFIX, conn_name_text(type), addr_text, + (item && item->add_params) ? item->add_params : ""); port_desc = g_strdup_printf("%s (%s)", name, scan_args->bt_type); scan_args->port_list = scan_args->append(scan_args->port_list, port_name, port_desc); @@ -765,7 +851,7 @@ static void scan_cb(void *cb_args, const char *addr, const char *name) static GSList *ser_bt_list(GSList *list, sr_ser_list_append_t append) { - static const int scan_duration = 2; + static const int scan_duration = 3; struct bt_scan_args_t scan_args; struct sr_bt_desc *desc;