| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include <errno.h> |
| #include <string.h> |
| #include "bsp/bsp.h" |
| #include "console/console.h" |
| #include "shell/shell.h" |
| |
| #include "nimble/ble.h" |
| #include "nimble/nimble_opt.h" |
| #include "nimble/hci_common.h" |
| #include "host/ble_gap.h" |
| #include "host/ble_hs_adv.h" |
| #include "host/ble_sm.h" |
| #include "host/ble_eddystone.h" |
| #include "host/ble_hs_id.h" |
| #include "services/gatt/ble_svc_gatt.h" |
| #include "../src/ble_l2cap_priv.h" |
| #include "../src/ble_hs_priv.h" |
| |
| #include "bletiny.h" |
| |
| #define CMD_BUF_SZ 256 |
| |
| static int cmd_b_exec(int argc, char **argv); |
| static struct shell_cmd cmd_b = { |
| .sc_cmd = "b", |
| .sc_cmd_func = cmd_b_exec |
| }; |
| |
| static bssnz_t uint8_t cmd_buf[CMD_BUF_SZ]; |
| |
| static struct kv_pair cmd_own_addr_types[] = { |
| { "public", BLE_OWN_ADDR_PUBLIC }, |
| { "random", BLE_OWN_ADDR_RANDOM }, |
| { "rpa_pub", BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT }, |
| { "rpa_rnd", BLE_OWN_ADDR_RPA_RANDOM_DEFAULT }, |
| { NULL } |
| }; |
| |
| static struct kv_pair cmd_peer_addr_types[] = { |
| { "public", BLE_ADDR_PUBLIC }, |
| { "random", BLE_ADDR_RANDOM }, |
| { "public_id", BLE_ADDR_PUBLIC_ID }, |
| { "random_id", BLE_ADDR_RANDOM_ID }, |
| { NULL } |
| }; |
| |
| static struct kv_pair cmd_addr_type[] = { |
| { "public", BLE_ADDR_PUBLIC }, |
| { "random", BLE_ADDR_RANDOM }, |
| { NULL } |
| }; |
| |
| /***************************************************************************** |
| * $misc * |
| *****************************************************************************/ |
| |
| static int |
| cmd_exec(const struct cmd_entry *cmds, int argc, char **argv) |
| { |
| const struct cmd_entry *cmd; |
| int rc; |
| |
| if (argc <= 1) { |
| return parse_err_too_few_args(argv[0]); |
| } |
| |
| cmd = parse_cmd_find(cmds, argv[1]); |
| if (cmd == NULL) { |
| console_printf("Error: unknown %s command: %s\n", argv[0], argv[1]); |
| return -1; |
| } |
| |
| rc = cmd->cb(argc - 1, argv + 1); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static void |
| cmd_print_dsc(struct bletiny_dsc *dsc) |
| { |
| console_printf(" dsc_handle=%d uuid=", dsc->dsc.handle); |
| print_uuid(&dsc->dsc.uuid.u); |
| console_printf("\n"); |
| } |
| |
| static void |
| cmd_print_chr(struct bletiny_chr *chr) |
| { |
| struct bletiny_dsc *dsc; |
| |
| console_printf(" def_handle=%d val_handle=%d properties=0x%02x " |
| "uuid=", chr->chr.def_handle, chr->chr.val_handle, |
| chr->chr.properties); |
| print_uuid(&chr->chr.uuid.u); |
| console_printf("\n"); |
| |
| SLIST_FOREACH(dsc, &chr->dscs, next) { |
| cmd_print_dsc(dsc); |
| } |
| } |
| |
| static void |
| cmd_print_svc(struct bletiny_svc *svc) |
| { |
| struct bletiny_chr *chr; |
| |
| console_printf(" start=%d end=%d uuid=", svc->svc.start_handle, |
| svc->svc.end_handle); |
| print_uuid(&svc->svc.uuid.u); |
| console_printf("\n"); |
| |
| SLIST_FOREACH(chr, &svc->chrs, next) { |
| cmd_print_chr(chr); |
| } |
| } |
| |
| static int |
| cmd_parse_conn_start_end(uint16_t *out_conn, uint16_t *out_start, |
| uint16_t *out_end) |
| { |
| int rc; |
| |
| *out_conn = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| *out_start = parse_arg_uint16("start", &rc); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| *out_end = parse_arg_uint16("end", &rc); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| cmd_parse_eddystone_url(char *full_url, uint8_t *out_scheme, char *out_body, |
| uint8_t *out_body_len, uint8_t *out_suffix) |
| { |
| static const struct { |
| char *s; |
| uint8_t scheme; |
| } schemes[] = { |
| { "http://www.", BLE_EDDYSTONE_URL_SCHEME_HTTP_WWW }, |
| { "https://www.", BLE_EDDYSTONE_URL_SCHEME_HTTPS_WWW }, |
| { "http://", BLE_EDDYSTONE_URL_SCHEME_HTTP }, |
| { "https://", BLE_EDDYSTONE_URL_SCHEME_HTTPS }, |
| }; |
| |
| static const struct { |
| char *s; |
| uint8_t code; |
| } suffixes[] = { |
| { ".com/", BLE_EDDYSTONE_URL_SUFFIX_COM_SLASH }, |
| { ".org/", BLE_EDDYSTONE_URL_SUFFIX_ORG_SLASH }, |
| { ".edu/", BLE_EDDYSTONE_URL_SUFFIX_EDU_SLASH }, |
| { ".net/", BLE_EDDYSTONE_URL_SUFFIX_NET_SLASH }, |
| { ".info/", BLE_EDDYSTONE_URL_SUFFIX_INFO_SLASH }, |
| { ".biz/", BLE_EDDYSTONE_URL_SUFFIX_BIZ_SLASH }, |
| { ".gov/", BLE_EDDYSTONE_URL_SUFFIX_GOV_SLASH }, |
| { ".com", BLE_EDDYSTONE_URL_SUFFIX_COM }, |
| { ".org", BLE_EDDYSTONE_URL_SUFFIX_ORG }, |
| { ".edu", BLE_EDDYSTONE_URL_SUFFIX_EDU }, |
| { ".net", BLE_EDDYSTONE_URL_SUFFIX_NET }, |
| { ".info", BLE_EDDYSTONE_URL_SUFFIX_INFO }, |
| { ".biz", BLE_EDDYSTONE_URL_SUFFIX_BIZ }, |
| { ".gov", BLE_EDDYSTONE_URL_SUFFIX_GOV }, |
| }; |
| |
| char *prefix; |
| char *suffix; |
| int full_url_len; |
| int prefix_len; |
| int suffix_len; |
| int suffix_idx; |
| int rc; |
| int i; |
| |
| full_url_len = strlen(full_url); |
| |
| rc = BLE_HS_EINVAL; |
| for (i = 0; i < sizeof schemes / sizeof schemes[0]; i++) { |
| prefix = schemes[i].s; |
| prefix_len = strlen(schemes[i].s); |
| |
| if (full_url_len >= prefix_len && |
| memcmp(full_url, prefix, prefix_len) == 0) { |
| |
| *out_scheme = i; |
| rc = 0; |
| break; |
| } |
| } |
| if (rc != 0) { |
| return rc; |
| } |
| |
| rc = BLE_HS_EINVAL; |
| for (i = 0; i < sizeof suffixes / sizeof suffixes[0]; i++) { |
| suffix = suffixes[i].s; |
| suffix_len = strlen(suffixes[i].s); |
| |
| suffix_idx = full_url_len - suffix_len; |
| if (suffix_idx >= prefix_len && |
| memcmp(full_url + suffix_idx, suffix, suffix_len) == 0) { |
| |
| *out_suffix = i; |
| rc = 0; |
| break; |
| } |
| } |
| if (rc != 0) { |
| *out_suffix = BLE_EDDYSTONE_URL_SUFFIX_NONE; |
| *out_body_len = full_url_len - prefix_len; |
| } else { |
| *out_body_len = full_url_len - prefix_len - suffix_len; |
| } |
| |
| memcpy(out_body, full_url + prefix_len, *out_body_len); |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $advertise * |
| *****************************************************************************/ |
| |
| static struct kv_pair cmd_adv_conn_modes[] = { |
| { "non", BLE_GAP_CONN_MODE_NON }, |
| { "und", BLE_GAP_CONN_MODE_UND }, |
| { "dir", BLE_GAP_CONN_MODE_DIR }, |
| { NULL } |
| }; |
| |
| static struct kv_pair cmd_adv_disc_modes[] = { |
| { "non", BLE_GAP_DISC_MODE_NON }, |
| { "ltd", BLE_GAP_DISC_MODE_LTD }, |
| { "gen", BLE_GAP_DISC_MODE_GEN }, |
| { NULL } |
| }; |
| |
| static struct kv_pair cmd_adv_filt_types[] = { |
| { "none", BLE_HCI_ADV_FILT_NONE }, |
| { "scan", BLE_HCI_ADV_FILT_SCAN }, |
| { "conn", BLE_HCI_ADV_FILT_CONN }, |
| { "both", BLE_HCI_ADV_FILT_BOTH }, |
| { NULL } |
| }; |
| |
| static void |
| print_enumerate_options(struct kv_pair *options) |
| { |
| int i; |
| for (i = 0; options[i].key != NULL; i++) { |
| if (i != 0) { |
| console_printf("|"); |
| } |
| console_printf("%s(%d)", options[i].key, options[i].val); |
| } |
| } |
| |
| static void |
| help_cmd_long_bounds(const char *cmd_name, long min, long max) |
| { |
| console_printf("\t%s=<%ld-%ld>\n", cmd_name, min, max); |
| } |
| |
| static void |
| help_cmd_long_bounds_dflt(const char *cmd_name, long min, long max, long dflt) |
| { |
| console_printf("\t%s=[%ld-%ld] default=%ld\n", cmd_name, min, max, dflt); |
| } |
| |
| static void |
| help_cmd_val(const char *cmd_name) |
| { |
| console_printf("\t%s=<val>\n", cmd_name); |
| } |
| |
| static void |
| help_cmd_long(const char *cmd_name) |
| { |
| help_cmd_val(cmd_name); |
| } |
| |
| static void |
| help_cmd_bool(const char *cmd_name) |
| { |
| console_printf("\t%s=<0|1>\n", cmd_name); |
| } |
| |
| static void |
| help_cmd_bool_dflt(const char *cmd_name, bool dflt) |
| { |
| console_printf("\t%s=[0|1] default=%d\n", cmd_name, dflt); |
| } |
| |
| static void |
| help_cmd_uint8(const char *cmd_name) |
| { |
| help_cmd_val(cmd_name); |
| } |
| |
| static void |
| help_cmd_uint8_dflt(const char *cmd_name, uint8_t dflt) |
| { |
| console_printf("\t%s=[val] default=%u\n", cmd_name, dflt); |
| } |
| |
| static void |
| help_cmd_uint16(const char *cmd_name) |
| { |
| help_cmd_val(cmd_name); |
| } |
| |
| static void |
| help_cmd_uint16_dflt(const char *cmd_name, uint16_t dflt) |
| { |
| console_printf("\t%s=[val] default=%u\n", cmd_name, dflt); |
| } |
| |
| static void |
| help_cmd_uint32(const char *cmd_name) |
| { |
| help_cmd_val(cmd_name); |
| } |
| |
| static void |
| help_cmd_uint64(const char *cmd_name) |
| { |
| help_cmd_val(cmd_name); |
| } |
| |
| static void |
| help_cmd_kv(const char *cmd_name, struct kv_pair *options) |
| { |
| console_printf("\t%s=<", cmd_name); |
| print_enumerate_options(options); |
| console_printf(">\n"); |
| } |
| |
| static void |
| help_cmd_kv_dflt(const char *cmd_name, struct kv_pair *options, int dflt) |
| { |
| console_printf("\t%s=[", cmd_name); |
| print_enumerate_options(options); |
| console_printf("] default=%d\n", dflt); |
| } |
| |
| static void |
| help_cmd_byte_stream(const char *cmd_name) |
| { |
| console_printf("\t%s=<xx:xx:xx: ...>\n", cmd_name); |
| } |
| |
| static void |
| help_cmd_byte_stream_exact_length(const char *cmd_name, int len) |
| { |
| console_printf("\t%s=<xx:xx:xx: ...> len=%d\n", cmd_name, len); |
| } |
| |
| static void |
| help_cmd_uuid(const char *cmd_name) |
| { |
| console_printf("\t%s=<UUID>\n", cmd_name); |
| } |
| |
| static void |
| help_cmd_extract(const char *cmd_name) |
| { |
| console_printf("\t%s=<str>\n", cmd_name); |
| } |
| |
| static void |
| help_cmd_conn_start_end(void) |
| { |
| console_printf("\t%s=<val> %s=<val> %s=<val>\n", "conn", "start", "end"); |
| } |
| |
| static void |
| bletiny_adv_help(void) |
| { |
| console_printf("Available adv commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("\tstop\n"); |
| console_printf("Available adv params: \n"); |
| help_cmd_kv_dflt("conn", cmd_adv_conn_modes, BLE_GAP_CONN_MODE_UND); |
| help_cmd_kv_dflt("disc", cmd_adv_disc_modes, BLE_GAP_DISC_MODE_GEN); |
| help_cmd_kv_dflt("peer_addr_type", cmd_peer_addr_types, BLE_ADDR_PUBLIC); |
| help_cmd_byte_stream_exact_length("peer_addr", 6); |
| help_cmd_kv_dflt("own_addr_type", cmd_own_addr_types, |
| BLE_OWN_ADDR_PUBLIC); |
| help_cmd_long_bounds_dflt("chan_map", 0, 0xff, 0); |
| help_cmd_kv_dflt("filt", cmd_adv_filt_types, BLE_HCI_ADV_FILT_NONE); |
| help_cmd_long_bounds_dflt("itvl_min", 0, UINT16_MAX, 0); |
| help_cmd_long_bounds_dflt("itvl_max", 0, UINT16_MAX, 0); |
| help_cmd_long_bounds_dflt("hd", 0, 1, 0); |
| help_cmd_long_bounds_dflt("dur", 1, INT32_MAX, BLE_HS_FOREVER); |
| } |
| |
| static int |
| cmd_adv(int argc, char **argv) |
| { |
| struct ble_gap_adv_params params; |
| int32_t duration_ms; |
| ble_addr_t peer_addr; |
| ble_addr_t *peer_addr_param = &peer_addr; |
| uint8_t own_addr_type; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_adv_help(); |
| return 0; |
| } |
| |
| if (argc > 1 && strcmp(argv[1], "stop") == 0) { |
| rc = bletiny_adv_stop(); |
| if (rc != 0) { |
| console_printf("advertise stop fail: %d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| params.conn_mode = parse_arg_kv_default("conn", cmd_adv_conn_modes, |
| BLE_GAP_CONN_MODE_UND, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_kv_dflt("conn", cmd_adv_conn_modes, BLE_GAP_CONN_MODE_UND); |
| return rc; |
| } |
| |
| params.disc_mode = parse_arg_kv_default("disc", cmd_adv_disc_modes, |
| BLE_GAP_DISC_MODE_GEN, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'disc' parameter\n"); |
| help_cmd_kv_dflt("disc", cmd_adv_disc_modes, BLE_GAP_DISC_MODE_GEN); |
| return rc; |
| } |
| |
| peer_addr.type = parse_arg_kv_default( |
| "peer_addr_type", cmd_peer_addr_types, BLE_ADDR_PUBLIC, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'peer_addr_type' parameter\n"); |
| help_cmd_kv_dflt("peer_addr_type", cmd_peer_addr_types, |
| BLE_ADDR_PUBLIC); |
| return rc; |
| } |
| |
| rc = parse_arg_mac("peer_addr", peer_addr.val); |
| if (rc == ENOENT) { |
| peer_addr_param = NULL; |
| } else if (rc != 0) { |
| console_printf("invalid 'peer_addr' parameter\n"); |
| help_cmd_byte_stream_exact_length("peer_addr", 6); |
| return rc; |
| } |
| |
| own_addr_type = parse_arg_kv_default( |
| "own_addr_type", cmd_own_addr_types, BLE_OWN_ADDR_PUBLIC, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'own_addr_type' parameter\n"); |
| help_cmd_kv_dflt("own_addr_type", cmd_own_addr_types, |
| BLE_OWN_ADDR_PUBLIC); |
| return rc; |
| } |
| |
| params.channel_map = parse_arg_long_bounds_default("chan_map", 0, 0xff, 0, |
| &rc); |
| if (rc != 0) { |
| console_printf("invalid 'chan_map' parameter\n"); |
| help_cmd_long_bounds_dflt("chan_map", 0, 0xff, 0); |
| return rc; |
| } |
| |
| params.filter_policy = parse_arg_kv_default("filt", cmd_adv_filt_types, |
| BLE_HCI_ADV_FILT_NONE, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'filt' parameter\n"); |
| help_cmd_kv_dflt("filt", cmd_adv_filt_types, BLE_HCI_ADV_FILT_NONE); |
| return rc; |
| } |
| |
| params.itvl_min = parse_arg_long_bounds_default("itvl_min", 0, UINT16_MAX, |
| 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'itvl_min' parameter\n"); |
| help_cmd_long_bounds_dflt("itvl_min", 0, UINT16_MAX, 0); |
| return rc; |
| } |
| |
| params.itvl_max = parse_arg_long_bounds_default("itvl_max", 0, UINT16_MAX, |
| 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'itvl_max' parameter\n"); |
| help_cmd_long_bounds_dflt("itvl_max", 0, UINT16_MAX, 0); |
| return rc; |
| } |
| |
| params.high_duty_cycle = parse_arg_long_bounds_default("hd", 0, 1, 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'hd' parameter\n"); |
| help_cmd_long_bounds_dflt("hd", 0, 1, 0); |
| return rc; |
| } |
| |
| duration_ms = parse_arg_long_bounds_default("dur", 1, INT32_MAX, |
| BLE_HS_FOREVER, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'dur' parameter\n"); |
| help_cmd_long_bounds_dflt("dur", 1, INT32_MAX, BLE_HS_FOREVER); |
| return rc; |
| } |
| |
| rc = bletiny_adv_start(own_addr_type, peer_addr_param, duration_ms, |
| ¶ms); |
| if (rc != 0) { |
| console_printf("advertise fail: %d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $connect * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_conn_help(void) |
| { |
| console_printf("Available conn commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("\tcancel\n"); |
| console_printf("Available conn params: \n"); |
| help_cmd_kv_dflt("peer_addr_type", cmd_peer_addr_types, BLE_ADDR_PUBLIC); |
| help_cmd_byte_stream_exact_length("peer_addr", 6); |
| help_cmd_kv_dflt("own_addr_type", cmd_own_addr_types, |
| BLE_OWN_ADDR_PUBLIC); |
| help_cmd_uint16_dflt("scan_itvl", 0x0010); |
| help_cmd_uint16_dflt("scan_window", 0x0010); |
| help_cmd_uint16_dflt("itvl_min", BLE_GAP_INITIAL_CONN_ITVL_MIN); |
| help_cmd_uint16_dflt("itvl_max", BLE_GAP_INITIAL_CONN_ITVL_MAX); |
| help_cmd_uint16_dflt("latency", 0); |
| help_cmd_uint16_dflt("timeout", 0x0100); |
| help_cmd_uint16_dflt("min_ce_len", 0x0010); |
| help_cmd_uint16_dflt("max_ce_len", 0x0300); |
| help_cmd_long_bounds_dflt("dur", 1, INT32_MAX, 0); |
| } |
| |
| static int |
| cmd_conn(int argc, char **argv) |
| { |
| struct ble_gap_conn_params params; |
| int32_t duration_ms; |
| ble_addr_t peer_addr; |
| ble_addr_t *peer_addr_param = &peer_addr; |
| int own_addr_type; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_conn_help(); |
| return 0; |
| } |
| |
| if (argc > 1 && strcmp(argv[1], "cancel") == 0) { |
| rc = bletiny_conn_cancel(); |
| if (rc != 0) { |
| console_printf("connection cancel fail: %d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| peer_addr.type = parse_arg_kv_default("peer_addr_type", cmd_peer_addr_types, |
| BLE_ADDR_PUBLIC, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'peer_addr_type' parameter\n"); |
| help_cmd_kv_dflt("peer_addr_type", cmd_peer_addr_types, |
| BLE_ADDR_PUBLIC); |
| return rc; |
| } |
| |
| rc = parse_arg_mac("peer_addr", peer_addr.val); |
| if (rc == ENOENT) { |
| /* Allow "addr" for backwards compatibility. */ |
| rc = parse_arg_mac("addr", peer_addr.val); |
| } |
| |
| if (rc == ENOENT) { |
| /* With no "peer_addr" specified we'll use white list */ |
| peer_addr_param = NULL; |
| } else if (rc != 0) { |
| console_printf("invalid 'peer_addr' parameter\n"); |
| help_cmd_byte_stream_exact_length("peer_addr", 6); |
| return rc; |
| } |
| |
| own_addr_type = parse_arg_kv_default("own_addr_type", cmd_own_addr_types, |
| BLE_OWN_ADDR_PUBLIC, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'own_addr_type' parameter\n"); |
| help_cmd_kv_dflt("own_addr_type", cmd_own_addr_types, |
| BLE_OWN_ADDR_PUBLIC); |
| return rc; |
| } |
| |
| params.scan_itvl = parse_arg_uint16_dflt("scan_itvl", 0x0010, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'scan_itvl' parameter\n"); |
| help_cmd_uint16_dflt("scan_itvl", 0x0010); |
| return rc; |
| } |
| |
| params.scan_window = parse_arg_uint16_dflt("scan_window", 0x0010, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'scan_window' parameter\n"); |
| help_cmd_uint16_dflt("scan_window", 0x0010); |
| return rc; |
| } |
| |
| params.itvl_min = parse_arg_uint16_dflt( |
| "itvl_min", BLE_GAP_INITIAL_CONN_ITVL_MIN, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'itvl_min' parameter\n"); |
| help_cmd_uint16_dflt("itvl_min", BLE_GAP_INITIAL_CONN_ITVL_MIN); |
| return rc; |
| } |
| |
| params.itvl_max = parse_arg_uint16_dflt( |
| "itvl_max", BLE_GAP_INITIAL_CONN_ITVL_MAX, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'itvl_max' parameter\n"); |
| help_cmd_uint16_dflt("itvl_max", BLE_GAP_INITIAL_CONN_ITVL_MAX); |
| return rc; |
| } |
| |
| params.latency = parse_arg_uint16_dflt("latency", 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'latency' parameter\n"); |
| help_cmd_uint16_dflt("latency", 0); |
| return rc; |
| } |
| |
| params.supervision_timeout = parse_arg_uint16_dflt("timeout", 0x0100, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'timeout' parameter\n"); |
| help_cmd_uint16_dflt("timeout", 0x0100); |
| return rc; |
| } |
| |
| params.min_ce_len = parse_arg_uint16_dflt("min_ce_len", 0x0010, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'min_ce_len' parameter\n"); |
| help_cmd_uint16_dflt("min_ce_len", 0x0010); |
| return rc; |
| } |
| |
| params.max_ce_len = parse_arg_uint16_dflt("max_ce_len", 0x0300, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'max_ce_len' parameter\n"); |
| help_cmd_uint16_dflt("max_ce_len", 0x0300); |
| return rc; |
| } |
| |
| duration_ms = parse_arg_long_bounds_default("dur", 1, INT32_MAX, 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'dur' parameter\n"); |
| help_cmd_long_bounds_dflt("dur", 1, INT32_MAX, 0); |
| return rc; |
| } |
| |
| rc = bletiny_conn_initiate(own_addr_type, peer_addr_param, duration_ms, |
| ¶ms); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $chrup * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_chrup_help(void) |
| { |
| console_printf("Available chrup commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available chrup params: \n"); |
| help_cmd_long("attr"); |
| } |
| |
| static int |
| cmd_chrup(int argc, char **argv) |
| { |
| uint16_t attr_handle; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_chrup_help(); |
| return 0; |
| } |
| |
| attr_handle = parse_arg_long("attr", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'attr' parameter\n"); |
| help_cmd_long("attr"); |
| return rc; |
| } |
| |
| bletiny_chrup(attr_handle); |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $datalen * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_datalen_help(void) |
| { |
| console_printf("Available datalen commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available datalen params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_uint16("octets"); |
| help_cmd_uint16("time"); |
| } |
| |
| static int |
| cmd_datalen(int argc, char **argv) |
| { |
| uint16_t conn_handle; |
| uint16_t tx_octets; |
| uint16_t tx_time; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_datalen_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| tx_octets = parse_arg_long("octets", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'octets' parameter\n"); |
| help_cmd_long("octets"); |
| return rc; |
| } |
| |
| tx_time = parse_arg_long("time", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'time' parameter\n"); |
| help_cmd_long("time"); |
| return rc; |
| } |
| |
| rc = bletiny_datalen(conn_handle, tx_octets, tx_time); |
| if (rc != 0) { |
| console_printf("error setting data length; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $discover * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_disc_chr_help(void) |
| { |
| console_printf("Available disc chr commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available disc chr params: \n"); |
| help_cmd_conn_start_end(); |
| help_cmd_uuid("uuid"); |
| } |
| |
| static int |
| cmd_disc_chr(int argc, char **argv) |
| { |
| uint16_t start_handle; |
| uint16_t conn_handle; |
| uint16_t end_handle; |
| ble_uuid_any_t uuid; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_disc_chr_help(); |
| return 0; |
| } |
| |
| rc = cmd_parse_conn_start_end(&conn_handle, &start_handle, &end_handle); |
| if (rc != 0) { |
| console_printf("invalid 'conn start end' parameter\n"); |
| help_cmd_conn_start_end(); |
| return rc; |
| } |
| |
| rc = parse_arg_uuid("uuid", &uuid); |
| if (rc == 0) { |
| rc = bletiny_disc_chrs_by_uuid(conn_handle, start_handle, end_handle, |
| &uuid.u); |
| } else if (rc == ENOENT) { |
| rc = bletiny_disc_all_chrs(conn_handle, start_handle, end_handle); |
| } else { |
| console_printf("invalid 'uuid' parameter\n"); |
| help_cmd_uuid("uuid"); |
| return rc; |
| } |
| if (rc != 0) { |
| console_printf("error discovering characteristics; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static void |
| bletiny_disc_dsc_help(void) |
| { |
| console_printf("Available disc dsc commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available disc dsc params: \n"); |
| help_cmd_conn_start_end(); |
| } |
| |
| static int |
| cmd_disc_dsc(int argc, char **argv) |
| { |
| uint16_t start_handle; |
| uint16_t conn_handle; |
| uint16_t end_handle; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_disc_dsc_help(); |
| return 0; |
| } |
| |
| rc = cmd_parse_conn_start_end(&conn_handle, &start_handle, &end_handle); |
| if (rc != 0) { |
| console_printf("invalid 'conn start end' parameter\n"); |
| help_cmd_conn_start_end(); |
| return rc; |
| } |
| |
| rc = bletiny_disc_all_dscs(conn_handle, start_handle, end_handle); |
| if (rc != 0) { |
| console_printf("error discovering descriptors; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static void |
| bletiny_disc_svc_help(void) |
| { |
| console_printf("Available disc svc commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available disc svc params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_uuid("uuid"); |
| } |
| |
| static int |
| cmd_disc_svc(int argc, char **argv) |
| { |
| ble_uuid_any_t uuid; |
| int conn_handle; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_disc_svc_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| rc = parse_arg_uuid("uuid", &uuid); |
| if (rc == 0) { |
| rc = bletiny_disc_svc_by_uuid(conn_handle, &uuid.u); |
| } else if (rc == ENOENT) { |
| rc = bletiny_disc_svcs(conn_handle); |
| } else { |
| console_printf("invalid 'uuid' parameter\n"); |
| help_cmd_uuid("uuid"); |
| return rc; |
| } |
| |
| if (rc != 0) { |
| console_printf("error discovering services; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static void |
| bletiny_disc_full_help(void) |
| { |
| console_printf("Available disc full commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available disc full params: \n"); |
| help_cmd_uint16("conn"); |
| } |
| |
| static int |
| cmd_disc_full(int argc, char **argv) |
| { |
| int conn_handle; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_disc_full_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| rc = bletiny_disc_full(conn_handle); |
| if (rc != 0) { |
| console_printf("error discovering all; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static struct cmd_entry cmd_disc_entries[]; |
| |
| static int |
| cmd_disc_help(int argc, char **argv) |
| { |
| int i; |
| |
| console_printf("Available disc commands:\n"); |
| for (i = 0; cmd_disc_entries[i].name != NULL; i++) { |
| console_printf("\t%s\n", cmd_disc_entries[i].name); |
| } |
| return 0; |
| } |
| |
| static struct cmd_entry cmd_disc_entries[] = { |
| { "chr", cmd_disc_chr }, |
| { "dsc", cmd_disc_dsc }, |
| { "svc", cmd_disc_svc }, |
| { "full", cmd_disc_full }, |
| { "help", cmd_disc_help }, |
| { NULL, NULL } |
| }; |
| |
| static int |
| cmd_disc(int argc, char **argv) |
| { |
| int rc; |
| |
| rc = cmd_exec(cmd_disc_entries, argc, argv); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $find * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_find_inc_svcs_help(void) |
| { |
| console_printf("Available find inc svcs commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available find inc svcs params: \n"); |
| help_cmd_conn_start_end(); |
| } |
| |
| static int |
| cmd_find_inc_svcs(int argc, char **argv) |
| { |
| uint16_t start_handle; |
| uint16_t conn_handle; |
| uint16_t end_handle; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_find_inc_svcs_help(); |
| return 0; |
| } |
| |
| rc = cmd_parse_conn_start_end(&conn_handle, &start_handle, &end_handle); |
| if (rc != 0) { |
| console_printf("invalid 'conn start end' parameter\n"); |
| help_cmd_conn_start_end(); |
| return rc; |
| } |
| |
| rc = bletiny_find_inc_svcs(conn_handle, start_handle, end_handle); |
| if (rc != 0) { |
| console_printf("error finding included services; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static const struct cmd_entry cmd_find_entries[]; |
| |
| static int |
| cmd_find_help(int argc, char **argv) |
| { |
| int i; |
| |
| console_printf("Available find commands:\n"); |
| for (i = 0; cmd_find_entries[i].name != NULL; i++) { |
| console_printf("\t%s\n", cmd_find_entries[i].name); |
| } |
| return 0; |
| } |
| |
| static const struct cmd_entry cmd_find_entries[] = { |
| { "inc_svcs", cmd_find_inc_svcs }, |
| { "help", cmd_find_help }, |
| { NULL, NULL } |
| }; |
| |
| static int |
| cmd_find(int argc, char **argv) |
| { |
| int rc; |
| |
| rc = cmd_exec(cmd_find_entries, argc, argv); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $l2cap * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_l2cap_update_help(void) |
| { |
| console_printf("Available l2cap update commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available l2cap update params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_uint16_dflt("itvl_min", BLE_GAP_INITIAL_CONN_ITVL_MIN); |
| help_cmd_uint16_dflt("itvl_max", BLE_GAP_INITIAL_CONN_ITVL_MAX); |
| help_cmd_uint16_dflt("latency", 0); |
| help_cmd_uint16_dflt("timeout", 0x0100); |
| } |
| |
| static int |
| cmd_l2cap_update(int argc, char **argv) |
| { |
| struct ble_l2cap_sig_update_params params; |
| uint16_t conn_handle; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_l2cap_update_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| params.itvl_min = parse_arg_uint16_dflt( |
| "itvl_min", BLE_GAP_INITIAL_CONN_ITVL_MIN, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'itvl_min' parameter\n"); |
| help_cmd_uint16_dflt("itvl_min", BLE_GAP_INITIAL_CONN_ITVL_MIN); |
| return rc; |
| } |
| |
| params.itvl_max = parse_arg_uint16_dflt( |
| "itvl_max", BLE_GAP_INITIAL_CONN_ITVL_MAX, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'itvl_max' parameter\n"); |
| help_cmd_uint16_dflt("itvl_max", BLE_GAP_INITIAL_CONN_ITVL_MAX); |
| return rc; |
| } |
| |
| params.slave_latency = parse_arg_uint16_dflt("latency", 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'latency' parameter\n"); |
| help_cmd_uint16_dflt("latency", 0); |
| return rc; |
| } |
| |
| params.timeout_multiplier = parse_arg_uint16_dflt("timeout", 0x0100, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'timeout' parameter\n"); |
| help_cmd_uint16_dflt("timeout", 0x0100); |
| return rc; |
| } |
| |
| rc = bletiny_l2cap_update(conn_handle, ¶ms); |
| if (rc != 0) { |
| console_printf("error txing l2cap update; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static void |
| bletiny_l2cap_create_srv_help(void) |
| { |
| console_printf("Available l2cap create_srv commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available l2cap create_srv params: \n"); |
| help_cmd_uint16("psm"); |
| help_cmd_uint16("mtu"); |
| } |
| |
| static int |
| cmd_l2cap_create_srv(int argc, char **argv) |
| { |
| uint16_t psm = 0; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_l2cap_create_srv_help(); |
| return 0; |
| } |
| |
| psm = parse_arg_uint16("psm", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'psm' parameter\n"); |
| help_cmd_uint16("psm"); |
| return rc; |
| } |
| |
| rc = bletiny_l2cap_create_srv(psm); |
| if (rc) { |
| console_printf("Server create error: 0x%02x", rc); |
| } |
| |
| return 0; |
| } |
| |
| static void |
| bletiny_l2cap_connect_help(void) |
| { |
| console_printf("Available l2cap connect commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available l2cap connect params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_uint16("psm"); |
| } |
| |
| static int |
| cmd_l2cap_connect(int argc, char **argv) |
| { |
| uint16_t conn = 0; |
| uint16_t psm = 0; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_l2cap_connect_help(); |
| return 0; |
| } |
| |
| conn = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| psm = parse_arg_uint16("psm", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'psm' parameter\n"); |
| help_cmd_uint16("psm"); |
| return rc; |
| } |
| |
| return bletiny_l2cap_connect(conn, psm); |
| } |
| |
| static void |
| bletiny_l2cap_disconnect_help(void) |
| { |
| console_printf("Available l2cap disconnect commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available l2cap disconnect params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_uint16("idx"); |
| console_printf("\n Use 'b show coc' to get those parameters \n"); |
| } |
| |
| static int |
| cmd_l2cap_disconnect(int argc, char **argv) |
| { |
| uint16_t conn; |
| uint16_t idx; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_l2cap_disconnect_help(); |
| return 0; |
| } |
| |
| conn = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| idx = parse_arg_uint16("idx", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'idx' parameter\n"); |
| help_cmd_uint16("idx"); |
| return rc; |
| } |
| |
| return bletiny_l2cap_disconnect(conn, idx); |
| } |
| |
| static void |
| bletiny_l2cap_send_help(void) |
| { |
| console_printf("Available l2cap send commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available l2cap disconnect params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_uint16("idx"); |
| help_cmd_uint16("bytes"); |
| console_printf("\n Use 'b show coc' to get conn and idx parameters.\n"); |
| console_printf("bytes stands for number of bytes to send .\n"); |
| } |
| |
| static int |
| cmd_l2cap_send(int argc, char **argv) |
| { |
| uint16_t conn; |
| uint16_t idx; |
| uint16_t bytes; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_l2cap_send_help(); |
| return 0; |
| } |
| conn = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| idx = parse_arg_uint16("idx", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'idx' parameter\n"); |
| help_cmd_uint16("idx"); |
| return rc; |
| } |
| |
| bytes = parse_arg_uint16("bytes", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'bytes' parameter\n"); |
| help_cmd_uint16("bytes"); |
| return rc; |
| } |
| |
| return bletiny_l2cap_send(conn, idx, bytes); |
| } |
| |
| static const struct cmd_entry cmd_l2cap_entries[]; |
| |
| static int |
| cmd_l2cap_help(int argc, char **argv) |
| { |
| int i; |
| |
| console_printf("Available l2cap commands:\n"); |
| for (i = 0; cmd_l2cap_entries[i].name != NULL; i++) { |
| console_printf("\t%s\n", cmd_l2cap_entries[i].name); |
| } |
| return 0; |
| } |
| |
| static const struct cmd_entry cmd_l2cap_entries[] = { |
| { "update", cmd_l2cap_update }, |
| { "create_srv", cmd_l2cap_create_srv }, |
| { "connect", cmd_l2cap_connect }, |
| { "disconnect", cmd_l2cap_disconnect }, |
| { "send", cmd_l2cap_send }, |
| { "help", cmd_l2cap_help }, |
| { NULL, NULL } |
| }; |
| |
| static int |
| cmd_l2cap(int argc, char **argv) |
| { |
| int rc; |
| |
| rc = cmd_exec(cmd_l2cap_entries, argc, argv); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $mtu * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_mtu_help(void) |
| { |
| console_printf("Available mtu commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available mtu params: \n"); |
| help_cmd_uint16("conn"); |
| } |
| |
| static int |
| cmd_mtu(int argc, char **argv) |
| { |
| uint16_t conn_handle; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_mtu_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| rc = bletiny_exchange_mtu(conn_handle); |
| if (rc != 0) { |
| console_printf("error exchanging mtu; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $read * |
| *****************************************************************************/ |
| |
| #define CMD_READ_MAX_ATTRS 8 |
| |
| static void |
| bletiny_read_help(void) |
| { |
| console_printf("Available read commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available read params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_long("long"); |
| help_cmd_uint16("attr"); |
| help_cmd_uuid("uuid"); |
| help_cmd_uint16("start"); |
| help_cmd_uint16("end"); |
| help_cmd_uint16("offset"); |
| } |
| |
| static int |
| cmd_read(int argc, char **argv) |
| { |
| static uint16_t attr_handles[CMD_READ_MAX_ATTRS]; |
| uint16_t conn_handle; |
| uint16_t start; |
| uint16_t end; |
| uint16_t offset; |
| ble_uuid_any_t uuid; |
| uint8_t num_attr_handles; |
| int is_uuid; |
| int is_long; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_read_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| is_long = parse_arg_long("long", &rc); |
| if (rc == ENOENT) { |
| is_long = 0; |
| } else if (rc != 0) { |
| console_printf("invalid 'long' parameter\n"); |
| help_cmd_long("long"); |
| return rc; |
| } |
| |
| for (num_attr_handles = 0; |
| num_attr_handles < CMD_READ_MAX_ATTRS; |
| num_attr_handles++) { |
| |
| attr_handles[num_attr_handles] = parse_arg_uint16("attr", &rc); |
| if (rc == ENOENT) { |
| break; |
| } else if (rc != 0) { |
| console_printf("invalid 'attr' parameter\n"); |
| help_cmd_uint16("attr"); |
| return rc; |
| } |
| } |
| |
| rc = parse_arg_uuid("uuid", &uuid); |
| if (rc == ENOENT) { |
| is_uuid = 0; |
| } else if (rc == 0) { |
| is_uuid = 1; |
| } else { |
| console_printf("invalid 'uuid' parameter\n"); |
| help_cmd_uuid("uuid"); |
| return rc; |
| } |
| |
| start = parse_arg_uint16("start", &rc); |
| if (rc == ENOENT) { |
| start = 0; |
| } else if (rc != 0) { |
| console_printf("invalid 'start' parameter\n"); |
| help_cmd_uint16("start"); |
| return rc; |
| } |
| |
| end = parse_arg_uint16("end", &rc); |
| if (rc == ENOENT) { |
| end = 0; |
| } else if (rc != 0) { |
| console_printf("invalid 'end' parameter\n"); |
| help_cmd_uint16("end"); |
| return rc; |
| } |
| |
| offset = parse_arg_uint16("offset", &rc); |
| if (rc == ENOENT) { |
| offset = 0; |
| } else if (rc != 0) { |
| console_printf("invalid 'offset' parameter\n"); |
| help_cmd_uint16("offset"); |
| return rc; |
| } |
| |
| if (num_attr_handles == 1) { |
| if (is_long) { |
| rc = bletiny_read_long(conn_handle, attr_handles[0], offset); |
| } else { |
| rc = bletiny_read(conn_handle, attr_handles[0]); |
| } |
| } else if (num_attr_handles > 1) { |
| rc = bletiny_read_mult(conn_handle, attr_handles, num_attr_handles); |
| } else if (is_uuid) { |
| if (start == 0 || end == 0) { |
| rc = EINVAL; |
| } else { |
| rc = bletiny_read_by_uuid(conn_handle, start, end, &uuid.u); |
| } |
| } else { |
| rc = EINVAL; |
| } |
| |
| if (rc != 0) { |
| console_printf("error reading characteristic; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $rssi * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_rssi_help(void) |
| { |
| console_printf("Available rssi commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available rssi params: \n"); |
| help_cmd_uint16("conn"); |
| } |
| |
| static int |
| cmd_rssi(int argc, char **argv) |
| { |
| uint16_t conn_handle; |
| int8_t rssi; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_rssi_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| rc = bletiny_rssi(conn_handle, &rssi); |
| if (rc != 0) { |
| console_printf("error reading rssi; rc=%d\n", rc); |
| return rc; |
| } |
| |
| console_printf("conn=%d rssi=%d\n", conn_handle, rssi); |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $scan * |
| *****************************************************************************/ |
| |
| static struct kv_pair cmd_scan_filt_policies[] = { |
| { "no_wl", BLE_HCI_SCAN_FILT_NO_WL }, |
| { "use_wl", BLE_HCI_SCAN_FILT_USE_WL }, |
| { "no_wl_inita", BLE_HCI_SCAN_FILT_NO_WL_INITA }, |
| { "use_wl_inita", BLE_HCI_SCAN_FILT_USE_WL_INITA }, |
| { NULL } |
| }; |
| |
| static void |
| bletiny_scan_help(void) |
| { |
| console_printf("Available scan commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("\tcancel\n"); |
| console_printf("Available scan params: \n"); |
| help_cmd_long_bounds_dflt("dur", 1, INT32_MAX, BLE_HS_FOREVER); |
| help_cmd_bool_dflt("ltd", 0); |
| help_cmd_bool_dflt("passive", 0); |
| help_cmd_uint16_dflt("itvl", 0); |
| help_cmd_uint16_dflt("window", 0); |
| help_cmd_kv_dflt("filt", cmd_scan_filt_policies, |
| BLE_HCI_SCAN_FILT_NO_WL); |
| help_cmd_uint16_dflt("nodups", 0); |
| help_cmd_kv_dflt("own_addr_type", cmd_own_addr_types, |
| BLE_OWN_ADDR_PUBLIC); |
| } |
| |
| static int |
| cmd_scan(int argc, char **argv) |
| { |
| struct ble_gap_disc_params params; |
| int32_t duration_ms; |
| uint8_t own_addr_type; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_scan_help(); |
| return 0; |
| } |
| |
| if (argc > 1 && strcmp(argv[1], "cancel") == 0) { |
| rc = bletiny_scan_cancel(); |
| if (rc != 0) { |
| console_printf("connection cancel fail: %d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| duration_ms = parse_arg_long_bounds_default("dur", 1, INT32_MAX, |
| BLE_HS_FOREVER, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'dur' parameter\n"); |
| help_cmd_long_bounds_dflt("dur", 1, INT32_MAX, BLE_HS_FOREVER); |
| return rc; |
| } |
| |
| params.limited = parse_arg_bool_default("ltd", 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'ltd' parameter\n"); |
| help_cmd_bool_dflt("ltd", 0); |
| return rc; |
| } |
| |
| params.passive = parse_arg_bool_default("passive", 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'passive' parameter\n"); |
| help_cmd_bool_dflt("passive", 0); |
| return rc; |
| } |
| |
| params.itvl = parse_arg_uint16_dflt("itvl", 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'itvl' parameter\n"); |
| help_cmd_uint16_dflt("itvl", 0); |
| return rc; |
| } |
| |
| params.window = parse_arg_uint16_dflt("window", 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'window' parameter\n"); |
| help_cmd_uint16_dflt("window", 0); |
| return rc; |
| } |
| |
| params.filter_policy = parse_arg_kv_default( |
| "filt", cmd_scan_filt_policies, BLE_HCI_SCAN_FILT_NO_WL, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'filt' parameter\n"); |
| help_cmd_kv_dflt("filt", cmd_scan_filt_policies, |
| BLE_HCI_SCAN_FILT_NO_WL); |
| return rc; |
| } |
| |
| params.filter_duplicates = parse_arg_bool_default("nodups", 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'nodups' parameter\n"); |
| help_cmd_uint16_dflt("nodups", 0); |
| return rc; |
| } |
| |
| own_addr_type = parse_arg_kv_default("own_addr_type", cmd_own_addr_types, |
| BLE_OWN_ADDR_PUBLIC, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'own_addr_type' parameter\n"); |
| help_cmd_kv_dflt("own_addr_type", cmd_own_addr_types, |
| BLE_OWN_ADDR_PUBLIC); |
| return rc; |
| } |
| |
| rc = bletiny_scan(own_addr_type, duration_ms, ¶ms); |
| if (rc != 0) { |
| console_printf("error scanning; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $show * |
| *****************************************************************************/ |
| |
| static int |
| cmd_show_addr(int argc, char **argv) |
| { |
| uint8_t id_addr[6]; |
| int rc; |
| |
| console_printf("public_id_addr="); |
| rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, id_addr, NULL); |
| if (rc == 0) { |
| print_addr(id_addr); |
| } else { |
| console_printf("none"); |
| } |
| |
| console_printf(" random_id_addr="); |
| rc = ble_hs_id_copy_addr(BLE_ADDR_RANDOM, id_addr, NULL); |
| if (rc == 0) { |
| print_addr(id_addr); |
| } else { |
| console_printf("none"); |
| } |
| console_printf("\n"); |
| |
| return 0; |
| } |
| |
| static int |
| cmd_show_chr(int argc, char **argv) |
| { |
| struct bletiny_conn *conn; |
| struct bletiny_svc *svc; |
| int i; |
| |
| for (i = 0; i < bletiny_num_conns; i++) { |
| conn = bletiny_conns + i; |
| |
| console_printf("CONNECTION: handle=%d\n", conn->handle); |
| |
| SLIST_FOREACH(svc, &conn->svcs, next) { |
| cmd_print_svc(svc); |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int |
| cmd_show_conn(int argc, char **argv) |
| { |
| struct ble_gap_conn_desc conn_desc; |
| struct bletiny_conn *conn; |
| int rc; |
| int i; |
| |
| for (i = 0; i < bletiny_num_conns; i++) { |
| conn = bletiny_conns + i; |
| |
| rc = ble_gap_conn_find(conn->handle, &conn_desc); |
| if (rc == 0) { |
| print_conn_desc(&conn_desc); |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int |
| cmd_show_coc(int argc, char **argv) |
| { |
| struct bletiny_conn *conn = NULL; |
| struct bletiny_l2cap_coc *coc; |
| int i, j; |
| |
| for (i = 0; i < bletiny_num_conns; i++) { |
| conn = bletiny_conns + i; |
| if (!conn) { |
| break; |
| } |
| |
| if (SLIST_EMPTY(&conn->coc_list)) { |
| continue; |
| } |
| |
| console_printf("conn_handle: 0x%04x\n", conn->handle); |
| j = 0; |
| SLIST_FOREACH(coc, &conn->coc_list, next) { |
| console_printf(" idx: %i, chan pointer = %p\n", j++, coc->chan); |
| } |
| } |
| |
| return 0; |
| } |
| |
| static struct cmd_entry cmd_show_entries[]; |
| |
| static int |
| cmd_show_help(int argc, char **argv) |
| { |
| int i; |
| |
| console_printf("Available show commands:\n"); |
| for (i = 0; cmd_show_entries[i].name != NULL; i++) { |
| console_printf("\t%s\n", cmd_show_entries[i].name); |
| } |
| return 0; |
| } |
| |
| static struct cmd_entry cmd_show_entries[] = { |
| { "addr", cmd_show_addr }, |
| { "chr", cmd_show_chr }, |
| { "conn", cmd_show_conn }, |
| { "coc", cmd_show_coc }, |
| { "help", cmd_show_help }, |
| { NULL, NULL } |
| }; |
| |
| static int |
| cmd_show(int argc, char **argv) |
| { |
| int rc; |
| |
| rc = cmd_exec(cmd_show_entries, argc, argv); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $sec * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_sec_pair_help(void) |
| { |
| console_printf("Available sec pair commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available sec pair params: \n"); |
| help_cmd_uint16("conn"); |
| } |
| |
| static int |
| cmd_sec_pair(int argc, char **argv) |
| { |
| uint16_t conn_handle; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_sec_pair_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| rc = bletiny_sec_pair(conn_handle); |
| if (rc != 0) { |
| console_printf("error initiating pairing; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static void |
| bletiny_sec_start_help(void) |
| { |
| console_printf("Available sec start commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available sec start params: \n"); |
| help_cmd_uint16("conn"); |
| } |
| |
| static int |
| cmd_sec_start(int argc, char **argv) |
| { |
| uint16_t conn_handle; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_sec_start_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| rc = bletiny_sec_start(conn_handle); |
| if (rc != 0) { |
| console_printf("error starting security; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static void |
| bletiny_sec_enc_help(void) |
| { |
| console_printf("Available sec enc commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available sec enc params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_uint64("rand"); |
| help_cmd_bool("auth"); |
| help_cmd_byte_stream_exact_length("ltk", 16); |
| } |
| |
| static int |
| cmd_sec_enc(int argc, char **argv) |
| { |
| uint16_t conn_handle; |
| uint16_t ediv; |
| uint64_t rand_val; |
| uint8_t ltk[16]; |
| int rc; |
| int auth; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_sec_enc_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| ediv = parse_arg_uint16("ediv", &rc); |
| if (rc == ENOENT) { |
| rc = bletiny_sec_restart(conn_handle, NULL, 0, 0, 0); |
| } else { |
| rand_val = parse_arg_uint64("rand", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'rand' parameter\n"); |
| help_cmd_uint64("rand"); |
| return rc; |
| } |
| |
| auth = parse_arg_bool("auth", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'auth' parameter\n"); |
| help_cmd_bool("auth"); |
| return rc; |
| } |
| |
| rc = parse_arg_byte_stream_exact_length("ltk", ltk, 16); |
| if (rc != 0) { |
| console_printf("invalid 'ltk' parameter\n"); |
| help_cmd_byte_stream_exact_length("ltk", 16); |
| return rc; |
| } |
| |
| rc = bletiny_sec_restart(conn_handle, ltk, ediv, rand_val, auth); |
| } |
| |
| if (rc != 0) { |
| console_printf("error initiating encryption; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static struct cmd_entry cmd_sec_entries[]; |
| |
| static int |
| cmd_sec_help(int argc, char **argv) |
| { |
| int i; |
| |
| console_printf("Available sec commands:\n"); |
| for (i = 0; cmd_sec_entries[i].name != NULL; i++) { |
| console_printf("\t%s\n", cmd_sec_entries[i].name); |
| } |
| return 0; |
| } |
| |
| static struct cmd_entry cmd_sec_entries[] = { |
| { "pair", cmd_sec_pair }, |
| { "start", cmd_sec_start }, |
| { "enc", cmd_sec_enc }, |
| { "help", cmd_sec_help }, |
| { NULL } |
| }; |
| |
| static int |
| cmd_sec(int argc, char **argv) |
| { |
| int rc; |
| |
| rc = cmd_exec(cmd_sec_entries, argc, argv); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $set * |
| *****************************************************************************/ |
| |
| #define CMD_ADV_DATA_MAX_UUIDS16 8 |
| #define CMD_ADV_DATA_MAX_UUIDS32 8 |
| #define CMD_ADV_DATA_MAX_UUIDS128 2 |
| #define CMD_ADV_DATA_MAX_PUBLIC_TGT_ADDRS 8 |
| #define CMD_ADV_DATA_SVC_DATA_UUID16_MAX_LEN BLE_HS_ADV_MAX_FIELD_SZ |
| #define CMD_ADV_DATA_SVC_DATA_UUID32_MAX_LEN BLE_HS_ADV_MAX_FIELD_SZ |
| #define CMD_ADV_DATA_SVC_DATA_UUID128_MAX_LEN BLE_HS_ADV_MAX_FIELD_SZ |
| #define CMD_ADV_DATA_URI_MAX_LEN BLE_HS_ADV_MAX_FIELD_SZ |
| #define CMD_ADV_DATA_MFG_DATA_MAX_LEN BLE_HS_ADV_MAX_FIELD_SZ |
| |
| static void |
| bletiny_set_adv_data_help(void) |
| { |
| console_printf("Available set adv_data params: \n"); |
| help_cmd_long_bounds("flags", 0, UINT8_MAX); |
| help_cmd_uint16("uuid16"); |
| help_cmd_long("uuids16_is_complete"); |
| help_cmd_uint32("uuid32"); |
| help_cmd_long("uuids32_is_complete"); |
| help_cmd_byte_stream_exact_length("uuid128", 16); |
| help_cmd_long("uuids128_is_complete"); |
| help_cmd_long_bounds("tx_pwr_lvl", INT8_MIN, INT8_MAX); |
| help_cmd_byte_stream_exact_length("slave_itvl_range", |
| BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN); |
| help_cmd_byte_stream("svc_data_uuid16"); |
| help_cmd_byte_stream_exact_length("public_tgt_addr", |
| BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN); |
| help_cmd_uint16("appearance"); |
| help_cmd_extract("name"); |
| help_cmd_uint16("adv_itvl"); |
| help_cmd_byte_stream("svc_data_uuid32"); |
| help_cmd_byte_stream("svc_data_uuid128"); |
| help_cmd_byte_stream("uri"); |
| help_cmd_byte_stream("mfg_data"); |
| } |
| |
| static int |
| cmd_set_adv_data(void) |
| { |
| static bssnz_t ble_uuid16_t uuids16[CMD_ADV_DATA_MAX_UUIDS16]; |
| static bssnz_t ble_uuid32_t uuids32[CMD_ADV_DATA_MAX_UUIDS32]; |
| static bssnz_t ble_uuid128_t uuids128[CMD_ADV_DATA_MAX_UUIDS128]; |
| static bssnz_t uint8_t |
| public_tgt_addrs[CMD_ADV_DATA_MAX_PUBLIC_TGT_ADDRS] |
| [BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN]; |
| static bssnz_t uint8_t slave_itvl_range[BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN]; |
| static bssnz_t uint8_t |
| svc_data_uuid16[CMD_ADV_DATA_SVC_DATA_UUID16_MAX_LEN]; |
| static bssnz_t uint8_t |
| svc_data_uuid32[CMD_ADV_DATA_SVC_DATA_UUID32_MAX_LEN]; |
| static bssnz_t uint8_t |
| svc_data_uuid128[CMD_ADV_DATA_SVC_DATA_UUID128_MAX_LEN]; |
| static bssnz_t uint8_t uri[CMD_ADV_DATA_URI_MAX_LEN]; |
| static bssnz_t uint8_t mfg_data[CMD_ADV_DATA_MFG_DATA_MAX_LEN]; |
| struct ble_hs_adv_fields adv_fields; |
| uint32_t uuid32; |
| uint16_t uuid16; |
| uint8_t uuid128[16]; |
| uint8_t public_tgt_addr[BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN]; |
| uint8_t eddystone_url_body_len; |
| uint8_t eddystone_url_suffix; |
| uint8_t eddystone_url_scheme; |
| char eddystone_url_body[BLE_EDDYSTONE_URL_MAX_LEN]; |
| char *eddystone_url_full; |
| int svc_data_uuid16_len; |
| int svc_data_uuid32_len; |
| int svc_data_uuid128_len; |
| int uri_len; |
| int mfg_data_len; |
| int tmp; |
| int rc; |
| |
| memset(&adv_fields, 0, sizeof adv_fields); |
| |
| tmp = parse_arg_long_bounds("flags", 0, UINT8_MAX, &rc); |
| if (rc == 0) { |
| adv_fields.flags = tmp; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'flags' parameter\n"); |
| help_cmd_long_bounds("flags", 0, UINT8_MAX); |
| return rc; |
| } |
| |
| while (1) { |
| uuid16 = parse_arg_uint16("uuid16", &rc); |
| if (rc == 0) { |
| if (adv_fields.num_uuids16 >= CMD_ADV_DATA_MAX_UUIDS16) { |
| console_printf("invalid 'uuid16' parameter\n"); |
| help_cmd_uint16("uuid16"); |
| return EINVAL; |
| } |
| uuids16[adv_fields.num_uuids16] = (ble_uuid16_t) BLE_UUID16_INIT(uuid16); |
| adv_fields.num_uuids16++; |
| } else if (rc == ENOENT) { |
| break; |
| } else { |
| console_printf("invalid 'uuid16' parameter\n"); |
| help_cmd_uint16("uuid16"); |
| return rc; |
| } |
| } |
| if (adv_fields.num_uuids16 > 0) { |
| adv_fields.uuids16 = uuids16; |
| } |
| |
| tmp = parse_arg_long("uuids16_is_complete", &rc); |
| if (rc == 0) { |
| adv_fields.uuids16_is_complete = !!tmp; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'uuids16_is_complete' parameter\n"); |
| help_cmd_long("uuids16_is_complete"); |
| return rc; |
| } |
| |
| while (1) { |
| uuid32 = parse_arg_uint32("uuid32", &rc); |
| if (rc == 0) { |
| if (adv_fields.num_uuids32 >= CMD_ADV_DATA_MAX_UUIDS32) { |
| console_printf("invalid 'uuid32' parameter\n"); |
| help_cmd_uint32("uuid32"); |
| return EINVAL; |
| } |
| uuids32[adv_fields.num_uuids32] = (ble_uuid32_t) BLE_UUID32_INIT(uuid32); |
| adv_fields.num_uuids32++; |
| } else if (rc == ENOENT) { |
| break; |
| } else { |
| console_printf("invalid 'uuid32' parameter\n"); |
| help_cmd_uint32("uuid32"); |
| return rc; |
| } |
| } |
| if (adv_fields.num_uuids32 > 0) { |
| adv_fields.uuids32 = uuids32; |
| } |
| |
| tmp = parse_arg_long("uuids32_is_complete", &rc); |
| if (rc == 0) { |
| adv_fields.uuids32_is_complete = !!tmp; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'uuids32_is_complete' parameter\n"); |
| help_cmd_long("uuids32_is_complete"); |
| return rc; |
| } |
| |
| while (1) { |
| rc = parse_arg_byte_stream_exact_length("uuid128", uuid128, 16); |
| if (rc == 0) { |
| if (adv_fields.num_uuids128 >= CMD_ADV_DATA_MAX_UUIDS128) { |
| console_printf("invalid 'uuid128' parameter\n"); |
| help_cmd_byte_stream_exact_length("uuid128", 16); |
| return EINVAL; |
| } |
| ble_uuid_init_from_buf((ble_uuid_any_t *) &uuids128[adv_fields.num_uuids128], |
| uuid128, 16); |
| adv_fields.num_uuids128++; |
| } else if (rc == ENOENT) { |
| break; |
| } else { |
| console_printf("invalid 'uuid128' parameter\n"); |
| help_cmd_byte_stream_exact_length("uuid128", 16); |
| return rc; |
| } |
| } |
| if (adv_fields.num_uuids128 > 0) { |
| adv_fields.uuids128 = uuids128; |
| } |
| |
| tmp = parse_arg_long("uuids128_is_complete", &rc); |
| if (rc == 0) { |
| adv_fields.uuids128_is_complete = !!tmp; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'uuids128_is_complete' parameter\n"); |
| help_cmd_long("uuids128_is_complete"); |
| return rc; |
| } |
| |
| adv_fields.name = (uint8_t *)parse_arg_extract("name"); |
| if (adv_fields.name != NULL) { |
| adv_fields.name_len = strlen((char *)adv_fields.name); |
| } |
| |
| tmp = parse_arg_long_bounds("tx_pwr_lvl", INT8_MIN, INT8_MAX, &rc); |
| if (rc == 0) { |
| adv_fields.tx_pwr_lvl = tmp; |
| adv_fields.tx_pwr_lvl_is_present = 1; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'tx_pwr_lvl' parameter\n"); |
| help_cmd_long_bounds("tx_pwr_lvl", INT8_MIN, INT8_MAX); |
| return rc; |
| } |
| |
| rc = parse_arg_byte_stream_exact_length("slave_itvl_range", |
| slave_itvl_range, |
| BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN); |
| if (rc == 0) { |
| adv_fields.slave_itvl_range = slave_itvl_range; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'slave_itvl_range' parameter\n"); |
| help_cmd_byte_stream_exact_length("slave_itvl_range", |
| BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN); |
| return rc; |
| } |
| |
| rc = parse_arg_byte_stream("svc_data_uuid16", |
| CMD_ADV_DATA_SVC_DATA_UUID16_MAX_LEN, |
| svc_data_uuid16, &svc_data_uuid16_len); |
| if (rc == 0) { |
| adv_fields.svc_data_uuid16 = svc_data_uuid16; |
| adv_fields.svc_data_uuid16_len = svc_data_uuid16_len; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'svc_data_uuid16' parameter\n"); |
| help_cmd_byte_stream("svc_data_uuid16"); |
| return rc; |
| } |
| |
| while (1) { |
| rc = parse_arg_byte_stream_exact_length( |
| "public_tgt_addr", public_tgt_addr, |
| BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN); |
| if (rc == 0) { |
| if (adv_fields.num_public_tgt_addrs >= |
| CMD_ADV_DATA_MAX_PUBLIC_TGT_ADDRS) { |
| |
| console_printf("invalid 'public_tgt_addr' parameter\n"); |
| help_cmd_byte_stream_exact_length("public_tgt_addr", |
| BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN); |
| return EINVAL; |
| } |
| memcpy(public_tgt_addrs[adv_fields.num_public_tgt_addrs], |
| public_tgt_addr, BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN); |
| adv_fields.num_public_tgt_addrs++; |
| } else if (rc == ENOENT) { |
| break; |
| } else { |
| console_printf("invalid 'public_tgt_addr' parameter\n"); |
| help_cmd_byte_stream_exact_length("public_tgt_addr", |
| BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN); |
| return rc; |
| } |
| } |
| if (adv_fields.num_public_tgt_addrs > 0) { |
| adv_fields.public_tgt_addr = (void *)public_tgt_addrs; |
| } |
| |
| adv_fields.appearance = parse_arg_uint16("appearance", &rc); |
| if (rc == 0) { |
| adv_fields.appearance_is_present = 1; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'appearance' parameter\n"); |
| help_cmd_uint16("appearance"); |
| return rc; |
| } |
| |
| adv_fields.adv_itvl = parse_arg_uint16("adv_itvl", &rc); |
| if (rc == 0) { |
| adv_fields.adv_itvl_is_present = 1; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'adv_itvl' parameter\n"); |
| help_cmd_uint16("adv_itvl"); |
| return rc; |
| } |
| |
| rc = parse_arg_byte_stream("svc_data_uuid32", |
| CMD_ADV_DATA_SVC_DATA_UUID32_MAX_LEN, |
| svc_data_uuid32, &svc_data_uuid32_len); |
| if (rc == 0) { |
| adv_fields.svc_data_uuid32 = svc_data_uuid32; |
| adv_fields.svc_data_uuid32_len = svc_data_uuid32_len; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'svc_data_uuid32' parameter\n"); |
| help_cmd_byte_stream("svc_data_uuid32"); |
| return rc; |
| } |
| |
| rc = parse_arg_byte_stream("svc_data_uuid128", |
| CMD_ADV_DATA_SVC_DATA_UUID128_MAX_LEN, |
| svc_data_uuid128, &svc_data_uuid128_len); |
| if (rc == 0) { |
| adv_fields.svc_data_uuid128 = svc_data_uuid128; |
| adv_fields.svc_data_uuid128_len = svc_data_uuid128_len; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'svc_data_uuid128' parameter\n"); |
| help_cmd_byte_stream("svc_data_uuid128"); |
| return rc; |
| } |
| |
| rc = parse_arg_byte_stream("uri", CMD_ADV_DATA_URI_MAX_LEN, uri, &uri_len); |
| if (rc == 0) { |
| adv_fields.uri = uri; |
| adv_fields.uri_len = uri_len; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'uri' parameter\n"); |
| help_cmd_byte_stream("uri"); |
| return rc; |
| } |
| |
| rc = parse_arg_byte_stream("mfg_data", CMD_ADV_DATA_MFG_DATA_MAX_LEN, |
| mfg_data, &mfg_data_len); |
| if (rc == 0) { |
| adv_fields.mfg_data = mfg_data; |
| adv_fields.mfg_data_len = mfg_data_len; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'mfg_data' parameter\n"); |
| help_cmd_byte_stream("mfg_data"); |
| return rc; |
| } |
| |
| eddystone_url_full = parse_arg_extract("eddystone_url"); |
| if (eddystone_url_full != NULL) { |
| rc = cmd_parse_eddystone_url(eddystone_url_full, &eddystone_url_scheme, |
| eddystone_url_body, |
| &eddystone_url_body_len, |
| &eddystone_url_suffix); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| rc = ble_eddystone_set_adv_data_url(&adv_fields, eddystone_url_scheme, |
| eddystone_url_body, |
| eddystone_url_body_len, |
| eddystone_url_suffix); |
| } else { |
| rc = bletiny_set_adv_data(&adv_fields); |
| } |
| if (rc != 0) { |
| console_printf("error setting advertisement data; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static void |
| bletiny_set_sm_data_help(void) |
| { |
| console_printf("Available set sm_data params: \n"); |
| help_cmd_bool("oob_flag"); |
| help_cmd_bool("mitm_flag"); |
| help_cmd_uint8("io_capabilities"); |
| help_cmd_uint8("our_key_dist"); |
| help_cmd_uint8("their_key_dist"); |
| help_cmd_bool("bonding"); |
| help_cmd_bool("sc"); |
| } |
| |
| static int |
| cmd_set_sm_data(void) |
| { |
| uint8_t tmp; |
| int good; |
| int rc; |
| |
| good = 0; |
| |
| tmp = parse_arg_bool("oob_flag", &rc); |
| if (rc == 0) { |
| ble_hs_cfg.sm_oob_data_flag = tmp; |
| good++; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'oob_flag' parameter\n"); |
| help_cmd_bool("oob_flag"); |
| return rc; |
| } |
| |
| tmp = parse_arg_bool("mitm_flag", &rc); |
| if (rc == 0) { |
| good++; |
| ble_hs_cfg.sm_mitm = tmp; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'mitm_flag' parameter\n"); |
| help_cmd_bool("mitm_flag"); |
| return rc; |
| } |
| |
| tmp = parse_arg_uint8("io_capabilities", &rc); |
| if (rc == 0) { |
| good++; |
| ble_hs_cfg.sm_io_cap = tmp; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'io_capabilities' parameter\n"); |
| help_cmd_uint8("io_capabilities"); |
| return rc; |
| } |
| |
| tmp = parse_arg_uint8("our_key_dist", &rc); |
| if (rc == 0) { |
| good++; |
| ble_hs_cfg.sm_our_key_dist = tmp; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'our_key_dist' parameter\n"); |
| help_cmd_uint8("our_key_dist"); |
| return rc; |
| } |
| |
| tmp = parse_arg_uint8("their_key_dist", &rc); |
| if (rc == 0) { |
| good++; |
| ble_hs_cfg.sm_their_key_dist = tmp; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'their_key_dist' parameter\n"); |
| help_cmd_uint8("their_key_dist"); |
| return rc; |
| } |
| |
| tmp = parse_arg_bool("bonding", &rc); |
| if (rc == 0) { |
| good++; |
| ble_hs_cfg.sm_bonding = tmp; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'bonding' parameter\n"); |
| help_cmd_bool("bonding"); |
| return rc; |
| } |
| |
| tmp = parse_arg_bool("sc", &rc); |
| if (rc == 0) { |
| good++; |
| ble_hs_cfg.sm_sc = tmp; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'sc' parameter\n"); |
| help_cmd_bool("sc"); |
| return rc; |
| } |
| |
| if (!good) { |
| console_printf("Error: no valid settings specified\n"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static struct kv_pair cmd_set_addr_types[] = { |
| { "public", BLE_ADDR_PUBLIC }, |
| { "random", BLE_ADDR_RANDOM }, |
| { NULL } |
| }; |
| |
| static void |
| bletiny_set_addr_help(void) |
| { |
| console_printf("Available set addr params: \n"); |
| help_cmd_kv_dflt("addr_type", cmd_set_addr_types, BLE_ADDR_PUBLIC); |
| help_cmd_byte_stream_exact_length("addr", 6); |
| } |
| |
| static int |
| cmd_set_addr(void) |
| { |
| uint8_t addr[6]; |
| int addr_type; |
| int rc; |
| |
| addr_type = parse_arg_kv_default("addr_type", cmd_set_addr_types, |
| BLE_ADDR_PUBLIC, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'addr_type' parameter\n"); |
| help_cmd_kv_dflt("addr_type", cmd_set_addr_types, BLE_ADDR_PUBLIC); |
| return rc; |
| } |
| |
| rc = parse_arg_mac("addr", addr); |
| if (rc != 0) { |
| console_printf("invalid 'addr' parameter\n"); |
| help_cmd_byte_stream_exact_length("addr", 6); |
| return rc; |
| } |
| |
| switch (addr_type) { |
| case BLE_ADDR_PUBLIC: |
| /* We shouldn't be writing to the controller's address (g_dev_addr). |
| * There is no standard way to set the local public address, so this is |
| * our only option at the moment. |
| */ |
| memcpy(g_dev_addr, addr, 6); |
| ble_hs_id_set_pub(g_dev_addr); |
| break; |
| |
| case BLE_ADDR_RANDOM: |
| rc = ble_hs_id_set_rnd(addr); |
| if (rc != 0) { |
| return rc; |
| } |
| break; |
| |
| default: |
| assert(0); |
| return BLE_HS_EUNKNOWN; |
| } |
| |
| return 0; |
| } |
| |
| static void |
| bletiny_set_help(void) |
| { |
| console_printf("Available set commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("\tadv_data\n"); |
| console_printf("\tsm_data\n"); |
| console_printf("\taddr\n"); |
| console_printf("Available set params: \n"); |
| help_cmd_uint16("mtu"); |
| help_cmd_byte_stream_exact_length("irk", 16); |
| } |
| |
| static int |
| cmd_set(int argc, char **argv) |
| { |
| uint16_t mtu; |
| uint8_t irk[16]; |
| int good; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_set_help(); |
| bletiny_set_adv_data_help(); |
| bletiny_set_sm_data_help(); |
| bletiny_set_addr_help(); |
| return 0; |
| } |
| |
| if (argc > 1 && strcmp(argv[1], "adv_data") == 0) { |
| rc = cmd_set_adv_data(); |
| return rc; |
| } |
| |
| if (argc > 1 && strcmp(argv[1], "sm_data") == 0) { |
| rc = cmd_set_sm_data(); |
| return rc; |
| } |
| |
| good = 0; |
| |
| rc = parse_arg_find_idx("addr"); |
| if (rc != -1) { |
| rc = cmd_set_addr(); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| good = 1; |
| } |
| |
| mtu = parse_arg_uint16("mtu", &rc); |
| if (rc == 0) { |
| rc = ble_att_set_preferred_mtu(mtu); |
| if (rc == 0) { |
| good = 1; |
| } |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'mtu' parameter\n"); |
| help_cmd_uint16("mtu"); |
| return rc; |
| } |
| |
| rc = parse_arg_byte_stream_exact_length("irk", irk, 16); |
| if (rc == 0) { |
| good = 1; |
| ble_hs_pvcy_set_our_irk(irk); |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'irk' parameter\n"); |
| help_cmd_byte_stream_exact_length("irk", 16); |
| return rc; |
| } |
| |
| if (!good) { |
| console_printf("Error: no valid settings specified\n"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $terminate * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_term_help(void) |
| { |
| console_printf("Available term commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available term params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_uint8_dflt("reason", BLE_ERR_REM_USER_CONN_TERM); |
| } |
| |
| static int |
| cmd_term(int argc, char **argv) |
| { |
| uint16_t conn_handle; |
| uint8_t reason; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_term_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| reason = parse_arg_uint8_dflt("reason", BLE_ERR_REM_USER_CONN_TERM, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'reason' parameter\n"); |
| help_cmd_uint8_dflt("reason", BLE_ERR_REM_USER_CONN_TERM); |
| return rc; |
| } |
| |
| rc = bletiny_term_conn(conn_handle, reason); |
| if (rc != 0) { |
| console_printf("error terminating connection; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $update connection parameters * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_update_help(void) |
| { |
| console_printf("Available update commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available update params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_uint16_dflt("itvl_min", BLE_GAP_INITIAL_CONN_ITVL_MIN); |
| help_cmd_uint16_dflt("itvl_max", BLE_GAP_INITIAL_CONN_ITVL_MAX); |
| help_cmd_uint16_dflt("latency", 0); |
| help_cmd_uint16_dflt("timeout", 0x0100); |
| help_cmd_uint16_dflt("min_ce_len", 0x0010); |
| help_cmd_uint16_dflt("max_ce_len", 0x0300); |
| } |
| |
| static int |
| cmd_update(int argc, char **argv) |
| { |
| struct ble_gap_upd_params params; |
| uint16_t conn_handle; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_update_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| params.itvl_min = parse_arg_uint16_dflt( |
| "itvl_min", BLE_GAP_INITIAL_CONN_ITVL_MIN, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'itvl_min' parameter\n"); |
| help_cmd_uint16_dflt("itvl_min", BLE_GAP_INITIAL_CONN_ITVL_MIN); |
| return rc; |
| } |
| |
| params.itvl_max = parse_arg_uint16_dflt( |
| "itvl_max", BLE_GAP_INITIAL_CONN_ITVL_MAX, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'itvl_max' parameter\n"); |
| help_cmd_uint16_dflt("itvl_max", BLE_GAP_INITIAL_CONN_ITVL_MAX); |
| return rc; |
| } |
| |
| params.latency = parse_arg_uint16_dflt("latency", 0, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'latency' parameter\n"); |
| help_cmd_uint16_dflt("latency", 0); |
| return rc; |
| } |
| |
| params.supervision_timeout = parse_arg_uint16_dflt("timeout", 0x0100, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'timeout' parameter\n"); |
| help_cmd_uint16_dflt("timeout", 0x0100); |
| return rc; |
| } |
| |
| params.min_ce_len = parse_arg_uint16_dflt("min_ce_len", 0x0010, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'min_ce_len' parameter\n"); |
| help_cmd_uint16_dflt("min_ce_len", 0x0010); |
| return rc; |
| } |
| |
| params.max_ce_len = parse_arg_uint16_dflt("max_ce_len", 0x0300, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'max_ce_len' parameter\n"); |
| help_cmd_uint16_dflt("max_ce_len", 0x0300); |
| return rc; |
| } |
| |
| rc = bletiny_update_conn(conn_handle, ¶ms); |
| if (rc != 0) { |
| console_printf("error updating connection; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $white list * |
| *****************************************************************************/ |
| |
| #define CMD_WL_MAX_SZ 8 |
| |
| static void |
| bletiny_wl_help(void) |
| { |
| console_printf("Available wl commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available wl params: \n"); |
| console_printf("\tlist of:\n"); |
| help_cmd_byte_stream_exact_length("addr", 6); |
| help_cmd_kv("addr_type", cmd_addr_type); |
| } |
| |
| static int |
| cmd_wl(int argc, char **argv) |
| { |
| static ble_addr_t addrs[CMD_WL_MAX_SZ]; |
| int addrs_cnt; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_wl_help(); |
| return 0; |
| } |
| |
| addrs_cnt = 0; |
| while (1) { |
| if (addrs_cnt >= CMD_WL_MAX_SZ) { |
| return EINVAL; |
| } |
| |
| rc = parse_arg_mac("addr", addrs[addrs_cnt].val); |
| if (rc == ENOENT) { |
| break; |
| } else if (rc != 0) { |
| console_printf("invalid 'addr' parameter\n"); |
| help_cmd_byte_stream_exact_length("addr", 6); |
| return rc; |
| } |
| |
| addrs[addrs_cnt].type = parse_arg_kv("addr_type", cmd_addr_type, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'addr' parameter\n"); |
| help_cmd_kv("addr_type", cmd_addr_type); |
| return rc; |
| } |
| |
| addrs_cnt++; |
| } |
| |
| if (addrs_cnt == 0) { |
| return EINVAL; |
| } |
| |
| bletiny_wl_set(addrs, addrs_cnt); |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $write * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_write_help(void) |
| { |
| console_printf("Available write commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available write params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_long("no_rsp"); |
| help_cmd_long("long"); |
| console_printf("\tlist of:\n"); |
| help_cmd_long("attr"); |
| help_cmd_byte_stream("value"); |
| help_cmd_uint16("offset"); |
| } |
| |
| static int |
| cmd_write(int argc, char **argv) |
| { |
| struct ble_gatt_attr attrs[MYNEWT_VAL(BLE_GATT_WRITE_MAX_ATTRS)] = { { 0 } }; |
| uint16_t attr_handle; |
| uint16_t conn_handle; |
| uint16_t offset; |
| int total_attr_len; |
| int num_attrs; |
| int attr_len; |
| int is_long; |
| int no_rsp; |
| int rc; |
| int i; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_write_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| no_rsp = parse_arg_long("no_rsp", &rc); |
| if (rc == ENOENT) { |
| no_rsp = 0; |
| } else if (rc != 0) { |
| console_printf("invalid 'no_rsp' parameter\n"); |
| help_cmd_long("no_rsp"); |
| return rc; |
| } |
| |
| is_long = parse_arg_long("long", &rc); |
| if (rc == ENOENT) { |
| is_long = 0; |
| } else if (rc != 0) { |
| console_printf("invalid 'long' parameter\n"); |
| help_cmd_long("long"); |
| return rc; |
| } |
| |
| total_attr_len = 0; |
| num_attrs = 0; |
| while (1) { |
| attr_handle = parse_arg_long("attr", &rc); |
| if (rc == ENOENT) { |
| break; |
| } else if (rc != 0) { |
| rc = -rc; |
| console_printf("invalid 'attr' parameter\n"); |
| help_cmd_long("attr"); |
| goto done; |
| } |
| |
| rc = parse_arg_byte_stream("value", sizeof cmd_buf - total_attr_len, |
| cmd_buf + total_attr_len, &attr_len); |
| if (rc == ENOENT) { |
| break; |
| } else if (rc != 0) { |
| console_printf("invalid 'value' parameter\n"); |
| help_cmd_byte_stream("value"); |
| goto done; |
| } |
| |
| offset = parse_arg_uint16("offset", &rc); |
| if (rc == ENOENT) { |
| offset = 0; |
| } else if (rc != 0) { |
| console_printf("invalid 'offset' parameter\n"); |
| help_cmd_uint16("offset"); |
| return rc; |
| } |
| |
| if (num_attrs >= sizeof attrs / sizeof attrs[0]) { |
| rc = -EINVAL; |
| goto done; |
| } |
| |
| attrs[num_attrs].handle = attr_handle; |
| attrs[num_attrs].offset = offset; |
| attrs[num_attrs].om = ble_hs_mbuf_from_flat(cmd_buf + total_attr_len, |
| attr_len); |
| if (attrs[num_attrs].om == NULL) { |
| goto done; |
| } |
| |
| total_attr_len += attr_len; |
| num_attrs++; |
| } |
| |
| if (no_rsp) { |
| if (num_attrs != 1) { |
| rc = -EINVAL; |
| goto done; |
| } |
| rc = bletiny_write_no_rsp(conn_handle, attrs[0].handle, attrs[0].om); |
| attrs[0].om = NULL; |
| } else if (is_long) { |
| if (num_attrs != 1) { |
| rc = -EINVAL; |
| goto done; |
| } |
| rc = bletiny_write_long(conn_handle, attrs[0].handle, |
| attrs[0].offset, attrs[0].om); |
| attrs[0].om = NULL; |
| } else if (num_attrs > 1) { |
| rc = bletiny_write_reliable(conn_handle, attrs, num_attrs); |
| } else if (num_attrs == 1) { |
| rc = bletiny_write(conn_handle, attrs[0].handle, attrs[0].om); |
| attrs[0].om = NULL; |
| } else { |
| rc = -EINVAL; |
| } |
| |
| done: |
| for (i = 0; i < sizeof attrs / sizeof attrs[0]; i++) { |
| os_mbuf_free_chain(attrs[i].om); |
| } |
| |
| if (rc != 0) { |
| console_printf("error writing characteristic; rc=%d\n", rc); |
| } |
| |
| return rc; |
| } |
| |
| /***************************************************************************** |
| * store * |
| *****************************************************************************/ |
| |
| static struct kv_pair cmd_keystore_entry_type[] = { |
| { "msec", BLE_STORE_OBJ_TYPE_PEER_SEC }, |
| { "ssec", BLE_STORE_OBJ_TYPE_OUR_SEC }, |
| { "cccd", BLE_STORE_OBJ_TYPE_CCCD }, |
| { NULL } |
| }; |
| |
| static void |
| bletiny_keystore_parse_keydata_help(void) |
| { |
| console_printf("Available keystore parse keydata params: \n"); |
| help_cmd_kv("type", cmd_keystore_entry_type); |
| help_cmd_kv("addr_type", cmd_addr_type); |
| help_cmd_byte_stream_exact_length("addr", 6); |
| help_cmd_uint16("ediv"); |
| help_cmd_uint64("rand"); |
| } |
| |
| static int |
| cmd_keystore_parse_keydata(int argc, char **argv, union ble_store_key *out, |
| int *obj_type) |
| { |
| int rc; |
| |
| memset(out, 0, sizeof(*out)); |
| *obj_type = parse_arg_kv("type", cmd_keystore_entry_type, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'type' parameter\n"); |
| help_cmd_kv("type", cmd_keystore_entry_type); |
| return rc; |
| } |
| |
| switch (*obj_type) { |
| case BLE_STORE_OBJ_TYPE_PEER_SEC: |
| case BLE_STORE_OBJ_TYPE_OUR_SEC: |
| out->sec.peer_addr.type = parse_arg_kv("addr_type", cmd_addr_type, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'addr_type' parameter\n"); |
| help_cmd_kv("addr_type", cmd_addr_type); |
| return rc; |
| } |
| |
| rc = parse_arg_mac("addr", out->sec.peer_addr.val); |
| if (rc != 0) { |
| console_printf("invalid 'addr' parameter\n"); |
| help_cmd_byte_stream_exact_length("addr", 6); |
| return rc; |
| } |
| |
| out->sec.ediv = parse_arg_uint16("ediv", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'ediv' parameter\n"); |
| help_cmd_uint16("ediv"); |
| return rc; |
| } |
| |
| out->sec.rand_num = parse_arg_uint64("rand", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'rand' parameter\n"); |
| help_cmd_uint64("rand"); |
| return rc; |
| } |
| return 0; |
| |
| default: |
| return EINVAL; |
| } |
| } |
| |
| static void |
| bletiny_keystore_parse_valuedata_help(void) |
| { |
| console_printf("Available keystore parse valuedata params: \n"); |
| help_cmd_byte_stream_exact_length("ltk", 16); |
| help_cmd_byte_stream_exact_length("irk", 16); |
| help_cmd_byte_stream_exact_length("csrk", 16); |
| } |
| |
| static int |
| cmd_keystore_parse_valuedata(int argc, char **argv, |
| int obj_type, |
| union ble_store_key *key, |
| union ble_store_value *out) |
| { |
| int rc; |
| int valcnt = 0; |
| memset(out, 0, sizeof(*out)); |
| |
| switch (obj_type) { |
| case BLE_STORE_OBJ_TYPE_PEER_SEC: |
| case BLE_STORE_OBJ_TYPE_OUR_SEC: |
| rc = parse_arg_byte_stream_exact_length("ltk", out->sec.ltk, 16); |
| if (rc == 0) { |
| out->sec.ltk_present = 1; |
| swap_in_place(out->sec.ltk, 16); |
| valcnt++; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'ltk' parameter\n"); |
| help_cmd_byte_stream_exact_length("ltk", 16); |
| return rc; |
| } |
| rc = parse_arg_byte_stream_exact_length("irk", out->sec.irk, 16); |
| if (rc == 0) { |
| out->sec.irk_present = 1; |
| swap_in_place(out->sec.irk, 16); |
| valcnt++; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'irk' parameter\n"); |
| help_cmd_byte_stream_exact_length("irk", 16); |
| return rc; |
| } |
| rc = parse_arg_byte_stream_exact_length("csrk", out->sec.csrk, 16); |
| if (rc == 0) { |
| out->sec.csrk_present = 1; |
| swap_in_place(out->sec.csrk, 16); |
| valcnt++; |
| } else if (rc != ENOENT) { |
| console_printf("invalid 'csrk' parameter\n"); |
| help_cmd_byte_stream_exact_length("csrk", 16); |
| return rc; |
| } |
| out->sec.peer_addr = key->sec.peer_addr; |
| out->sec.ediv = key->sec.ediv; |
| out->sec.rand_num = key->sec.rand_num; |
| break; |
| } |
| |
| if (valcnt) { |
| return 0; |
| } |
| return -1; |
| } |
| |
| static void |
| bletiny_keystore_add_help(void) |
| { |
| console_printf("Available keystore add commands: \n"); |
| console_printf("\thelp\n"); |
| bletiny_keystore_parse_keydata_help(); |
| bletiny_keystore_parse_valuedata_help(); |
| } |
| |
| static int |
| cmd_keystore_add(int argc, char **argv) |
| { |
| union ble_store_key key; |
| union ble_store_value value; |
| int obj_type; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_keystore_add_help(); |
| return 0; |
| } |
| |
| rc = cmd_keystore_parse_keydata(argc, argv, &key, &obj_type); |
| |
| if (rc) { |
| return rc; |
| } |
| |
| rc = cmd_keystore_parse_valuedata(argc, argv, obj_type, &key, &value); |
| |
| if (rc) { |
| return rc; |
| } |
| |
| switch(obj_type) { |
| case BLE_STORE_OBJ_TYPE_PEER_SEC: |
| rc = ble_store_write_peer_sec(&value.sec); |
| break; |
| case BLE_STORE_OBJ_TYPE_OUR_SEC: |
| rc = ble_store_write_our_sec(&value.sec); |
| break; |
| case BLE_STORE_OBJ_TYPE_CCCD: |
| rc = ble_store_write_cccd(&value.cccd); |
| break; |
| default: |
| rc = ble_store_write(obj_type, &value); |
| } |
| return rc; |
| } |
| |
| static void |
| bletiny_keystore_del_help(void) |
| { |
| console_printf("Available keystore del commands: \n"); |
| console_printf("\thelp\n"); |
| bletiny_keystore_parse_keydata_help(); |
| } |
| |
| static int |
| cmd_keystore_del(int argc, char **argv) |
| { |
| union ble_store_key key; |
| int obj_type; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_keystore_del_help(); |
| return 0; |
| } |
| |
| rc = cmd_keystore_parse_keydata(argc, argv, &key, &obj_type); |
| |
| if (rc) { |
| return rc; |
| } |
| rc = ble_store_delete(obj_type, &key); |
| return rc; |
| } |
| |
| static int |
| cmd_keystore_iterator(int obj_type, |
| union ble_store_value *val, |
| void *cookie) { |
| |
| switch (obj_type) { |
| case BLE_STORE_OBJ_TYPE_PEER_SEC: |
| case BLE_STORE_OBJ_TYPE_OUR_SEC: |
| console_printf("Key: "); |
| if (ble_addr_cmp(&val->sec.peer_addr, BLE_ADDR_ANY) == 0) { |
| console_printf("ediv=%u ", val->sec.ediv); |
| console_printf("ediv=%llu ", val->sec.rand_num); |
| } else { |
| console_printf("addr_type=%u ", val->sec.peer_addr.type); |
| print_addr(val->sec.peer_addr.val); |
| } |
| console_printf("\n"); |
| |
| if (val->sec.ltk_present) { |
| console_printf(" LTK: "); |
| print_bytes(val->sec.ltk, 16); |
| console_printf("\n"); |
| } |
| if (val->sec.irk_present) { |
| console_printf(" IRK: "); |
| print_bytes(val->sec.irk, 16); |
| console_printf("\n"); |
| } |
| if (val->sec.csrk_present) { |
| console_printf(" CSRK: "); |
| print_bytes(val->sec.csrk, 16); |
| console_printf("\n"); |
| } |
| break; |
| } |
| return 0; |
| } |
| |
| static void |
| bletiny_keystore_show_help(void) |
| { |
| console_printf("Available keystore show commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available keystore show params: \n"); |
| help_cmd_kv("type", cmd_keystore_entry_type); |
| } |
| |
| static int |
| cmd_keystore_show(int argc, char **argv) |
| { |
| int type; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_keystore_show_help(); |
| return 0; |
| } |
| |
| type = parse_arg_kv("type", cmd_keystore_entry_type, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'type' parameter\n"); |
| help_cmd_kv("type", cmd_keystore_entry_type); |
| return rc; |
| } |
| |
| ble_store_iterate(type, &cmd_keystore_iterator, NULL); |
| return 0; |
| } |
| |
| static struct cmd_entry cmd_keystore_entries[]; |
| |
| static int |
| cmd_keystore_help(int argc, char **argv) |
| { |
| int i; |
| |
| console_printf("Available keystore commands:\n"); |
| for (i = 0; cmd_keystore_entries[i].name != NULL; i++) { |
| console_printf("\t%s\n", cmd_keystore_entries[i].name); |
| } |
| return 0; |
| } |
| |
| static struct cmd_entry cmd_keystore_entries[] = { |
| { "add", cmd_keystore_add }, |
| { "del", cmd_keystore_del }, |
| { "show", cmd_keystore_show }, |
| { "help", cmd_keystore_help }, |
| { NULL, NULL } |
| }; |
| |
| static int |
| cmd_keystore(int argc, char **argv) |
| { |
| int rc; |
| |
| rc = cmd_exec(cmd_keystore_entries, argc, argv); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $passkey * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_passkey_help(void) |
| { |
| console_printf("Available passkey commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available passkey params: \n"); |
| help_cmd_uint16("conn"); |
| help_cmd_uint16("action"); |
| help_cmd_long_bounds("key", 0, 999999); |
| help_cmd_byte_stream_exact_length("oob", 16); |
| help_cmd_extract("yesno"); |
| } |
| |
| static int |
| cmd_passkey(int argc, char **argv) |
| { |
| #if !NIMBLE_BLE_SM |
| return BLE_HS_ENOTSUP; |
| #endif |
| |
| uint16_t conn_handle; |
| struct ble_sm_io pk; |
| char *yesno; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_passkey_help(); |
| return 0; |
| } |
| |
| conn_handle = parse_arg_uint16("conn", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'conn' parameter\n"); |
| help_cmd_uint16("conn"); |
| return rc; |
| } |
| |
| pk.action = parse_arg_uint16("action", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'action' parameter\n"); |
| help_cmd_uint16("action"); |
| return rc; |
| } |
| |
| switch (pk.action) { |
| case BLE_SM_IOACT_INPUT: |
| case BLE_SM_IOACT_DISP: |
| /* passkey is 6 digit number */ |
| pk.passkey = parse_arg_long_bounds("key", 0, 999999, &rc); |
| if (rc != 0) { |
| console_printf("invalid 'key' parameter\n"); |
| help_cmd_long_bounds("key", 0, 999999); |
| return rc; |
| } |
| break; |
| |
| case BLE_SM_IOACT_OOB: |
| rc = parse_arg_byte_stream_exact_length("oob", pk.oob, 16); |
| if (rc != 0) { |
| console_printf("invalid 'oob' parameter\n"); |
| help_cmd_byte_stream_exact_length("oob", 16); |
| return rc; |
| } |
| break; |
| |
| case BLE_SM_IOACT_NUMCMP: |
| yesno = parse_arg_extract("yesno"); |
| if (yesno == NULL) { |
| console_printf("invalid 'yesno' parameter\n"); |
| help_cmd_extract("yesno"); |
| return EINVAL; |
| } |
| |
| switch (yesno[0]) { |
| case 'y': |
| case 'Y': |
| pk.numcmp_accept = 1; |
| break; |
| case 'n': |
| case 'N': |
| pk.numcmp_accept = 0; |
| break; |
| |
| default: |
| console_printf("invalid 'yesno' parameter\n"); |
| help_cmd_extract("yesno"); |
| return EINVAL; |
| } |
| break; |
| |
| default: |
| console_printf("invalid passkey action action=%d\n", pk.action); |
| return EINVAL; |
| } |
| |
| rc = ble_sm_inject_io(conn_handle, &pk); |
| if (rc != 0) { |
| console_printf("error providing passkey; rc=%d\n", rc); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $tx * |
| * * |
| * Command to transmit 'num' packets of size 'len' at rate 'r' to |
| * handle 'h' Note that length must be <= 251. The rate is in msecs. |
| * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_tx_help(void) |
| { |
| console_printf("Available tx commands: \n"); |
| console_printf("\thelp\n"); |
| console_printf("Available tx params: \n"); |
| help_cmd_uint16("r"); |
| help_cmd_uint16("l"); |
| help_cmd_uint16("n"); |
| help_cmd_uint16("h"); |
| } |
| |
| static int |
| cmd_tx(int argc, char **argv) |
| { |
| int rc; |
| uint16_t rate; |
| uint16_t len; |
| uint16_t handle; |
| uint16_t num; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_tx_help(); |
| return 0; |
| } |
| |
| rate = parse_arg_uint16("r", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'r' parameter\n"); |
| help_cmd_uint16("r"); |
| return rc; |
| } |
| |
| len = parse_arg_uint16("l", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'l' parameter\n"); |
| help_cmd_uint16("l"); |
| return rc; |
| } |
| if ((len > 251) || (len < 4)) { |
| console_printf("error: len must be between 4 and 251, inclusive"); |
| } |
| |
| num = parse_arg_uint16("n", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'n' parameter\n"); |
| help_cmd_uint16("n"); |
| return rc; |
| } |
| |
| handle = parse_arg_uint16("h", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'h' parameter\n"); |
| help_cmd_uint16("h"); |
| return rc; |
| } |
| |
| rc = bletiny_tx_start(handle, len, rate, num); |
| return rc; |
| } |
| |
| static struct cmd_entry cmd_b_entries[]; |
| |
| static int |
| cmd_help(int argc, char **argv) |
| { |
| int i; |
| |
| console_printf("Available commands:\n"); |
| for (i = 0; cmd_b_entries[i].name != NULL; i++) { |
| console_printf("\t%s\n", cmd_b_entries[i].name); |
| } |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $svcch * |
| *****************************************************************************/ |
| |
| static void |
| bletiny_svcchg_help(void) |
| { |
| console_printf("Available svcchg params: \n"); |
| help_cmd_uint16("start"); |
| help_cmd_uint16("end"); |
| } |
| |
| static int |
| cmd_svcchg(int argc, char **argv) |
| { |
| uint16_t start; |
| uint16_t end; |
| int rc; |
| |
| if (argc > 1 && strcmp(argv[1], "help") == 0) { |
| bletiny_svcchg_help(); |
| return 0; |
| } |
| |
| start = parse_arg_uint16("start", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'start' parameter\n"); |
| help_cmd_uint16("start"); |
| return rc; |
| } |
| |
| end = parse_arg_uint16("end", &rc); |
| if (rc != 0) { |
| console_printf("invalid 'end' parameter\n"); |
| help_cmd_uint16("end"); |
| return rc; |
| } |
| |
| ble_svc_gatt_changed(start, end); |
| |
| return 0; |
| } |
| |
| /***************************************************************************** |
| * $init * |
| *****************************************************************************/ |
| |
| static struct cmd_entry cmd_b_entries[] = { |
| { "adv", cmd_adv }, |
| { "conn", cmd_conn }, |
| { "chrup", cmd_chrup }, |
| { "datalen", cmd_datalen }, |
| { "disc", cmd_disc }, |
| { "find", cmd_find }, |
| { "help", cmd_help }, |
| { "l2cap", cmd_l2cap }, |
| { "mtu", cmd_mtu }, |
| { "passkey", cmd_passkey }, |
| { "read", cmd_read }, |
| { "rssi", cmd_rssi }, |
| { "scan", cmd_scan }, |
| { "show", cmd_show }, |
| { "sec", cmd_sec }, |
| { "set", cmd_set }, |
| { "store", cmd_keystore }, |
| { "term", cmd_term }, |
| { "update", cmd_update }, |
| { "tx", cmd_tx }, |
| { "wl", cmd_wl }, |
| { "write", cmd_write }, |
| { "svcchg", cmd_svcchg }, |
| { NULL, NULL } |
| }; |
| |
| static int |
| cmd_b_exec(int argc, char **argv) |
| { |
| int rc; |
| |
| rc = parse_arg_all(argc - 1, argv + 1); |
| if (rc != 0) { |
| goto done; |
| } |
| |
| rc = cmd_exec(cmd_b_entries, argc, argv); |
| if (rc != 0) { |
| console_printf("error; rc=%d\n", rc); |
| goto done; |
| } |
| |
| rc = 0; |
| |
| done: |
| return rc; |
| } |
| |
| int |
| cmd_init(void) |
| { |
| int rc; |
| |
| rc = shell_cmd_register(&cmd_b); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |